summaryrefslogtreecommitdiff
path: root/chromium/chrome/common
diff options
context:
space:
mode:
authorThe Qt Project <gerrit-noreply@qt-project.org>2020-03-11 10:00:21 +0000
committerThe Qt Project <gerrit-noreply@qt-project.org>2020-03-11 10:00:21 +0000
commit7dac0dcbe24b3fe53a575342b848eb2a127a199e (patch)
tree3a4a7d3590dfa31296b3b345f539eccc85295aa2 /chromium/chrome/common
parent9ee7f2b72eff3ef35d50db0cb7fa268dcc46adbf (diff)
parent28db9b54de6402bd38770ecc1d620255e9d1e78f (diff)
downloadqtwebengine-chromium-7dac0dcbe24b3fe53a575342b848eb2a127a199e.tar.gz
Merge "Merge remote-tracking branch 'origin/upstream-master' into 79-based" into 79-based
Diffstat (limited to 'chromium/chrome/common')
-rw-r--r--chromium/chrome/common/DEPS70
-rw-r--r--chromium/chrome/common/OWNERS64
-rw-r--r--chromium/chrome/common/all_messages.h28
-rw-r--r--chromium/chrome/common/apps/OWNERS2
-rw-r--r--chromium/chrome/common/apps/platform_apps/OWNERS2
-rw-r--r--chromium/chrome/common/apps/platform_apps/api/arc_apps_private.idl33
-rw-r--r--chromium/chrome/common/apps/platform_apps/api/browser.idl26
-rw-r--r--chromium/chrome/common/apps/platform_apps/api/media_galleries.idl255
-rw-r--r--chromium/chrome/common/apps/platform_apps/api/music_manager_private.idl16
-rw-r--r--chromium/chrome/common/apps/platform_apps/api/sync_file_system.idl199
-rw-r--r--chromium/chrome/common/apps/platform_apps/api/webstore_widget_private.idl24
-rw-r--r--chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc45
-rw-r--r--chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.h19
-rw-r--r--chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.cc65
-rw-r--r--chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.h36
-rw-r--r--chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.cc30
-rw-r--r--chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.h11
-rw-r--r--chromium/chrome/common/apps/platform_apps/chrome_apps_messages.h15
-rw-r--r--chromium/chrome/common/apps/platform_apps/media_galleries_permission.cc157
-rw-r--r--chromium/chrome/common/apps/platform_apps/media_galleries_permission.h63
-rw-r--r--chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.cc60
-rw-r--r--chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.h50
-rw-r--r--chromium/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc304
-rw-r--r--chromium/chrome/common/attrition_experiments.h26
-rw-r--r--chromium/chrome/common/auto_start_linux.cc95
-rw-r--r--chromium/chrome/common/auto_start_linux.h33
-rw-r--r--chromium/chrome/common/cast_messages.cc55
-rw-r--r--chromium/chrome/common/cast_messages.h254
-rw-r--r--chromium/chrome/common/channel_info.cc16
-rw-r--r--chromium/chrome/common/channel_info.h66
-rw-r--r--chromium/chrome/common/channel_info_android.cc31
-rw-r--r--chromium/chrome/common/channel_info_chromeos.cc75
-rw-r--r--chromium/chrome/common/channel_info_mac.mm63
-rw-r--r--chromium/chrome/common/channel_info_posix.cc100
-rw-r--r--chromium/chrome/common/channel_info_win.cc33
-rw-r--r--chromium/chrome/common/child_process_logging.h19
-rw-r--r--chromium/chrome/common/child_process_logging_win.cc32
-rw-r--r--chromium/chrome/common/chrome_constants_win_unittest.cc32
-rw-r--r--chromium/chrome/common/chrome_content_client.cc853
-rw-r--r--chromium/chrome/common/chrome_content_client.h115
-rw-r--r--chromium/chrome/common/chrome_content_client_constants.cc28
-rw-r--r--chromium/chrome/common/chrome_content_client_unittest.cc180
-rw-r--r--chromium/chrome/common/chrome_descriptors.h23
-rw-r--r--chromium/chrome/common/chrome_features.cc894
-rw-r--r--chromium/chrome/common/chrome_features.h552
-rw-r--r--chromium/chrome/common/chrome_icon_resources_win.h50
-rw-r--r--chromium/chrome/common/chrome_isolated_world_ids.h29
-rw-r--r--chromium/chrome/common/chrome_result_codes.h121
-rw-r--r--chromium/chrome/common/chrome_utility_printing_messages.h99
-rw-r--r--chromium/chrome/common/chrome_version.h.in20
-rw-r--r--chromium/chrome/common/client_hints/OWNERS8
-rw-r--r--chromium/chrome/common/client_hints/client_hints.cc66
-rw-r--r--chromium/chrome/common/client_hints/client_hints.h28
-rw-r--r--chromium/chrome/common/cloud_print/OWNERS5
-rw-r--r--chromium/chrome/common/cloud_print/cloud_print_class_mac.h17
-rw-r--r--chromium/chrome/common/cloud_print/cloud_print_class_mac.mm11
-rw-r--r--chromium/chrome/common/cloud_print/cloud_print_constants.cc79
-rw-r--r--chromium/chrome/common/cloud_print/cloud_print_constants.h135
-rw-r--r--chromium/chrome/common/cloud_print/cloud_print_helpers.cc240
-rw-r--r--chromium/chrome/common/cloud_print/cloud_print_helpers.h86
-rw-r--r--chromium/chrome/common/cloud_print/cloud_print_helpers_unittest.cc131
-rw-r--r--chromium/chrome/common/cloud_print/cloud_print_proxy_info.cc14
-rw-r--r--chromium/chrome/common/cloud_print/cloud_print_proxy_info.h24
-rw-r--r--chromium/chrome/common/common.vsprops8
-rw-r--r--chromium/chrome/common/common_message_generator.cc33
-rw-r--r--chromium/chrome/common/common_message_generator.h51
-rw-r--r--chromium/chrome/common/common_param_traits.cc27
-rw-r--r--chromium/chrome/common/common_param_traits.h13
-rw-r--r--chromium/chrome/common/common_param_traits_macros.h16
-rw-r--r--chromium/chrome/common/component_flash_hint_file_linux.cc229
-rw-r--r--chromium/chrome/common/component_flash_hint_file_linux.h49
-rw-r--r--chromium/chrome/common/component_flash_hint_file_linux_unittest.cc168
-rw-r--r--chromium/chrome/common/conflicts/OWNERS8
-rw-r--r--chromium/chrome/common/conflicts/module_watcher_win.cc266
-rw-r--r--chromium/chrome/common/conflicts/module_watcher_win.h149
-rw-r--r--chromium/chrome/common/conflicts/module_watcher_win_unittest.cc119
-rw-r--r--chromium/chrome/common/conflicts/remote_module_watcher_win.cc84
-rw-r--r--chromium/chrome/common/conflicts/remote_module_watcher_win.h87
-rw-r--r--chromium/chrome/common/conflicts/remote_module_watcher_win_unittest.cc122
-rw-r--r--chromium/chrome/common/crash_keys.cc118
-rw-r--r--chromium/chrome/common/crash_keys.h34
-rw-r--r--chromium/chrome/common/crash_keys_unittest.cc111
-rw-r--r--chromium/chrome/common/env_vars.cc36
-rw-r--r--chromium/chrome/common/env_vars.h23
-rw-r--r--chromium/chrome/common/extensions/DEPS18
-rw-r--r--chromium/chrome/common/extensions/OWNERS13
-rw-r--r--chromium/chrome/common/extensions/PRESUBMIT.py169
-rwxr-xr-xchromium/chrome/common/extensions/PRESUBMIT_test.py75
-rw-r--r--chromium/chrome/common/extensions/chrome_extensions_api_provider.cc67
-rw-r--r--chromium/chrome/common/extensions/chrome_extensions_api_provider.h35
-rw-r--r--chromium/chrome/common/extensions/chrome_extensions_client.cc257
-rw-r--r--chromium/chrome/common/extensions/chrome_extensions_client.h70
-rw-r--r--chromium/chrome/common/extensions/chrome_extensions_client_unittest.cc93
-rw-r--r--chromium/chrome/common/extensions/chrome_manifest_handlers.cc79
-rw-r--r--chromium/chrome/common/extensions/chrome_manifest_handlers.h16
-rw-r--r--chromium/chrome/common/extensions/chrome_manifest_url_handlers.cc187
-rw-r--r--chromium/chrome/common/extensions/chrome_manifest_url_handlers.h70
-rw-r--r--chromium/chrome/common/extensions/chrome_manifest_url_handlers_unittest.cc39
-rw-r--r--chromium/chrome/common/extensions/command.cc542
-rw-r--r--chromium/chrome/common/extensions/command.h87
-rw-r--r--chromium/chrome/common/extensions/command_unittest.cc348
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/bookmarks/basic/manifest.json15
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/browserAction/make_page_red/manifest.json16
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/browserAction/print/manifest.json17
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/browserAction/set_icon_path/manifest.json14
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/browserAction/set_page_color/manifest.json14
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/browsingData/basic/manifest.json13
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/commands/manifest.json28
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/contentSettings/manifest.json11
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/contextMenus/basic/manifest.json10
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/contextMenus/event_page/manifest.json11
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/contextMenus/global_context_search/manifest.json20
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/cookies/manifest.json14
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/debugger/live-headers/manifest.json17
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/debugger/pause-resume/manifest.json16
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/default_command_override/manifest.json36
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/desktopCapture/manifest.json19
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/deviceInfo/basic/manifest.json15
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/devtools/network/chrome-firephp/manifest.json13
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/devtools/panels/chrome-query/manifest.json7
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/displaySource/tabCast/manifest.json17
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/document_scan/manifest.json13
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/manifest.json8
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/downloads/download_links/manifest.json9
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json290
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json15
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/downloads/download_open/_locales/en/messages.json9
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/downloads/download_open/manifest.json8
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/downloads/downloads_overwrite/manifest.json14
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/eventPage/basic/manifest.json24
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/manifest.json16
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/fileSystemProvider/archive/manifest.json28
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/fileSystemProvider/basic/manifest.json18
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/fontSettings/manifest.json12
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/history/historyOverride/manifest.json22
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/history/showHistory/manifest.json13
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/i18n/cld/manifest.json12
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/i18n/detectLanguage/manifest.json12
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/en_US/messages.json27
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/es/messages.json27
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/sr/messages.json24
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/manifest.json12
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/_locales/de/messages.json8
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/_locales/en/messages.json10
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/manifest.json15
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/idle/idle_simple/manifest.json18
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/input.ime/basic/manifest.json22
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/messaging/timer/manifest.json17
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/app/manifest.json19
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/host/com.google.chrome.example.echo-win.json13
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/host/com.google.chrome.example.echo.json13
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/notifications/manifest.json18
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/omnibox/newtab_search/manifest.json23
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/omnibox/simple-example/manifest.json11
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/override/blank_ntp/manifest.json10
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/override/override_igoogle/manifest.json9
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/pageAction/pageaction_by_content/manifest.json20
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/pageAction/pageaction_by_url/manifest.json22
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/pageAction/set_icon/manifest.json12
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/permissions/extension-questions/manifest.json17
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/power/_locales/en/messages.json22
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/power/manifest.json30
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/preferences/allowThirdPartyCookies/manifest.json11
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json11
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/processes/process_monitor/manifest.json14
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/processes/show_tabs/manifest.json14
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/storage/stylizr/manifest.json20
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/tabCapture/manifest.json22
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/tabs/inspector/manifest.json14
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/tabs/pin/manifest.json16
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/tabs/screenshot/manifest.json17
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/tabs/zoom/manifest.json24
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/topsites/basic/manifest.json11
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/topsites/magic8ball/manifest.json13
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/ttsEngine/console_tts_engine/manifest.json19
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/water_alarm_notification/manifest.json21
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json52
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json18
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/webview/capturevisibleregion/manifest.json22
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/webview/comm_demo_app/manifest.json19
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/webview/comm_demo_ext/manifest.json13
-rw-r--r--chromium/chrome/common/extensions/docs/examples/api/windows/merge_windows/manifest.json18
-rw-r--r--chromium/chrome/common/extensions/docs/examples/apps/background-simple/manifest.json12
-rw-r--r--chromium/chrome/common/extensions/docs/examples/apps/calculator/app/manifest.json12
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/app_launcher/manifest.json15
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/buildbot/manifest.json31
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ar/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/bg/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ca/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/cs/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/da/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/de/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/el/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/en/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/en_GB/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/es/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/es_419/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/et/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fi/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fil/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fr/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/he/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hi/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hr/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hu/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/id/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/it/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ja/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ko/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/lt/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/lv/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/nb/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/nl/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pl/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pt_BR/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pt_PT/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ro/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ru/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sk/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sl/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sr/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sv/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/th/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/tr/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/uk/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/vi/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/zh_CN/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/zh_TW/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/calendar/manifest.json31
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/catblock/manifest.json12
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/catifier/manifest.json12
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json13
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/constant_context/manifest.json37
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/download_images/manifest.json32
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/email_this_page/manifest.json20
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/fx/manifest.json22
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gdocs/manifest.json25
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ar/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/bg/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ca/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/cs/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/da/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/de/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/el/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/en/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/en_GB/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/es/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/es_419/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/et/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fi/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fil/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fr/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/he/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hi/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hr/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hu/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/id/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/it/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ja/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ko/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/lt/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/lv/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/nb/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/nl/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pl/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pt_BR/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pt_PT/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ro/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ru/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sk/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sl/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sr/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sv/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/th/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/tr/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/uk/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/vi/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/zh_CN/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/zh_TW/messages.json1
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/gmail/manifest.json23
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/imageinfo/manifest.json19
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/irc/app/manifest.json11
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/_locales/en/messages.json10
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/manifest.json18
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/schema.json36
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/mappy/manifest.json28
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/maps_app/manifest.json15
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/news/_locales/en/messages.json102
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/news/manifest.json20
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/news_a11y/manifest.json17
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/en/messages.json63
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/es/messages.json63
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/sr/messages.json59
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/manifest.json17
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/no_cookies/manifest.json15
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/oauth_contacts/manifest.json26
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/optional_permissions/manifest.json19
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/plugin_settings/_locales/en/messages.json23
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/plugin_settings/manifest.json16
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/proxy_configuration/_locales/en/messages.json54
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/proxy_configuration/manifest.json27
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/speak_selection/manifest.json49
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/talking_alarm_clock/manifest.json23
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/ttsdebug/manifest.json18
-rw-r--r--chromium/chrome/common/extensions/docs/examples/extensions/ttsdemo/manifest.json19
-rw-r--r--chromium/chrome/common/extensions/docs/examples/howto/sandbox/manifest.json19
-rw-r--r--chromium/chrome/common/extensions/docs/examples/howto/tab_shortcuts/manifest.json26
-rw-r--r--chromium/chrome/common/extensions/docs/examples/tutorials/analytics/manifest.json17
-rw-r--r--chromium/chrome/common/extensions/docs/examples/tutorials/broken_background_color/manifest.json27
-rw-r--r--chromium/chrome/common/extensions/docs/examples/tutorials/get_started/manifest.json6
-rw-r--r--chromium/chrome/common/extensions/docs/examples/tutorials/get_started_complete/manifest.json27
-rw-r--r--chromium/chrome/common/extensions/docs/examples/tutorials/getstarted/manifest.json16
-rw-r--r--chromium/chrome/common/extensions/docs/examples/tutorials/hello_extensions/manifest.json19
-rw-r--r--chromium/chrome/common/extensions/docs/examples/tutorials/oauth_starter/manifest.json15
-rw-r--r--chromium/chrome/common/extensions/docs/examples/tutorials/oauth_tutorial_complete/manifest.json23
-rw-r--r--chromium/chrome/common/extensions/docs/server2/known_broken_links.json2019
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/branch_utility/first.json310
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/branch_utility/second.json1
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/file_system/stat_result.json86
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/github_file_system/expected_list.json41
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/expected/extensions_sidenav.json6
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/samples_data_source/expected.json10
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/samples_data_source/samples.json24
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/input.json7
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_def_test.json19
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/test_json/expected_tester.json218
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/test_json/ref_test_data_source.json23
-rw-r--r--chromium/chrome/common/extensions/docs/server2/test_data/test_json/test_file_data_source.json13
-rw-r--r--chromium/chrome/common/extensions/docs/templates/json/api_availabilities.json51
-rw-r--r--chromium/chrome/common/extensions/docs/templates/json/apps_sidenav.json278
-rw-r--r--chromium/chrome/common/extensions/docs/templates/json/chrome_sidenav.json834
-rw-r--r--chromium/chrome/common/extensions/docs/templates/json/content_providers.json105
-rw-r--r--chromium/chrome/common/extensions/docs/templates/json/extensions_sidenav.json222
-rw-r--r--chromium/chrome/common/extensions/docs/templates/json/intro_tables.json333
-rw-r--r--chromium/chrome/common/extensions/docs/templates/json/manifest.json252
-rw-r--r--chromium/chrome/common/extensions/docs/templates/json/permissions.json69
-rw-r--r--chromium/chrome/common/extensions/docs/templates/json/strings.json42
-rw-r--r--chromium/chrome/common/extensions/docs/templates/json/whats_new.json367
-rw-r--r--chromium/chrome/common/extensions/docs/templates/public/apps/redirects.json33
-rw-r--r--chromium/chrome/common/extensions/docs/templates/public/extensions/redirects.json20
-rw-r--r--chromium/chrome/common/extensions/docs/templates/public/redirects.json4
-rw-r--r--chromium/chrome/common/extensions/extension_constants.cc132
-rw-r--r--chromium/chrome/common/extensions/extension_constants.h272
-rw-r--r--chromium/chrome/common/extensions/extension_metrics.cc50
-rw-r--r--chromium/chrome/common/extensions/extension_metrics.h30
-rw-r--r--chromium/chrome/common/extensions/extension_test_util.cc115
-rw-r--r--chromium/chrome/common/extensions/extension_test_util.h70
-rw-r--r--chromium/chrome/common/extensions/extension_unittest.cc447
-rw-r--r--chromium/chrome/common/extensions/feature_switch_unittest.cc132
-rw-r--r--chromium/chrome/common/extensions/image_writer/OWNERS1
-rw-r--r--chromium/chrome/common/extensions/image_writer/image_writer_util_mac.cc112
-rw-r--r--chromium/chrome/common/extensions/image_writer/image_writer_util_mac.h24
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/app_icon_color_info.cc86
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/app_icon_color_info.h46
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/app_launch_info.cc330
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/app_launch_info.h85
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/app_theme_color_info.cc68
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/app_theme_color_info.h43
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/app_theme_color_manifest_unittest.cc37
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/automation_unittest.cc292
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/content_scripts_manifest_unittest.cc105
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/exclude_matches_manifest_unittest.cc32
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/extension_action_handler.cc135
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/extension_action_handler.h35
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/extension_action_handler_unittest.cc307
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/linked_app_icons.cc110
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/linked_app_icons.h51
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.cc63
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.h31
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler.cc72
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler.h48
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler_unittest.cc57
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc183
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler.h55
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc202
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/theme_handler.cc224
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/theme_handler.h64
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler.cc181
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler.h64
-rw-r--r--chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler_unittest.cc107
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/chrome_manifest_test.cc23
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/chrome_manifest_test.h35
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_about_unittest.cc30
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_background_unittest.cc261
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_chromepermission_unittest.cc58
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_contentsecuritypolicy_unittest.cc35
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_default_extent_path_unittest.cc17
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_devtools_unittest.cc25
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_dummy_unittest.cc27
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_experimental_unittest.cc27
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_homepage_unittest.cc49
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_icons_unittest.cc53
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc177
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_isolatedapp_unittest.cc34
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc108
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc131
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_manifest_version_unittest.cc54
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_offline_unittest.cc44
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_old_unittest.cc19
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_options_unittest.cc141
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_override_unittest.cc34
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc149
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_portsinpermissions_unittest.cc12
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_requirements_unittest.cc70
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_ui_unittest.cc19
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_update_unittest.cc42
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_validapp_unittest.cc36
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_web_accessible_resources_unittest.cc55
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_web_unittest.cc52
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/extension_manifests_webview_accessible_resources_unittest.cc85
-rw-r--r--chromium/chrome/common/extensions/manifest_tests/permissions_parser_unittest.cc138
-rw-r--r--chromium/chrome/common/extensions/manifest_unittest.cc222
-rw-r--r--chromium/chrome/common/extensions/sync_helper.cc79
-rw-r--r--chromium/chrome/common/extensions/sync_helper.h29
-rw-r--r--chromium/chrome/common/extensions/sync_type_unittest.cc233
-rw-r--r--chromium/chrome/common/extensions/webstore_install_result.cc20
-rw-r--r--chromium/chrome/common/extensions/webstore_install_result.h87
-rw-r--r--chromium/chrome/common/extra_defines.vsprops7
-rw-r--r--chromium/chrome/common/google_url_loader_throttle.cc114
-rw-r--r--chromium/chrome/common/google_url_loader_throttle.h43
-rw-r--r--chromium/chrome/common/heap_profiler_controller.cc114
-rw-r--r--chromium/chrome/common/heap_profiler_controller.h34
-rw-r--r--chromium/chrome/common/heap_profiler_controller_unittest.cc91
-rw-r--r--chromium/chrome/common/importer/DEPS3
-rw-r--r--chromium/chrome/common/importer/OWNERS13
-rw-r--r--chromium/chrome/common/importer/edge_importer_utils_win.cc91
-rw-r--r--chromium/chrome/common/importer/edge_importer_utils_win.h28
-rw-r--r--chromium/chrome/common/importer/firefox_importer_utils.cc330
-rw-r--r--chromium/chrome/common/importer/firefox_importer_utils.h92
-rw-r--r--chromium/chrome/common/importer/firefox_importer_utils_linux.cc25
-rw-r--r--chromium/chrome/common/importer/firefox_importer_utils_mac.mm45
-rw-r--r--chromium/chrome/common/importer/firefox_importer_utils_unittest.cc163
-rw-r--r--chromium/chrome/common/importer/firefox_importer_utils_win.cc82
-rw-r--r--chromium/chrome/common/importer/ie_importer_utils_win.cc48
-rw-r--r--chromium/chrome/common/importer/ie_importer_utils_win.h26
-rw-r--r--chromium/chrome/common/importer/imported_bookmark_entry.cc24
-rw-r--r--chromium/chrome/common/importer/imported_bookmark_entry.h29
-rw-r--r--chromium/chrome/common/importer/importer_autofill_form_data_entry.cc11
-rw-r--r--chromium/chrome/common/importer/importer_autofill_form_data_entry.h33
-rw-r--r--chromium/chrome/common/importer/importer_bridge.cc9
-rw-r--r--chromium/chrome/common/importer/importer_bridge.h89
-rw-r--r--chromium/chrome/common/importer/importer_data_types.cc32
-rw-r--r--chromium/chrome/common/importer/importer_data_types.h90
-rw-r--r--chromium/chrome/common/importer/importer_test_registry_overrider_win.cc70
-rw-r--r--chromium/chrome/common/importer/importer_test_registry_overrider_win.h34
-rw-r--r--chromium/chrome/common/importer/importer_type.h36
-rw-r--r--chromium/chrome/common/importer/importer_url_row.cc21
-rw-r--r--chromium/chrome/common/importer/importer_url_row.h39
-rw-r--r--chromium/chrome/common/importer/mock_importer_bridge.cc9
-rw-r--r--chromium/chrome/common/importer/mock_importer_bridge.h45
-rw-r--r--chromium/chrome/common/importer/profile_import_process_param_traits.cc33
-rw-r--r--chromium/chrome/common/importer/profile_import_process_param_traits.h10
-rw-r--r--chromium/chrome/common/importer/profile_import_process_param_traits_macros.h94
-rw-r--r--chromium/chrome/common/importer/pstore_declarations.h188
-rw-r--r--chromium/chrome/common/importer/safari_importer_utils.h22
-rw-r--r--chromium/chrome/common/importer/safari_importer_utils.mm29
-rw-r--r--chromium/chrome/common/ini_parser.cc64
-rw-r--r--chromium/chrome/common/ini_parser.h64
-rw-r--r--chromium/chrome/common/ini_parser_unittest.cc130
-rw-r--r--chromium/chrome/common/initialize_extensions_client.cc33
-rw-r--r--chromium/chrome/common/initialize_extensions_client.h18
-rw-r--r--chromium/chrome/common/instant_mojom_traits.h90
-rw-r--r--chromium/chrome/common/logging_chrome.cc434
-rw-r--r--chromium/chrome/common/logging_chrome.h72
-rw-r--r--chromium/chrome/common/mac/DEPS3
-rw-r--r--chromium/chrome/common/mac/OWNERS15
-rw-r--r--chromium/chrome/common/mac/app_mode_chrome_locator.h40
-rw-r--r--chromium/chrome/common/mac/app_mode_chrome_locator.mm153
-rw-r--r--chromium/chrome/common/mac/app_mode_chrome_locator_browsertest.mm133
-rw-r--r--chromium/chrome/common/mac/app_mode_common.h187
-rw-r--r--chromium/chrome/common/mac/app_mode_common.mm73
-rw-r--r--chromium/chrome/common/mac/app_shim_launch.h61
-rw-r--r--chromium/chrome/common/mac/app_shim_param_traits.h26
-rw-r--r--chromium/chrome/common/mac/launchd.h95
-rw-r--r--chromium/chrome/common/mac/launchd.mm165
-rw-r--r--chromium/chrome/common/mac/mock_launchd.h77
-rw-r--r--chromium/chrome/common/mac/mock_launchd.mm168
-rw-r--r--chromium/chrome/common/mac/service_management.h72
-rw-r--r--chromium/chrome/common/mac/service_management.mm217
-rw-r--r--chromium/chrome/common/mac/staging_watcher.h72
-rw-r--r--chromium/chrome/common/mac/staging_watcher.mm191
-rw-r--r--chromium/chrome/common/mac/staging_watcher_unittest.mm181
-rw-r--r--chromium/chrome/common/media/OWNERS9
-rw-r--r--chromium/chrome/common/media/cdm_host_file_path.cc123
-rw-r--r--chromium/chrome/common/media/cdm_host_file_path.h16
-rw-r--r--chromium/chrome/common/media/cdm_manifest.cc372
-rw-r--r--chromium/chrome/common/media/cdm_manifest.h42
-rw-r--r--chromium/chrome/common/media/cdm_manifest_unittest.cc542
-rw-r--r--chromium/chrome/common/media/chrome_media_drm_bridge_client.cc17
-rw-r--r--chromium/chrome/common/media/chrome_media_drm_bridge_client.h29
-rw-r--r--chromium/chrome/common/media/component_widevine_cdm_hint_file_linux.cc89
-rw-r--r--chromium/chrome/common/media/component_widevine_cdm_hint_file_linux.h57
-rw-r--r--chromium/chrome/common/media/component_widevine_cdm_hint_file_linux_unittest.cc119
-rw-r--r--chromium/chrome/common/media/media_resource_provider.cc31
-rw-r--r--chromium/chrome/common/media/media_resource_provider.h15
-rw-r--r--chromium/chrome/common/media_galleries/OWNERS2
-rw-r--r--chromium/chrome/common/media_galleries/metadata_types.h19
-rw-r--r--chromium/chrome/common/media_router/OWNERS2
-rw-r--r--chromium/chrome/common/media_router/discovery/DEPS3
-rw-r--r--chromium/chrome/common/media_router/discovery/media_sink_internal.cc211
-rw-r--r--chromium/chrome/common/media_router/discovery/media_sink_internal.h142
-rw-r--r--chromium/chrome/common/media_router/discovery/media_sink_internal_unittest.cc141
-rw-r--r--chromium/chrome/common/media_router/discovery/media_sink_service_base.cc125
-rw-r--r--chromium/chrome/common/media_router/discovery/media_sink_service_base.h135
-rw-r--r--chromium/chrome/common/media_router/discovery/media_sink_service_base_unittest.cc147
-rw-r--r--chromium/chrome/common/media_router/discovery/media_sink_service_util.cc29
-rw-r--r--chromium/chrome/common/media_router/discovery/media_sink_service_util.h44
-rw-r--r--chromium/chrome/common/media_router/issue.cc50
-rw-r--r--chromium/chrome/common/media_router/issue.h102
-rw-r--r--chromium/chrome/common/media_router/issue_unittest.cc117
-rw-r--r--chromium/chrome/common/media_router/media_route.cc64
-rw-r--r--chromium/chrome/common/media_router/media_route.h144
-rw-r--r--chromium/chrome/common/media_router/media_route_provider_helper.cc29
-rw-r--r--chromium/chrome/common/media_router/media_route_provider_helper.h27
-rw-r--r--chromium/chrome/common/media_router/media_route_unittest.cc57
-rw-r--r--chromium/chrome/common/media_router/media_sink.cc73
-rw-r--r--chromium/chrome/common/media_router/media_sink.h117
-rw-r--r--chromium/chrome/common/media_router/media_sink_unittest.cc52
-rw-r--r--chromium/chrome/common/media_router/media_source.cc131
-rw-r--r--chromium/chrome/common/media_router/media_source.h122
-rw-r--r--chromium/chrome/common/media_router/media_source_unittest.cc155
-rw-r--r--chromium/chrome/common/media_router/mojom/OWNERS6
-rw-r--r--chromium/chrome/common/media_router/mojom/media_router_mojom_traits.cc226
-rw-r--r--chromium/chrome/common/media_router/mojom/media_router_mojom_traits.h525
-rw-r--r--chromium/chrome/common/media_router/mojom/media_router_mojom_traits_unittest.cc112
-rw-r--r--chromium/chrome/common/media_router/providers/cast/DEPS3
-rw-r--r--chromium/chrome/common/media_router/providers/cast/cast_media_source.cc388
-rw-r--r--chromium/chrome/common/media_router/providers/cast/cast_media_source.h178
-rw-r--r--chromium/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc153
-rw-r--r--chromium/chrome/common/media_router/route_request_result.cc42
-rw-r--r--chromium/chrome/common/media_router/route_request_result.h87
-rw-r--r--chromium/chrome/common/metrics_constants_util_win.cc15
-rw-r--r--chromium/chrome/common/metrics_constants_util_win.h20
-rw-r--r--chromium/chrome/common/multi_process_lock.h33
-rw-r--r--chromium/chrome/common/multi_process_lock_linux.cc111
-rw-r--r--chromium/chrome/common/multi_process_lock_mac.cc59
-rw-r--r--chromium/chrome/common/multi_process_lock_unittest.cc168
-rw-r--r--chromium/chrome/common/multi_process_lock_win.cc63
-rw-r--r--chromium/chrome/common/net/DEPS5
-rw-r--r--chromium/chrome/common/net/OWNERS4
-rw-r--r--chromium/chrome/common/net/net_resource_provider.cc64
-rw-r--r--chromium/chrome/common/net/net_resource_provider.h13
-rw-r--r--chromium/chrome/common/net/safe_search_util.cc113
-rw-r--r--chromium/chrome/common/net/safe_search_util.h55
-rw-r--r--chromium/chrome/common/net/safe_search_util_unittest.cc155
-rw-r--r--chromium/chrome/common/net/x509_certificate_model_nss.cc365
-rw-r--r--chromium/chrome/common/net/x509_certificate_model_nss.h117
-rw-r--r--chromium/chrome/common/net/x509_certificate_model_nss_unittest.cc403
-rw-r--r--chromium/chrome/common/origin_trials/OWNERS3
-rw-r--r--chromium/chrome/common/origin_trials/chrome_origin_trial_policy.cc117
-rw-r--r--chromium/chrome/common/origin_trials/chrome_origin_trial_policy.h41
-rw-r--r--chromium/chrome/common/origin_trials/chrome_origin_trial_policy_unittest.cc262
-rw-r--r--chromium/chrome/common/pdf_util.cc33
-rw-r--r--chromium/chrome/common/pdf_util.h31
-rw-r--r--chromium/chrome/common/pepper_flash.cc155
-rw-r--r--chromium/chrome/common/pepper_flash.h25
-rw-r--r--chromium/chrome/common/pepper_permission_util.cc101
-rw-r--r--chromium/chrome/common/pepper_permission_util.h37
-rw-r--r--chromium/chrome/common/pepper_permission_util_unittest.cc144
-rw-r--r--chromium/chrome/common/performance_manager/OWNERS1
-rw-r--r--chromium/chrome/common/performance_manager/mojom/OWNERS2
-rw-r--r--chromium/chrome/common/plugin_utils.cc23
-rw-r--r--chromium/chrome/common/plugin_utils.h15
-rw-r--r--chromium/chrome/common/ppapi_utils.cc130
-rw-r--r--chromium/chrome/common/ppapi_utils.h12
-rw-r--r--chromium/chrome/common/pref_font_script_names-inl.h163
-rw-r--r--chromium/chrome/common/pref_font_webkit_names.h19
-rw-r--r--chromium/chrome/common/pref_names.cc2815
-rw-r--r--chromium/chrome/common/pref_names.h999
-rw-r--r--chromium/chrome/common/pref_names_util.cc88
-rw-r--r--chromium/chrome/common/pref_names_util.h30
-rw-r--r--chromium/chrome/common/pref_names_util_unittest.cc52
-rw-r--r--chromium/chrome/common/prerender_messages.h67
-rw-r--r--chromium/chrome/common/prerender_types.h25
-rw-r--r--chromium/chrome/common/prerender_url_loader_throttle.cc217
-rw-r--r--chromium/chrome/common/prerender_url_loader_throttle.h83
-rw-r--r--chromium/chrome/common/prerender_util.cc112
-rw-r--r--chromium/chrome/common/prerender_util.h45
-rw-r--r--chromium/chrome/common/process_singleton_lock_posix.cc43
-rw-r--r--chromium/chrome/common/process_singleton_lock_posix.h20
-rw-r--r--chromium/chrome/common/profiler/OWNERS4
-rw-r--r--chromium/chrome/common/profiler/main_thread_stack_sampling_profiler.cc44
-rw-r--r--chromium/chrome/common/profiler/main_thread_stack_sampling_profiler.h35
-rw-r--r--chromium/chrome/common/ref_counted_util.h32
-rw-r--r--chromium/chrome/common/render_messages.h142
-rw-r--r--chromium/chrome/common/safe_browsing/DEPS6
-rw-r--r--chromium/chrome/common/safe_browsing/OWNERS23
-rw-r--r--chromium/chrome/common/safe_browsing/archive_analyzer_results.cc182
-rw-r--r--chromium/chrome/common/safe_browsing/archive_analyzer_results.h55
-rw-r--r--chromium/chrome/common/safe_browsing/binary_feature_extractor.cc71
-rw-r--r--chromium/chrome/common/safe_browsing/binary_feature_extractor.h87
-rw-r--r--chromium/chrome/common/safe_browsing/binary_feature_extractor_fuzzer.cc24
-rw-r--r--chromium/chrome/common/safe_browsing/binary_feature_extractor_mac.cc68
-rw-r--r--chromium/chrome/common/safe_browsing/binary_feature_extractor_mac_unittest.cc75
-rw-r--r--chromium/chrome/common/safe_browsing/binary_feature_extractor_posix.cc30
-rw-r--r--chromium/chrome/common/safe_browsing/binary_feature_extractor_unittest.cc106
-rw-r--r--chromium/chrome/common/safe_browsing/binary_feature_extractor_win.cc173
-rw-r--r--chromium/chrome/common/safe_browsing/binary_feature_extractor_win_unittest.cc210
-rw-r--r--chromium/chrome/common/safe_browsing/client_model.proto97
-rw-r--r--chromium/chrome/common/safe_browsing/crx_info.proto38
-rw-r--r--chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac.cc64
-rw-r--r--chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac.h43
-rw-r--r--chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac_unittest.cc115
-rw-r--r--chromium/chrome/common/safe_browsing/download_file_types.proto80
-rw-r--r--chromium/chrome/common/safe_browsing/download_type_util.cc101
-rw-r--r--chromium/chrome/common/safe_browsing/download_type_util.h21
-rw-r--r--chromium/chrome/common/safe_browsing/download_type_util_unittest.cc31
-rw-r--r--chromium/chrome/common/safe_browsing/file_type_policies.cc273
-rw-r--r--chromium/chrome/common/safe_browsing/file_type_policies.h156
-rw-r--r--chromium/chrome/common/safe_browsing/file_type_policies_test_util.cc36
-rw-r--r--chromium/chrome/common/safe_browsing/file_type_policies_test_util.h41
-rw-r--r--chromium/chrome/common/safe_browsing/file_type_policies_unittest.cc219
-rw-r--r--chromium/chrome/common/safe_browsing/ipc_protobuf_message_macros.h59
-rw-r--r--chromium/chrome/common/safe_browsing/ipc_protobuf_message_null_macros.h19
-rw-r--r--chromium/chrome/common/safe_browsing/ipc_protobuf_message_test.proto19
-rw-r--r--chromium/chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h24
-rw-r--r--chromium/chrome/common/safe_browsing/ipc_protobuf_message_unittest.cc162
-rw-r--r--chromium/chrome/common/safe_browsing/mach_o_image_reader_mac.cc257
-rw-r--r--chromium/chrome/common/safe_browsing/mach_o_image_reader_mac.h107
-rw-r--r--chromium/chrome/common/safe_browsing/mach_o_image_reader_mac_unittest.cc515
-rw-r--r--chromium/chrome/common/safe_browsing/mock_binary_feature_extractor.cc13
-rw-r--r--chromium/chrome/common/safe_browsing/mock_binary_feature_extractor.h34
-rw-r--r--chromium/chrome/common/safe_browsing/pe_image_reader_win.cc390
-rw-r--r--chromium/chrome/common/safe_browsing/pe_image_reader_win.h164
-rw-r--r--chromium/chrome/common/safe_browsing/pe_image_reader_win_unittest.cc294
-rw-r--r--chromium/chrome/common/safe_browsing/protobuf_message_log_macros.h39
-rw-r--r--chromium/chrome/common/safe_browsing/protobuf_message_read_macros.h61
-rw-r--r--chromium/chrome/common/safe_browsing/protobuf_message_write_macros.h33
-rw-r--r--chromium/chrome/common/safe_browsing/rar_analyzer.cc74
-rw-r--r--chromium/chrome/common/safe_browsing/rar_analyzer.h47
-rw-r--r--chromium/chrome/common/safe_browsing/zip_analyzer.cc111
-rw-r--r--chromium/chrome/common/safe_browsing/zip_analyzer.h26
-rw-r--r--chromium/chrome/common/search/OWNERS2
-rw-r--r--chromium/chrome/common/search/chrome_colors_icon_template.h23
-rw-r--r--chromium/chrome/common/search/generate_colors_info.cc120
-rw-r--r--chromium/chrome/common/search/instant_types.cc54
-rw-r--r--chromium/chrome/common/search/instant_types.h188
-rw-r--r--chromium/chrome/common/search/mock_embedded_search_client.cc8
-rw-r--r--chromium/chrome/common/search/mock_embedded_search_client.h24
-rw-r--r--chromium/chrome/common/search/ntp_logging_events.h190
-rw-r--r--chromium/chrome/common/search/selected_colors_info.h65
-rw-r--r--chromium/chrome/common/secure_origin_whitelist.cc27
-rw-r--r--chromium/chrome/common/secure_origin_whitelist.h24
-rw-r--r--chromium/chrome/common/service_process_util.cc276
-rw-r--r--chromium/chrome/common/service_process_util.h197
-rw-r--r--chromium/chrome/common/service_process_util_linux.cc89
-rw-r--r--chromium/chrome/common/service_process_util_mac.mm405
-rw-r--r--chromium/chrome/common/service_process_util_mac_unittest.mm191
-rw-r--r--chromium/chrome/common/service_process_util_posix.cc360
-rw-r--r--chromium/chrome/common/service_process_util_posix.h93
-rw-r--r--chromium/chrome/common/service_process_util_unittest.cc253
-rw-r--r--chromium/chrome/common/service_process_util_win.cc268
-rw-r--r--chromium/chrome/common/ssl_insecure_content.cc45
-rw-r--r--chromium/chrome/common/ssl_insecure_content.h61
-rw-r--r--chromium/chrome/common/stack_sampling_configuration.cc219
-rw-r--r--chromium/chrome/common/stack_sampling_configuration.h88
-rw-r--r--chromium/chrome/common/themes/OWNERS3
-rw-r--r--chromium/chrome/common/themes/autogenerated_theme_util.cc136
-rw-r--r--chromium/chrome/common/themes/autogenerated_theme_util.h30
-rw-r--r--chromium/chrome/common/thread_profiler.cc312
-rw-r--r--chromium/chrome/common/thread_profiler.h155
-rw-r--r--chromium/chrome/common/thread_profiler_unittest.cc98
-rw-r--r--chromium/chrome/common/time_format_browsertest.cc42
-rw-r--r--chromium/chrome/common/web_application_info.cc19
-rw-r--r--chromium/chrome/common/web_application_info.h75
-rw-r--r--chromium/chrome/common/web_application_info_provider_param_traits.h27
-rw-r--r--chromium/chrome/common/win/OWNERS1
-rw-r--r--chromium/chrome/common/win/eventlog_messages.mc32
-rw-r--r--chromium/chrome/common/win/eventlog_provider.cc9
-rw-r--r--chromium/chrome/common/win/eventlog_provider.ver2
670 files changed, 44995 insertions, 8370 deletions
diff --git a/chromium/chrome/common/DEPS b/chromium/chrome/common/DEPS
new file mode 100644
index 00000000000..33b6ceeeda3
--- /dev/null
+++ b/chromium/chrome/common/DEPS
@@ -0,0 +1,70 @@
+include_rules = [
+ "+chrome/chrome_elf/chrome_elf_main.h",
+ "+chrome/grit",
+ "+chrome/install_static",
+ "+chrome/services/file_util/public",
+ "+chromeos", # For chromeos_switches.h
+ "+components/autofill/content/common",
+ "+components/autofill/core/common",
+ "+components/bookmarks/common",
+ "+components/cast_certificate",
+ "+components/cdm/common",
+ "+components/cloud_devices/common",
+ "+components/content_settings/core/common",
+ "+components/crash/content/app",
+ "+components/crash/core/common",
+ "+components/crx_file",
+ "+components/data_reduction_proxy/core/common",
+ "+components/dom_distiller/core",
+ "+components/favicon_base",
+ "+components/flags_ui/flags_ui_switches.h",
+ "+components/gcm_driver",
+ "+components/metrics/call_stack_profile_builder.h",
+ "+components/metrics/call_stack_profile_metrics_provider.h",
+ "+components/metrics/call_stack_profile_params.h",
+ "+components/metrics/child_call_stack_profile_collector.h",
+ "+components/metrics/client_info.h",
+ "+components/metrics/metadata_recorder.h",
+ "+components/metrics/metrics_pref_names.h",
+ "+components/metrics/public",
+ "+components/nacl/common",
+ "+components/net_log",
+ "+components/network_session_configurator/common",
+ "+components/ntp_tiles",
+ "+components/nux",
+ "+components/offline_pages/buildflags",
+ "+components/password_manager/core/common",
+ "+components/policy/core/common",
+ "+components/prefs",
+ "+components/printing/common",
+ "+components/safe_browsing/buildflags.h",
+ "+components/safe_browsing/proto/csd.pb.h",
+ "+components/safe_browsing/web_ui/constants.h",
+ "+components/services/app_service/public",
+ "+components/strings/grit/components_strings.h",
+ "+components/translate/core/common",
+ "+components/url_formatter",
+ "+components/variations/net",
+ "+components/version_info",
+ "+device/vr/buildflags/buildflags.h",
+ "+extensions/buildflags",
+ "+extensions/common",
+ "+gin/public", # For profiling.cc
+ "+google_apis/gaia", # For gaia_switches.h
+ "+media",
+ "+ppapi/c",
+ "+ppapi/shared_impl",
+ "+ppapi/thunk",
+ "+rlz/buildflags/buildflags.h",
+ "+sandbox/linux/services/credentials.h",
+ "+services/network/public/cpp",
+ "+services/network/public/mojom",
+ "+third_party/blink/public/mojom",
+ "+third_party/boringssl/src/include",
+ "+third_party/metrics_proto", # For heap profiler test.
+ "+third_party/widevine/cdm/buildflags.h",
+ "+third_party/widevine/cdm/widevine_cdm_common.h",
+
+ # FIXME - refactor code and remove these dependencies
+ "+chrome/installer/util",
+]
diff --git a/chromium/chrome/common/OWNERS b/chromium/chrome/common/OWNERS
new file mode 100644
index 00000000000..163695aea31
--- /dev/null
+++ b/chromium/chrome/common/OWNERS
@@ -0,0 +1,64 @@
+per-file chrome_features.cc=*
+per-file chrome_features.h=*
+per-file chrome_switches.cc=*
+per-file chrome_switches.h=*
+per-file pref_names.cc=*
+per-file pref_names.h=*
+per-file url_constants.cc=*
+per-file url_constants.h=*
+
+# This is for the common case of adding or renaming files. If you're doing
+# structural changes, use usual OWNERS rules.
+per-file BUILD.gn=*
+
+per-file *_messages*.h=set noparent
+per-file *_messages*.h=file://ipc/SECURITY_OWNERS
+
+per-file *_messages.cc=set noparent
+per-file *_messages.cc=file://ipc/SECURITY_OWNERS
+
+per-file *_param_traits*.*=set noparent
+per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS
+
+per-file *_type_converter*.*=set noparent
+per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
+
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
+
+# 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
+
+# Content client.
+per-file chrome_content_client.cc=*
+per-file chrome_content_client_constants.h=*
+per-file chrome_content_client.h=*
+per-file chrome_content_client_unittest.cc=*
+
+# Content settings
+per-file content_settings*=markusheintz@chromium.org
+
+# Pepper files.
+per-file pepper_*=bbudge@chromium.org
+per-file pepper_*=raymes@chromium.org
+
+# Other stuff.
+per-file autocomplete_match_type.*=mpearson@chromium.org
+per-file autocomplete_match_type.*=pkasting@chromium.org
+per-file autocomplete_match_type.*=sky@chromium.org
+per-file crash_keys*=rsesek@chromium.org
+
+# WebUI. See also chrome/browser/ui/webui/OWNERS.
+per-file webui_url_constants.cc=file://ui/webui/PLATFORM_OWNERS
+per-file webui_url_constants.h=file://ui/webui/PLATFORM_OWNERS
+
+# Thread profiling
+per-file thread_profiler*=wittman@chromium.org
+
+# Heap profiler
+per-file heap_profiler*=alph@chromium.org
diff --git a/chromium/chrome/common/all_messages.h b/chromium/chrome/common/all_messages.h
new file mode 100644
index 00000000000..211030e352e
--- /dev/null
+++ b/chromium/chrome/common/all_messages.h
@@ -0,0 +1,28 @@
+// 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.
+
+// Multiply-included file, hence no include guard.
+// Inclusion of all message files present in chrome. Keep this file
+// up to date when adding a new value to the IPCMessageStart enum in
+// ipc/ipc_message_start.h to ensure the corresponding message file is
+// included here. Message classes used exclusively outside of chrome
+// should not be listed here and instead get an exemption in
+// chrome/tools/ipclist/ipclist.cc.
+
+#include "build/build_config.h"
+#include "components/nacl/common/buildflags.h"
+#include "printing/buildflags/buildflags.h"
+
+#include "chrome/common/common_message_generator.h"
+
+#if BUILDFLAG(ENABLE_PRINTING)
+// TODO(dgn) remove from here when all the code using these messages is removed
+// from /chrome. (crbug.com/311308, crbug.com/450822)
+#undef COMPONENTS_PRINTING_COMMON_PRINT_MESSAGES_H_
+#include "components/printing/common/print_messages.h" // nogncheck
+#endif
+
+#if BUILDFLAG(ENABLE_NACL)
+#include "components/nacl/common/nacl_messages.h"
+#endif
diff --git a/chromium/chrome/common/apps/OWNERS b/chromium/chrome/common/apps/OWNERS
new file mode 100644
index 00000000000..0f8012a3b96
--- /dev/null
+++ b/chromium/chrome/common/apps/OWNERS
@@ -0,0 +1,2 @@
+file://apps/OWNERS
+# COMPONENT: Platform>Extensions
diff --git a/chromium/chrome/common/apps/platform_apps/OWNERS b/chromium/chrome/common/apps/platform_apps/OWNERS
new file mode 100644
index 00000000000..42444bcd16d
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/OWNERS
@@ -0,0 +1,2 @@
+per-file *_messages*.h=set noparent
+per-file *_messages*.h=file://ipc/SECURITY_OWNERS
diff --git a/chromium/chrome/common/apps/platform_apps/api/arc_apps_private.idl b/chromium/chrome/common/apps/platform_apps/api/arc_apps_private.idl
new file mode 100644
index 00000000000..1a3dd23237c
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/api/arc_apps_private.idl
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Use the <code>chrome.arcAppsPrivate</code> API to manage ARC apps.
+[platforms=("chromeos"), nodoc]
+namespace arcAppsPrivate {
+
+ dictionary AppInfo {
+ // The app package name.
+ DOMString packageName;
+ };
+
+ callback VoidCallback = void ();
+ callback GetLaunchableAppsCallback = void (AppInfo[] appsInfo);
+
+ interface Functions {
+ // Returns info of the installed ARC apps that are launchable, including
+ // ready and non-ready apps.
+ static void getLaunchableApps(GetLaunchableAppsCallback callback);
+
+ // Launches the ARC app with its package name. The app is launched
+ // immediately if it's ready, otherwise it will be launched when it becomes
+ // ready. The callback is called as soon as the launch is scheduled.
+ static void launchApp(DOMString packageName,
+ optional VoidCallback callback);
+ };
+
+ interface Events {
+ // Fires when a new app can be launched via $(ref:launchApp).
+ static void onInstalled(AppInfo app_info);
+ };
+};
diff --git a/chromium/chrome/common/apps/platform_apps/api/browser.idl b/chromium/chrome/common/apps/platform_apps/api/browser.idl
new file mode 100644
index 00000000000..971164bd068
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/api/browser.idl
@@ -0,0 +1,26 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Use the <code>chrome.browser</code> API to interact with the Chrome browser
+// associated with the current application and Chrome profile.
+namespace browser {
+ // Options for the $(ref:openTab) function.
+ dictionary OpenTabOptions {
+ // The URL to navigate to when the new tab is initially opened.
+ DOMString url;
+ };
+
+ callback Callback = void();
+
+ interface Functions {
+ // Opens a new tab in a browser window associated with the current
+ // application and Chrome profile. If no browser window for the Chrome
+ // profile is opened, a new one is opened prior to creating the new tab.
+ // |options|: Configures how the tab should be opened.
+ // |callback|: Called when the tab was successfully created, or failed to
+ // be created. If failed, $(ref:runtime.lastError) will be set.
+ static void openTab(OpenTabOptions options,
+ optional Callback callback);
+ };
+};
diff --git a/chromium/chrome/common/apps/platform_apps/api/media_galleries.idl b/chromium/chrome/common/apps/platform_apps/api/media_galleries.idl
new file mode 100644
index 00000000000..ebbb1f35db3
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/api/media_galleries.idl
@@ -0,0 +1,255 @@
+// 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.
+
+
+// Use the <code>chrome.mediaGalleries</code> API to access media files (audio,
+// images, video) from the user's local disks (with the user's consent).
+namespace mediaGalleries {
+
+ [inline_doc] enum GalleryChangeType {
+ // The contents of the gallery have changed.
+ contents_changed,
+ // The watch has been dropped because the device has been detached,
+ // the gallery permission has been removed, or any other reason.
+ watch_dropped
+ };
+
+ [inline_doc] enum GetMediaFileSystemsInteractivity {
+ // Do not act interactively.
+ no,
+ // Ask the user to manage permitted media galleries.
+ yes,
+ // Ask the user to manage permitted galleries only if the return set would
+ // otherwise be empty.
+ if_needed
+ };
+
+ [inline_doc] enum GetMetadataType {
+ // Retrieve the mime type, metadata tags, and attached images.
+ all,
+ // Retrieve only the mime type and the metadata tags.
+ mimeTypeAndTags,
+ // Retrieve only the mime type.
+ mimeTypeOnly
+ };
+
+ [nodefine, inline_doc] enum ScanProgressType {
+ // The scan started.
+ start,
+ // The scan was cancelled.
+ cancel,
+ // The scan finished but none of the result have been added,
+ // addScanResults() has to be called to ask the user for permission.
+ finish,
+ // The scan encountered an error and could not proceed.
+ error
+ };
+
+ [inline_doc] dictionary GalleryChangeDetails {
+ // Type of change event.
+ GalleryChangeType type;
+
+ // Identifies the modified gallery.
+ DOMString galleryId;
+ };
+
+ [inline_doc] dictionary MediaFileSystemsDetails {
+ // Whether to prompt the user for permission to additional media galleries
+ // before returning the permitted set. Default is silent. If the value
+ // 'yes' is passed, or if the application has not been granted access to
+ // any media galleries and the value 'if_needed' is passed, then the
+ // media gallery configuration dialog will be displayed.
+ GetMediaFileSystemsInteractivity? interactive;
+ };
+
+ [inline_doc] dictionary MediaMetadataOptions {
+ // Specifies which subset of the metadata to retrieve. Defaults to 'all'
+ // if the option is omitted.
+ GetMetadataType? metadataType;
+ };
+
+ callback MediaFileSystemsCallback =
+ void ([instanceOf=DOMFileSystem] object[] mediaFileSystems);
+
+ callback AddUserFolderCallback =
+ void ([instanceOf=DOMFileSystem] object[] mediaFileSystems,
+ DOMString selectedFileSystemName);
+
+ [nodefine] callback DropPermissionForMediaFileSystemCallback = void ();
+
+ [inline_doc] dictionary MediaFileSystemMetadata {
+ // The name of the file system.
+ DOMString name;
+
+ // A unique and persistent id for the media gallery.
+ DOMString galleryId;
+
+ // If the media gallery is on a removable device, a unique id for the
+ // device while the device is online.
+ DOMString? deviceId;
+
+ // True if the media gallery is on a removable device.
+ boolean isRemovable;
+
+ // True if the device the media gallery is on was detected as a media
+ // device. i.e. a PTP or MTP device, or a DCIM directory is present.
+ boolean isMediaDevice;
+
+ // True if the device is currently available.
+ boolean isAvailable;
+ };
+
+ [nodefine, inline_doc] dictionary ScanProgressDetails {
+ // The type of progress event, i.e. start, finish, etc.
+ ScanProgressType type;
+
+ // The number of Galleries found.
+ long? galleryCount;
+
+ // Appoximate number of media files found; some file types can be either
+ // audio or video and are included in both counts.
+ long? audioCount;
+ long? imageCount;
+ long? videoCount;
+ };
+
+ callback MediaFileSystemsMetadataCallback =
+ void (MediaFileSystemMetadata[] metadata);
+
+ dictionary StreamInfo {
+ // Describes format of container or codec of stream, i.e. "mp3", "h264".
+ DOMString type;
+
+ // An unfiltered string->string dictionary of tags for the stream.
+ object tags;
+ };
+
+ dictionary MediaMetadata {
+ // The browser sniffed mime type.
+ DOMString mimeType;
+
+ // Defined for video. In pixels.
+ long? height;
+ long? width;
+
+ // Defined for audio and video. In seconds.
+ double? duration;
+
+ // Defined for video. In degrees.
+ long? rotation;
+
+ // Defined for audio and video.
+ DOMString? album;
+ DOMString? artist;
+ DOMString? comment;
+ DOMString? copyright;
+ long? disc;
+ DOMString? genre;
+ DOMString? language;
+ DOMString? title;
+ long? track;
+
+ // All the metadata in the media file. For formats with multiple streams,
+ // stream order will be preserved. Container metadata is the first element.
+ StreamInfo[] rawTags;
+
+ // The images embedded in the media file's metadata. This is most often
+ // used for album art or video thumbnails.
+ [instanceOf=Blob] object[] attachedImages;
+ };
+
+ callback MediaMetadataCallback = void (MediaMetadata metadata);
+
+ // A dictionary that describes the add gallery watch request results.
+ dictionary AddGalleryWatchResult {
+ DOMString galleryId;
+ boolean success;
+ };
+
+ callback AddGalleryWatchCallback = void (AddGalleryWatchResult result);
+ [nodefine] callback GetAllGalleryWatchCallback =
+ void (DOMString[] galleryIds);
+
+ interface Functions {
+ // Get the media galleries configured in this user agent. If none are
+ // configured or available, the callback will receive an empty array.
+ static void getMediaFileSystems(optional MediaFileSystemsDetails details,
+ MediaFileSystemsCallback callback);
+
+ // Present a directory picker to the user and add the selected directory
+ // as a gallery. If the user cancels the picker, selectedFileSystemName
+ // will be empty.
+ // A user gesture is required for the dialog to display. Without a user
+ // gesture, the callback will run as though the user canceled.
+ static void addUserSelectedFolder(AddUserFolderCallback callback);
+
+ // Give up access to a given media gallery.
+ [nodefine, deprecated="The user can manually drop access to galleries
+ via the permissions dialog."]
+ static void dropPermissionForMediaFileSystem(
+ DOMString galleryId,
+ optional DropPermissionForMediaFileSystemCallback callback);
+
+ // Start a scan of the user's hard disks for directories containing media.
+ // The scan may take a long time so progress and completion is communicated
+ // by events. No permission is granted as a result of the scan, see
+ // addScanResults.
+ [nodefine, deprecated="The mediaGalleries API no longer supports scanning."]
+ static void startMediaScan();
+
+ // Cancel any pending media scan. Well behaved apps should provide a way
+ // for the user to cancel scans they start.
+ [nodefine, deprecated="The mediaGalleries API no longer supports scanning."]
+ static void cancelMediaScan();
+
+ // Show the user the scan results and let them add any or all of them as
+ // galleries. This should be used after the 'finish' onScanProgress()
+ // event has happened. All galleries the app has access to are returned, not
+ // just the newly added galleries.
+ [nodefine, deprecated="The mediaGalleries API no longer supports scanning."]
+ static void addScanResults(MediaFileSystemsCallback callback);
+
+ // Get metadata about a specific media file system.
+ [nocompile] static MediaFileSystemMetadata getMediaFileSystemMetadata(
+ [instanceOf=DOMFileSystem] object mediaFileSystem);
+
+ // Get metadata for all available media galleries.
+ [nodefine, deprecated="Use getMediaFileSystemMetadata instead."]
+ static void getAllMediaFileSystemMetadata(
+ MediaFileSystemsMetadataCallback callback);
+
+ // Gets the media-specific metadata for a media file. This should work
+ // for files in media galleries as well as other DOM filesystems.
+ static void getMetadata([instanceOf=Blob] object mediaFile,
+ optional MediaMetadataOptions options,
+ MediaMetadataCallback callback);
+
+ // Adds a gallery watch for the gallery with the specified gallery ID.
+ // The given callback is then fired with a success or failure result.
+ static void addGalleryWatch(DOMString galleryId,
+ AddGalleryWatchCallback callback);
+
+ // Removes a gallery watch for the gallery with the specified gallery ID.
+ static void removeGalleryWatch(DOMString galleryId);
+
+ // Notifies which galleries are being watched via the given callback.
+ [nodefine, deprecated="Applications should store their own gallery watches
+ as they are added."]
+ static void getAllGalleryWatch(GetAllGalleryWatchCallback callback);
+
+ // Removes all gallery watches.
+ [nodefine, deprecated="Use removeGalleryWatch instead."]
+ static void removeAllGalleryWatch();
+ };
+
+ interface Events {
+ // Fired when a media gallery is changed or a gallery watch is dropped.
+ static void onGalleryChanged(GalleryChangeDetails details);
+
+ // The pending media scan has changed state. See details for more
+ // information.
+ [nodefine, deprecated="The mediaGalleries API no longer supports scanning."]
+ static void onScanProgress(ScanProgressDetails details);
+ };
+};
diff --git a/chromium/chrome/common/apps/platform_apps/api/music_manager_private.idl b/chromium/chrome/common/apps/platform_apps/api/music_manager_private.idl
new file mode 100644
index 00000000000..b6d13fba921
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/api/music_manager_private.idl
@@ -0,0 +1,16 @@
+// 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.
+
+// musicManagerPrivate.
+namespace musicManagerPrivate {
+
+ callback GetDeviceIdCallback = void (DOMString device_id);
+
+ interface Functions {
+ // Returns an identifier stable across users and reboots.
+ //
+ // |callback| : Called with the stable identifier value.
+ static void getDeviceId(GetDeviceIdCallback callback);
+ };
+};
diff --git a/chromium/chrome/common/apps/platform_apps/api/sync_file_system.idl b/chromium/chrome/common/apps/platform_apps/api/sync_file_system.idl
new file mode 100644
index 00000000000..711625661e9
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/api/sync_file_system.idl
@@ -0,0 +1,199 @@
+// 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.
+
+// Use the <code>chrome.syncFileSystem</code> API to save and synchronize data
+// on Google Drive. This API is NOT for accessing arbitrary user docs stored in
+// Google Drive. It provides app-specific syncable storage for offline and
+// caching usage so that the same data can be available across different
+// clients. Read <a href="app_storage.html">Manage Data</a> for more on using
+// this API.
+namespace syncFileSystem {
+ enum SyncAction {
+ added, updated, deleted
+ };
+
+ enum ServiceStatus {
+ // The sync service is being initialized (e.g. restoring data from the
+ // database, checking connectivity and authenticating to the service etc).
+ initializing,
+
+ // The sync service is up and running.
+ running,
+
+ // The sync service is not synchronizing files because the remote service
+ // needs to be authenticated by the user to proceed.
+ authentication_required,
+
+ // The sync service is not synchronizing files because the remote service
+ // is (temporarily) unavailable due to some recoverable errors, e.g.
+ // network is offline, the remote service is down or not
+ // reachable etc. More details should be given by |description| parameter
+ // in OnServiceInfoUpdated (which could contain service-specific details).
+ temporary_unavailable,
+
+ // The sync service is disabled and the content will never sync.
+ // (E.g. this could happen when the user has no account on
+ // the remote service or the sync service has had an unrecoverable
+ // error.)
+ disabled
+ };
+
+ enum FileStatus {
+ // Not conflicting and has no pending local changes.
+ synced,
+
+ // Has one or more pending local changes that haven't been synchronized.
+ pending,
+
+ // File conflicts with remote version and must be resolved manually.
+ conflicting
+ };
+
+ enum SyncDirection {
+ local_to_remote, remote_to_local
+ };
+
+ enum ConflictResolutionPolicy {
+ last_write_win, manual
+ };
+
+ dictionary FileInfo {
+ // <code>fileEntry</code> for the target file whose status has changed.
+ // Contains name and path information of synchronized file.
+ // On file deletion,
+ // <code>fileEntry</code> information will still be available
+ // but file will no longer exist.
+ [instanceOf=Entry] object fileEntry;
+
+ // Resulting file status after $(ref:onFileStatusChanged) event.
+ // The status value can be <code>'synced'</code>,
+ // <code>'pending'</code> or <code>'conflicting'</code>.
+ FileStatus status;
+
+ // Sync action taken to fire $(ref:onFileStatusChanged) event.
+ // The action value can be
+ // <code>'added'</code>, <code>'updated'</code> or <code>'deleted'</code>.
+ // Only applies if status is <code>'synced'</code>.
+ SyncAction? action;
+
+ // Sync direction for the $(ref:onFileStatusChanged) event.
+ // Sync direction value can be
+ // <code>'local_to_remote'</code> or <code>'remote_to_local'</code>.
+ // Only applies if status is <code>'synced'</code>.
+ SyncDirection? direction;
+ };
+
+ dictionary FileStatusInfo {
+ // One of the Entry's originally given to getFileStatuses.
+ [instanceOf=Entry] object fileEntry;
+
+ // The status value can be <code>'synced'</code>,
+ // <code>'pending'</code> or <code>'conflicting'</code>.
+ FileStatus status;
+
+ // Optional error that is only returned if there was a problem retrieving
+ // the FileStatus for the given file.
+ DOMString? error;
+ };
+
+ dictionary StorageInfo {
+ long usageBytes;
+ long quotaBytes;
+ };
+
+ dictionary ServiceInfo {
+ ServiceStatus state;
+ DOMString description;
+ };
+
+ // A callback type for requestFileSystem.
+ callback GetFileSystemCallback =
+ void ([instanceOf=DOMFileSystem] object fileSystem);
+
+ // A callback type for getUsageAndQuota.
+ callback QuotaAndUsageCallback = void (StorageInfo info);
+
+ // Returns true if operation was successful.
+ callback DeleteFileSystemCallback = void (boolean result);
+
+ // A callback type for getFileStatus.
+ callback GetFileStatusCallback = void (FileStatus status);
+
+ // A callback type for getFileStatuses.
+ callback GetFileStatusesCallback = void (FileStatusInfo[] status);
+
+ // A callback type for getServiceStatus.
+ callback GetServiceStatusCallback = void (ServiceStatus status);
+
+ // A callback type for getConflictResolutionPolicy.
+ callback GetConflictResolutionPolicyCallback =
+ void (ConflictResolutionPolicy policy);
+
+ // A generic result callback to indicate success or failure.
+ callback ResultCallback = void ();
+
+ interface Functions {
+ // Returns a syncable filesystem backed by Google Drive.
+ // The returned <code>DOMFileSystem</code> instance can be operated on
+ // in the same way as the Temporary and Persistant file systems (see
+ // <a href="http://dev.w3.org/2009/dap/file-system/file-dir-sys.html">
+ // http://dev.w3.org/2009/dap/file-system/file-dir-sys.html</a>).
+ //
+ // Calling this multiple times from
+ // the same app will return the same handle to the same file system.
+ //
+ // Note this call can fail. For example, if the user is not signed in to
+ // Chrome or if there is no network operation. To handle these errors it is
+ // important chrome.runtime.lastError is checked in the callback.
+ static void requestFileSystem(GetFileSystemCallback callback);
+
+ // Sets the default conflict resolution policy
+ // for the <code>'syncable'</code> file storage for the app.
+ // By default it is set to <code>'last_write_win'</code>.
+ // When conflict resolution policy is set to <code>'last_write_win'</code>
+ // conflicts for existing files are automatically resolved next time
+ // the file is updated.
+ // |callback| can be optionally given to know if the request has
+ // succeeded or not.
+ static void setConflictResolutionPolicy(
+ ConflictResolutionPolicy policy,
+ optional ResultCallback callback);
+
+ // Gets the current conflict resolution policy.
+ static void getConflictResolutionPolicy(
+ GetConflictResolutionPolicyCallback callback);
+
+ // Returns the current usage and quota in bytes
+ // for the <code>'syncable'</code> file storage for the app.
+ static void getUsageAndQuota([instanceOf=DOMFileSystem] object fileSystem,
+ QuotaAndUsageCallback callback);
+
+ // Returns the $(ref:FileStatus) for the given <code>fileEntry</code>.
+ // The status value can be <code>'synced'</code>,
+ // <code>'pending'</code> or <code>'conflicting'</code>.
+ // Note that <code>'conflicting'</code> state only happens when
+ // the service's conflict resolution policy is set to <code>'manual'</code>.
+ static void getFileStatus([instanceOf=Entry] object fileEntry,
+ GetFileStatusCallback callback);
+
+ // Returns each $(ref:FileStatus) for the given <code>fileEntry</code> array.
+ // Typically called with the result from dirReader.readEntries().
+ static void getFileStatuses(object[] fileEntries,
+ GetFileStatusesCallback callback);
+
+ // Returns the current sync backend status.
+ static void getServiceStatus(GetServiceStatusCallback callback);
+ };
+
+ interface Events {
+ // Fired when an error or other status change has happened in the
+ // sync backend (for example, when the sync is temporarily disabled due to
+ // network or authentication error).
+ static void onServiceStatusChanged(ServiceInfo detail);
+
+ // Fired when a file has been updated by the background sync service.
+ static void onFileStatusChanged(FileInfo detail);
+ };
+
+};
diff --git a/chromium/chrome/common/apps/platform_apps/api/webstore_widget_private.idl b/chromium/chrome/common/apps/platform_apps/api/webstore_widget_private.idl
new file mode 100644
index 00000000000..ea0d07a6778
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/api/webstore_widget_private.idl
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// webstoreWidgetPrivate API.
+// This is a private API used to install apps via Chrome Web Store widget - for
+// example in Files app to install file system provider services.
+[platforms=("chromeos")]
+namespace webstoreWidgetPrivate {
+
+// Callback that does not take arguments.
+callback SimpleCallback = void();
+
+interface Functions {
+ // Requests to install a webstore item.
+ // |item_id| The id of the item to install.
+ // |silentInstallation| False to show installation prompt. True not to show.
+ // Can be set to true only for a subset of installation requests.
+ static void installWebstoreItem(DOMString itemId,
+ boolean silentInstallation,
+ SimpleCallback callback);
+};
+
+};
diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc
new file mode 100644
index 00000000000..99e1f557bb7
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.cc
@@ -0,0 +1,45 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/apps/platform_apps/chrome_apps_api_permissions.h"
+
+#include <memory>
+
+#include "chrome/common/apps/platform_apps/media_galleries_permission.h"
+
+namespace chrome_apps_api_permissions {
+namespace {
+
+template <typename T>
+std::unique_ptr<extensions::APIPermission> CreateAPIPermission(
+ const extensions::APIPermissionInfo* permission) {
+ return std::make_unique<T>(permission);
+}
+
+// WARNING: If you are modifying a permission message in this list, be sure to
+// add the corresponding permission message rule to
+// ChromePermissionMessageProvider::GetPermissionMessages as well.
+constexpr extensions::APIPermissionInfo::InitInfo permissions_to_register[] = {
+ {extensions::APIPermission::kArcAppsPrivate, "arcAppsPrivate"},
+ {extensions::APIPermission::kBrowser, "browser"},
+ {extensions::APIPermission::kFirstRunPrivate, "firstRunPrivate",
+ extensions::APIPermissionInfo::kFlagCannotBeOptional},
+ {extensions::APIPermission::kMusicManagerPrivate, "musicManagerPrivate",
+ extensions::APIPermissionInfo::kFlagCannotBeOptional},
+ {extensions::APIPermission::kMediaGalleries, "mediaGalleries",
+ extensions::APIPermissionInfo::kFlagNone,
+ &CreateAPIPermission<chrome_apps::MediaGalleriesPermission>},
+ {extensions::APIPermission::kPointerLock, "pointerLock"},
+ {extensions::APIPermission::kSyncFileSystem, "syncFileSystem"},
+ {extensions::APIPermission::kWebstoreWidgetPrivate, "webstoreWidgetPrivate",
+ extensions::APIPermissionInfo::kFlagCannotBeOptional},
+};
+
+} // namespace
+
+base::span<const extensions::APIPermissionInfo::InitInfo> GetPermissionInfos() {
+ return base::make_span(permissions_to_register);
+}
+
+} // namespace chrome_apps_api_permissions
diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.h b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.h
new file mode 100644
index 00000000000..eec3cad6d55
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_permissions.h
@@ -0,0 +1,19 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PERMISSIONS_H_
+#define CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PERMISSIONS_H_
+
+#include "base/containers/span.h"
+#include "extensions/common/permissions/api_permission.h"
+
+namespace chrome_apps_api_permissions {
+
+// Returns the information necessary to construct Chrome app-specific
+// APIPermissions.
+base::span<const extensions::APIPermissionInfo::InitInfo> GetPermissionInfos();
+
+} // namespace chrome_apps_api_permissions
+
+#endif // CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PERMISSIONS_H_
diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.cc b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.cc
new file mode 100644
index 00000000000..1f7de94c949
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.cc
@@ -0,0 +1,65 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/apps/platform_apps/chrome_apps_api_provider.h"
+
+#include "chrome/common/apps/platform_apps/api/api_features.h"
+#include "chrome/common/apps/platform_apps/api/generated_schemas.h"
+#include "chrome/common/apps/platform_apps/api/permission_features.h"
+#include "chrome/common/apps/platform_apps/chrome_apps_api_permissions.h"
+#include "chrome/grit/common_resources.h"
+#include "extensions/common/alias.h"
+#include "extensions/common/features/json_feature_provider_source.h"
+#include "extensions/common/permissions/permissions_info.h"
+
+namespace chrome_apps {
+
+ChromeAppsAPIProvider::ChromeAppsAPIProvider() {}
+ChromeAppsAPIProvider::~ChromeAppsAPIProvider() = default;
+
+void ChromeAppsAPIProvider::AddAPIFeatures(
+ extensions::FeatureProvider* provider) {
+ AddChromeAppsAPIFeatures(provider);
+}
+
+void ChromeAppsAPIProvider::AddManifestFeatures(
+ extensions::FeatureProvider* provider) {
+ // No Chrome-apps-specific manifest features (yet).
+}
+
+void ChromeAppsAPIProvider::AddPermissionFeatures(
+ extensions::FeatureProvider* provider) {
+ AddChromeAppsPermissionFeatures(provider);
+}
+
+void ChromeAppsAPIProvider::AddBehaviorFeatures(
+ extensions::FeatureProvider* provider) {
+ // No Chrome-apps-specific manifest features.
+}
+
+void ChromeAppsAPIProvider::AddAPIJSONSources(
+ extensions::JSONFeatureProviderSource* json_source) {
+ json_source->LoadJSON(IDR_CHROME_APP_API_FEATURES);
+}
+
+bool ChromeAppsAPIProvider::IsAPISchemaGenerated(const std::string& name) {
+ return api::ChromeAppsGeneratedSchemas::IsGenerated(name);
+}
+
+base::StringPiece ChromeAppsAPIProvider::GetAPISchema(const std::string& name) {
+ return api::ChromeAppsGeneratedSchemas::Get(name);
+}
+
+void ChromeAppsAPIProvider::RegisterPermissions(
+ extensions::PermissionsInfo* permissions_info) {
+ permissions_info->RegisterPermissions(
+ chrome_apps_api_permissions::GetPermissionInfos(),
+ base::span<const extensions::Alias>());
+}
+
+void ChromeAppsAPIProvider::RegisterManifestHandlers() {
+ // No apps-specific manifest handlers (yet).
+}
+
+} // namespace chrome_apps
diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.h b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.h
new file mode 100644
index 00000000000..b5312b85422
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_api_provider.h
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PROVIDER_H_
+#define CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PROVIDER_H_
+
+#include "extensions/common/extensions_api_provider.h"
+
+namespace chrome_apps {
+
+class ChromeAppsAPIProvider : public extensions::ExtensionsAPIProvider {
+ public:
+ ChromeAppsAPIProvider();
+ ~ChromeAppsAPIProvider() override;
+
+ // ExtensionsAPIProvider:
+ void AddAPIFeatures(extensions::FeatureProvider* provider) override;
+ void AddManifestFeatures(extensions::FeatureProvider* provider) override;
+ void AddPermissionFeatures(extensions::FeatureProvider* provider) override;
+ void AddBehaviorFeatures(extensions::FeatureProvider* provider) override;
+ void AddAPIJSONSources(
+ extensions::JSONFeatureProviderSource* json_source) override;
+ bool IsAPISchemaGenerated(const std::string& name) override;
+ base::StringPiece GetAPISchema(const std::string& name) override;
+ void RegisterPermissions(
+ extensions::PermissionsInfo* permissions_info) override;
+ void RegisterManifestHandlers() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChromeAppsAPIProvider);
+};
+
+} // namespace chrome_apps
+
+#endif // CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_API_PROVIDER_H_
diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.cc b/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.cc
new file mode 100644
index 00000000000..e22ff4b8edd
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.cc
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "chrome/common/apps/platform_apps/chrome_apps_message_generator.h"
+} // namespace IPC
+
diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.h b/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.h
new file mode 100644
index 00000000000..1903b73d9b5
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_message_generator.h
@@ -0,0 +1,11 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Multiply-included file, hence no include guard.
+
+#undef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_
+#include "chrome/common/apps/platform_apps/chrome_apps_messages.h"
+#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_
+#error "Failed to include header chrome/common/apps/platform_apps/chrome_apps_messages.h"
+#endif
diff --git a/chromium/chrome/common/apps/platform_apps/chrome_apps_messages.h b/chromium/chrome/common/apps/platform_apps/chrome_apps_messages.h
new file mode 100644
index 00000000000..f8138b4fc56
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/chrome_apps_messages.h
@@ -0,0 +1,15 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_
+#define CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_
+
+#include "chrome/common/apps/platform_apps/media_galleries_permission_data.h"
+#include "ipc/ipc_message_macros.h"
+
+IPC_STRUCT_TRAITS_BEGIN(chrome_apps::MediaGalleriesPermissionData)
+ IPC_STRUCT_TRAITS_MEMBER(permission())
+IPC_STRUCT_TRAITS_END()
+
+#endif // CHROME_COMMON_APPS_PLATFORM_APPS_CHROME_APPS_MESSAGES_H_
diff --git a/chromium/chrome/common/apps/platform_apps/media_galleries_permission.cc b/chromium/chrome/common/apps/platform_apps/media_galleries_permission.cc
new file mode 100644
index 00000000000..372145687f4
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/media_galleries_permission.cc
@@ -0,0 +1,157 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/apps/platform_apps/media_galleries_permission.h"
+
+#include <stddef.h>
+
+#include <set>
+#include <string>
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "extensions/common/permissions/permissions_info.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace chrome_apps {
+
+namespace {
+
+// copyTo permission requires delete permission as a prerequisite.
+// delete permission requires read permission as a prerequisite.
+bool IsValidPermissionSet(bool has_read,
+ bool has_copy_to,
+ bool has_delete,
+ std::string* error) {
+ if (has_copy_to) {
+ if (has_read && has_delete)
+ return true;
+ if (error)
+ *error = "copyTo permission requires read and delete permissions";
+ return false;
+ }
+ if (has_delete) {
+ if (has_read)
+ return true;
+ if (error)
+ *error = "delete permission requires read permission";
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+const char MediaGalleriesPermission::kAllAutoDetectedPermission[] =
+ "allAutoDetected";
+const char MediaGalleriesPermission::kReadPermission[] = "read";
+const char MediaGalleriesPermission::kCopyToPermission[] = "copyTo";
+const char MediaGalleriesPermission::kDeletePermission[] = "delete";
+
+MediaGalleriesPermission::MediaGalleriesPermission(
+ const extensions::APIPermissionInfo* info)
+ : SetDisjunctionPermission<MediaGalleriesPermissionData,
+ MediaGalleriesPermission>(info) {}
+
+MediaGalleriesPermission::~MediaGalleriesPermission() {}
+
+bool MediaGalleriesPermission::FromValue(
+ const base::Value* value,
+ std::string* error,
+ std::vector<std::string>* unhandled_permissions) {
+ size_t unhandled_permissions_count = 0;
+ if (unhandled_permissions)
+ unhandled_permissions_count = unhandled_permissions->size();
+ bool parsed_ok = SetDisjunctionPermission<
+ MediaGalleriesPermissionData,
+ MediaGalleriesPermission>::FromValue(value, error, unhandled_permissions);
+ if (unhandled_permissions) {
+ for (size_t i = unhandled_permissions_count;
+ i < unhandled_permissions->size(); i++) {
+ (*unhandled_permissions)[i] =
+ "{\"mediaGalleries\": [" + (*unhandled_permissions)[i] + "]}";
+ }
+ }
+ if (!parsed_ok)
+ return false;
+
+ bool has_read = false;
+ bool has_copy_to = false;
+ bool has_delete = false;
+ for (auto it = data_set_.cbegin(); it != data_set_.cend(); ++it) {
+ if (it->permission() == kAllAutoDetectedPermission) {
+ continue;
+ }
+ if (it->permission() == kReadPermission) {
+ has_read = true;
+ continue;
+ }
+ if (it->permission() == kCopyToPermission) {
+ has_copy_to = true;
+ continue;
+ }
+ if (it->permission() == kDeletePermission) {
+ has_delete = true;
+ continue;
+ }
+
+ // No other permissions, so reaching this means
+ // MediaGalleriesPermissionData is probably out of sync in some way.
+ // Fail so developers notice this.
+ NOTREACHED();
+ return false;
+ }
+
+ return IsValidPermissionSet(has_read, has_copy_to, has_delete, error);
+}
+
+extensions::PermissionIDSet MediaGalleriesPermission::GetPermissions() const {
+ extensions::PermissionIDSet result;
+
+ bool has_all_auto_detected = false;
+ bool has_read = false;
+ bool has_copy_to = false;
+ bool has_delete = false;
+
+ for (const MediaGalleriesPermissionData& data : data_set_) {
+ if (data.permission() == kAllAutoDetectedPermission)
+ has_all_auto_detected = true;
+ else if (data.permission() == kReadPermission)
+ has_read = true;
+ else if (data.permission() == kCopyToPermission)
+ has_copy_to = true;
+ else if (data.permission() == kDeletePermission)
+ has_delete = true;
+ }
+
+ if (!IsValidPermissionSet(has_read, has_copy_to, has_delete, nullptr)) {
+ NOTREACHED();
+ return result;
+ }
+
+ // If |has_all_auto_detected| is false, then Chrome will prompt the user at
+ // runtime when the extension calls the getMediaGalleries API.
+ if (!has_all_auto_detected)
+ return result;
+ // No access permission case.
+ if (!has_read)
+ return result;
+
+ // Separate PermissionMessage IDs for read, copyTo, and delete. Otherwise an
+ // extension can silently gain new access capabilities.
+ result.insert(extensions::APIPermission::kMediaGalleriesAllGalleriesRead);
+
+ // For copyTo and delete, the proper combined permission message will be
+ // derived in ChromePermissionMessageProvider::GetWarningMessages(), such
+ // that the user get 1 entry for all media galleries access permissions,
+ // rather than several separate entries.
+ if (has_copy_to)
+ result.insert(extensions::APIPermission::kMediaGalleriesAllGalleriesCopyTo);
+ if (has_delete)
+ result.insert(extensions::APIPermission::kMediaGalleriesAllGalleriesDelete);
+
+ return result;
+}
+
+} // namespace chrome_apps
diff --git a/chromium/chrome/common/apps/platform_apps/media_galleries_permission.h b/chromium/chrome/common/apps/platform_apps/media_galleries_permission.h
new file mode 100644
index 00000000000..c5792fdab85
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/media_galleries_permission.h
@@ -0,0 +1,63 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_H_
+#define CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_H_
+
+#include "chrome/common/apps/platform_apps/chrome_apps_messages.h"
+#include "chrome/common/apps/platform_apps/media_galleries_permission_data.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/set_disjunction_permission.h"
+
+namespace chrome_apps {
+
+// Media Galleries permissions are as follows:
+// <media-galleries-permission-pattern>
+// := <access> | <access> 'allAutoDetected' | 'allAutoDetected' |
+// <access> 'scan' | 'scan'
+// <access> := 'read' | 'read' <access> | 'read' <secondary-access>
+// <secondary-access>
+// := 'delete' | 'delete' <secondary-access> |
+// 'delete' <tertiary-access>
+// <tertiary-access>
+// := 'copyTo' | 'copyTo' <tertiary-access>
+// An example of a line for mediaGalleries permissions in a manifest file:
+// {"mediaGalleries": "read delete"},
+// We also allow a permission without any sub-permissions:
+// "mediaGalleries",
+// TODO(devlin): Move this class to chrome/common/apps/platform_apps.
+class MediaGalleriesPermission
+ : public extensions::SetDisjunctionPermission<MediaGalleriesPermissionData,
+ MediaGalleriesPermission> {
+ public:
+ struct CheckParam : public extensions::APIPermission::CheckParam {
+ explicit CheckParam(const std::string& permission)
+ : permission(permission) {}
+ const std::string permission;
+ };
+
+ explicit MediaGalleriesPermission(const extensions::APIPermissionInfo* info);
+ ~MediaGalleriesPermission() override;
+
+ // SetDisjunctionPermission overrides.
+ // MediaGalleriesPermission does additional checks to make sure the
+ // permissions do not contain unknown values.
+ bool FromValue(const base::Value* value,
+ std::string* error,
+ std::vector<std::string>* unhandled_permissions) override;
+
+ // extensions::APIPermission overrides.
+ extensions::PermissionIDSet GetPermissions() const override;
+
+ // Permission strings.
+ static const char kAllAutoDetectedPermission[];
+ static const char kScanPermission[];
+ static const char kReadPermission[];
+ static const char kCopyToPermission[];
+ static const char kDeletePermission[];
+};
+
+} // namespace chrome_apps
+
+#endif // CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_H_
diff --git a/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.cc b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.cc
new file mode 100644
index 00000000000..148abbac461
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.cc
@@ -0,0 +1,60 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/apps/platform_apps/media_galleries_permission_data.h"
+
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "chrome/common/apps/platform_apps/media_galleries_permission.h"
+
+namespace chrome_apps {
+
+MediaGalleriesPermissionData::MediaGalleriesPermissionData() {}
+
+bool MediaGalleriesPermissionData::Check(
+ const extensions::APIPermission::CheckParam* param) const {
+ if (!param)
+ return false;
+
+ const MediaGalleriesPermission::CheckParam& specific_param =
+ *static_cast<const MediaGalleriesPermission::CheckParam*>(param);
+ return permission_ == specific_param.permission;
+}
+
+std::unique_ptr<base::Value> MediaGalleriesPermissionData::ToValue() const {
+ return std::make_unique<base::Value>(permission_);
+}
+
+bool MediaGalleriesPermissionData::FromValue(const base::Value* value) {
+ if (!value)
+ return false;
+
+ std::string raw_permission;
+ if (!value->GetAsString(&raw_permission))
+ return false;
+
+ std::string permission;
+ base::TrimWhitespaceASCII(raw_permission, base::TRIM_ALL, &permission);
+
+ if (permission == MediaGalleriesPermission::kAllAutoDetectedPermission ||
+ permission == MediaGalleriesPermission::kReadPermission ||
+ permission == MediaGalleriesPermission::kCopyToPermission ||
+ permission == MediaGalleriesPermission::kDeletePermission) {
+ permission_ = permission;
+ return true;
+ }
+ return false;
+}
+
+bool MediaGalleriesPermissionData::operator<(
+ const MediaGalleriesPermissionData& rhs) const {
+ return permission_ < rhs.permission_;
+}
+
+bool MediaGalleriesPermissionData::operator==(
+ const MediaGalleriesPermissionData& rhs) const {
+ return permission_ == rhs.permission_;
+}
+
+} // namespace chrome_apps
diff --git a/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.h b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.h
new file mode 100644
index 00000000000..495cb48d4be
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_data.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_DATA_H_
+#define CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_DATA_H_
+
+#include <memory>
+#include <string>
+
+#include "extensions/common/permissions/api_permission.h"
+
+namespace base {
+class Value;
+}
+
+namespace chrome_apps {
+
+// A MediaGalleriesPermissionData instance represents a single part of the
+// MediaGalleriesPermission. e.g. "read" or "allAutoDetected".
+class MediaGalleriesPermissionData {
+ public:
+ MediaGalleriesPermissionData();
+
+ // Check if |param| (which must be a MediaGalleriesPermission::CheckParam)
+ // matches the encapsulated attribute.
+ bool Check(const extensions::APIPermission::CheckParam* param) const;
+
+ // Convert |this| into a base::Value.
+ std::unique_ptr<base::Value> ToValue() const;
+
+ // Populate |this| from a base::Value.
+ bool FromValue(const base::Value* value);
+
+ bool operator<(const MediaGalleriesPermissionData& rhs) const;
+ bool operator==(const MediaGalleriesPermissionData& rhs) const;
+
+ std::string permission() const { return permission_; }
+
+ // This accessor is provided for IPC_STRUCT_TRAITS_MEMBER. Please think
+ // twice before using it for anything else.
+ std::string& permission() { return permission_; }
+
+ private:
+ std::string permission_;
+};
+
+} // namespace chrome_apps
+
+#endif // CHROME_COMMON_APPS_PLATFORM_APPS_MEDIA_GALLERIES_PERMISSION_DATA_H_
diff --git a/chromium/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc
new file mode 100644
index 00000000000..d8fbc24b8be
--- /dev/null
+++ b/chromium/chrome/common/apps/platform_apps/media_galleries_permission_unittest.cc
@@ -0,0 +1,304 @@
+// 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.
+
+// These tests make sure MediaGalleriesPermission values are parsed correctly.
+
+#include <memory>
+
+#include "base/values.h"
+#include "chrome/common/apps/platform_apps/media_galleries_permission.h"
+#include "chrome/common/apps/platform_apps/media_galleries_permission_data.h"
+#include "extensions/common/permissions/api_permission.h"
+#include "extensions/common/permissions/permissions_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::SocketPermissionRequest;
+using extensions::SocketPermissionData;
+
+namespace chrome_apps {
+
+namespace {
+
+void CheckFromValue(extensions::APIPermission* permission,
+ base::ListValue* value,
+ bool success_expected) {
+ std::string error;
+ std::vector<std::string> unhandled;
+ EXPECT_EQ(success_expected, permission->FromValue(value, &error, &unhandled));
+ EXPECT_EQ(success_expected, error.empty());
+ EXPECT_TRUE(unhandled.empty());
+}
+
+TEST(MediaGalleriesPermissionTest, GoodValues) {
+ const extensions::APIPermissionInfo* permission_info =
+ extensions::PermissionsInfo::GetInstance()->GetByID(
+ extensions::APIPermission::kMediaGalleries);
+
+ std::unique_ptr<extensions::APIPermission> permission(
+ permission_info->CreateAPIPermission());
+
+ // access_type + all_detected
+ std::unique_ptr<base::ListValue> value(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ CheckFromValue(permission.get(), value.get(), true);
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ CheckFromValue(permission.get(), value.get(), true);
+
+ // all_detected
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ CheckFromValue(permission.get(), value.get(), true);
+
+ // access_type
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ CheckFromValue(permission.get(), value.get(), true);
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ CheckFromValue(permission.get(), value.get(), true);
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ CheckFromValue(permission.get(), value.get(), true);
+
+ // Repeats do not make a difference.
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ CheckFromValue(permission.get(), value.get(), true);
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ CheckFromValue(permission.get(), value.get(), true);
+}
+
+TEST(MediaGalleriesPermissionTest, BadValues) {
+ const extensions::APIPermissionInfo* permission_info =
+ extensions::PermissionsInfo::GetInstance()->GetByID(
+ extensions::APIPermission::kMediaGalleries);
+
+ std::unique_ptr<extensions::APIPermission> permission(
+ permission_info->CreateAPIPermission());
+
+ // copyTo and delete without read
+ std::unique_ptr<base::ListValue> value(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ CheckFromValue(permission.get(), value.get(), false);
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ CheckFromValue(permission.get(), value.get(), false);
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ CheckFromValue(permission.get(), value.get(), false);
+
+ // copyTo without delete
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ CheckFromValue(permission.get(), value.get(), false);
+
+ // Repeats do not make a difference.
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ CheckFromValue(permission.get(), value.get(), false);
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ CheckFromValue(permission.get(), value.get(), false);
+}
+
+TEST(MediaGalleriesPermissionTest, UnknownValues) {
+ std::string error;
+ std::vector<std::string> unhandled;
+ const extensions::APIPermissionInfo* permission_info =
+ extensions::PermissionsInfo::GetInstance()->GetByID(
+ extensions::APIPermission::kMediaGalleries);
+
+ std::unique_ptr<extensions::APIPermission> permission(
+ permission_info->CreateAPIPermission());
+
+ // A good one and an unknown one.
+ std::unique_ptr<base::ListValue> value(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString("Unknown");
+ EXPECT_TRUE(permission->FromValue(value.get(), &error, &unhandled));
+ EXPECT_TRUE(error.empty());
+ EXPECT_EQ(1U, unhandled.size());
+ error.clear();
+ unhandled.clear();
+
+ // Multiple unknown permissions.
+ value.reset(new base::ListValue());
+ value->AppendString("Unknown1");
+ value->AppendString("Unknown2");
+ EXPECT_TRUE(permission->FromValue(value.get(), &error, &unhandled));
+ EXPECT_TRUE(error.empty());
+ EXPECT_EQ(2U, unhandled.size());
+ error.clear();
+ unhandled.clear();
+
+ // Unnknown with a NULL argument.
+ value.reset(new base::ListValue());
+ value->AppendString("Unknown1");
+ EXPECT_FALSE(permission->FromValue(value.get(), &error, NULL));
+ EXPECT_FALSE(error.empty());
+ error.clear();
+}
+
+TEST(MediaGalleriesPermissionTest, Equal) {
+ const extensions::APIPermissionInfo* permission_info =
+ extensions::PermissionsInfo::GetInstance()->GetByID(
+ extensions::APIPermission::kMediaGalleries);
+
+ std::unique_ptr<extensions::APIPermission> permission1(
+ permission_info->CreateAPIPermission());
+ std::unique_ptr<extensions::APIPermission> permission2(
+ permission_info->CreateAPIPermission());
+
+ std::unique_ptr<base::ListValue> value(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL));
+ EXPECT_TRUE(permission1->Equal(permission2.get()));
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL));
+ EXPECT_TRUE(permission1->Equal(permission2.get()));
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL));
+ EXPECT_TRUE(permission1->Equal(permission2.get()));
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL));
+ EXPECT_TRUE(permission1->Equal(permission2.get()));
+}
+
+TEST(MediaGalleriesPermissionTest, NotEqual) {
+ const extensions::APIPermissionInfo* permission_info =
+ extensions::PermissionsInfo::GetInstance()->GetByID(
+ extensions::APIPermission::kMediaGalleries);
+
+ std::unique_ptr<extensions::APIPermission> permission1(
+ permission_info->CreateAPIPermission());
+ std::unique_ptr<extensions::APIPermission> permission2(
+ permission_info->CreateAPIPermission());
+
+ std::unique_ptr<base::ListValue> value(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ ASSERT_TRUE(permission2->FromValue(value.get(), NULL, NULL));
+ EXPECT_FALSE(permission1->Equal(permission2.get()));
+}
+
+TEST(MediaGalleriesPermissionTest, ToFromValue) {
+ const extensions::APIPermissionInfo* permission_info =
+ extensions::PermissionsInfo::GetInstance()->GetByID(
+ extensions::APIPermission::kMediaGalleries);
+
+ std::unique_ptr<extensions::APIPermission> permission1(
+ permission_info->CreateAPIPermission());
+ std::unique_ptr<extensions::APIPermission> permission2(
+ permission_info->CreateAPIPermission());
+
+ std::unique_ptr<base::ListValue> value(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kAllAutoDetectedPermission);
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+
+ std::unique_ptr<base::Value> vtmp(permission1->ToValue());
+ ASSERT_TRUE(vtmp);
+ ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL));
+ EXPECT_TRUE(permission1->Equal(permission2.get()));
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ value->AppendString(MediaGalleriesPermission::kCopyToPermission);
+ ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+
+ vtmp = permission1->ToValue();
+ ASSERT_TRUE(vtmp);
+ ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL));
+ EXPECT_TRUE(permission1->Equal(permission2.get()));
+
+ value.reset(new base::ListValue());
+ value->AppendString(MediaGalleriesPermission::kReadPermission);
+ value->AppendString(MediaGalleriesPermission::kDeletePermission);
+ ASSERT_TRUE(permission1->FromValue(value.get(), NULL, NULL));
+
+ vtmp = permission1->ToValue();
+ ASSERT_TRUE(vtmp);
+ ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL));
+ EXPECT_TRUE(permission1->Equal(permission2.get()));
+
+ value.reset(new base::ListValue());
+ // without sub-permission
+ ASSERT_TRUE(permission1->FromValue(NULL, NULL, NULL));
+
+ vtmp = permission1->ToValue();
+ ASSERT_TRUE(vtmp);
+ ASSERT_TRUE(permission2->FromValue(vtmp.get(), NULL, NULL));
+ EXPECT_TRUE(permission1->Equal(permission2.get()));
+}
+
+} // namespace
+
+} // namespace chrome_apps
diff --git a/chromium/chrome/common/attrition_experiments.h b/chromium/chrome/common/attrition_experiments.h
new file mode 100644
index 00000000000..56c08b3f26e
--- /dev/null
+++ b/chromium/chrome/common/attrition_experiments.h
@@ -0,0 +1,26 @@
+// 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 CHROME_COMMON_ATTRITION_EXPERIMENTS_H_
+#define CHROME_COMMON_ATTRITION_EXPERIMENTS_H_
+
+#include "chrome/grit/chromium_strings.h"
+
+namespace attrition_experiments {
+
+// A list of all the IDs we use for the attrition experiments.
+enum Experiment {
+ kEnUs1 = IDS_TRY_TOAST_HEADING,
+ kEnUs2 = IDS_TRY_TOAST_HEADING2,
+ kEnUs3 = IDS_TRY_TOAST_HEADING3,
+ kEnUs4 = IDS_TRY_TOAST_HEADING4,
+ kSkype1 = IDS_TRY_TOAST_HEADING_SKYPE,
+};
+
+// A comma-separated list of brand codes that are associated with Skype.
+const wchar_t kSkypeBrandCode[] = L"SKPC,SKPG,SKPH,SKPI,SKPL,SKPM,SKPN";
+
+} // namespace attrition_experiments
+
+#endif // CHROME_COMMON_ATTRITION_EXPERIMENTS_H_
diff --git a/chromium/chrome/common/auto_start_linux.cc b/chromium/chrome/common/auto_start_linux.cc
new file mode 100644
index 00000000000..66b6739bfb4
--- /dev/null
+++ b/chromium/chrome/common/auto_start_linux.cc
@@ -0,0 +1,95 @@
+// 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 "chrome/common/auto_start_linux.h"
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/nix/xdg_util.h"
+#include "base/strings/string_tokenizer.h"
+
+namespace {
+
+const base::FilePath::CharType kAutostart[] = "autostart";
+
+base::FilePath GetAutostartDirectory(base::Environment* environment) {
+ base::FilePath result = base::nix::GetXDGDirectory(
+ environment,
+ base::nix::kXdgConfigHomeEnvVar,
+ base::nix::kDotConfigDir);
+ result = result.Append(kAutostart);
+ return result;
+}
+
+} // namespace
+
+bool AutoStart::AddApplication(const std::string& autostart_filename,
+ const std::string& application_name,
+ const std::string& command_line,
+ bool is_terminal_app) {
+ std::unique_ptr<base::Environment> environment(base::Environment::Create());
+ base::FilePath autostart_directory = GetAutostartDirectory(environment.get());
+ if (!base::DirectoryExists(autostart_directory) &&
+ !base::CreateDirectory(autostart_directory)) {
+ return false;
+ }
+
+ base::FilePath autostart_file =
+ autostart_directory.Append(autostart_filename);
+ std::string terminal = is_terminal_app ? "true" : "false";
+ std::string autostart_file_contents =
+ "[Desktop Entry]\n"
+ "Type=Application\n"
+ "Terminal=" + terminal + "\n"
+ "Exec=" + command_line + "\n"
+ "Name=" + application_name + "\n";
+ std::string::size_type content_length = autostart_file_contents.length();
+ if (base::WriteFile(autostart_file, autostart_file_contents.c_str(),
+ content_length) !=
+ static_cast<int>(content_length)) {
+ base::DeleteFile(autostart_file, false);
+ return false;
+ }
+ return true;
+}
+
+bool AutoStart::Remove(const std::string& autostart_filename) {
+ std::unique_ptr<base::Environment> environment(base::Environment::Create());
+ base::FilePath autostart_directory = GetAutostartDirectory(environment.get());
+ base::FilePath autostart_file =
+ autostart_directory.Append(autostart_filename);
+ return base::DeleteFile(autostart_file, false);
+}
+
+bool AutoStart::GetAutostartFileContents(
+ const std::string& autostart_filename, std::string* contents) {
+ std::unique_ptr<base::Environment> environment(base::Environment::Create());
+ base::FilePath autostart_directory = GetAutostartDirectory(environment.get());
+ base::FilePath autostart_file =
+ autostart_directory.Append(autostart_filename);
+ return base::ReadFileToString(autostart_file, contents);
+}
+
+bool AutoStart::GetAutostartFileValue(const std::string& autostart_filename,
+ const std::string& value_name,
+ std::string* value) {
+ std::string contents;
+ if (!GetAutostartFileContents(autostart_filename, &contents))
+ return false;
+ base::StringTokenizer tokenizer(contents, "\n");
+ std::string token = value_name + "=";
+ while (tokenizer.GetNext()) {
+ if (tokenizer.token().substr(0, token.length()) == token) {
+ *value = tokenizer.token().substr(token.length());
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/chromium/chrome/common/auto_start_linux.h b/chromium/chrome/common/auto_start_linux.h
new file mode 100644
index 00000000000..e04e3b62a50
--- /dev/null
+++ b/chromium/chrome/common/auto_start_linux.h
@@ -0,0 +1,33 @@
+// 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 CHROME_COMMON_AUTO_START_LINUX_H_
+#define CHROME_COMMON_AUTO_START_LINUX_H_
+
+#include <string>
+
+#include "base/macros.h"
+
+class AutoStart {
+ public:
+ // Registers an application to autostart on user login. |is_terminal_app|
+ // specifies whether the app will run in a terminal window.
+ static bool AddApplication(const std::string& autostart_filename,
+ const std::string& application_name,
+ const std::string& command_line,
+ bool is_terminal_app);
+ // Removes an autostart file.
+ static bool Remove(const std::string& autostart_filename);
+ // Gets the entire contents of an autostart file.
+ static bool GetAutostartFileContents(const std::string& autostart_filename,
+ std::string* contents);
+ // Gets a specific value from an autostart file.
+ static bool GetAutostartFileValue(const std::string& autostart_filename,
+ const std::string& value_name,
+ std::string* value);
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(AutoStart);
+};
+
+#endif // CHROME_COMMON_AUTO_START_LINUX_H_
diff --git a/chromium/chrome/common/cast_messages.cc b/chromium/chrome/common/cast_messages.cc
new file mode 100644
index 00000000000..d1629f808cd
--- /dev/null
+++ b/chromium/chrome/common/cast_messages.cc
@@ -0,0 +1,55 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/cast_messages.h"
+
+namespace IPC {
+
+void ParamTraits<media::cast::RtpTimeTicks>::Write(base::Pickle* m,
+ const param_type& p) {
+ ParamTraits<uint64_t>::Write(m, p.SerializeForIPC());
+}
+
+bool ParamTraits<media::cast::RtpTimeTicks>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ uint64_t serialized = UINT64_C(0);
+ if (ParamTraits<uint64_t>::Read(m, iter, &serialized)) {
+ *r = param_type::DeserializeForIPC(serialized);
+ return true;
+ }
+ return false;
+}
+
+void ParamTraits<media::cast::RtpTimeTicks>::Log(const param_type& p,
+ std::string* l) {
+ std::ostringstream oss;
+ oss << p;
+ l->append(oss.str());
+}
+
+void ParamTraits<media::cast::FrameId>::Write(base::Pickle* m,
+ const param_type& p) {
+ ParamTraits<uint64_t>::Write(m, p.SerializeForIPC());
+}
+
+bool ParamTraits<media::cast::FrameId>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ uint64_t serialized = UINT64_C(0);
+ if (ParamTraits<uint64_t>::Read(m, iter, &serialized)) {
+ *r = param_type::DeserializeForIPC(serialized);
+ return true;
+ }
+ return false;
+}
+
+void ParamTraits<media::cast::FrameId>::Log(const param_type& p,
+ std::string* l) {
+ std::ostringstream oss;
+ oss << p;
+ l->append(oss.str());
+}
+
+} // namespace IPC
diff --git a/chromium/chrome/common/cast_messages.h b/chromium/chrome/common/cast_messages.h
new file mode 100644
index 00000000000..9a99cec4240
--- /dev/null
+++ b/chromium/chrome/common/cast_messages.h
@@ -0,0 +1,254 @@
+// Copyright 2014 The Chromium 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 the Cast transport API.
+
+#ifndef CHROME_COMMON_CAST_MESSAGES_H_
+#define CHROME_COMMON_CAST_MESSAGES_H_
+
+#include <stdint.h>
+
+#include "ipc/ipc_message_macros.h"
+#include "media/cast/common/rtp_time.h"
+#include "media/cast/logging/logging_defines.h"
+#include "media/cast/net/cast_transport.h"
+#include "media/cast/net/rtcp/rtcp_defines.h"
+#include "net/base/ip_endpoint.h"
+
+#ifndef INTERNAL_CHROME_COMMON_CAST_MESSAGES_H_
+#define INTERNAL_CHROME_COMMON_CAST_MESSAGES_H_
+
+namespace IPC {
+
+template<>
+struct ParamTraits<media::cast::RtpTimeTicks> {
+ using param_type = media::cast::RtpTimeTicks;
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template<>
+struct ParamTraits<media::cast::FrameId> {
+ using param_type = media::cast::FrameId;
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+#endif // INTERNAL_CHROME_COMMON_CAST_MESSAGES_H_
+
+// Multiply-included message file, hence no include guard from here.
+
+#undef IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_START CastMsgStart
+
+IPC_ENUM_TRAITS_MAX_VALUE(
+ media::cast::EncodedFrame::Dependency,
+ media::cast::EncodedFrame::DEPENDENCY_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(media::cast::Codec,
+ media::cast::CODEC_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(media::cast::CastTransportStatus,
+ media::cast::CAST_TRANSPORT_STATUS_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(media::cast::CastLoggingEvent,
+ media::cast::kNumOfLoggingEvents)
+IPC_ENUM_TRAITS_MAX_VALUE(media::cast::EventMediaType,
+ media::cast::EVENT_MEDIA_TYPE_LAST)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(media::cast::RtpPayloadType,
+ media::cast::RtpPayloadType::FIRST,
+ media::cast::RtpPayloadType::LAST)
+
+IPC_STRUCT_TRAITS_BEGIN(media::cast::EncodedFrame)
+ IPC_STRUCT_TRAITS_MEMBER(dependency)
+ IPC_STRUCT_TRAITS_MEMBER(frame_id)
+ IPC_STRUCT_TRAITS_MEMBER(referenced_frame_id)
+ IPC_STRUCT_TRAITS_MEMBER(rtp_timestamp)
+ IPC_STRUCT_TRAITS_MEMBER(reference_time)
+ IPC_STRUCT_TRAITS_MEMBER(new_playout_delay_ms)
+ IPC_STRUCT_TRAITS_MEMBER(data)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::cast::RtcpDlrrReportBlock)
+ IPC_STRUCT_TRAITS_MEMBER(last_rr)
+ IPC_STRUCT_TRAITS_MEMBER(delay_since_last_rr)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::cast::CastTransportRtpConfig)
+ IPC_STRUCT_TRAITS_MEMBER(ssrc)
+ IPC_STRUCT_TRAITS_MEMBER(rtp_stream_id)
+ IPC_STRUCT_TRAITS_MEMBER(feedback_ssrc)
+ IPC_STRUCT_TRAITS_MEMBER(rtp_payload_type)
+ IPC_STRUCT_TRAITS_MEMBER(aes_key)
+ IPC_STRUCT_TRAITS_MEMBER(aes_iv_mask)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::cast::PacketEvent)
+ IPC_STRUCT_TRAITS_MEMBER(rtp_timestamp)
+ IPC_STRUCT_TRAITS_MEMBER(frame_id)
+ IPC_STRUCT_TRAITS_MEMBER(max_packet_id)
+ IPC_STRUCT_TRAITS_MEMBER(packet_id)
+ IPC_STRUCT_TRAITS_MEMBER(size)
+ IPC_STRUCT_TRAITS_MEMBER(timestamp)
+ IPC_STRUCT_TRAITS_MEMBER(type)
+ IPC_STRUCT_TRAITS_MEMBER(media_type)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::cast::FrameEvent)
+ IPC_STRUCT_TRAITS_MEMBER(rtp_timestamp)
+ IPC_STRUCT_TRAITS_MEMBER(frame_id)
+ IPC_STRUCT_TRAITS_MEMBER(size)
+ IPC_STRUCT_TRAITS_MEMBER(timestamp)
+ IPC_STRUCT_TRAITS_MEMBER(type)
+ IPC_STRUCT_TRAITS_MEMBER(media_type)
+ IPC_STRUCT_TRAITS_MEMBER(delay_delta)
+ IPC_STRUCT_TRAITS_MEMBER(key_frame)
+ IPC_STRUCT_TRAITS_MEMBER(target_bitrate)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::cast::RtcpCastMessage)
+ IPC_STRUCT_TRAITS_MEMBER(remote_ssrc)
+ IPC_STRUCT_TRAITS_MEMBER(ack_frame_id)
+ IPC_STRUCT_TRAITS_MEMBER(target_delay_ms)
+ IPC_STRUCT_TRAITS_MEMBER(missing_frames_and_packets)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::cast::RtcpPliMessage)
+ IPC_STRUCT_TRAITS_MEMBER(remote_ssrc)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::cast::RtcpEvent)
+ IPC_STRUCT_TRAITS_MEMBER(type)
+ IPC_STRUCT_TRAITS_MEMBER(timestamp)
+ IPC_STRUCT_TRAITS_MEMBER(delay_delta)
+ IPC_STRUCT_TRAITS_MEMBER(packet_id)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::cast::RtcpReportBlock)
+ IPC_STRUCT_TRAITS_MEMBER(remote_ssrc)
+ IPC_STRUCT_TRAITS_MEMBER(media_ssrc)
+ IPC_STRUCT_TRAITS_MEMBER(fraction_lost)
+ IPC_STRUCT_TRAITS_MEMBER(cumulative_lost)
+ IPC_STRUCT_TRAITS_MEMBER(extended_high_sequence_number)
+ IPC_STRUCT_TRAITS_MEMBER(jitter)
+ IPC_STRUCT_TRAITS_MEMBER(last_sr)
+ IPC_STRUCT_TRAITS_MEMBER(delay_since_last_sr)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(media::cast::RtcpTimeData)
+ IPC_STRUCT_TRAITS_MEMBER(ntp_seconds)
+ IPC_STRUCT_TRAITS_MEMBER(ntp_fraction)
+ IPC_STRUCT_TRAITS_MEMBER(timestamp)
+IPC_STRUCT_TRAITS_END()
+
+// Cast messages sent from the browser to the renderer.
+
+IPC_MESSAGE_CONTROL2(CastMsg_ReceivedPacket,
+ int32_t /* channel_id */,
+ media::cast::Packet /* packet */)
+
+IPC_MESSAGE_CONTROL3(CastMsg_Rtt,
+ int32_t /* channel_id */,
+ uint32_t /* rtp sender ssrc */,
+ base::TimeDelta /* rtt */)
+
+IPC_MESSAGE_CONTROL3(CastMsg_RtcpCastMessage,
+ int32_t /* channel_id */,
+ uint32_t /* rtp sender ssrc */,
+ media::cast::RtcpCastMessage /* cast_message */)
+
+// This message indicates receiving picture loss indicator from rtp receiver.
+IPC_MESSAGE_CONTROL2(CastMsg_Pli,
+ int32_t /* channel_id */,
+ uint32_t /* rtp sender ssrc */)
+
+IPC_MESSAGE_CONTROL2(CastMsg_NotifyStatusChange,
+ int32_t /* channel_id */,
+ media::cast::CastTransportStatus /* status */)
+
+IPC_MESSAGE_CONTROL3(CastMsg_RawEvents,
+ int32_t /* channel_id */,
+ std::vector<media::cast::PacketEvent> /* packet_events */,
+ std::vector<media::cast::FrameEvent> /* frame_events */)
+
+// Cast messages sent from the renderer to the browser.
+
+IPC_MESSAGE_CONTROL2(CastHostMsg_InitializeStream,
+ int32_t /*channel_id*/,
+ media::cast::CastTransportRtpConfig /*config*/)
+
+IPC_MESSAGE_CONTROL3(CastHostMsg_InsertFrame,
+ int32_t /* channel_id */,
+ uint32_t /* ssrc */,
+ media::cast::EncodedFrame /* audio/video frame */)
+
+IPC_MESSAGE_CONTROL4(CastHostMsg_SendSenderReport,
+ int32_t /* channel_id */,
+ uint32_t /* ssrc */,
+ base::TimeTicks /* current_time */,
+ media::cast::RtpTimeTicks /* cur_time_as_rtp_timestamp */)
+
+IPC_MESSAGE_CONTROL3(CastHostMsg_CancelSendingFrames,
+ int32_t /* channel_id */,
+ uint32_t /* ssrc */,
+ std::vector<media::cast::FrameId> /* frame_ids */)
+
+IPC_MESSAGE_CONTROL3(CastHostMsg_ResendFrameForKickstart,
+ int32_t /* channel_id */,
+ uint32_t /* ssrc */,
+ media::cast::FrameId /* frame_id */)
+
+IPC_MESSAGE_CONTROL3(CastHostMsg_AddValidRtpReceiver,
+ int32_t /* channel id */,
+ uint32_t /* rtp sender ssrc */,
+ uint32_t /* rtp receiver ssrc */)
+
+IPC_MESSAGE_CONTROL4(CastHostMsg_New,
+ int32_t /* channel_id */,
+ net::IPEndPoint /* local_end_point */,
+ net::IPEndPoint /* remote_end_point */,
+ base::DictionaryValue /* options */)
+
+IPC_MESSAGE_CONTROL1(CastHostMsg_Delete, int32_t /* channel_id */)
+
+// The following messages are used to build and send the RTCP packet from the
+// RTP receiver. |CastHostMsg_InitializeRtpReceiverRtcpBuilder| needs to be sent
+// before sending other optional RTCP messages.
+// |CastHostMsg_SendRtcpFromRtpReceiver| has to be sent in the end to finish
+// building the packet. The built packet will then be sent out.
+
+IPC_MESSAGE_CONTROL3(CastHostMsg_InitializeRtpReceiverRtcpBuilder,
+ int32_t /* channel id */,
+ uint32_t /* rtp_receiver_ssrc */,
+ media::cast::RtcpTimeData /* time_data */)
+
+IPC_MESSAGE_CONTROL3(CastHostMsg_AddCastFeedback,
+ int32_t /* channel id */,
+ media::cast::RtcpCastMessage /* cast message */,
+ base::TimeDelta /* target delay */)
+
+IPC_MESSAGE_CONTROL2(CastHostMsg_AddPli,
+ int32_t /* channel id */,
+ media::cast::RtcpPliMessage /* pli message */)
+
+IPC_MESSAGE_CONTROL2(
+ CastHostMsg_AddRtcpEvents,
+ int32_t /* channel id */,
+ media::cast::ReceiverRtcpEventSubscriber::RtcpEvents /* rtcp_events */)
+
+IPC_MESSAGE_CONTROL2(
+ CastHostMsg_AddRtpReceiverReport,
+ int32_t /* channel id */,
+ media::cast::RtcpReportBlock /* rtp_receiver_report_block */)
+
+IPC_MESSAGE_CONTROL1(CastHostMsg_SendRtcpFromRtpReceiver,
+ int32_t /* channel id */)
+
+#endif // CHROME_COMMON_CAST_MESSAGES_H_
diff --git a/chromium/chrome/common/channel_info.cc b/chromium/chrome/common/channel_info.cc
new file mode 100644
index 00000000000..7345984f2a7
--- /dev/null
+++ b/chromium/chrome/common/channel_info.cc
@@ -0,0 +1,16 @@
+// 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 "chrome/common/channel_info.h"
+
+#include "components/version_info/version_info.h"
+#include "components/version_info/version_string.h"
+
+namespace chrome {
+
+std::string GetVersionString() {
+ return version_info::GetVersionStringWithModifier(GetChannelName());
+}
+
+} // namespace chrome
diff --git a/chromium/chrome/common/channel_info.h b/chromium/chrome/common/channel_info.h
new file mode 100644
index 00000000000..c2c6c3c2496
--- /dev/null
+++ b/chromium/chrome/common/channel_info.h
@@ -0,0 +1,66 @@
+// 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 CHROME_COMMON_CHANNEL_INFO_H_
+#define CHROME_COMMON_CHANNEL_INFO_H_
+
+#include <string>
+
+#include "build/build_config.h"
+
+namespace base {
+class Environment;
+}
+
+namespace version_info {
+enum class Channel;
+}
+
+namespace chrome {
+
+// Returns a version string to be displayed in "About Chromium" dialog.
+std::string GetVersionString();
+
+// Returns a human-readable modifier for the version string. For a branded
+// build, this modifier is the channel ("canary", "dev", or "beta", but ""
+// for stable). On Windows, this may be modified with additional information
+// after a hyphen. For multi-user installations, it will return "canary-m",
+// "dev-m", "beta-m", and for a stable channel multi-user installation, "m".
+// In branded builds, when the channel cannot be determined, "unknown" will
+// be returned. In unbranded builds, the modifier is usually an empty string
+// (""), although on Linux, it may vary in certain distributions.
+// GetChannelName() is intended to be used for display purposes.
+// To simply test the channel, use GetChannel().
+std::string GetChannelName();
+
+// Returns the channel for the installation. In branded builds, this will be
+// version_info::Channel::{STABLE,BETA,DEV,CANARY}. In unbranded builds, or
+// in branded builds when the channel cannot be determined, this will be
+// version_info::Channel::UNKNOWN.
+version_info::Channel GetChannel();
+
+#if defined(OS_MACOSX)
+// Maps the name of the channel to version_info::Channel, always returning
+// Channel::UNKNOWN for unbranded builds. For branded builds defaults to
+// Channel::STABLE, if channel is empty, else matches the name and returns
+// {STABLE,BETA,DEV,CANARY, UNKNOWN}.
+version_info::Channel GetChannelByName(const std::string& channel);
+#endif
+
+#if defined(OS_POSIX) && defined(GOOGLE_CHROME_BUILD)
+// Returns a channel-specific suffix to use when constructing the path of the
+// default user data directory, allowing multiple channels to run side-by-side.
+// In the stable channel, this returns the empty string.
+std::string GetChannelSuffixForDataDir();
+#endif
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// Returns the channel-specific filename of the desktop shortcut used to launch
+// the browser.
+std::string GetDesktopName(base::Environment* env);
+#endif
+
+} // namespace chrome
+
+#endif // CHROME_COMMON_CHANNEL_INFO_H_
diff --git a/chromium/chrome/common/channel_info_android.cc b/chromium/chrome/common/channel_info_android.cc
new file mode 100644
index 00000000000..d73a9460685
--- /dev/null
+++ b/chromium/chrome/common/channel_info_android.cc
@@ -0,0 +1,31 @@
+// 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 "chrome/common/channel_info.h"
+
+#include "base/android/build_info.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "components/version_info/android/channel_getter.h"
+#include "components/version_info/version_info.h"
+
+namespace chrome {
+
+std::string GetChannelName() {
+ switch (GetChannel()) {
+ case version_info::Channel::UNKNOWN: return "unknown";
+ case version_info::Channel::CANARY: return "canary";
+ case version_info::Channel::DEV: return "dev";
+ case version_info::Channel::BETA: return "beta";
+ case version_info::Channel::STABLE: return std::string();
+ }
+ NOTREACHED() << "Unknown channel " << static_cast<int>(GetChannel());
+ return std::string();
+}
+
+version_info::Channel GetChannel() {
+ return version_info::android::GetChannel();
+}
+
+} // namespace chrome
diff --git a/chromium/chrome/common/channel_info_chromeos.cc b/chromium/chrome/common/channel_info_chromeos.cc
new file mode 100644
index 00000000000..4f540e15166
--- /dev/null
+++ b/chromium/chrome/common/channel_info_chromeos.cc
@@ -0,0 +1,75 @@
+// 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 "chrome/common/channel_info.h"
+
+#include "base/system/sys_info.h"
+#include "build/branding_buildflags.h"
+#include "components/version_info/version_info.h"
+
+namespace chrome {
+namespace {
+
+version_info::Channel g_chromeos_channel = version_info::Channel::UNKNOWN;
+
+#if defined(GOOGLE_CHROME_BUILD)
+// Sets the |g_chromeos_channel|.
+void SetChannel(const std::string& channel) {
+ if (channel == "stable-channel")
+ g_chromeos_channel = version_info::Channel::STABLE;
+ else if (channel == "beta-channel")
+ g_chromeos_channel = version_info::Channel::BETA;
+ else if (channel == "dev-channel")
+ g_chromeos_channel = version_info::Channel::DEV;
+ else if (channel == "canary-channel")
+ g_chromeos_channel = version_info::Channel::CANARY;
+ else
+ g_chromeos_channel = version_info::Channel::UNKNOWN;
+}
+#endif
+
+} // namespace
+
+std::string GetChannelName() {
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ switch (g_chromeos_channel) {
+ case version_info::Channel::STABLE:
+ return std::string();
+ case version_info::Channel::BETA:
+ return "beta";
+ case version_info::Channel::DEV:
+ return "dev";
+ case version_info::Channel::CANARY:
+ return "canary";
+ default:
+ return "unknown";
+ }
+#endif
+ return std::string();
+}
+
+version_info::Channel GetChannel() {
+ static bool is_channel_set = false;
+ if (is_channel_set)
+ return g_chromeos_channel;
+
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ static const char kChromeOSReleaseTrack[] = "CHROMEOS_RELEASE_TRACK";
+ std::string channel;
+ if (base::SysInfo::GetLsbReleaseValue(kChromeOSReleaseTrack, &channel)) {
+ SetChannel(channel);
+ is_channel_set = true;
+ }
+#endif
+ return g_chromeos_channel;
+}
+
+#if defined(GOOGLE_CHROME_BUILD)
+std::string GetChannelSuffixForDataDir() {
+ // ChromeOS doesn't support side-by-side installations.
+ return std::string();
+}
+#endif // defined(GOOGLE_CHROME_BUILD)
+
+} // namespace chrome
diff --git a/chromium/chrome/common/channel_info_mac.mm b/chromium/chrome/common/channel_info_mac.mm
new file mode 100644
index 00000000000..3c8e51c4acb
--- /dev/null
+++ b/chromium/chrome/common/channel_info_mac.mm
@@ -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.
+
+#include "chrome/common/channel_info.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/mac/bundle_locations.h"
+#include "base/strings/sys_string_conversions.h"
+#include "build/branding_buildflags.h"
+#include "components/version_info/version_info.h"
+
+namespace chrome {
+
+std::string GetChannelName() {
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ // Use the main Chrome application bundle and not the framework bundle.
+ // Keystone keys don't live in the framework.
+ NSBundle* bundle = base::mac::OuterBundle();
+ NSString* channel = [bundle objectForInfoDictionaryKey:@"KSChannelID"];
+
+ // Only ever return "", "unknown", "beta", "dev", or "canary" in a branded
+ // build.
+ if (![bundle objectForInfoDictionaryKey:@"KSProductID"]) {
+ // This build is not Keystone-enabled, it can't have a channel.
+ channel = @"unknown";
+ } else if (!channel) {
+ // For the stable channel, KSChannelID is not set.
+ channel = @"";
+ } else if ([channel isEqual:@"beta"] ||
+ [channel isEqual:@"dev"] ||
+ [channel isEqual:@"canary"]) {
+ // do nothing.
+ } else {
+ channel = @"unknown";
+ }
+
+ return base::SysNSStringToUTF8(channel);
+#else
+ return std::string();
+#endif
+}
+
+version_info::Channel GetChannelByName(const std::string& channel) {
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ if (channel.empty())
+ return version_info::Channel::STABLE;
+ if (channel == "beta")
+ return version_info::Channel::BETA;
+ if (channel == "dev")
+ return version_info::Channel::DEV;
+ if (channel == "canary")
+ return version_info::Channel::CANARY;
+#endif
+ return version_info::Channel::UNKNOWN;
+}
+
+version_info::Channel GetChannel() {
+ return GetChannelByName(GetChannelName());
+}
+
+} // namespace chrome
diff --git a/chromium/chrome/common/channel_info_posix.cc b/chromium/chrome/common/channel_info_posix.cc
new file mode 100644
index 00000000000..d5dfbe13e27
--- /dev/null
+++ b/chromium/chrome/common/channel_info_posix.cc
@@ -0,0 +1,100 @@
+// 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 "chrome/common/channel_info.h"
+
+#include "base/environment.h"
+#include "base/strings/string_util.h"
+#include "build/branding_buildflags.h"
+#include "build/build_config.h"
+#include "components/version_info/version_info.h"
+
+namespace chrome {
+
+namespace {
+
+// Helper function to return both the channel enum and modifier string.
+// Implements both together to prevent their behavior from diverging, which has
+// happened multiple times in the past.
+version_info::Channel GetChannelImpl(std::string* modifier_out,
+ std::string* data_dir_suffix_out) {
+ version_info::Channel channel = version_info::Channel::UNKNOWN;
+ std::string modifier;
+ std::string data_dir_suffix;
+
+ char* env = getenv("CHROME_VERSION_EXTRA");
+ if (env)
+ modifier = env;
+
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ // Only ever return "", "unknown", "dev" or "beta" in a branded build.
+ if (modifier == "unstable") // linux version of "dev"
+ modifier = "dev";
+ if (modifier == "stable") {
+ channel = version_info::Channel::STABLE;
+ modifier = "";
+ } else if (modifier == "dev") {
+ channel = version_info::Channel::DEV;
+ data_dir_suffix = "-unstable";
+ } else if (modifier == "beta") {
+ channel = version_info::Channel::BETA;
+ data_dir_suffix = "-beta";
+ } else {
+ modifier = "unknown";
+ }
+#endif
+
+ if (modifier_out)
+ modifier_out->swap(modifier);
+ if (data_dir_suffix_out)
+ data_dir_suffix_out->swap(data_dir_suffix);
+
+ return channel;
+}
+
+} // namespace
+
+std::string GetChannelName() {
+ std::string modifier;
+ GetChannelImpl(&modifier, nullptr);
+ return modifier;
+}
+
+#if defined(GOOGLE_CHROME_BUILD)
+std::string GetChannelSuffixForDataDir() {
+ std::string data_dir_suffix;
+ GetChannelImpl(nullptr, &data_dir_suffix);
+ return data_dir_suffix;
+}
+#endif // defined(GOOGLE_CHROME_BUILD)
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+std::string GetDesktopName(base::Environment* env) {
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ version_info::Channel product_channel(GetChannel());
+ switch (product_channel) {
+ case version_info::Channel::DEV:
+ return "google-chrome-unstable.desktop";
+ case version_info::Channel::BETA:
+ return "google-chrome-beta.desktop";
+ default:
+ return "google-chrome.desktop";
+ }
+#else // BUILDFLAG(CHROMIUM_BRANDING)
+ // Allow $CHROME_DESKTOP to override the built-in value, so that development
+ // versions can set themselves as the default without interfering with
+ // non-official, packaged versions using the built-in value.
+ std::string name;
+ if (env->GetVar("CHROME_DESKTOP", &name) && !name.empty())
+ return name;
+ return "chromium-browser.desktop";
+#endif
+}
+#endif // defined(OS_LINUX) && !defined(OS_CHROMEOS)
+
+version_info::Channel GetChannel() {
+ return GetChannelImpl(nullptr, nullptr);
+}
+
+} // namespace chrome
diff --git a/chromium/chrome/common/channel_info_win.cc b/chromium/chrome/common/channel_info_win.cc
new file mode 100644
index 00000000000..8a9e2d3335b
--- /dev/null
+++ b/chromium/chrome/common/channel_info_win.cc
@@ -0,0 +1,33 @@
+// 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 "chrome/common/channel_info.h"
+
+#include "base/debug/profiler.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
+#include "chrome/install_static/install_util.h"
+
+namespace chrome {
+
+std::string GetChannelName() {
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ base::string16 channel(install_static::GetChromeChannelName());
+#if defined(DCHECK_IS_CONFIGURABLE)
+ // Adorn the channel when DCHECKs are baked into the build, as there will be
+ // a performance hit. See https://crbug.com/812058 for details.
+ channel += L"-dcheck";
+#endif // defined(DCHECK_IS_CONFIGURABLE)
+ return base::UTF16ToASCII(channel);
+#else
+ return std::string();
+#endif
+}
+
+version_info::Channel GetChannel() {
+ return install_static::GetChromeChannel();
+}
+
+} // namespace chrome
diff --git a/chromium/chrome/common/child_process_logging.h b/chromium/chrome/common/child_process_logging.h
new file mode 100644
index 00000000000..cf69a11eea4
--- /dev/null
+++ b/chromium/chrome/common/child_process_logging.h
@@ -0,0 +1,19 @@
+// 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 CHROME_COMMON_CHILD_PROCESS_LOGGING_H_
+#define CHROME_COMMON_CHILD_PROCESS_LOGGING_H_
+
+#include "build/build_config.h"
+
+namespace child_process_logging {
+
+#if defined(OS_WIN)
+// Sets up the base/debug/crash_logging.h mechanism.
+void Init();
+#endif // defined(OS_WIN)
+
+} // namespace child_process_logging
+
+#endif // CHROME_COMMON_CHILD_PROCESS_LOGGING_H_
diff --git a/chromium/chrome/common/child_process_logging_win.cc b/chromium/chrome/common/child_process_logging_win.cc
new file mode 100644
index 00000000000..3cb69614ff7
--- /dev/null
+++ b/chromium/chrome/common/child_process_logging_win.cc
@@ -0,0 +1,32 @@
+// 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 "chrome/common/child_process_logging.h"
+
+#include <windows.h>
+
+#include <memory>
+
+#include "chrome/chrome_elf/chrome_elf_main.h"
+#include "chrome/common/crash_keys.h"
+#include "chrome/installer/util/google_update_settings.h"
+#include "components/metrics/client_info.h"
+
+namespace child_process_logging {
+
+void Init() {
+ // This would be handled by BreakpadClient::SetCrashClientIdFromGUID(), but
+ // because of the aforementioned issue, crash keys aren't ready yet at the
+ // time of Breakpad initialization, load the client id backed up in Google
+ // Update settings instead.
+ // Please note if we are using Crashpad via chrome_elf then we need to call
+ // into chrome_elf to pass in the client id.
+ std::unique_ptr<metrics::ClientInfo> client_info =
+ GoogleUpdateSettings::LoadMetricsClientInfo();
+
+ // Set the client id chrome_elf (in tests this is stubbed).
+ SetMetricsClientId(client_info ? client_info->client_id.c_str() : nullptr);
+}
+
+} // namespace child_process_logging
diff --git a/chromium/chrome/common/chrome_constants_win_unittest.cc b/chromium/chrome/common/chrome_constants_win_unittest.cc
new file mode 100644
index 00000000000..0e5bd0f996b
--- /dev/null
+++ b/chromium/chrome/common/chrome_constants_win_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/chrome_constants.h"
+
+#include <memory>
+
+#include "base/file_version_info.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome {
+
+// Verify that |kChromeVersion| is equal to the version in the VS_VERSION_INFO
+// resource of chrome.exe.
+TEST(ChromeConstants, ChromeVersion) {
+ base::FilePath current_exe_dir;
+ EXPECT_TRUE(base::PathService::Get(base::DIR_EXE, &current_exe_dir));
+ base::FilePath chrome_exe_path =
+ current_exe_dir.Append(chrome::kBrowserProcessExecutableName);
+
+ std::unique_ptr<FileVersionInfo> file_version_info(
+ FileVersionInfo::CreateFileVersionInfo(chrome_exe_path));
+ ASSERT_TRUE(file_version_info);
+ EXPECT_EQ(base::UTF16ToASCII(file_version_info->file_version()),
+ kChromeVersion);
+}
+
+} // namespace chrome
diff --git a/chromium/chrome/common/chrome_content_client.cc b/chromium/chrome/common/chrome_content_client.cc
new file mode 100644
index 00000000000..c0b96efac11
--- /dev/null
+++ b/chromium/chrome/common/chrome_content_client.cc
@@ -0,0 +1,853 @@
+// 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 "chrome/common/chrome_content_client.h"
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <tuple>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/containers/flat_set.h"
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/native_library.h"
+#include "base/no_destructor.h"
+#include "base/path_service.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/version.h"
+#include "build/branding_buildflags.h"
+#include "build/build_config.h"
+#include "chrome/common/channel_info.h"
+#include "chrome/common/child_process_logging.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/crash_keys.h"
+#include "chrome/common/pepper_flash.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/grit/common_resources.h"
+#include "components/crash/core/common/crash_key.h"
+#include "components/dom_distiller/core/url_constants.h"
+#include "components/net_log/chrome_net_log.h"
+#include "components/services/heap_profiling/public/cpp/profiling_client.h"
+#include "content/public/common/cdm_info.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/buildflags/buildflags.h"
+#include "extensions/common/constants.h"
+#include "gpu/config/gpu_info.h"
+#include "gpu/config/gpu_util.h"
+#include "media/base/decrypt_config.h"
+#include "media/base/media_switches.h"
+#include "media/base/video_codecs.h"
+#include "media/media_buildflags.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "net/http/http_util.h"
+#include "pdf/buildflags.h"
+#include "ppapi/buildflags/buildflags.h"
+#include "third_party/widevine/cdm/buildflags.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/layout.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "url/url_constants.h"
+
+#if defined(OS_LINUX)
+#include <fcntl.h>
+#include "chrome/common/component_flash_hint_file_linux.h"
+#include "sandbox/linux/services/credentials.h"
+#endif // defined(OS_LINUX)
+
+#if defined(OS_MACOSX)
+#include "services/service_manager/sandbox/mac/nacl_loader.sb.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+#if BUILDFLAG(ENABLE_NACL)
+#include "components/nacl/common/nacl_constants.h"
+#include "components/nacl/common/nacl_process_type.h"
+#endif
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+#include "content/public/common/pepper_plugin_info.h"
+#include "flapper_version.h" // nogncheck In SHARED_INTERMEDIATE_DIR.
+#include "ppapi/shared_impl/ppapi_permissions.h" // nogncheck
+#endif
+
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+#include "media/cdm/cdm_paths.h" // nogncheck
+#endif
+
+#if BUILDFLAG(ENABLE_WIDEVINE) && defined(OS_LINUX)
+#include "base/no_destructor.h"
+#include "chrome/common/media/cdm_manifest.h"
+#include "third_party/widevine/cdm/widevine_cdm_common.h" // nogncheck
+// TODO(crbug.com/663554): Needed for WIDEVINE_CDM_VERSION_STRING. Support
+// component updated CDM on all desktop platforms and remove this.
+// This file is In SHARED_INTERMEDIATE_DIR.
+#include "widevine_cdm_version.h" // nogncheck
+#if !defined(OS_CHROMEOS)
+#include "chrome/common/media/component_widevine_cdm_hint_file_linux.h"
+#endif // !defined(OS_CHROMEOS)
+#endif // BUILDFLAG(ENABLE_WIDEVINE) && defined(OS_LINUX)
+
+#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
+#include "chrome/common/media/cdm_host_file_path.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "chrome/common/media/chrome_media_drm_bridge_client.h"
+#endif
+
+namespace {
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+#if BUILDFLAG(ENABLE_PDF)
+const char kPDFPluginExtension[] = "pdf";
+const char kPDFPluginDescription[] = "Portable Document Format";
+const char kPDFPluginOutOfProcessMimeType[] =
+ "application/x-google-chrome-pdf";
+const uint32_t kPDFPluginPermissions = ppapi::PERMISSION_PDF |
+ ppapi::PERMISSION_DEV;
+
+content::PepperPluginInfo::GetInterfaceFunc g_pdf_get_interface;
+content::PepperPluginInfo::PPP_InitializeModuleFunc g_pdf_initialize_module;
+content::PepperPluginInfo::PPP_ShutdownModuleFunc g_pdf_shutdown_module;
+#endif // BUILDFLAG(ENABLE_PDF)
+
+#if BUILDFLAG(ENABLE_NACL)
+content::PepperPluginInfo::GetInterfaceFunc g_nacl_get_interface;
+content::PepperPluginInfo::PPP_InitializeModuleFunc g_nacl_initialize_module;
+content::PepperPluginInfo::PPP_ShutdownModuleFunc g_nacl_shutdown_module;
+#endif
+
+// Appends the known built-in plugins to the given vector. Some built-in
+// plugins are "internal" which means they are compiled into the Chrome binary,
+// and some are extra shared libraries distributed with the browser (these are
+// not marked internal, aside from being automatically registered, they're just
+// regular plugins).
+void ComputeBuiltInPlugins(std::vector<content::PepperPluginInfo>* plugins) {
+#if BUILDFLAG(ENABLE_PDF)
+ content::PepperPluginInfo pdf_info;
+ pdf_info.is_internal = true;
+ pdf_info.is_out_of_process = true;
+ pdf_info.name = ChromeContentClient::kPDFInternalPluginName;
+ pdf_info.description = kPDFPluginDescription;
+ pdf_info.path = base::FilePath(ChromeContentClient::kPDFPluginPath);
+ content::WebPluginMimeType pdf_mime_type(
+ kPDFPluginOutOfProcessMimeType,
+ kPDFPluginExtension,
+ kPDFPluginDescription);
+ pdf_info.mime_types.push_back(pdf_mime_type);
+ pdf_info.internal_entry_points.get_interface = g_pdf_get_interface;
+ pdf_info.internal_entry_points.initialize_module = g_pdf_initialize_module;
+ pdf_info.internal_entry_points.shutdown_module = g_pdf_shutdown_module;
+ pdf_info.permissions = kPDFPluginPermissions;
+ plugins->push_back(pdf_info);
+#endif // BUILDFLAG(ENABLE_PDF)
+
+#if BUILDFLAG(ENABLE_NACL)
+ // Handle Native Client just like the PDF plugin. This means that it is
+ // enabled by default for the non-portable case. This allows apps installed
+ // from the Chrome Web Store to use NaCl even if the command line switch
+ // isn't set. For other uses of NaCl we check for the command line switch.
+ content::PepperPluginInfo nacl;
+ // The nacl plugin is now built into the Chromium binary.
+ nacl.is_internal = true;
+ nacl.path = base::FilePath(ChromeContentClient::kNaClPluginFileName);
+ nacl.name = nacl::kNaClPluginName;
+ content::WebPluginMimeType nacl_mime_type(nacl::kNaClPluginMimeType,
+ nacl::kNaClPluginExtension,
+ nacl::kNaClPluginDescription);
+ nacl.mime_types.push_back(nacl_mime_type);
+ content::WebPluginMimeType pnacl_mime_type(nacl::kPnaclPluginMimeType,
+ nacl::kPnaclPluginExtension,
+ nacl::kPnaclPluginDescription);
+ nacl.mime_types.push_back(pnacl_mime_type);
+ nacl.internal_entry_points.get_interface = g_nacl_get_interface;
+ nacl.internal_entry_points.initialize_module = g_nacl_initialize_module;
+ nacl.internal_entry_points.shutdown_module = g_nacl_shutdown_module;
+ nacl.permissions = ppapi::PERMISSION_PRIVATE | ppapi::PERMISSION_DEV;
+ plugins->push_back(nacl);
+#endif // BUILDFLAG(ENABLE_NACL)
+}
+
+// Creates a PepperPluginInfo for the specified plugin.
+// |path| is the full path to the plugin.
+// |version| is a string representation of the plugin version.
+// |is_external| is whether the plugin is supplied external to Chrome e.g. a
+// system installation of Adobe Flash.
+content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path,
+ const std::string& version,
+ bool is_external) {
+ content::PepperPluginInfo plugin;
+
+ plugin.is_out_of_process = true;
+ plugin.name = content::kFlashPluginName;
+ plugin.path = path;
+ plugin.permissions = kPepperFlashPermissions;
+ plugin.is_external = is_external;
+
+ std::vector<std::string> flash_version_numbers = base::SplitString(
+ version, ".", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ if (flash_version_numbers.size() < 1)
+ flash_version_numbers.push_back("11");
+ if (flash_version_numbers.size() < 2)
+ flash_version_numbers.push_back("2");
+ if (flash_version_numbers.size() < 3)
+ flash_version_numbers.push_back("999");
+ if (flash_version_numbers.size() < 4)
+ flash_version_numbers.push_back("999");
+ // E.g., "Shockwave Flash 10.2 r154":
+ plugin.description = plugin.name + " " + flash_version_numbers[0] + "." +
+ flash_version_numbers[1] + " r" + flash_version_numbers[2];
+ plugin.version = base::JoinString(flash_version_numbers, ".");
+ content::WebPluginMimeType swf_mime_type(content::kFlashPluginSwfMimeType,
+ content::kFlashPluginSwfExtension,
+ content::kFlashPluginSwfDescription);
+ plugin.mime_types.push_back(swf_mime_type);
+ content::WebPluginMimeType spl_mime_type(content::kFlashPluginSplMimeType,
+ content::kFlashPluginSplExtension,
+ content::kFlashPluginSplDescription);
+ plugin.mime_types.push_back(spl_mime_type);
+
+ return plugin;
+}
+
+bool GetCommandLinePepperFlash(content::PepperPluginInfo* plugin) {
+ const base::CommandLine::StringType flash_path =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
+ switches::kPpapiFlashPath);
+ if (flash_path.empty())
+ return false;
+
+ // Also get the version from the command-line. Should be something like 11.2
+ // or 11.2.123.45.
+ std::string flash_version =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kPpapiFlashVersion);
+
+ *plugin = CreatePepperFlashInfo(base::FilePath(flash_path), flash_version,
+ true);
+ return true;
+}
+
+// Check if flash player exists on disk, and if so, populate a PepperPluginInfo
+// structure. Returns false if the flash player found is not compatible with the
+// system (architecture, OS, versions, etc.).
+bool TryCreatePepperFlashInfo(const base::FilePath& flash_filename,
+ content::PepperPluginInfo* plugin) {
+ if (!base::PathExists(flash_filename))
+ return false;
+
+ base::FilePath manifest_path(
+ flash_filename.DirName().Append(FILE_PATH_LITERAL("manifest.json")));
+
+ std::string manifest_data;
+ if (!base::ReadFileToString(manifest_path, &manifest_data))
+ return false;
+
+ std::unique_ptr<base::DictionaryValue> manifest =
+ base::DictionaryValue::From(base::JSONReader::ReadDeprecated(
+ manifest_data, base::JSON_ALLOW_TRAILING_COMMAS));
+ if (!manifest)
+ return false;
+
+ base::Version version;
+ if (!CheckPepperFlashManifest(*manifest, &version)) {
+ LOG(ERROR) << "Browser not compatible with given flash manifest.";
+ return false;
+ }
+
+ *plugin = CreatePepperFlashInfo(flash_filename, version.GetString(), true);
+ return true;
+}
+
+#if defined(OS_CHROMEOS)
+bool GetComponentUpdatedPepperFlash(content::PepperPluginInfo* plugin) {
+ base::FilePath flash_filename;
+ if (!base::PathService::Get(chrome::FILE_CHROME_OS_COMPONENT_FLASH,
+ &flash_filename)) {
+ return false;
+ }
+
+ // Chrome OS mounts a disk image containing component updated flash player, at
+ // boot time, if and only if a component update is present.
+ if (!base::PathExists(flash_filename))
+ return false;
+
+ return TryCreatePepperFlashInfo(flash_filename, plugin);
+}
+#elif defined(OS_LINUX)
+// This method is used on Linux only because of architectural differences in how
+// it loads the component updated flash plugin, and not because the other
+// platforms do not support component updated flash. On other platforms, the
+// component updater sends an IPC message to all threads, at undefined points in
+// time, with the URL of the component updated flash. Because the linux zygote
+// thread has no access to the file system after it warms up, it must preload
+// the component updated flash.
+bool GetComponentUpdatedPepperFlash(content::PepperPluginInfo* plugin) {
+#if defined(FLAPPER_AVAILABLE)
+ if (component_flash_hint_file::DoesHintFileExist()) {
+ base::FilePath flash_path;
+ std::string version;
+ if (component_flash_hint_file::VerifyAndReturnFlashLocation(&flash_path,
+ &version)) {
+ // Test if the file can be mapped as executable. If the user's home
+ // directory is mounted noexec, the component flash plugin will not load.
+ // By testing for this, Chrome can fallback to the bundled flash plugin.
+ if (!component_flash_hint_file::TestExecutableMapping(flash_path)) {
+ LOG(WARNING) << "The component updated flash plugin could not be "
+ "mapped as executable. Attempting to fallback to the "
+ "bundled or system plugin.";
+ return false;
+ }
+ *plugin = CreatePepperFlashInfo(flash_path, version, false);
+ return true;
+ }
+ LOG(ERROR)
+ << "Failed to locate and load the component updated flash plugin.";
+ }
+#endif // defined(FLAPPER_AVAILABLE)
+ return false;
+}
+#endif // defined(OS_CHROMEOS)
+
+bool GetSystemPepperFlash(content::PepperPluginInfo* plugin) {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ // Do not try and find System Pepper Flash if there is a specific path on
+ // the commmand-line.
+ if (command_line->HasSwitch(switches::kPpapiFlashPath))
+ return false;
+
+ base::FilePath flash_filename;
+ if (!base::PathService::Get(chrome::FILE_PEPPER_FLASH_SYSTEM_PLUGIN,
+ &flash_filename))
+ return false;
+
+ return TryCreatePepperFlashInfo(flash_filename, plugin);
+}
+#endif // BUILDFLAG(ENABLE_PLUGINS)
+
+#if (BUILDFLAG(BUNDLE_WIDEVINE_CDM) || \
+ BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)) && \
+ defined(OS_LINUX)
+// Create a CdmInfo for a Widevine CDM, using |version|, |cdm_library_path|, and
+// |capability|.
+std::unique_ptr<content::CdmInfo> CreateWidevineCdmInfo(
+ const base::Version& version,
+ const base::FilePath& cdm_library_path,
+ content::CdmCapability capability) {
+ return std::make_unique<content::CdmInfo>(
+ kWidevineCdmDisplayName, kWidevineCdmGuid, version, cdm_library_path,
+ kWidevineCdmFileSystemId, std::move(capability), kWidevineKeySystem,
+ false);
+}
+
+#if !defined(OS_CHROMEOS)
+// On desktop Linux, given |cdm_base_path| that points to a folder containing
+// the Widevine CDM and associated files, read the manifest included in that
+// directory and create a CdmInfo. If that is successful, return the CdmInfo. If
+// not, return nullptr.
+std::unique_ptr<content::CdmInfo> CreateCdmInfoFromWidevineDirectory(
+ const base::FilePath& cdm_base_path) {
+ // Library should be inside a platform specific directory.
+ auto cdm_library_path =
+ media::GetPlatformSpecificDirectory(cdm_base_path)
+ .Append(base::GetNativeLibraryName(kWidevineCdmLibraryName));
+ if (!base::PathExists(cdm_library_path))
+ return nullptr;
+
+ // Manifest should be at the top level.
+ auto manifest_path = cdm_base_path.Append(FILE_PATH_LITERAL("manifest.json"));
+ base::Version version;
+ content::CdmCapability capability;
+ if (!ParseCdmManifestFromPath(manifest_path, &version, &capability))
+ return nullptr;
+
+ return CreateWidevineCdmInfo(version, cdm_library_path,
+ std::move(capability));
+}
+#endif // !defined(OS_CHROMEOS)
+#endif // (BUILDFLAG(BUNDLE_WIDEVINE_CDM) ||
+ // BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)) && defined(OS_LINUX)
+
+#if BUILDFLAG(BUNDLE_WIDEVINE_CDM) && defined(OS_LINUX)
+// On Linux/ChromeOS we have to preload the CDM since it uses the zygote
+// sandbox. On Windows and Mac, the bundled CDM is handled by the component
+// updater.
+
+#if defined(OS_CHROMEOS)
+std::unique_ptr<content::CdmInfo> CreateCdmInfoForChromeOS(
+ const base::FilePath& install_dir) {
+ // On ChromeOS the Widevine CDM library is in the component directory and
+ // does not have a manifest.
+ // TODO(crbug.com/971433): Move Widevine CDM to a separate folder in the
+ // component directory so that the manifest can be included.
+ auto cdm_library_path =
+ install_dir.Append(base::GetNativeLibraryName(kWidevineCdmLibraryName));
+ if (!base::PathExists(cdm_library_path))
+ return nullptr;
+
+ // As there is no manifest, set |capability| as if it came from one. These
+ // values must match the CDM that is being bundled with Chrome.
+ content::CdmCapability capability;
+
+ // Add the supported codecs as if they came from the component manifest.
+ capability.video_codecs.push_back(media::VideoCodec::kCodecVP8);
+ capability.video_codecs.push_back(media::VideoCodec::kCodecVP9);
+ capability.video_codecs.push_back(media::VideoCodec::kCodecAV1);
+ // TODO(crbug.com/899403): Update this and tests after Widevine CDM supports
+ // VP9 profile 2.
+ capability.supports_vp9_profile2 = false;
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+ capability.video_codecs.push_back(media::VideoCodec::kCodecH264);
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+
+ // Both encryption schemes are supported on ChromeOS.
+ capability.encryption_schemes.insert(media::EncryptionMode::kCenc);
+ capability.encryption_schemes.insert(media::EncryptionMode::kCbcs);
+
+ // Both temporary and persistent sessions are supported on ChromeOS.
+ capability.session_types.insert(media::CdmSessionType::kTemporary);
+ capability.session_types.insert(media::CdmSessionType::kPersistentLicense);
+
+ return CreateWidevineCdmInfo(base::Version(WIDEVINE_CDM_VERSION_STRING),
+ cdm_library_path, std::move(capability));
+}
+#endif // defined(OS_CHROMEOS)
+
+// This code checks to see if the Widevine CDM was bundled with Chrome. If one
+// can be found and looks valid, it returns the CdmInfo for the CDM. Otherwise
+// it returns nullptr.
+content::CdmInfo* GetBundledWidevine() {
+ // We only want to do this on the first call, as if Widevine wasn't bundled
+ // with Chrome (or it was deleted/removed) it won't be loaded into the zygote.
+ static base::NoDestructor<std::unique_ptr<content::CdmInfo>> s_cdm_info(
+ []() -> std::unique_ptr<content::CdmInfo> {
+ base::FilePath install_dir;
+ CHECK(base::PathService::Get(chrome::DIR_BUNDLED_WIDEVINE_CDM,
+ &install_dir));
+
+#if defined(OS_CHROMEOS)
+ // On ChromeOS the Widevine CDM library is in the component directory
+ // (returned above) and does not have a manifest.
+ // TODO(crbug.com/971433): Move Widevine CDM to a separate folder in
+ // the component directory so that the manifest can be included.
+ return CreateCdmInfoForChromeOS(install_dir);
+#else
+ // On desktop Linux the MANIFEST is bundled with the CDM.
+ return CreateCdmInfoFromWidevineDirectory(install_dir);
+#endif // defined(OS_CHROMEOS)
+ }());
+ return s_cdm_info->get();
+}
+#endif // BUILDFLAG(BUNDLE_WIDEVINE_CDM) && defined(OS_LINUX)
+
+#if BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT) && defined(OS_LINUX)
+// This code checks to see if a component updated Widevine CDM can be found. If
+// there is one and it looks valid, return the CdmInfo for that CDM. Otherwise
+// return nullptr.
+content::CdmInfo* GetComponentUpdatedWidevine() {
+ // We only want to do this on the first call, as the component updater may run
+ // and download a new version once Chrome has been running for a while. Since
+ // the first returned version will be the one loaded into the zygote, we want
+ // to return the same thing on subsequent calls.
+ static base::NoDestructor<std::unique_ptr<content::CdmInfo>> s_cdm_info(
+ []() -> std::unique_ptr<content::CdmInfo> {
+ auto install_dir = GetLatestComponentUpdatedWidevineCdmDirectory();
+ if (install_dir.empty())
+ return nullptr;
+
+ return CreateCdmInfoFromWidevineDirectory(install_dir);
+ }());
+ return s_cdm_info->get();
+}
+#endif // BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT) && defined(OS_LINUX)
+
+} // namespace
+
+ChromeContentClient::ChromeContentClient() {
+}
+
+ChromeContentClient::~ChromeContentClient() {
+}
+
+#if BUILDFLAG(ENABLE_NACL)
+void ChromeContentClient::SetNaClEntryFunctions(
+ content::PepperPluginInfo::GetInterfaceFunc get_interface,
+ content::PepperPluginInfo::PPP_InitializeModuleFunc initialize_module,
+ content::PepperPluginInfo::PPP_ShutdownModuleFunc shutdown_module) {
+ g_nacl_get_interface = get_interface;
+ g_nacl_initialize_module = initialize_module;
+ g_nacl_shutdown_module = shutdown_module;
+}
+#endif
+
+#if BUILDFLAG(ENABLE_PLUGINS) && BUILDFLAG(ENABLE_PDF)
+void ChromeContentClient::SetPDFEntryFunctions(
+ content::PepperPluginInfo::GetInterfaceFunc get_interface,
+ content::PepperPluginInfo::PPP_InitializeModuleFunc initialize_module,
+ content::PepperPluginInfo::PPP_ShutdownModuleFunc shutdown_module) {
+ g_pdf_get_interface = get_interface;
+ g_pdf_initialize_module = initialize_module;
+ g_pdf_shutdown_module = shutdown_module;
+}
+#endif
+
+void ChromeContentClient::SetActiveURL(const GURL& url,
+ std::string top_origin) {
+ static crash_reporter::CrashKeyString<1024> active_url("url-chunk");
+ active_url.Set(url.possibly_invalid_spec());
+
+ // Use a large enough size for Origin::GetDebugString.
+ static crash_reporter::CrashKeyString<128> top_origin_key("top-origin");
+ top_origin_key.Set(top_origin);
+}
+
+void ChromeContentClient::SetGpuInfo(const gpu::GPUInfo& gpu_info) {
+ gpu::SetKeysForCrashLogging(gpu_info);
+}
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+// static
+content::PepperPluginInfo* ChromeContentClient::FindMostRecentPlugin(
+ const std::vector<std::unique_ptr<content::PepperPluginInfo>>& plugins) {
+ if (plugins.empty())
+ return nullptr;
+
+ using PluginSortKey = std::tuple<base::Version, bool>;
+
+ std::map<PluginSortKey, content::PepperPluginInfo*> plugin_map;
+
+ for (auto& plugin : plugins) {
+ base::Version version(plugin->version);
+ DCHECK(version.IsValid());
+ plugin_map[PluginSortKey(version, plugin->is_external)] = plugin.get();
+ }
+
+ return plugin_map.rbegin()->second;
+}
+#endif // BUILDFLAG(ENABLE_PLUGINS)
+
+void ChromeContentClient::AddPepperPlugins(
+ std::vector<content::PepperPluginInfo>* plugins) {
+#if BUILDFLAG(ENABLE_PLUGINS)
+ ComputeBuiltInPlugins(plugins);
+
+ // If flash is disabled, do not try to add any flash plugin.
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ bool disable_bundled_flash =
+ command_line->HasSwitch(switches::kDisableBundledPpapiFlash);
+
+ std::vector<std::unique_ptr<content::PepperPluginInfo>> flash_versions;
+
+// Get component updated flash for desktop Linux and Chrome OS.
+#if defined(OS_LINUX)
+ // Depending on the sandbox configuration, the file system
+ // is not always available. If it is not available, do not try and load any
+ // flash plugin. The flash player, if any, preloaded before the sandbox
+ // initialization will continue to be used.
+ if (!sandbox::Credentials::HasFileSystemAccess())
+ return;
+
+ auto component_flash = std::make_unique<content::PepperPluginInfo>();
+ if (!disable_bundled_flash &&
+ GetComponentUpdatedPepperFlash(component_flash.get()))
+ flash_versions.push_back(std::move(component_flash));
+#endif // defined(OS_LINUX)
+
+ auto command_line_flash = std::make_unique<content::PepperPluginInfo>();
+ if (GetCommandLinePepperFlash(command_line_flash.get()))
+ flash_versions.push_back(std::move(command_line_flash));
+
+ auto system_flash = std::make_unique<content::PepperPluginInfo>();
+ if (GetSystemPepperFlash(system_flash.get()))
+ flash_versions.push_back(std::move(system_flash));
+
+ // This function will return only the most recent version of the flash plugin.
+ content::PepperPluginInfo* max_flash = FindMostRecentPlugin(flash_versions);
+ if (max_flash) {
+ plugins->push_back(*max_flash);
+ } else if (!disable_bundled_flash) {
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(FLAPPER_AVAILABLE)
+ // Add a fake Flash plugin even though it doesn't actually exist - if a
+ // web page requests it, it will be component-updated on-demand. There is
+ // nothing that guarantees the component update will give us the
+ // FLAPPER_VERSION_STRING version of Flash, but using this version seems
+ // better than any other hardcoded alternative.
+ plugins->push_back(
+ CreatePepperFlashInfo(base::FilePath(ChromeContentClient::kNotPresent),
+ FLAPPER_VERSION_STRING, false));
+#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(FLAPPER_AVAILABLE)
+ }
+#endif // BUILDFLAG(ENABLE_PLUGINS)
+}
+
+void ChromeContentClient::AddContentDecryptionModules(
+ std::vector<content::CdmInfo>* cdms,
+ std::vector<media::CdmHostFilePath>* cdm_host_file_paths) {
+ if (cdms) {
+#if BUILDFLAG(ENABLE_WIDEVINE) && defined(OS_LINUX)
+ // The Widevine CDM on Linux needs to be registered (and loaded) before the
+ // zygote is locked down. The CDM can be found from the version bundled with
+ // Chrome (if BUNDLE_WIDEVINE_CDM = true) and/or the version downloaded by
+ // the component updater (if ENABLE_WIDEVINE_CDM_COMPONENT = true). If two
+ // versions exist, take the one with the higher version number.
+ //
+ // Note that the component updater will detect the bundled version, and if
+ // there is no newer version available, select the bundled version. In this
+ // case both versions will be the same and point to the same directory, so
+ // it doesn't matter which one is loaded.
+ content::CdmInfo* bundled_widevine = nullptr;
+#if BUILDFLAG(BUNDLE_WIDEVINE_CDM)
+ bundled_widevine = GetBundledWidevine();
+#endif
+
+ content::CdmInfo* updated_widevine = nullptr;
+#if BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
+ updated_widevine = GetComponentUpdatedWidevine();
+#endif
+
+ // If only a bundled version is available, or both are available and the
+ // bundled version is not less than the updated version, register the
+ // bundled version. If only the updated version is available, or both are
+ // available and the updated version is greater, then register the updated
+ // version. If neither are available, then nothing is registered.
+ if (bundled_widevine &&
+ (!updated_widevine ||
+ bundled_widevine->version >= updated_widevine->version)) {
+ VLOG(1) << "Registering bundled Widevine " << bundled_widevine->version;
+ cdms->push_back(*bundled_widevine);
+ } else if (updated_widevine) {
+ VLOG(1) << "Registering component updated Widevine "
+ << updated_widevine->version;
+ cdms->push_back(*updated_widevine);
+ } else {
+ VLOG(1) << "Widevine enabled but no library found";
+ }
+#endif // BUILDFLAG(ENABLE_WIDEVINE) && defined(OS_LINUX)
+
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+ // Register Clear Key CDM if specified in command line.
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ base::FilePath clear_key_cdm_path =
+ command_line->GetSwitchValuePath(switches::kClearKeyCdmPathForTesting);
+ if (!clear_key_cdm_path.empty() && base::PathExists(clear_key_cdm_path)) {
+ // TODO(crbug.com/764480): Remove these after we have a central place for
+ // External Clear Key (ECK) related information.
+ // Normal External Clear Key key system.
+ const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey";
+ // A variant of ECK key system that has a different GUID.
+ const char kExternalClearKeyDifferentGuidTestKeySystem[] =
+ "org.chromium.externalclearkey.differentguid";
+
+ // Supported codecs are hard-coded in ExternalClearKeyProperties.
+ content::CdmCapability capability(
+ {}, {media::EncryptionMode::kCenc, media::EncryptionMode::kCbcs},
+ {media::CdmSessionType::kTemporary,
+ media::CdmSessionType::kPersistentLicense,
+ media::CdmSessionType::kPersistentUsageRecord},
+ {});
+
+ // Register kExternalClearKeyDifferentGuidTestKeySystem first separately.
+ // Otherwise, it'll be treated as a sub-key-system of normal
+ // kExternalClearKeyKeySystem. See MultipleCdmTypes test in
+ // ECKEncryptedMediaTest.
+ cdms->push_back(content::CdmInfo(
+ media::kClearKeyCdmDisplayName, media::kClearKeyCdmDifferentGuid,
+ base::Version("0.1.0.0"), clear_key_cdm_path,
+ media::kClearKeyCdmFileSystemId, capability,
+ kExternalClearKeyDifferentGuidTestKeySystem, false));
+
+ cdms->push_back(
+ content::CdmInfo(media::kClearKeyCdmDisplayName,
+ media::kClearKeyCdmGuid, base::Version("0.1.0.0"),
+ clear_key_cdm_path, media::kClearKeyCdmFileSystemId,
+ capability, kExternalClearKeyKeySystem, true));
+ }
+#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
+ }
+
+#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)
+ if (cdm_host_file_paths)
+ AddCdmHostFilePaths(cdm_host_file_paths);
+#endif
+}
+
+// New schemes by which content can be retrieved should almost certainly be
+// marked as "standard" schemes, even if they're internal, chrome-only schemes.
+// "Standard" here just means that its URLs behave like 'normal' URL do.
+// - Standard schemes get canonicalized like "new-scheme://hostname/[path]"
+// - Whereas "new-scheme:hostname" is a valid nonstandard URL.
+// - Thus, hostnames can't be extracted from non-standard schemes.
+// - The presence of hostnames enables the same-origin policy. Resources like
+// "new-scheme://foo/" are kept separate from "new-scheme://bar/". For
+// a nonstandard scheme, every resource loaded from that scheme could
+// have access to every other resource.
+// - The same-origin policy is very important if webpages can be
+// loaded via the scheme. Try to organize the URL space of any new scheme
+// such that hostnames provide meaningful compartmentalization of
+// privileges.
+//
+// Example standard schemes: https://, chrome-extension://, chrome://, file://
+// Example nonstandard schemes: mailto:, data:, javascript:, about:
+static const char* const kChromeStandardURLSchemes[] = {
+ extensions::kExtensionScheme,
+ chrome::kChromeNativeScheme,
+ chrome::kChromeSearchScheme,
+ dom_distiller::kDomDistillerScheme,
+#if defined(OS_CHROMEOS)
+ chrome::kCrosScheme,
+#endif
+};
+
+void ChromeContentClient::AddAdditionalSchemes(Schemes* schemes) {
+ for (auto* standard_scheme : kChromeStandardURLSchemes)
+ schemes->standard_schemes.push_back(standard_scheme);
+
+#if defined(OS_ANDROID)
+ schemes->referrer_schemes.push_back(chrome::kAndroidAppScheme);
+#endif
+
+ schemes->savable_schemes.push_back(extensions::kExtensionScheme);
+ schemes->savable_schemes.push_back(chrome::kChromeSearchScheme);
+ schemes->savable_schemes.push_back(dom_distiller::kDomDistillerScheme);
+
+ // chrome-search: resources shouldn't trigger insecure content warnings.
+ schemes->secure_schemes.push_back(chrome::kChromeSearchScheme);
+
+ // Treat as secure because communication with them is entirely in the browser,
+ // so there is no danger of manipulation or eavesdropping on communication
+ // with them by third parties.
+ schemes->secure_schemes.push_back(extensions::kExtensionScheme);
+
+ // chrome-native: is a scheme used for placeholder navigations that allow
+ // UIs to be drawn with platform native widgets instead of HTML. These pages
+ // should be treated as empty documents that can commit synchronously.
+ schemes->empty_document_schemes.push_back(chrome::kChromeNativeScheme);
+ schemes->no_access_schemes.push_back(chrome::kChromeNativeScheme);
+ schemes->secure_schemes.push_back(chrome::kChromeNativeScheme);
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ schemes->service_worker_schemes.push_back(extensions::kExtensionScheme);
+
+ // As far as Blink is concerned, they should be allowed to receive CORS
+ // requests. At the Extensions layer, requests will actually be blocked unless
+ // overridden by the web_accessible_resources manifest key.
+ // TODO(kalman): See what happens with a service worker.
+ schemes->cors_enabled_schemes.push_back(extensions::kExtensionScheme);
+
+ schemes->csp_bypassing_schemes.push_back(extensions::kExtensionScheme);
+#endif
+
+#if defined(OS_CHROMEOS)
+ schemes->local_schemes.push_back(content::kExternalFileScheme);
+#endif
+
+#if defined(OS_ANDROID)
+ schemes->local_schemes.push_back(url::kContentScheme);
+#endif
+}
+
+base::string16 ChromeContentClient::GetLocalizedString(int message_id) {
+ return l10n_util::GetStringUTF16(message_id);
+}
+
+base::string16 ChromeContentClient::GetLocalizedString(
+ int message_id,
+ const base::string16& replacement) {
+ return l10n_util::GetStringFUTF16(message_id, replacement);
+}
+
+base::StringPiece ChromeContentClient::GetDataResource(
+ int resource_id,
+ ui::ScaleFactor scale_factor) {
+ return ui::ResourceBundle::GetSharedInstance().GetRawDataResourceForScale(
+ resource_id, scale_factor);
+}
+
+base::RefCountedMemory* ChromeContentClient::GetDataResourceBytes(
+ int resource_id) {
+ return ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
+ resource_id);
+}
+
+gfx::Image& ChromeContentClient::GetNativeImageNamed(int resource_id) {
+ return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(
+ resource_id);
+}
+
+base::DictionaryValue ChromeContentClient::GetNetLogConstants() {
+ auto platform_dict = net_log::GetPlatformConstantsForNetLog(
+ base::CommandLine::ForCurrentProcess()->GetCommandLineString(),
+ chrome::GetChannelName());
+ if (platform_dict)
+ return std::move(*platform_dict);
+ else
+ return base::DictionaryValue();
+}
+
+std::string ChromeContentClient::GetProcessTypeNameInEnglish(int type) {
+#if BUILDFLAG(ENABLE_NACL)
+ switch (type) {
+ case PROCESS_TYPE_NACL_LOADER:
+ return "Native Client module";
+ case PROCESS_TYPE_NACL_BROKER:
+ return "Native Client broker";
+ }
+#endif
+
+ NOTREACHED() << "Unknown child process type!";
+ return "Unknown";
+}
+
+bool ChromeContentClient::AllowScriptExtensionForServiceWorker(
+ const url::Origin& script_origin) {
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ return script_origin.scheme() == extensions::kExtensionScheme;
+#else
+ return false;
+#endif
+}
+
+blink::OriginTrialPolicy* ChromeContentClient::GetOriginTrialPolicy() {
+ // Prevent initialization race (see crbug.com/721144). There may be a
+ // race when the policy is needed for worker startup (which happens on a
+ // separate worker thread).
+ base::AutoLock auto_lock(origin_trial_policy_lock_);
+ if (!origin_trial_policy_)
+ origin_trial_policy_ = std::make_unique<ChromeOriginTrialPolicy>();
+ return origin_trial_policy_.get();
+}
+
+#if defined(OS_ANDROID)
+media::MediaDrmBridgeClient* ChromeContentClient::GetMediaDrmBridgeClient() {
+ return new ChromeMediaDrmBridgeClient();
+}
+#endif // OS_ANDROID
+
+void ChromeContentClient::BindChildProcessInterface(
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* receiving_handle) {
+ static base::NoDestructor<heap_profiling::ProfilingClient> profiling_client;
+ if (interface_name == heap_profiling::ProfilingClient::Name_) {
+ profiling_client->BindToInterface(
+ mojo::PendingReceiver<heap_profiling::mojom::ProfilingClient>(
+ std::move(*receiving_handle)));
+ }
+}
diff --git a/chromium/chrome/common/chrome_content_client.h b/chromium/chrome/common/chrome_content_client.h
new file mode 100644
index 00000000000..ff03027bd25
--- /dev/null
+++ b/chromium/chrome/common/chrome_content_client.h
@@ -0,0 +1,115 @@
+// 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 CHROME_COMMON_CHROME_CONTENT_CLIENT_H_
+#define CHROME_COMMON_CHROME_CONTENT_CLIENT_H_
+
+#include <memory>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+#include "chrome/common/buildflags.h"
+#include "chrome/common/origin_trials/chrome_origin_trial_policy.h"
+#include "components/nacl/common/buildflags.h"
+#include "content/public/common/content_client.h"
+#include "pdf/buildflags.h"
+#include "ppapi/buildflags/buildflags.h"
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+#include "content/public/common/pepper_plugin_info.h"
+#endif
+
+class ChromeContentClient : public content::ContentClient {
+ public:
+#if defined(GOOGLE_CHROME_BUILD)
+ // |kNotPresent| is a placeholder plugin location for plugins that are not
+ // currently present in this installation of Chrome, but which can be fetched
+ // on-demand and therefore should still appear in navigator.plugins.
+ static const base::FilePath::CharType kNotPresent[];
+#endif
+
+#if BUILDFLAG(ENABLE_NACL)
+ static const base::FilePath::CharType kNaClPluginFileName[];
+#endif
+
+ static const char kPDFExtensionPluginName[];
+ static const char kPDFInternalPluginName[];
+ static const base::FilePath::CharType kPDFPluginPath[];
+
+ ChromeContentClient();
+ ~ChromeContentClient() override;
+
+ // The methods below are called by child processes to set the function
+ // pointers for built-in plugins. We avoid linking these plugins into
+ // chrome_common because then on Windows we would ship them twice because of
+ // the split DLL.
+#if BUILDFLAG(ENABLE_NACL)
+ static void SetNaClEntryFunctions(
+ content::PepperPluginInfo::GetInterfaceFunc get_interface,
+ content::PepperPluginInfo::PPP_InitializeModuleFunc initialize_module,
+ content::PepperPluginInfo::PPP_ShutdownModuleFunc shutdown_module);
+#endif
+
+#if BUILDFLAG(ENABLE_PLUGINS) && BUILDFLAG(ENABLE_PDF)
+ static void SetPDFEntryFunctions(
+ content::PepperPluginInfo::GetInterfaceFunc get_interface,
+ content::PepperPluginInfo::PPP_InitializeModuleFunc initialize_module,
+ content::PepperPluginInfo::PPP_ShutdownModuleFunc shutdown_module);
+#endif
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+ // This returns the most recent plugin based on the plugin versions. In the
+ // event of a tie, a debug plugin will be considered more recent than a
+ // non-debug plugin.
+ // It does not make sense to call this on a vector that contains more than one
+ // plugin type. This function may return a nullptr if given an empty vector.
+ // The method is only visible for testing purposes.
+ static content::PepperPluginInfo* FindMostRecentPlugin(
+ const std::vector<std::unique_ptr<content::PepperPluginInfo>>& plugins);
+#endif
+
+ void SetActiveURL(const GURL& url, std::string top_origin) override;
+ void SetGpuInfo(const gpu::GPUInfo& gpu_info) override;
+ void AddPepperPlugins(
+ std::vector<content::PepperPluginInfo>* plugins) override;
+ void AddContentDecryptionModules(
+ std::vector<content::CdmInfo>* cdms,
+ std::vector<media::CdmHostFilePath>* cdm_host_file_paths) override;
+
+ void AddAdditionalSchemes(Schemes* schemes) override;
+ base::string16 GetLocalizedString(int message_id) override;
+ base::string16 GetLocalizedString(int message_id,
+ const base::string16& replacement) override;
+ base::StringPiece GetDataResource(int resource_id,
+ ui::ScaleFactor scale_factor) override;
+ base::RefCountedMemory* GetDataResourceBytes(int resource_id) override;
+ gfx::Image& GetNativeImageNamed(int resource_id) override;
+ base::DictionaryValue GetNetLogConstants() override;
+ std::string GetProcessTypeNameInEnglish(int type) override;
+
+ bool AllowScriptExtensionForServiceWorker(
+ const url::Origin& script_origin) override;
+
+ blink::OriginTrialPolicy* GetOriginTrialPolicy() override;
+
+#if defined(OS_ANDROID)
+ media::MediaDrmBridgeClient* GetMediaDrmBridgeClient() override;
+#endif // OS_ANDROID
+
+ void BindChildProcessInterface(
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle* receiving_handle) override;
+
+ private:
+ // Used to lock when |origin_trial_policy_| is initialized.
+ base::Lock origin_trial_policy_lock_;
+ std::unique_ptr<ChromeOriginTrialPolicy> origin_trial_policy_;
+};
+
+#endif // CHROME_COMMON_CHROME_CONTENT_CLIENT_H_
diff --git a/chromium/chrome/common/chrome_content_client_constants.cc b/chromium/chrome/common/chrome_content_client_constants.cc
new file mode 100644
index 00000000000..a8365688d3e
--- /dev/null
+++ b/chromium/chrome/common/chrome_content_client_constants.cc
@@ -0,0 +1,28 @@
+// 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 "chrome/common/chrome_content_client.h"
+
+#if defined(GOOGLE_CHROME_BUILD)
+const base::FilePath::CharType ChromeContentClient::kNotPresent[] =
+ FILE_PATH_LITERAL("internal-not-yet-present");
+#endif
+
+#if BUILDFLAG(ENABLE_NACL)
+const base::FilePath::CharType ChromeContentClient::kNaClPluginFileName[] =
+ FILE_PATH_LITERAL("internal-nacl-plugin");
+#endif
+
+#if defined(GOOGLE_CHROME_BUILD)
+const char ChromeContentClient::kPDFExtensionPluginName[] = "Chrome PDF Viewer";
+const char ChromeContentClient::kPDFInternalPluginName[] = "Chrome PDF Plugin";
+#else
+const char ChromeContentClient::kPDFExtensionPluginName[] =
+ "Chromium PDF Viewer";
+const char ChromeContentClient::kPDFInternalPluginName[] =
+ "Chromium PDF Plugin";
+#endif
+
+const base::FilePath::CharType ChromeContentClient::kPDFPluginPath[] =
+ FILE_PATH_LITERAL("internal-pdf-viewer");
diff --git a/chromium/chrome/common/chrome_content_client_unittest.cc b/chromium/chrome/common/chrome_content_client_unittest.cc
new file mode 100644
index 00000000000..7db44b74a63
--- /dev/null
+++ b/chromium/chrome/common/chrome_content_client_unittest.cc
@@ -0,0 +1,180 @@
+// 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 "chrome/common/chrome_content_client.h"
+
+#include <string>
+
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/test/scoped_command_line.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/origin_util.h"
+#include "content/public/test/test_utils.h"
+#include "extensions/common/constants.h"
+#include "ppapi/buildflags/buildflags.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+#include "url/url_util.h"
+
+namespace chrome_common {
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+TEST(ChromeContentClientTest, FindMostRecent) {
+ std::vector<std::unique_ptr<content::PepperPluginInfo>> version_vector;
+ // Test an empty vector.
+ EXPECT_EQ(nullptr, ChromeContentClient::FindMostRecentPlugin(version_vector));
+
+ // Now test the vector with one element.
+ content::PepperPluginInfo info;
+ info.version = "1.0.0.0";
+ version_vector.push_back(std::make_unique<content::PepperPluginInfo>(info));
+
+ content::PepperPluginInfo* most_recent =
+ ChromeContentClient::FindMostRecentPlugin(version_vector);
+ EXPECT_EQ("1.0.0.0", most_recent->version);
+
+ content::PepperPluginInfo info5;
+ info5.version = "5.0.12.1";
+ content::PepperPluginInfo info6_12;
+ info6_12.version = "6.0.0.12";
+ content::PepperPluginInfo info6_13;
+ info6_13.version = "6.0.0.13";
+
+ // Test highest version is picked.
+ version_vector.clear();
+ version_vector.push_back(std::make_unique<content::PepperPluginInfo>(info5));
+ version_vector.push_back(
+ std::make_unique<content::PepperPluginInfo>(info6_12));
+ version_vector.push_back(
+ std::make_unique<content::PepperPluginInfo>(info6_13));
+
+ most_recent = ChromeContentClient::FindMostRecentPlugin(version_vector);
+ EXPECT_EQ("6.0.0.13", most_recent->version);
+
+ // Test that order does not matter, validates tests below.
+ version_vector.clear();
+ version_vector.push_back(
+ std::make_unique<content::PepperPluginInfo>(info6_13));
+ version_vector.push_back(
+ std::make_unique<content::PepperPluginInfo>(info6_12));
+ version_vector.push_back(std::make_unique<content::PepperPluginInfo>(info5));
+
+ most_recent = ChromeContentClient::FindMostRecentPlugin(version_vector);
+ EXPECT_EQ("6.0.0.13", most_recent->version);
+
+ // Test real scenarios.
+ content::PepperPluginInfo component_flash;
+ component_flash.version = "4.3.2.1";
+ component_flash.is_external = false;
+ component_flash.name = "component_flash";
+
+ content::PepperPluginInfo system_flash;
+ system_flash.version = "4.3.2.1";
+ system_flash.is_external = true;
+ system_flash.name = "system_flash";
+
+ // The order here should be:
+ // 1. System Flash.
+ // 2. Component update.
+ version_vector.clear();
+ version_vector.push_back(
+ std::make_unique<content::PepperPluginInfo>(system_flash));
+ version_vector.push_back(
+ std::make_unique<content::PepperPluginInfo>(component_flash));
+ most_recent = ChromeContentClient::FindMostRecentPlugin(version_vector);
+ EXPECT_STREQ("system_flash", most_recent->name.c_str());
+}
+#endif // BUILDFLAG(ENABLE_PLUGINS)
+
+TEST(ChromeContentClientTest, AdditionalSchemes) {
+ EXPECT_TRUE(url::IsStandard(
+ extensions::kExtensionScheme,
+ url::Component(0, strlen(extensions::kExtensionScheme))));
+
+ GURL extension_url(
+ "chrome-extension://abcdefghijklmnopqrstuvwxyzabcdef/foo.html");
+ url::Origin origin = url::Origin::Create(extension_url);
+ EXPECT_EQ("chrome-extension://abcdefghijklmnopqrstuvwxyzabcdef",
+ origin.Serialize());
+
+ EXPECT_TRUE(content::IsOriginSecure(GURL("chrome-native://newtab/")));
+
+ GURL chrome_url(content::GetWebUIURL("dummyurl"));
+ EXPECT_TRUE(content::IsOriginSecure(chrome_url));
+ EXPECT_FALSE(content::OriginCanAccessServiceWorkers(chrome_url));
+ EXPECT_TRUE(
+ content::IsPotentiallyTrustworthyOrigin(url::Origin::Create(chrome_url)));
+}
+
+class OriginTrialInitializationTestThread
+ : public base::PlatformThread::Delegate {
+ public:
+ explicit OriginTrialInitializationTestThread(
+ ChromeContentClient* chrome_client)
+ : chrome_client_(chrome_client) {}
+
+ void ThreadMain() override { AccessPolicy(chrome_client_, &policy_objects_); }
+
+ // Static helper which can also be called from the main thread.
+ static void AccessPolicy(
+ ChromeContentClient* content_client,
+ std::vector<blink::OriginTrialPolicy*>* policy_objects) {
+ // Repeatedly access the lazily-created origin trial policy
+ for (int i = 0; i < 20; i++) {
+ blink::OriginTrialPolicy* policy = content_client->GetOriginTrialPolicy();
+ policy_objects->push_back(policy);
+ base::PlatformThread::YieldCurrentThread();
+ }
+ }
+
+ const std::vector<blink::OriginTrialPolicy*>* policy_objects() const {
+ return &policy_objects_;
+ }
+
+ private:
+ ChromeContentClient* chrome_client_;
+ std::vector<blink::OriginTrialPolicy*> policy_objects_;
+
+ DISALLOW_COPY_AND_ASSIGN(OriginTrialInitializationTestThread);
+};
+
+// Test that the lazy initialization of Origin Trial policy is resistant to
+// races with concurrent access. Failures (especially flaky) indicate that the
+// race prevention is no longer sufficient.
+TEST(ChromeContentClientTest, OriginTrialPolicyConcurrentInitialization) {
+ ChromeContentClient content_client;
+ std::vector<blink::OriginTrialPolicy*> policy_objects;
+ OriginTrialInitializationTestThread thread(&content_client);
+ base::PlatformThreadHandle handle;
+
+ ASSERT_TRUE(base::PlatformThread::Create(0, &thread, &handle));
+
+ // Repeatedly access the lazily-created origin trial policy
+ OriginTrialInitializationTestThread::AccessPolicy(&content_client,
+ &policy_objects);
+
+ base::PlatformThread::Join(handle);
+
+ ASSERT_EQ(20UL, policy_objects.size());
+
+ blink::OriginTrialPolicy* first_policy = policy_objects[0];
+
+ const std::vector<blink::OriginTrialPolicy*>* all_policy_objects[] = {
+ &policy_objects, thread.policy_objects(),
+ };
+
+ for (const std::vector<blink::OriginTrialPolicy*>* thread_policy_objects :
+ all_policy_objects) {
+ EXPECT_GE(20UL, thread_policy_objects->size());
+ for (blink::OriginTrialPolicy* policy : *(thread_policy_objects)) {
+ EXPECT_EQ(first_policy, policy);
+ }
+ }
+}
+
+} // namespace chrome_common
diff --git a/chromium/chrome/common/chrome_descriptors.h b/chromium/chrome/common/chrome_descriptors.h
new file mode 100644
index 00000000000..dd14978db86
--- /dev/null
+++ b/chromium/chrome/common/chrome_descriptors.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 CHROME_COMMON_CHROME_DESCRIPTORS_H_
+#define CHROME_COMMON_CHROME_DESCRIPTORS_H_
+
+#include "build/build_config.h"
+#include "content/public/common/content_descriptors.h"
+
+enum {
+#if defined(OS_ANDROID)
+ kAndroidLocalePakDescriptor = kContentIPCDescriptorMax + 1,
+ kAndroidSecondaryLocalePakDescriptor,
+ kAndroidChrome100PercentPakDescriptor,
+ kAndroidUIResourcesPakDescriptor,
+ // DFMs with native resources typically do not share file descriptors with
+ // child processes. Hence no corresponding *PakDescriptor is defined.
+ kAndroidMinidumpDescriptor,
+#endif
+};
+
+#endif // CHROME_COMMON_CHROME_DESCRIPTORS_H_
diff --git a/chromium/chrome/common/chrome_features.cc b/chromium/chrome/common/chrome_features.cc
new file mode 100644
index 00000000000..4b8205a3b36
--- /dev/null
+++ b/chromium/chrome/common/chrome_features.cc
@@ -0,0 +1,894 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/chrome_features.h"
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/no_destructor.h"
+#include "base/strings/string_split.h"
+#include "build/build_config.h"
+#include "chrome/common/chrome_switches.h"
+#include "extensions/buildflags/buildflags.h"
+#include "ppapi/buildflags/buildflags.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/build_info.h"
+#endif
+
+namespace features {
+
+// All features in alphabetical order.
+
+#if defined(OS_ANDROID)
+const base::Feature kAddToHomescreenMessaging{
+ "AddToHomescreenMessaging", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+// Controls whether web apps can be installed via APKs on Chrome OS.
+const base::Feature kApkWebAppInstalls{"ApkWebAppInstalls",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif // defined(OS_CHROMEOS)
+
+#if defined(OS_MACOSX)
+// Enable the new multi-profile-aware app shim mode.
+// TODO(https://crbug.com/982024): Delete this flag when feature is complete.
+const base::Feature kAppShimMultiProfile{"AppShimMultiProfile",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Can be used to disable RemoteCocoa (hosting NSWindows for apps in the app
+// process). For debugging purposes only.
+const base::Feature kAppShimRemoteCocoa{"AppShimRemoteCocoa",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables the "this OS is obsolete" infobar on Mac 10.9.
+// TODO(ellyjones): Remove this after the last 10.9 release.
+const base::Feature kShow10_9ObsoleteInfobar{"Show109ObsoleteInfobar",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Use the Toolkit-Views Task Manager window.
+const base::Feature kViewsTaskManager{"ViewsTaskManager",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // defined(OS_MACOSX)
+
+#if defined(OS_ANDROID)
+// Enables messaging in site permissions UI informing user when notifications
+// are disabled for the entire app.
+const base::Feature kAppNotificationStatusMessaging{
+ "AppNotificationStatusMessaging", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // defined(OS_ANDROID)
+
+#if !defined(OS_ANDROID)
+// App Service related flags. See chrome/services/app_service/README.md.
+const base::Feature kAppServiceAsh{"AppServiceAsh",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kAppServiceIntentHandling{
+ "AppServiceIntentHandling", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAppServiceShelf{"AppServiceShelf",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif // !defined(OS_ANDROID)
+
+// Enables the built-in DNS resolver.
+const base::Feature kAsyncDns {
+ "AsyncDns",
+#if defined(OS_CHROMEOS) || defined(OS_MACOSX) || defined(OS_ANDROID)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
+
+#if defined(OS_ANDROID)
+const base::Feature kAutoFetchOnNetErrorPage{"AutoFetchOnNetErrorPage",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_WIN) || defined(OS_LINUX)
+// Enables the Restart background mode optimization. When all Chrome UI is
+// closed and it goes in the background, allows to restart the browser to
+// discard memory.
+const base::Feature kBackgroundModeAllowRestart{
+ "BackgroundModeAllowRestart", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // defined(OS_WIN) || defined(OS_LINUX)
+
+// Enables or disables whether permission prompts are automatically blocked
+// after the user has explicitly dismissed them too many times.
+const base::Feature kBlockPromptsIfDismissedOften{
+ "BlockPromptsIfDismissedOften", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables or disables whether permission prompts are automatically blocked
+// after the user has ignored them too many times.
+const base::Feature kBlockPromptsIfIgnoredOften{
+ "BlockPromptsIfIgnoredOften", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Once the user declines a notification permission prompt in a WebContents,
+// automatically dismiss subsequent prompts in the same WebContents, from any
+// origin, until the next user-initiated navigation.
+const base::Feature kBlockRepeatedNotificationPermissionPrompts{
+ "BlockRepeatedNotificationPermissionPrompts",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Fixes for browser hang bugs are deployed in a field trial in order to measure
+// their impact. See crbug.com/478209.
+const base::Feature kBrowserHangFixesExperiment{
+ "BrowserHangFixesExperiment", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables or disables redirecting users who get an interstitial when
+// accessing https://support.google.com/chrome/answer/6098869 to local
+// connection help content.
+const base::Feature kBundledConnectionHelpFeature{
+ "BundledConnectionHelp", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables the UI to configure caption settings.
+const base::Feature kCaptionSettings{"CaptionSettings",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+#if !defined(OS_ANDROID)
+// Enables logging UKMs for background tab activity by TabActivityWatcher.
+const base::Feature kTabMetricsLogging{"TabMetricsLogging",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+#if defined(OS_WIN)
+// Enables the blocking of third-party modules. This feature requires Windows 8
+// or higher because it depends on the ProcessExtensionPointDisablePolicy
+// mitigation, which was not available on Windows 7.
+// Note: Due to a limitation in the implementation of this feature, it is
+// required to start the browser two times to fully enable or disable it.
+const base::Feature kThirdPartyModulesBlocking{
+ "ThirdPartyModulesBlocking", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+// Enables the additional TLS 1.3 server-random-based downgrade protection
+// described in https://tools.ietf.org/html/rfc8446#section-4.1.3 for
+// connections which chain to a local trust anchor. The protection is
+// unconditionally enabled for known trust anchors.
+//
+// This is a MUST-level requirement of TLS 1.3, but may have compatibility
+// issues with some outdated buggy TLS-terminating proxies.
+const base::Feature kTLS13HardeningForLocalAnchors{
+ "TLS13HardeningForLocalAnchors", base::FEATURE_DISABLED_BY_DEFAULT};
+
+#if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX)
+// Enables the dual certificate verification trial feature.
+// https://crbug.com/649026
+const base::Feature kCertDualVerificationTrialFeature{
+ "CertDualVerificationTrial", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+// Enables change picture video mode.
+const base::Feature kChangePictureVideoMode{"ChangePictureVideoMode",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+#if defined(OS_CHROMEOS)
+// Enables passing additional user authentication in requests to DMServer
+// (policy fetch, status report upload).
+const base::Feature kDMServerOAuthForChildUser{
+ "DMServerOAuthForChildUser", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+#if defined(OS_ANDROID)
+// Enables clearing of browsing data which is older than given time period.
+const base::Feature kClearOldBrowsingData{"ClearOldBrowsingData",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+const base::Feature kClickToOpenPDFPlaceholder{
+ "ClickToOpenPDFPlaceholder", base::FEATURE_ENABLED_BY_DEFAULT};
+
+#if defined(OS_MACOSX)
+const base::Feature kImmersiveFullscreen{"ImmersiveFullscreen",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+#if defined(OS_CHROMEOS)
+// Shows a setting that allows disabling mouse acceleration.
+const base::Feature kAllowDisableMouseAcceleration{
+ "AllowDisableMouseAcceleration", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enable project Crostini, Linux VMs on Chrome OS.
+const base::Feature kCrostini{"Crostini", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enable additional Crostini session status reporting for
+// managed devices only, i.e. reports of installed apps and kernel version.
+const base::Feature kCrostiniAdditionalEnterpriseReporting{
+ "CrostiniAdditionalEnterpriseReporting", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enable advanced access controls for Crostini-related features
+// (e.g. restricting VM CLI tools access, restricting Crostini root access).
+const base::Feature kCrostiniAdvancedAccessControls{
+ "CrostiniAdvancedAccessControls", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables infrastructure for applying Ansible playbook to default Crostini
+// container.
+const base::Feature kCrostiniAnsibleInfrastructure{
+ "CrostiniAnsibleInfrastructure", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables infrastructure for generating Ansible playbooks for the default
+// Crostini container from software configurations in JSON schema.
+const base::Feature kCrostiniAnsibleSoftwareManagement{
+ "CrostiniAnsibleSoftwareManagement", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables custom UI for forcibly closing unresponsive windows.
+const base::Feature kCrostiniForceClose{"CrostiniForceClose",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables or disables the UI overhaul for Cups Printers in settings page.
+const base::Feature kCupsPrintersUiOverhaul{"CupsPrintersUiOverhaul",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enable support for "Plugin VMs" on Chrome OS.
+const base::Feature kPluginVm{"PluginVm", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Allow a Wilco DTC (diagnostics and telemetry controller) on Chrome OS.
+// More info about the project may be found here:
+// https://docs.google.com/document/d/18Ijj8YlC8Q3EWRzLspIi2dGxg4vIBVe5sJgMPt9SWYo
+const base::Feature kWilcoDtc{"WilcoDtc", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enable uploading of a zip archive of system logs instead of individual files.
+const base::Feature kUploadZippedSystemLogs{"UploadZippedSystemLogs",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+// Enable chrome://terminal. Terminal System App will only run on
+// OS_CHROMEOS, but this flag must be defined for all platforms since
+// it is required for SystemWebApp tests.
+const base::Feature kTerminalSystemApp{"TerminalSystemApp",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enable using tab sharing infobars for desktop capture.
+const base::Feature kDesktopCaptureTabSharingInfobar{
+ "DesktopCaptureTabSharingInfobar", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables or disables new Desktop PWAs implementation that does not use
+// extensions.
+const base::Feature kDesktopPWAsWithoutExtensions{
+ "DesktopPWAsWithoutExtensions", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// When installing default installed PWAs, we wait for service workers
+// to cache resources.
+const base::Feature kDesktopPWAsCacheDuringDefaultInstall{
+ "DesktopPWAsCacheDuringDefaultInstall", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables local PWA installs to update their app manifest data if the site
+// changes its manifest.
+const base::Feature kDesktopPWAsLocalUpdating {
+ "DesktopPWAsLocalUpdating",
+#if defined(OS_CHROMEOS)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
+
+// Enables or disables use of new Desktop PWAs browser controller (that uses the
+// universal web_app::AppRegistrar) by extensions-based bookmark apps. Note that
+// the new Desktop PWAs implementation (not based on extensions) always uses the
+// new browser controller.
+const base::Feature kDesktopPWAsUnifiedUiController{
+ "DesktopPWAsUnifiedUiController", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables or disables use of new Desktop PWAs launch manager by
+// extensions-based bookmark apps. (Note that Bookmark apps not based
+// on extensions unconditionally use the new launch manager.)
+const base::Feature kDesktopPWAsUnifiedLaunch{
+ "DesktopPWAsUnifiedLaunch", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables or disables new Desktop PWAs Unified Sync and Storage (USS)
+// implementation that does not use extensions. Requires
+// kDesktopPWAsWithoutExtensions to be enabled.
+const base::Feature kDesktopPWAsUSS{"DesktopPWAsUSS",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables or disables the ability to install PWAs from the omnibox.
+const base::Feature kDesktopPWAsOmniboxInstall{
+ "DesktopPWAsOmniboxInstall", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Disables downloads of unsafe file types over HTTP.
+const base::Feature kDisallowUnsafeHttpDownloads{
+ "DisallowUnsafeHttpDownloads", base::FEATURE_DISABLED_BY_DEFAULT};
+const char kDisallowUnsafeHttpDownloadsParamName[] = "MimeTypeList";
+
+// Enable DNS over HTTPS (DoH).
+const base::Feature kDnsOverHttps{"DnsOverHttps",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Set whether fallback to insecure DNS is allowed by default. This setting may
+// be overridden for individual transactions.
+const base::FeatureParam<bool> kDnsOverHttpsFallbackParam{&kDnsOverHttps,
+ "Fallback", true};
+
+// Supply one or more space-separated DoH server URI templates to use when this
+// feature is enabled. If no templates are specified, then a hardcoded mapping
+// will be used to construct a list of DoH templates associated with the IP
+// addresses of insecure resolvers in the discovered configuration.
+const base::FeatureParam<std::string> kDnsOverHttpsTemplatesParam{
+ &kDnsOverHttps, "Templates", ""};
+
+#if defined(OS_ANDROID)
+// Enable changing default downloads storage location on Android.
+const base::Feature kDownloadsLocationChange{"DownloadsLocationChange",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+// If enabled, Drive will use FCM for its invalidations.
+const base::Feature kDriveFcmInvalidations{"DriveFCMInvalidations",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// If enabled, policies will use FCM (Firebase Cloud Messaging) for its
+// invalidations.
+const base::Feature kPolicyFcmInvalidations{"PolicyFCMInvalidations",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables ambient authentication in incognito mode.
+// TODO(https://crbug.com/458508): Change to disabled by default after proper
+// notice to use the policy to activate when required, M79-M80.
+const base::Feature kEnableAmbientAuthenticationInIncognito{
+ "EnableAmbientAuthenticationInIncognito", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables ambient authentication in guest sessions.
+// TODO(https://crbug.com/458508): Change to disabled by default after proper
+// notice to use the policy to activate when required, M79-M80.
+const base::Feature kEnableAmbientAuthenticationInGuestSession{
+ "EnableAmbientAuthenticationInGuestSession",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+// Enables support for FTP URLs. When disabled ftp:// URLs will behave the same
+// as any other URL scheme that's unknown to the browser.
+// TODO(https://crbug.com/333943): FTP support is being phased out.
+const base::Feature kEnableFtp{"EnableFtpSupport",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+#if !defined(OS_ANDROID)
+// Upload enterprise cloud reporting without the extension.
+const base::Feature kEnterpriseReportingInBrowser{
+ "EnterpriseReportingInBrowser", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+#if defined(OS_CHROMEOS)
+// Enables event-based status reporting for child accounts in Chrome OS.
+const base::Feature kEventBasedStatusReporting{
+ "EventBasedStatusReporting", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+// If enabled, this feature's |kExternalInstallDefaultButtonKey| field trial
+// parameter value controls which |ExternalInstallBubbleAlert| button is the
+// default.
+const base::Feature kExternalExtensionDefaultButtonControl{
+ "ExternalExtensionDefaultButtonControl", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables Focus Mode which brings up a PWA-like window look.
+const base::Feature kFocusMode{"FocusMode", base::FEATURE_DISABLED_BY_DEFAULT};
+
+#if BUILDFLAG(ENABLE_VR)
+
+#if BUILDFLAG(ENABLE_OCULUS_VR)
+// Controls Oculus support.
+const base::Feature kOculusVR{"OculusVR", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // ENABLE_OCULUS_VR
+
+#if BUILDFLAG(ENABLE_OPENVR)
+// Controls OpenVR support.
+const base::Feature kOpenVR{"OpenVR", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // ENABLE_OPENVR
+
+#if BUILDFLAG(ENABLE_WINDOWS_MR)
+// Controls Windows Mixed Reality support.
+const base::Feature kWindowsMixedReality{"WindowsMixedReality",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif // ENABLE_WINDOWS_MR
+
+#if BUILDFLAG(ENABLE_OPENXR)
+// Controls OpenXR support.
+const base::Feature kOpenXR{"OpenXR", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // ENABLE_OPENXR
+
+#endif // BUILDFLAG(ENABLE_VR)
+
+#if defined(OS_WIN)
+// Enables using GDI to print text as simply text.
+const base::Feature kGdiTextPrinting{"GdiTextPrinting",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+// Controls whether the GeoLanguage system is enabled. GeoLanguage uses IP-based
+// coarse geolocation to provide an estimate (for use by other Chrome features
+// such as Translate) of the local/regional language(s) corresponding to the
+// device's location. If this feature is disabled, the GeoLanguage provider is
+// not initialized at startup, and clients calling it will receive an empty list
+// of languages.
+const base::Feature kGeoLanguage{"GeoLanguage",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+#if !defined(OS_ANDROID)
+const base::Feature kGoogleBrandedContextMenu{
+ "GoogleBrandedContextMenu", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // !defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+// Enables or disables the Happiness Tracking System for the device.
+const base::Feature kHappinessTrackingSystem{"HappinessTrackingSystem",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+#if !defined(OS_ANDROID)
+// Enables or disables the Happiness Tracking System for Desktop Chrome.
+const base::Feature kHappinessTrackingSurveysForDesktop{
+ "HappinessTrackingSurveysForDesktop", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables or disables the Happiness Tracking System demo mode for Desktop
+// Chrome.
+const base::Feature kHappinessTrackingSurveysForDesktopDemo{
+ "HappinessTrackingSurveysForDesktopDemo",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // !defined(OS_ANDROID)
+
+// Enables committed error pages instead of transient navigation entries for
+// HTTP auth interstitial pages (i.e. HTTP auth prompts initiated cross-origin).
+const base::Feature kHTTPAuthCommittedInterstitials{
+ "HTTPAuthCommittedInterstitials", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables navigation suggestions UI for lookalike URLs (e.g. internationalized
+// domain names that are visually similar to popular domains or to domains with
+// engagement score, such as googlé.com).
+const base::Feature kLookalikeUrlNavigationSuggestionsUI{
+ "LookalikeUrlNavigationSuggestionsUI", base::FEATURE_ENABLED_BY_DEFAULT};
+
+#if defined(OS_WIN)
+// A feature that controls whether Chrome warns about incompatible applications.
+// This feature requires Windows 10 or higher to work because it depends on
+// the "Apps & Features" system settings.
+const base::Feature kIncompatibleApplicationsWarning{
+ "IncompatibleApplicationsWarning", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+#if defined(OS_CHROMEOS)
+// Enables scraping of password-expiry information during SAML login flow, which
+// can lead to an in-session flow for changing SAML password if it has expired.
+// This is safe to enable by default since it does not cause the password-expiry
+// information to be stored, or any user-visible change - in order for anything
+// to happen, the domain administrator has to intentionally send this extra
+// info in the SAML response, and enable the InSessionPasswordChange policy.
+// So, this feature is just for disabling the scraping code if it causes
+// any unforeseen issues.
+const base::Feature kInSessionPasswordChange{"InSessionPasswordChange",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif // defined(OS_CHROMEOS)
+
+#if defined(OS_ANDROID)
+// Enables or disables the installable ambient badge infobar.
+const base::Feature kInstallableAmbientBadgeInfoBar{
+ "InstallableAmbientBadgeInfoBar", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+#if !defined(OS_ANDROID)
+// Enables or disables intent picker.
+const base::Feature kIntentPicker{"IntentPicker",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif // !defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+const base::Feature kKernelnextVMs{"KernelnextVMs",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+// Uses KidsManagement UrlClassification instead of SafeSearch for supervised
+// accounts.
+const base::Feature kKidsManagementUrlClassification{
+ "KidsManagementUrlClassification", base::FEATURE_ENABLED_BY_DEFAULT};
+
+#if defined(OS_MACOSX)
+// Uses NSFullSizeContentViewWindowMask where available instead of adding our
+// own views to the window frame. This is a temporary kill switch, it can be
+// removed once we feel okay about leaving it on.
+const base::Feature kMacFullSizeContentView{"MacFullSizeContentView",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+#endif
+
+#if defined(OS_MACOSX)
+// Enables the Material Design download shelf on Mac.
+const base::Feature kMacMaterialDesignDownloadShelf{
+ "MacMDDownloadShelf", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+#if defined(OS_MACOSX)
+// In case a website is trying to use the camera/microphone, but Chrome itself
+// is blocked on the system level to access these, show an icon in the Omnibox,
+// which, when clicked, displays a bubble with information on how to toggle
+// Chrome's system-level media permissions.
+const base::Feature kMacSystemMediaPermissionsInfoUi{
+ "MacSystemMediaPermissionsInfoUI", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enable screen capture system permission check on Mac 10.15+.
+const base::Feature kMacSystemScreenCapturePermissionCheck{
+ "MacSystemScreenCapturePermissionCheck", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+// Sets whether dismissing the new-tab-page override bubble counts as
+// acknowledgement.
+const base::Feature kAcknowledgeNtpOverrideOnDeactivate{
+ "AcknowledgeNtpOverrideOnDeactivate", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+// Enables showing an entry for mixed content in site settings, which controls
+// allowing blockable mixed content. When enabled, the mixed content shield is
+// not shown on the omnibox, since its functionality is replaced by the
+// setting.
+const base::Feature kMixedContentSiteSetting{"MixedContentSiteSetting",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+#if !defined(OS_ANDROID)
+const base::Feature kOnConnectNative{"OnConnectNative",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+// Enables the use of native notification centers instead of using the Message
+// Center for displaying the toasts. The feature is hardcoded to enabled for
+// Chrome OS.
+#if BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS) && !defined(OS_CHROMEOS)
+const base::Feature kNativeNotifications{"NativeNotifications",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif // BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
+
+// When kNoReferrers is enabled, most HTTP requests will provide empty
+// referrers instead of their ordinary behavior.
+const base::Feature kNoReferrers{"NoReferrers",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+#if defined(OS_WIN)
+// Changes behavior of requireInteraction for notifications. Instead of staying
+// on-screen until dismissed, they are instead shown for a very long time.
+const base::Feature kNotificationDurationLongForRequireInteraction{
+ "NotificationDurationLongForRequireInteraction",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // OS_WIN
+
+#if defined(OS_POSIX)
+// Enables NTLMv2, which implicitly disables NTLMv1.
+const base::Feature kNtlmV2Enabled{"NtlmV2Enabled",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+#if defined(OS_ANDROID)
+// Enables or disabled the OOM intervention.
+const base::Feature kOomIntervention{"OomIntervention",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+// Adds the base language code to the Language-Accept headers if at least one
+// corresponding language+region code is present in the user preferences.
+// For example: "en-US, fr-FR" --> "en-US, en, fr-FR, fr".
+const base::Feature kUseNewAcceptLanguageHeader{
+ "UseNewAcceptLanguageHeader", base::FEATURE_ENABLED_BY_DEFAULT};
+
+#if defined(OS_CHROMEOS)
+// Enables usage of Parent Access Code to authorize certain actions on child
+// user device.
+const base::Feature kParentAccessCode{"ParentAccessCode",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+const base::Feature kParentAccessCodeForTimeChange{
+ "ParentAccessCodeForTimeChange", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+// Delegate permissions to cross-origin iframes when the feature has been
+// allowed by feature policy.
+const base::Feature kPermissionDelegation{"PermissionDelegation",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Allows prediction operations (e.g., prefetching) on all connection types.
+const base::Feature kPredictivePrefetchingAllowedOnAllConnectionTypes{
+ "PredictivePrefetchingAllowedOnAllConnectionTypes",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Allows Chrome to do preconnect when prerender fails.
+const base::Feature kPrerenderFallbackToPreconnect{
+ "PrerenderFallbackToPreconnect", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Whether to display redesign of the chrome privacy settings page
+// to the user.
+const base::Feature kPrivacySettingsRedesign{"PrivacySettingsRedesign",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+// Show Flash deprecation warning to users who have manually enabled Flash.
+// https://crbug.com/918428
+const base::Feature kFlashDeprecationWarning{"FlashDeprecationWarning",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
+// If enabled, Print Preview will use the CloudPrinterHandler instead of the
+// cloud print interface to communicate with the cloud print server. This
+// prevents Print Preview from making direct network requests. See
+// https://crbug.com/829414.
+const base::Feature kCloudPrinterHandler{"CloudPrinterHandler",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// If enabled, the Print Preview UI will use a different layout. See
+// https://crbug.com/945619
+const base::Feature kNewPrintPreviewLayout{"NewPrintPreviewLayout",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+// Enables or disables push subscriptions keeping Chrome running in the
+// background when closed.
+const base::Feature kPushMessagingBackgroundMode{
+ "PushMessagingBackgroundMode", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables using quiet prompts for notification permission requests.
+const base::Feature kQuietNotificationPrompts{
+ "QuietNotificationPrompts", base::FEATURE_DISABLED_BY_DEFAULT};
+
+#if defined(OS_CHROMEOS)
+// Enables permanent removal of Legacy Supervised Users on startup.
+const base::Feature kRemoveSupervisedUsersOnStartup{
+ "RemoveSupervisedUsersOnStartup", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+// Controls whether the user is prompted when sites request attestation.
+const base::Feature kSecurityKeyAttestationPrompt{
+ "SecurityKeyAttestationPrompt", base::FEATURE_ENABLED_BY_DEFAULT};
+
+#if defined(OS_ANDROID)
+const base::Feature kShowTrustedPublisherURL{"ShowTrustedPublisherURL",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+// Alternative to switches::kSitePerProcess, for turning on full site isolation.
+// Launch bug: https://crbug.com/810843. This is a //chrome-layer feature to
+// avoid turning on site-per-process by default for *all* //content embedders
+// (e.g. this approach lets ChromeCast avoid site-per-process mode).
+//
+// TODO(alexmos): Move this and the other site isolation features below to
+// browser_features, as they are only used on the browser side.
+const base::Feature kSitePerProcess {
+ "site-per-process",
+#if defined(OS_ANDROID)
+ base::FEATURE_DISABLED_BY_DEFAULT
+#else
+ base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+};
+
+// Controls a mode for dynamically process-isolating sites where the user has
+// entered a password. This is intended to be used primarily when full site
+// isolation is turned off. To check whether this mode is enabled, use
+// SiteIsolationPolicy::IsIsolationForPasswordSitesEnabled() rather than
+// checking the feature directly, since that decision is influenced by other
+// factors as well.
+const base::Feature kSiteIsolationForPasswordSites{
+ "site-isolation-for-password-sites",
+// Enabled by default on Android; see https://crbug.com/849815. Note that this
+// should not affect Android Webview, which does not include this code.
+#if defined(OS_ANDROID)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+};
+
+// kSitePerProcessOnlyForHighMemoryClients is checked before kSitePerProcess,
+// and (if enabled) can restrict if kSitePerProcess feature is checked at all -
+// no check will be made on devices with low memory (these devices will have no
+// Site Isolation via kSitePerProcess trials and won't activate either the
+// control or the experiment group). The threshold for what is considered a
+// "low memory" device is set (in MB) via a field trial param with the name
+// defined below ("site-per-process-low-memory-cutoff-mb") and compared against
+// base::SysInfo::AmountOfPhysicalMemoryMB().
+const base::Feature kSitePerProcessOnlyForHighMemoryClients{
+ "site-per-process-only-for-high-memory-clients",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+const char kSitePerProcessOnlyForHighMemoryClientsParamName[] =
+ "site-per-process-low-memory-cutoff-mb";
+
+#if defined(OS_CHROMEOS)
+// Enables or disables automatic setup of USB printers.
+const base::Feature kStreamlinedUsbPrinterSetup{
+ "StreamlinedUsbPrinterSetup", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables or disables the ability to add a Samba Share to the Files app
+const base::Feature kNativeSmb{"NativeSmb", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif // defined(OS_CHROMEOS)
+
+// Enables or disables the ability to use the sound content setting to mute a
+// website.
+const base::Feature kSoundContentSetting{"SoundContentSetting",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables filtering URLs by suffix to include subresources that look
+// like image resources for compression. For example,
+// http://chromium.org/image.jpg would be included.
+const base::Feature kSubresourceRedirectIncludedMediaSuffixes{
+ "SubresourceRedirectIncludedMediaSuffixes",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+#if !defined(OS_ANDROID)
+// Enables or disables the Javascript API to propagate sync encryption keys.
+const base::Feature kSyncEncryptionKeysWebApi{
+ "SyncEncryptionKeysWebApi", base::FEATURE_DISABLED_BY_DEFAULT};
+#endif // !defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+// Enables or disables chrome://sys-internals.
+const base::Feature kSysInternals{"SysInternals",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+// Enables or disables the System Web App manager.
+const base::Feature kSystemWebApps{"SystemWebApps",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables or disables the App Management UI.
+const base::Feature kAppManagement{"AppManagement",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Disable downloads of unsafe file types over insecure transports if initiated
+// from a secure page
+const base::Feature kTreatUnsafeDownloadsAsActive{
+ "TreatUnsafeDownloadsAsActive", base::FEATURE_DISABLED_BY_DEFAULT};
+const char kTreatUnsafeDownloadsAsActiveParamName[] = "ExtensionList";
+
+// Enables or disables the intervention that unloads ad iframes with intensive
+// resource usage.
+const base::Feature kHeavyAdIntervention{"HeavyAdIntervention",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables or disables the blocklist for the heavy ad intervention. This
+// throttles the amount of interventions that can occur on a given host in a
+// time period. This is separate from the intervention feature so it does not
+// interfere with field trial activation, as this blocklist is created for every
+// user.
+const base::Feature kHeavyAdBlocklist{"HeavyAdBlocklist",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+#if defined(OS_ANDROID)
+const base::Feature kUseDisplayWideColorGamut{"UseDisplayWideColorGamut",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+bool UseDisplayWideColorGamut() {
+ auto compute_use_display_wide_color_gamut = []() {
+ // Enabled this feature for devices listed in "enabled_models" field trial
+ // param. This is a comma separated list.
+ std::string enabled_models_list = base::GetFieldTrialParamValueByFeature(
+ kUseDisplayWideColorGamut, "enabled_models");
+ if (enabled_models_list.empty())
+ return false;
+
+ const char* current_model =
+ base::android::BuildInfo::GetInstance()->model();
+ std::vector<std::string> enabled_models =
+ base::SplitString(enabled_models_list, ",", base::KEEP_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+ for (const std::string& model : enabled_models) {
+ if (model == current_model)
+ return true;
+ }
+
+ return false;
+ };
+
+ // As it takes some work to compute this, cache the result.
+ static base::NoDestructor<bool> is_wide_color_gamut_enabled(
+ compute_use_display_wide_color_gamut());
+ return *is_wide_color_gamut_enabled;
+}
+#endif
+
+#if defined(OS_CHROMEOS)
+// Enables or disables the FTL signaling service for CRD sessions in Kiosk mode.
+const base::Feature kUseFtlSignalingForCrdHostDelegate{
+ "UseFtlSignalingForCrdHostDelegate", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+#if defined(OS_CHROMEOS)
+// Enables or disables logging for adaptive screen brightness on Chrome OS.
+const base::Feature kAdaptiveScreenBrightnessLogging{
+ "AdaptiveScreenBrightnessLogging", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables or disables user activity event logging for power management on
+// Chrome OS.
+const base::Feature kUserActivityEventLogging{"UserActivityEventLogging",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+#endif
+
+#if defined(OS_CHROMEOS)
+// Enables support of libcups APIs from ARC
+const base::Feature kArcCupsApi{"ArcCupsApi",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables or disables pin quick unlock.
+// TODO(https://crbug.com/935613): Remove this & the backing code.
+const base::Feature kQuickUnlockPin{"QuickUnlockPin",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables pin on the login screen.
+const base::Feature kQuickUnlockPinSignin{"QuickUnlockPinSignin",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables or disables fingerprint quick unlock.
+const base::Feature kQuickUnlockFingerprint{"QuickUnlockFingerprint",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables or disables flash component updates on Chrome OS.
+const base::Feature kCrosCompUpdates{"CrosCompUpdates",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables or disables TPM firmware update capability on Chrome OS.
+const base::Feature kTPMFirmwareUpdate{"TPMFirmwareUpdate",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables or disables "usm" service in the list of user services returned by
+// userInfo Gaia message.
+const base::Feature kCrOSEnableUSMUserService{"CrOSEnableUSMUserService",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables or disables SmartDim on Chrome OS.
+const base::Feature kSmartDim{"SmartDim", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enable USBGuard at the lockscreen on Chrome OS.
+// TODO(crbug.com/874630): Remove this kill-switch
+const base::Feature kUsbguard{"USBGuard", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enable USB Bouncer for managing a device whitelist for USBGuard on Chrome OS.
+const base::Feature kUsbbouncer{"USBBouncer",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enable support for multiple scheduler configurations.
+const base::Feature kSchedulerConfiguration{"SchedulerConfiguration",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+#endif // defined(OS_CHROMEOS)
+
+#if !defined(OS_ANDROID)
+// Allow capturing of WebRTC event logs, and uploading of those logs to Crash.
+// Please note that a Chrome policy must also be set, for this to have effect.
+// Effectively, this is a kill-switch for the feature.
+// TODO(crbug.com/775415): Remove this kill-switch.
+const base::Feature kWebRtcRemoteEventLog{"WebRtcRemoteEventLog",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+// Compress remote-bound WebRTC event logs (if used; see kWebRtcRemoteEventLog).
+const base::Feature kWebRtcRemoteEventLogGzipped{
+ "WebRtcRemoteEventLogGzipped", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enable WebUI accessibility enhancements for review and testing.
+const base::Feature kWebUIA11yEnhancements{"WebUIA11yEnhancements",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
+// Whether to enable "dark mode" enhancements in Mac Mojave or Windows 10 for
+// UIs implemented with web technologies.
+const base::Feature kWebUIDarkMode {
+ "WebUIDarkMode",
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_ANDROID)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif // defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_ANDROID)
+};
+
+#if defined(OS_WIN)
+// Enables the accelerated default browser flow for Windows 10.
+const base::Feature kWin10AcceleratedDefaultBrowserFlow{
+ "Win10AcceleratedDefaultBrowserFlow", base::FEATURE_ENABLED_BY_DEFAULT};
+#endif // defined(OS_WIN)
+
+// Enables writing basic system profile to the persistent histograms files
+// earlier.
+const base::Feature kWriteBasicSystemProfileToPersistentHistogramsFile{
+ "WriteBasicSystemProfileToPersistentHistogramsFile",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables improvements to the chrome://accessibility page.
+const base::Feature kAccessibilityInternalsPageImprovements{
+ "AccessibilityInternalsPageImprovements",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace features
diff --git a/chromium/chrome/common/chrome_features.h b/chromium/chrome/common/chrome_features.h
new file mode 100644
index 00000000000..6a3e6c22860
--- /dev/null
+++ b/chromium/chrome/common/chrome_features.h
@@ -0,0 +1,552 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines all the public base::FeatureList features for the chrome
+// module.
+
+#ifndef CHROME_COMMON_CHROME_FEATURES_H_
+#define CHROME_COMMON_CHROME_FEATURES_H_
+
+#include "base/component_export.h"
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "build/build_config.h"
+#include "build/buildflag.h"
+#include "chrome/common/buildflags.h"
+#include "device/vr/buildflags/buildflags.h"
+#include "extensions/buildflags/buildflags.h"
+#include "net/net_buildflags.h"
+#include "ppapi/buildflags/buildflags.h"
+#include "printing/buildflags/buildflags.h"
+#include "ui/base/buildflags.h"
+
+namespace features {
+
+// All features in alphabetical order. The features should be documented
+// alongside the definition of their values in the .cc file.
+
+#if defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAddToHomescreenMessaging;
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kApkWebAppInstalls;
+#endif // defined(OS_CHROMEOS)
+
+#if defined(OS_MACOSX)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAppShimMultiProfile;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAppShimRemoteCocoa;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kShow10_9ObsoleteInfobar;
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kViewsTaskManager;
+#endif // defined(OS_MACOSX)
+
+#if defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAppNotificationStatusMessaging;
+#endif // defined(OS_ANDROID)
+
+#if !defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAppServiceAsh;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAppServiceIntentHandling;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAppServiceShelf;
+#endif // !defined(OS_ANDROID)
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kAsyncDns;
+
+#if defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAutoFetchOnNetErrorPage;
+#endif
+
+#if defined(OS_WIN) || defined(OS_LINUX)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kBackgroundModeAllowRestart;
+#endif // defined(OS_WIN) || defined(OS_LINUX)
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kBlockPromptsIfDismissedOften;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kBlockPromptsIfIgnoredOften;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kBlockRepeatedNotificationPermissionPrompts;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kBrowserHangFixesExperiment;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kBundledConnectionHelpFeature;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kCaptionSettings;
+
+#if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_MACOSX)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kCertDualVerificationTrialFeature;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kChangePictureVideoMode;
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDMServerOAuthForChildUser;
+#endif
+
+#if defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kClearOldBrowsingData;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kClickToOpenPDFPlaceholder;
+
+#if defined(OS_MACOSX)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kImmersiveFullscreen;
+#endif
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAllowDisableMouseAcceleration;
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCrostini;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kCrostiniAdditionalEnterpriseReporting;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kCrostiniAdvancedAccessControls;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kCrostiniAnsibleInfrastructure;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kCrostiniAnsibleSoftwareManagement;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kCrostiniForceClose;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kCupsPrintersUiOverhaul;
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kPluginVm;
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kWilcoDtc;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kUploadZippedSystemLogs;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kTerminalSystemApp;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopCaptureTabSharingInfobar;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopPWAsWithoutExtensions;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopPWAsCacheDuringDefaultInstall;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopPWAsLocalUpdating;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopPWAsUnifiedUiController;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopPWAsUnifiedLaunch;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopPWAsUSS;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDesktopPWAsOmniboxInstall;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDisallowUnsafeHttpDownloads;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const char kDisallowUnsafeHttpDownloadsParamName[];
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDnsOverHttps;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<bool> kDnsOverHttpsFallbackParam;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::FeatureParam<std::string> kDnsOverHttpsTemplatesParam;
+
+#if defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDownloadsLocationChange;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kDriveFcmInvalidations;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kPolicyFcmInvalidations;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kEnableAmbientAuthenticationInGuestSession;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kEnableAmbientAuthenticationInIncognito;
+
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kEnableFtp;
+#endif
+
+#if !defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kEnterpriseReportingInBrowser;
+#endif
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kEventBasedStatusReporting;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kExternalExtensionDefaultButtonControl;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kFocusMode;
+
+// Android expects this string from Java code, so it is always needed.
+// TODO(crbug.com/731802): Use #if BUILDFLAG(ENABLE_VR_BROWSING) instead.
+#if BUILDFLAG(ENABLE_VR) || defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kVrBrowsing;
+#endif
+#if BUILDFLAG(ENABLE_VR)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kVrBrowsingExperimentalFeatures;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kVrBrowsingExperimentalRendering;
+
+#if BUILDFLAG(ENABLE_OCULUS_VR)
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kOculusVR;
+#endif // ENABLE_OCULUS_VR
+
+#if BUILDFLAG(ENABLE_OPENVR)
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kOpenVR;
+#endif // ENABLE_OPENVR
+
+#if BUILDFLAG(ENABLE_WINDOWS_MR)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kWindowsMixedReality;
+#endif // ENABLE_WINDOWS_MR
+
+#if BUILDFLAG(ENABLE_OPENXR)
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kOpenXR;
+#endif // ENABLE_OPENXR
+
+#endif // ENABLE_VR
+
+#if defined(OS_WIN)
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kGdiTextPrinting;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kGeoLanguage;
+
+#if !defined(OS_ANDROID)
+// Only has an effect in branded builds.
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kGoogleBrandedContextMenu;
+#endif
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kHappinessTrackingSystem;
+#endif
+
+#if !defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kHappinessTrackingSurveysForDesktop;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kHappinessTrackingSurveysForDesktopDemo;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kHTTPAuthCommittedInterstitials;
+
+#if defined(OS_WIN)
+// Only has an effect in branded builds.
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kIncompatibleApplicationsWarning;
+#endif
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kInSessionPasswordChange;
+#endif
+
+#if defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kInstallableAmbientBadgeInfoBar;
+#endif // defined(OS_ANDROID)
+
+#if !defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kIntentPicker;
+#endif
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kKernelnextVMs;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kKidsManagementUrlClassification;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kLookalikeUrlNavigationSuggestionsUI;
+
+#if defined(OS_MACOSX)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kMacFullSizeContentView;
+#endif
+
+#if defined(OS_MACOSX)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kMacMaterialDesignDownloadShelf;
+#endif
+
+#if defined(OS_MACOSX)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kMacSystemMediaPermissionsInfoUi;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kMacSystemScreenCapturePermissionCheck;
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAcknowledgeNtpOverrideOnDeactivate;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kMixedContentSiteSetting;
+
+#if !defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kOnConnectNative;
+#endif
+
+#if BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kNativeNotifications;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kNoReferrers;
+
+#if defined(OS_WIN)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kNotificationDurationLongForRequireInteraction;
+#endif
+
+#if defined(OS_POSIX)
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kNtlmV2Enabled;
+#endif
+
+#if defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kOomIntervention;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kUseNewAcceptLanguageHeader;
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kParentAccessCode;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kParentAccessCodeForTimeChange;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kPermissionDelegation;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kPredictivePrefetchingAllowedOnAllConnectionTypes;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kPrerenderFallbackToPreconnect;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kPrivacySettingsRedesign;
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kFlashDeprecationWarning;
+#endif
+
+#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kCloudPrinterHandler;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kNewPrintPreviewLayout;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kPushMessagingBackgroundMode;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kQuietNotificationPrompts;
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kRemoveSupervisedUsersOnStartup;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kSecurityKeyAttestationPrompt;
+
+#if defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kShowTrustedPublisherURL;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kSitePerProcess;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kSiteIsolationForPasswordSites;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kSitePerProcessOnlyForHighMemoryClients;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const char kSitePerProcessOnlyForHighMemoryClientsParamName[];
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kStreamlinedUsbPrinterSetup;
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kNativeSmb;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kSoundContentSetting;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kSubresourceRedirectIncludedMediaSuffixes;
+
+#if !defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kSyncEncryptionKeysWebApi;
+#endif // !defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kSysInternals;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kSystemWebApps;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAppManagement;
+
+#if !defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kTabMetricsLogging;
+#endif
+
+#if defined(OS_WIN)
+// Only has an effect in branded builds.
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kThirdPartyModulesBlocking;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kTLS13HardeningForLocalAnchors;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kTreatUnsafeDownloadsAsActive;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const char kTreatUnsafeDownloadsAsActiveParamName[];
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kHeavyAdIntervention;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kHeavyAdBlocklist;
+
+#if defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kUseDisplayWideColorGamut;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+bool UseDisplayWideColorGamut();
+#endif
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kUseFtlSignalingForCrdHostDelegate;
+#endif
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAdaptiveScreenBrightnessLogging;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kUserActivityEventLogging;
+
+#endif
+
+#if defined(OS_CHROMEOS)
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kArcCupsApi;
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kQuickUnlockPin;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kQuickUnlockPinSignin;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kQuickUnlockFingerprint;
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCrosCompUpdates;
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kTPMFirmwareUpdate;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kCrOSEnableUSMUserService;
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kSmartDim;
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kUsbguard;
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kUsbbouncer;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kSchedulerConfiguration;
+#endif // defined(OS_CHROMEOS)
+
+#if !defined(OS_ANDROID)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kWebRtcRemoteEventLog;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kWebRtcRemoteEventLogGzipped;
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kWebUIA11yEnhancements;
+#endif
+
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kWebUIDarkMode;
+
+#if defined(OS_WIN)
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kWin10AcceleratedDefaultBrowserFlow;
+#endif // defined(OS_WIN)
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kWriteBasicSystemProfileToPersistentHistogramsFile;
+
+COMPONENT_EXPORT(CHROME_FEATURES)
+extern const base::Feature kAccessibilityInternalsPageImprovements;
+
+bool PrefServiceEnabled();
+
+// DON'T ADD RANDOM STUFF HERE. Put it in the main section above in
+// alphabetical order, or in one of the ifdefs (also in order in each section).
+
+} // namespace features
+
+#endif // CHROME_COMMON_CHROME_FEATURES_H_
diff --git a/chromium/chrome/common/chrome_icon_resources_win.h b/chromium/chrome/common/chrome_icon_resources_win.h
new file mode 100644
index 00000000000..9400c0b27ae
--- /dev/null
+++ b/chromium/chrome/common/chrome_icon_resources_win.h
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CHROME_ICON_RESOURCES_WIN_H_
+#define CHROME_COMMON_CHROME_ICON_RESOURCES_WIN_H_
+
+namespace icon_resources {
+
+// This file contains the indices of icon resources in chrome_exe.rc.
+
+enum {
+ // The main application icon is always index 0.
+ kApplicationIndex = 0,
+
+#if defined(GOOGLE_CHROME_BUILD)
+ // Legacy indices that are no longer used.
+ kApplication2Index = 1,
+ kApplication3Index = 2,
+ kApplication4Index = 3,
+
+ // The Chrome Canary application icon.
+ kSxSApplicationIndex = 4,
+
+ // The Chrome App Launcher icon.
+ kAppLauncherIndex = 5,
+
+ // The Chrome App Launcher Canary icon.
+ kSxSAppLauncherIndex = 6,
+
+ // The Chrome incognito icon.
+ kIncognitoIndex = 7,
+
+ // The Chrome Dev application icon.
+ kDevApplicationIndex = 8,
+
+ // The Chrome Beta application icon.
+ kBetaApplicationIndex = 9,
+#else // defined(GOOGLE_CHROME_BUILD)
+ // The Chromium App Launcher icon.
+ kAppLauncherIndex = 1,
+
+ // The Chromium incognito icon.
+ kIncognitoIndex = 2,
+#endif // defined(GOOGLE_CHROME_BUILD)
+};
+
+} // namespace icon_resources
+
+#endif // CHROME_COMMON_CHROME_ICON_RESOURCES_WIN_H_
diff --git a/chromium/chrome/common/chrome_isolated_world_ids.h b/chromium/chrome/common/chrome_isolated_world_ids.h
new file mode 100644
index 00000000000..abc94221e4e
--- /dev/null
+++ b/chromium/chrome/common/chrome_isolated_world_ids.h
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CHROME_ISOLATED_WORLD_IDS_H_
+#define CHROME_COMMON_CHROME_ISOLATED_WORLD_IDS_H_
+
+#include "build/build_config.h"
+#include "content/public/common/isolated_world_ids.h"
+
+enum ChromeIsolatedWorldIDs {
+ // Isolated world ID for Chrome Translate.
+ ISOLATED_WORLD_ID_TRANSLATE = content::ISOLATED_WORLD_ID_CONTENT_END + 1,
+
+ // Isolated world ID for internal Chrome features.
+ ISOLATED_WORLD_ID_CHROME_INTERNAL,
+
+#if defined(OS_MACOSX)
+ // Isolated world ID for AppleScript.
+ ISOLATED_WORLD_ID_APPLESCRIPT,
+#endif // defined(OS_MACOSX)
+
+ // Numbers for isolated worlds for extensions are set in
+ // extensions/renderer/script_injection.cc, and are are greater than or equal
+ // to this number.
+ ISOLATED_WORLD_ID_EXTENSIONS
+};
+
+#endif // CHROME_COMMON_CHROME_ISOLATED_WORLD_IDS_H_
diff --git a/chromium/chrome/common/chrome_result_codes.h b/chromium/chrome/common/chrome_result_codes.h
new file mode 100644
index 00000000000..43d4a985fb7
--- /dev/null
+++ b/chromium/chrome/common/chrome_result_codes.h
@@ -0,0 +1,121 @@
+// 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 CHROME_COMMON_CHROME_RESULT_CODES_H_
+#define CHROME_COMMON_CHROME_RESULT_CODES_H_
+
+#include "content/public/common/result_codes.h"
+
+namespace chrome {
+
+// IMPORTANT: This needs to stay in sync with <enum name="CrashExitCodes"> and
+// <enum name="WindowsExitCode"> in tools/metrics/histograms/enums.xml. So do
+// not remove any entries, and always append entries to the bottom just above
+// RESULT_CODE_CHROME_LAST_CODE.
+
+enum ResultCode {
+ RESULT_CODE_CHROME_START = content::RESULT_CODE_LAST_CODE,
+
+ // An invalid command line url was given.
+ RESULT_CODE_INVALID_CMDLINE_URL = RESULT_CODE_CHROME_START,
+
+ // The process is of an unknown type.
+ RESULT_CODE_BAD_PROCESS_TYPE,
+
+ // A critical chrome file is missing.
+ RESULT_CODE_MISSING_DATA,
+
+ // Failed to make Chrome default browser (not used?).
+ RESULT_CODE_SHELL_INTEGRATION_FAILED,
+
+ // Machine level install exists
+ RESULT_CODE_MACHINE_LEVEL_INSTALL_EXISTS,
+
+ // Uninstall detected another chrome instance.
+ RESULT_CODE_UNINSTALL_CHROME_ALIVE,
+
+ // The user changed their mind.
+ RESULT_CODE_UNINSTALL_USER_CANCEL,
+
+ // Delete profile as well during uninstall.
+ RESULT_CODE_UNINSTALL_DELETE_PROFILE,
+
+ // Command line parameter is not supported.
+ RESULT_CODE_UNSUPPORTED_PARAM,
+
+ // Browser import hung and was killed.
+ RESULT_CODE_IMPORTER_HUNG,
+
+ // Trying to restart the browser we crashed.
+ RESULT_CODE_RESPAWN_FAILED,
+
+ // The EXP1, EXP2, EXP3, EXP4 are generic codes used to communicate some
+ // simple outcome back to the process that launched us. This is used for
+ // experiments and the actual meaning depends on the experiment.
+ // (only EXP2 is used?)
+ RESULT_CODE_NORMAL_EXIT_EXP1,
+ RESULT_CODE_NORMAL_EXIT_EXP2,
+ RESULT_CODE_NORMAL_EXIT_EXP3,
+ RESULT_CODE_NORMAL_EXIT_EXP4,
+
+ // For experiments this return code means that the user canceled causes the
+ // did_run "dr" signal to be reset soi this chrome run does not count as
+ // active chrome usage.
+ RESULT_CODE_NORMAL_EXIT_CANCEL,
+
+ // The profile was in use on another host.
+ RESULT_CODE_PROFILE_IN_USE,
+
+ // Failed to pack an extension via the cmd line.
+ RESULT_CODE_PACK_EXTENSION_ERROR,
+
+ // Failed to silently uninstall an extension.
+ RESULT_CODE_UNINSTALL_EXTENSION_ERROR,
+
+ // The browser process exited early by passing the command line to another
+ // running browser.
+ RESULT_CODE_NORMAL_EXIT_PROCESS_NOTIFIED,
+
+ // A dummy value we should not use. See crbug.com/152285.
+ RESULT_CODE_NOTUSED_1,
+
+ // Failed to install an item from the webstore when the
+ // kInstallEphemeralAppFromWebstore command line flag was present.
+ // As this flag is no longer supported, this return code should never be
+ // returned.
+ RESULT_CODE_INSTALL_FROM_WEBSTORE_ERROR_2,
+
+ // A dummy value we should not use. See crbug.com/152285.
+ RESULT_CODE_NOTUSED_2,
+
+ // Returned when the user has not yet accepted the EULA.
+ RESULT_CODE_EULA_REFUSED,
+
+ // Failed to migrate user data directory for side-by-side package support
+ // (Linux-only).
+ RESULT_CODE_SXS_MIGRATION_FAILED_NOT_USED,
+
+ // The action is not allowed by a policy.
+ RESULT_CODE_ACTION_DISALLOWED_BY_POLICY,
+
+ // An browser process was sandboxed. This should never happen.
+ RESULT_CODE_INVALID_SANDBOX_STATE,
+
+ // Cloud policy enrollment is failed or given up by user.
+ RESULT_CODE_CLOUD_POLICY_ENROLLMENT_FAILED,
+
+ // Chrome was downgraded since the last launch. Perform downgrade processing
+ // and relaunch.
+ RESULT_CODE_DOWNGRADE_AND_RELAUNCH,
+
+ // Last return code (keep this last).
+ RESULT_CODE_CHROME_LAST_CODE
+};
+
+static_assert(RESULT_CODE_CHROME_LAST_CODE == 34,
+ "Please make sure the enum values are in sync with enums.xml");
+
+} // namespace chrome
+
+#endif // CHROME_COMMON_CHROME_RESULT_CODES_H_
diff --git a/chromium/chrome/common/chrome_utility_printing_messages.h b/chromium/chrome/common/chrome_utility_printing_messages.h
new file mode 100644
index 00000000000..6bd558079c9
--- /dev/null
+++ b/chromium/chrome/common/chrome_utility_printing_messages.h
@@ -0,0 +1,99 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CHROME_UTILITY_PRINTING_MESSAGES_H_
+#define CHROME_COMMON_CHROME_UTILITY_PRINTING_MESSAGES_H_
+
+#include <string>
+
+#include "build/build_config.h"
+#include "components/printing/common/printing_param_traits_macros.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+#include "printing/backend/print_backend.h"
+#include "printing/buildflags/buildflags.h"
+
+#define IPC_MESSAGE_START ChromeUtilityPrintingMsgStart
+
+#if defined(OS_WIN) && BUILDFLAG(ENABLE_PRINT_PREVIEW)
+// Preview and Cloud Print messages.
+IPC_STRUCT_TRAITS_BEGIN(printing::PrinterCapsAndDefaults)
+ IPC_STRUCT_TRAITS_MEMBER(printer_capabilities)
+ IPC_STRUCT_TRAITS_MEMBER(caps_mime_type)
+ IPC_STRUCT_TRAITS_MEMBER(printer_defaults)
+ IPC_STRUCT_TRAITS_MEMBER(defaults_mime_type)
+IPC_STRUCT_TRAITS_END()
+
+IPC_ENUM_TRAITS_MAX_VALUE(printing::ColorModel, printing::PROCESSCOLORMODEL_RGB)
+
+IPC_STRUCT_TRAITS_BEGIN(printing::PrinterSemanticCapsAndDefaults::Paper)
+ IPC_STRUCT_TRAITS_MEMBER(display_name)
+ IPC_STRUCT_TRAITS_MEMBER(vendor_id)
+ IPC_STRUCT_TRAITS_MEMBER(size_um)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(printing::PrinterSemanticCapsAndDefaults)
+ IPC_STRUCT_TRAITS_MEMBER(collate_capable)
+ IPC_STRUCT_TRAITS_MEMBER(collate_default)
+ IPC_STRUCT_TRAITS_MEMBER(copies_capable)
+ IPC_STRUCT_TRAITS_MEMBER(duplex_modes)
+ IPC_STRUCT_TRAITS_MEMBER(duplex_default)
+ IPC_STRUCT_TRAITS_MEMBER(color_changeable)
+ IPC_STRUCT_TRAITS_MEMBER(color_default)
+ IPC_STRUCT_TRAITS_MEMBER(color_model)
+ IPC_STRUCT_TRAITS_MEMBER(bw_model)
+ IPC_STRUCT_TRAITS_MEMBER(papers)
+ IPC_STRUCT_TRAITS_MEMBER(default_paper)
+ IPC_STRUCT_TRAITS_MEMBER(dpis)
+ IPC_STRUCT_TRAITS_MEMBER(default_dpi)
+IPC_STRUCT_TRAITS_END()
+
+//------------------------------------------------------------------------------
+// Utility process messages:
+// These are messages from the browser to the utility process.
+
+// Tells the utility process to get capabilities and defaults for the specified
+// printer. Used on Windows to isolate the service process from printer driver
+// crashes by executing this in a separate process. This does not run in a
+// sandbox.
+IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_GetPrinterCapsAndDefaults,
+ std::string /* printer name */)
+
+// Tells the utility process to get capabilities and defaults for the specified
+// printer. Used on Windows to isolate the service process from printer driver
+// crashes by executing this in a separate process. This does not run in a
+// sandbox. Returns result as printing::PrinterSemanticCapsAndDefaults.
+IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_GetPrinterSemanticCapsAndDefaults,
+ std::string /* printer name */)
+
+//------------------------------------------------------------------------------
+// Utility process host messages:
+// These are messages from the utility process to the browser.
+
+// Reply when the utility process has succeeded in obtaining the printer
+// capabilities and defaults.
+IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded,
+ std::string /* printer name */,
+ printing::PrinterCapsAndDefaults)
+
+// Reply when the utility process has succeeded in obtaining the printer
+// semantic capabilities and defaults.
+IPC_MESSAGE_CONTROL2(
+ ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Succeeded,
+ std::string /* printer name */,
+ printing::PrinterSemanticCapsAndDefaults)
+
+// Reply when the utility process has failed to obtain the printer
+// capabilities and defaults.
+IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Failed,
+ std::string /* printer name */)
+
+// Reply when the utility process has failed to obtain the printer
+// semantic capabilities and defaults.
+IPC_MESSAGE_CONTROL1(
+ ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Failed,
+ std::string /* printer name */)
+#endif // defined(OS_WIN) && BUILDFLAG(ENABLE_PRINT_PREVIEW)
+
+#endif // CHROME_COMMON_CHROME_UTILITY_PRINTING_MESSAGES_H_
diff --git a/chromium/chrome/common/chrome_version.h.in b/chromium/chrome/common/chrome_version.h.in
new file mode 100644
index 00000000000..54c1b1d12f2
--- /dev/null
+++ b/chromium/chrome/common/chrome_version.h.in
@@ -0,0 +1,20 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// version.h is generated from version.h.in. Edit the source!
+
+
+// Version Information
+
+#define CHROME_VERSION @MAJOR@,@MINOR@,@BUILD@,@PATCH@
+#define CHROME_VERSION_STRING "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
+
+// Branding Information
+
+#define COMPANY_FULLNAME_STRING "@COMPANY_FULLNAME@"
+#define COMPANY_SHORTNAME_STRING "@COMPANY_SHORTNAME@"
+#define PRODUCT_FULLNAME_STRING "@PRODUCT_FULLNAME@"
+#define PRODUCT_SHORTNAME_STRING "@PRODUCT_SHORTNAME@"
+#define COPYRIGHT_STRING "@COPYRIGHT@"
+#define OFFICIAL_BUILD_STRING "@OFFICIAL_BUILD@"
diff --git a/chromium/chrome/common/client_hints/OWNERS b/chromium/chrome/common/client_hints/OWNERS
new file mode 100644
index 00000000000..22542699c2f
--- /dev/null
+++ b/chromium/chrome/common/client_hints/OWNERS
@@ -0,0 +1,8 @@
+yoavweiss@chromium.org
+tbansal@chromium.org
+ryansturm@chromium.org
+
+# For IPC security review
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+# COMPONENT: Blink>Loader
diff --git a/chromium/chrome/common/client_hints/client_hints.cc b/chromium/chrome/common/client_hints/client_hints.cc
new file mode 100644
index 00000000000..4c27309acae
--- /dev/null
+++ b/chromium/chrome/common/client_hints/client_hints.cc
@@ -0,0 +1,66 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/client_hints/client_hints.h"
+
+#include "content/public/common/origin_util.h"
+#include "third_party/blink/public/platform/web_client_hints_type.h"
+#include "url/gurl.h"
+
+namespace client_hints {
+
+void GetAllowedClientHintsFromSource(
+ const GURL& url,
+ const ContentSettingsForOneType& client_hints_rules,
+ blink::WebEnabledClientHints* client_hints) {
+ if (client_hints_rules.empty())
+ return;
+
+ if (!content::IsOriginSecure(url))
+ return;
+
+ const GURL& origin = url.GetOrigin();
+
+ for (const auto& rule : client_hints_rules) {
+ // Look for an exact match since persisted client hints are disabled by
+ // default, and enabled only on per-host basis.
+ if (rule.primary_pattern == ContentSettingsPattern::Wildcard() ||
+ !rule.primary_pattern.Matches(origin)) {
+ continue;
+ }
+
+ // Found an exact match.
+ DCHECK(ContentSettingsPattern::Wildcard() == rule.secondary_pattern);
+ DCHECK(rule.setting_value.is_dict());
+ const base::Value* expiration_time =
+ rule.setting_value.FindKey("expiration_time");
+
+ // |expiration_time| may be null in rare cases. See
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=942398.
+ if (expiration_time == nullptr)
+ continue;
+ DCHECK(expiration_time->is_double());
+
+ if (base::Time::Now().ToDoubleT() > expiration_time->GetDouble()) {
+ // The client hint is expired.
+ return;
+ }
+
+ const base::Value* list_value = rule.setting_value.FindKey("client_hints");
+ if (list_value == nullptr)
+ continue;
+ DCHECK(list_value->is_list());
+ base::span<const base::Value> client_hints_list = list_value->GetList();
+ for (const auto& client_hint : client_hints_list) {
+ DCHECK(client_hint.is_int());
+ client_hints->SetIsEnabled(
+ static_cast<blink::mojom::WebClientHintsType>(client_hint.GetInt()),
+ true);
+ }
+ // Match found for |url| and client hints have been set.
+ return;
+ }
+}
+
+} // namespace client_hints
diff --git a/chromium/chrome/common/client_hints/client_hints.h b/chromium/chrome/common/client_hints/client_hints.h
new file mode 100644
index 00000000000..a904642a1bb
--- /dev/null
+++ b/chromium/chrome/common/client_hints/client_hints.h
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CLIENT_HINTS_CLIENT_HINTS_H_
+#define CHROME_COMMON_CLIENT_HINTS_CLIENT_HINTS_H_
+
+#include "components/content_settings/core/common/content_settings.h"
+
+class GURL;
+
+namespace blink {
+struct WebEnabledClientHints;
+}
+
+namespace client_hints {
+
+// Retrieves the persistent client hints that should be set when fetching a
+// resource from |url|. The method updates |client_hints| with the result.
+// |client_hints_rules| contains the content settings for the client hints.
+void GetAllowedClientHintsFromSource(
+ const GURL& url,
+ const ContentSettingsForOneType& client_hints_rules,
+ blink::WebEnabledClientHints* client_hints);
+
+} // namespace client_hints
+
+#endif // CHROME_COMMON_CLIENT_HINTS_CLIENT_HINTS_H_
diff --git a/chromium/chrome/common/cloud_print/OWNERS b/chromium/chrome/common/cloud_print/OWNERS
new file mode 100644
index 00000000000..26c7dfb98b5
--- /dev/null
+++ b/chromium/chrome/common/cloud_print/OWNERS
@@ -0,0 +1,5 @@
+# This is for the common case of adding or renaming files. If you're doing
+# structural changes, use usual OWNERS rules.
+per-file BUILD.gn=*
+
+# COMPONENT: Services>CloudPrint
diff --git a/chromium/chrome/common/cloud_print/cloud_print_class_mac.h b/chromium/chrome/common/cloud_print/cloud_print_class_mac.h
new file mode 100644
index 00000000000..c2b7e4480d5
--- /dev/null
+++ b/chromium/chrome/common/cloud_print/cloud_print_class_mac.h
@@ -0,0 +1,17 @@
+// 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 CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_CLASS_MAC_H_
+#define CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_CLASS_MAC_H_
+
+#import <AppKit/AppKit.h>
+
+namespace cloud_print {
+
+// Four character constant to identify Cloud print IPC call.
+extern const AEEventClass kAECloudPrintClass;
+
+} // namespace cloud_print
+
+#endif // CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_CLASS_MAC_H_
diff --git a/chromium/chrome/common/cloud_print/cloud_print_class_mac.mm b/chromium/chrome/common/cloud_print/cloud_print_class_mac.mm
new file mode 100644
index 00000000000..9905e89deb7
--- /dev/null
+++ b/chromium/chrome/common/cloud_print/cloud_print_class_mac.mm
@@ -0,0 +1,11 @@
+// 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.
+
+#import "chrome/common/cloud_print/cloud_print_class_mac.h"
+
+namespace cloud_print {
+
+const AEEventClass kAECloudPrintClass = 'GCPp';
+
+} // namespace cloud_print
diff --git a/chromium/chrome/common/cloud_print/cloud_print_constants.cc b/chromium/chrome/common/cloud_print/cloud_print_constants.cc
new file mode 100644
index 00000000000..6c9f5d3292e
--- /dev/null
+++ b/chromium/chrome/common/cloud_print/cloud_print_constants.cc
@@ -0,0 +1,79 @@
+// 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 "chrome/common/cloud_print/cloud_print_constants.h"
+
+namespace cloud_print {
+
+const char kCloudPrintUserAgent[] = "GoogleCloudPrintProxy";
+const char kChromeCloudPrintProxyHeader[] = "X-CloudPrint-Proxy: Chrome";
+const char kCloudPrintPushNotificationsSource[] = "cloudprint.google.com";
+
+const char kProxyIdValue[] = "proxy";
+const char kPrinterNameValue[] = "printer";
+const char kPrinterDescValue[] = "description";
+const char kPrinterCapsValue[] = "capabilities";
+const char kPrinterDisplayNameValue[] = "default_display_name";
+const char kPrinterDefaultsValue[] = "defaults";
+const char kPrinterStatusValue[] = "status";
+const char kPrinterTagValue[] = "tag";
+const char kPrinterRemoveTagValue[] = "remove_tag";
+const char kPrinterLocalSettingsValue[] = "local_settings";
+const char kMessageTextValue[] = "message";
+const char kUseCDD[] = "use_cdd";
+
+const char kContentTypeJSON[] = "application/json";
+const char kContentTypePDF[] = "application/pdf";
+const char kContentTypeXML[] = "application/xml";
+const char kContentTypeXPS[] = "application/vnd.ms-xpsdocument";
+
+const char kPrintSystemFailedMessageId[] = "printsystemfail";
+const char kGetPrinterCapsFailedMessageId[] = "getprncapsfail";
+const char kEnumPrintersFailedMessageId[] = "enumfail";
+const char kZombiePrinterMessageId[] = "zombieprinter";
+
+const char kSuccessValue[] = "success";
+const char kNameValue[] = "name";
+const char kDisplayNameValue[] = "displayName";
+const char kIdValue[] = "id";
+const char kTicketUrlValue[] = "ticketUrl";
+const char kFileUrlValue[] = "fileUrl";
+const char kPrinterListValue[] = "printers";
+const char kJobListValue[] = "jobs";
+const char kTitleValue[] = "title";
+const char kOwnerValue[] = "ownerId";
+const char kPrinterCapsHashValue[] = "capsHash";
+const char kTagsValue[] = "tags";
+const char kXMPPJidValue[] = "xmpp_jid";
+const char kOAuthCodeValue[] = "authorization_code";
+const char kCreateTimeValue[] = "createTime";
+const char kPrinterTypeValue[] = "type";
+const char kUserValue[] = "request.user";
+const char kUsersValue[] = "request.users";
+const char kLocalSettingsPendingXmppValue[] =
+ "local_settings.pending.xmpp_timeout_value";
+
+const char kNotificationUpdateSettings[] = "/update_settings";
+
+const char kChromeVersionTagName[] = "chrome_version";
+const char kSystemNameTagName[] = "system_name";
+const char kSystemVersionTagName[] = "system_version";
+
+const char kCloudPrintServiceProxyTagPrefix[] = "__cp__";
+const char kCloudPrintServiceTagsHashTagName[] = "__cp__tagshash";
+const char kCloudPrintServiceTagDryRunFlag[] = "__cp__dry_run";
+
+const char kJobFetchReasonStartup[] = "startup";
+const char kJobFetchReasonPoll[] = "poll";
+const char kJobFetchReasonNotified[] = "notified";
+const char kJobFetchReasonQueryMore[] = "querymore";
+const char kJobFetchReasonFailure[] = "failure";
+const char kJobFetchReasonRetry[] = "retry";
+
+const char kCreateLocalSettingsXmppPingFormat[] =
+ "{\"current\":{\"xmpp_timeout_value\": %d}}";
+const char kUpdateLocalSettingsXmppPingFormat[] =
+ "{\"current\":{\"xmpp_timeout_value\": %d},\"pending\":{}}";
+
+} // namespace cloud_print
diff --git a/chromium/chrome/common/cloud_print/cloud_print_constants.h b/chromium/chrome/common/cloud_print/cloud_print_constants.h
new file mode 100644
index 00000000000..b9648347f45
--- /dev/null
+++ b/chromium/chrome/common/cloud_print/cloud_print_constants.h
@@ -0,0 +1,135 @@
+// 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 CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_CONSTANTS_H_
+#define CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_CONSTANTS_H_
+
+
+namespace cloud_print {
+
+// The string to be appended to the user-agent for cloud print requests.
+extern const char kCloudPrintUserAgent[];
+// The proxy header required by cloud print server.
+extern const char kChromeCloudPrintProxyHeader[];
+// The source of cloud print notifications.
+extern const char kCloudPrintPushNotificationsSource[];
+
+// Values used to register or update a printer with the cloud print service.
+extern const char kProxyIdValue[];
+extern const char kPrinterNameValue[];
+extern const char kPrinterDescValue[];
+extern const char kPrinterCapsValue[];
+extern const char kPrinterDisplayNameValue[];
+extern const char kPrinterDefaultsValue[];
+extern const char kPrinterStatusValue[];
+extern const char kPrinterTagValue[];
+extern const char kPrinterRemoveTagValue[];
+extern const char kPrinterLocalSettingsValue[];
+extern const char kMessageTextValue[];
+extern const char kUseCDD[];
+
+extern const char kContentTypeJSON[];
+extern const char kContentTypePDF[];
+extern const char kContentTypeXML[];
+extern const char kContentTypeXPS[];
+
+// Value of "code" parameter in cloud print "/message" requests.
+extern const char kPrintSystemFailedMessageId[];
+extern const char kGetPrinterCapsFailedMessageId[];
+extern const char kEnumPrintersFailedMessageId[];
+extern const char kZombiePrinterMessageId[];
+
+// Values in the respone JSON from the cloud print server.
+extern const char kSuccessValue[];
+extern const char kNameValue[];
+extern const char kDisplayNameValue[];
+extern const char kIdValue[];
+extern const char kTicketUrlValue[];
+extern const char kFileUrlValue[];
+extern const char kPrinterListValue[];
+extern const char kJobListValue[];
+extern const char kTitleValue[];
+extern const char kOwnerValue[];
+extern const char kPrinterCapsHashValue[];
+extern const char kTagsValue[];
+extern const char kXMPPJidValue[];
+extern const char kOAuthCodeValue[];
+extern const char kCreateTimeValue[];
+extern const char kPrinterTypeValue[];
+extern const char kUserValue[];
+extern const char kUsersValue[];
+extern const char kLocalSettingsPendingXmppValue[];
+
+// Value in XMPP notification.
+extern const char kNotificationUpdateSettings[];
+
+// Printer tag names. Don't need prefixes. They will be added on submit.
+extern const char kChromeVersionTagName[];
+extern const char kSystemNameTagName[];
+extern const char kSystemVersionTagName[];
+
+// Tags for cloud print service.
+extern const char kCloudPrintServiceProxyTagPrefix[];
+extern const char kCloudPrintServiceTagsHashTagName[];
+extern const char kCloudPrintServiceTagDryRunFlag[];
+
+// Reasons for fetching print jobs.
+// Job fetch on proxy startup.
+extern const char kJobFetchReasonStartup[];
+// Job fetch because we are polling.
+extern const char kJobFetchReasonPoll[];
+// Job fetch on being notified by the server.
+extern const char kJobFetchReasonNotified[];
+// Job fetch after a successful print to query for more jobs.
+extern const char kJobFetchReasonQueryMore[];
+// Job fetch after a job failure to query for more jobs.
+extern const char kJobFetchReasonFailure[];
+// Job fetch due to scheduled retry.
+extern const char kJobFetchReasonRetry[];
+
+// Format of the local settings containing only XMPP ping.
+extern const char kCreateLocalSettingsXmppPingFormat[];
+extern const char kUpdateLocalSettingsXmppPingFormat[];
+
+// Max retry count for job data fetch requests.
+const int kJobDataMaxRetryCount = 1;
+// Max retry count (infinity) for API fetch requests.
+const int kCloudPrintAPIMaxRetryCount = -1;
+// Max retry count (infinity) for Registration requests.
+const int kCloudPrintRegisterMaxRetryCount = -1;
+// Max retry count (infinity) for authentication requests.
+const int kCloudPrintAuthMaxRetryCount = -1;
+
+// When we don't have XMPP notifications available, we resort to polling for
+// print jobs. We choose a random interval in seconds between these 2 values.
+const int kMinJobPollIntervalSecs = 5*60; // 5 minutes in seconds
+const int kMaxJobPollIntervalSecs = 8*60; // 8 minutes in seconds
+
+// When we have XMPP notifications available, we ping server to keep connection
+// alive or check connection status.
+const int kDefaultXmppPingTimeoutSecs = 5*60;
+const int kMinXmppPingTimeoutSecs = 1*60;
+const int kXmppPingCheckIntervalSecs = 60;
+
+// Number of failed pings before we try to reinstablish XMPP connection.
+const int kMaxFailedXmppPings = 2;
+
+// The number of seconds before the OAuth2 access token is due to expire that
+// we try and refresh it.
+const int kTokenRefreshGracePeriodSecs = 5*60; // 5 minutes in seconds
+
+// The number of retries before we abandon a print job in exponential backoff
+const int kNumRetriesBeforeAbandonJob = 5;
+
+// The wait time for the second (first with wait time) retry for a job that
+// fails due to network errors
+const int kJobFirstWaitTimeSecs = 1;
+
+// The multiplier for the wait time for retrying a job that fails due to
+// network errors
+const int kJobWaitTimeExponentialMultiplier = 2;
+
+} // namespace cloud_print
+
+#endif // CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_CONSTANTS_H_
diff --git a/chromium/chrome/common/cloud_print/cloud_print_helpers.cc b/chromium/chrome/common/cloud_print/cloud_print_helpers.cc
new file mode 100644
index 00000000000..f6a4aa0bc4f
--- /dev/null
+++ b/chromium/chrome/common/cloud_print/cloud_print_helpers.cc
@@ -0,0 +1,240 @@
+// 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 "chrome/common/cloud_print/cloud_print_helpers.h"
+
+#include <stdint.h>
+
+#include <limits>
+#include <memory>
+#include <utility>
+
+#include "base/hash/md5.h"
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/system/sys_info.h"
+#include "base/values.h"
+#include "chrome/common/channel_info.h"
+#include "chrome/common/cloud_print/cloud_print_constants.h"
+#include "net/base/mime_util.h"
+#include "url/gurl.h"
+
+namespace cloud_print {
+
+namespace {
+
+// Returns printer tags generated from |printer_tags| and the default tags
+// required by cloud print server.
+PrinterTags PreparePrinterTags(const PrinterTags& printer_tags) {
+ PrinterTags printer_tags_out = printer_tags;
+ printer_tags_out[kChromeVersionTagName] = chrome::GetVersionString();
+ printer_tags_out[kSystemNameTagName] =
+ base::SysInfo::OperatingSystemName();
+ printer_tags_out[kSystemVersionTagName] =
+ base::SysInfo::OperatingSystemVersion();
+ return printer_tags_out;
+}
+
+// Returns the hash of |printer_tags|.
+std::string HashPrinterTags(const PrinterTags& printer_tags) {
+ std::string values_list;
+ PrinterTags::const_iterator it;
+ for (it = printer_tags.begin(); it != printer_tags.end(); ++it) {
+ values_list.append(it->first);
+ values_list.append(it->second);
+ }
+ return base::MD5String(values_list);
+}
+
+} // namespace
+
+std::string AppendPathToUrl(const GURL& url, const std::string& path) {
+ DCHECK_NE(path[0], '/');
+ std::string ret = url.path();
+ if (url.has_path() && (ret.back() != '/'))
+ ret += '/';
+ ret += path;
+ return ret;
+}
+
+GURL GetUrlForSearch(const GURL& cloud_print_server_url) {
+ std::string path(AppendPathToUrl(cloud_print_server_url, "search"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+GURL GetUrlForSubmit(const GURL& cloud_print_server_url) {
+ std::string path(AppendPathToUrl(cloud_print_server_url, "submit"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+GURL GetUrlForPrinterList(const GURL& cloud_print_server_url,
+ const std::string& proxy_id) {
+ std::string path(AppendPathToUrl(cloud_print_server_url, "list"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ std::string query = base::StringPrintf("proxy=%s", proxy_id.c_str());
+ replacements.SetQueryStr(query);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+GURL GetUrlForPrinterRegistration(const GURL& cloud_print_server_url) {
+ std::string path(AppendPathToUrl(cloud_print_server_url, "register"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+GURL GetUrlForPrinterUpdate(const GURL& cloud_print_server_url,
+ const std::string& printer_id) {
+ std::string path(AppendPathToUrl(cloud_print_server_url, "update"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ std::string query = base::StringPrintf("printerid=%s", printer_id.c_str());
+ replacements.SetQueryStr(query);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+GURL GetUrlForPrinterDelete(const GURL& cloud_print_server_url,
+ const std::string& printer_id,
+ const std::string& reason) {
+ std::string path(AppendPathToUrl(cloud_print_server_url, "delete"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ std::string query = base::StringPrintf(
+ "printerid=%s&reason=%s", printer_id.c_str(), reason.c_str());
+ replacements.SetQueryStr(query);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+GURL GetUrlForJobFetch(const GURL& cloud_print_server_url,
+ const std::string& printer_id,
+ const std::string& reason) {
+ std::string path(AppendPathToUrl(cloud_print_server_url, "fetch"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ std::string query = base::StringPrintf(
+ "printerid=%s&deb=%s", printer_id.c_str(), reason.c_str());
+ replacements.SetQueryStr(query);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+GURL GetUrlForJobCjt(const GURL& cloud_print_server_url,
+ const std::string& job_id,
+ const std::string& reason) {
+ std::string path(AppendPathToUrl(cloud_print_server_url, "ticket"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ std::string query = base::StringPrintf(
+ "jobid=%s&deb=%s&use_cjt=true", job_id.c_str(), reason.c_str());
+ replacements.SetQueryStr(query);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+GURL GetUrlForJobDelete(const GURL& cloud_print_server_url,
+ const std::string& job_id) {
+ std::string path(AppendPathToUrl(cloud_print_server_url, "deletejob"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ std::string query = base::StringPrintf("jobid=%s", job_id.c_str());
+ replacements.SetQueryStr(query);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+GURL GetUrlForJobStatusUpdate(const GURL& cloud_print_server_url,
+ const std::string& job_id,
+ const std::string& status_string,
+ int connector_code) {
+ std::string path(AppendPathToUrl(cloud_print_server_url, "control"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ std::string query = base::StringPrintf(
+ "jobid=%s&status=%s&connector_code=%d", job_id.c_str(),
+ status_string.c_str(), connector_code);
+ replacements.SetQueryStr(query);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+GURL GetUrlForUserMessage(const GURL& cloud_print_server_url,
+ const std::string& message_id) {
+ std::string path(AppendPathToUrl(cloud_print_server_url, "message"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ std::string query = base::StringPrintf("code=%s", message_id.c_str());
+ replacements.SetQueryStr(query);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+GURL GetUrlForGetAuthCode(const GURL& cloud_print_server_url,
+ const std::string& oauth_client_id,
+ const std::string& proxy_id) {
+ // We use the internal API "createrobot" instead of "getauthcode". This API
+ // will add the robot as owner to all the existing printers for this user.
+ std::string path(AppendPathToUrl(cloud_print_server_url, "createrobot"));
+ GURL::Replacements replacements;
+ replacements.SetPathStr(path);
+ std::string query = base::StringPrintf("oauth_client_id=%s&proxy=%s",
+ oauth_client_id.c_str(),
+ proxy_id.c_str());
+ replacements.SetQueryStr(query);
+ return cloud_print_server_url.ReplaceComponents(replacements);
+}
+
+base::Value ParseResponseJSON(const std::string& response_data,
+ bool* succeeded) {
+ base::Optional<base::Value> message_value =
+ base::JSONReader::Read(response_data);
+ if (!message_value || !message_value->is_dict())
+ return base::Value();
+
+ *succeeded = message_value->FindBoolKey(kSuccessValue).value_or(false);
+ return std::move(*message_value);
+}
+
+std::string GetMultipartMimeType(const std::string& mime_boundary) {
+ return std::string("multipart/form-data; boundary=") + mime_boundary;
+}
+
+std::string GetHashOfPrinterTags(const PrinterTags& printer_tags) {
+ return HashPrinterTags(PreparePrinterTags(printer_tags));
+}
+
+std::string GetPostDataForPrinterTags(
+ const PrinterTags& printer_tags,
+ const std::string& mime_boundary,
+ const std::string& proxy_tag_prefix,
+ const std::string& tags_hash_tag_name) {
+ PrinterTags printer_tags_prepared = PreparePrinterTags(printer_tags);
+ std::string post_data;
+ for (PrinterTags::const_iterator it = printer_tags_prepared.begin();
+ it != printer_tags_prepared.end(); ++it) {
+ // TODO(gene) Escape '=' char from name. Warning for now.
+ if (it->first.find('=') != std::string::npos) {
+ LOG(WARNING) <<
+ "CP_PROXY: Printer option name contains '=' character";
+ NOTREACHED();
+ }
+ // All our tags have a special prefix to identify them as such.
+ std::string msg = base::StringPrintf("%s%s=%s",
+ proxy_tag_prefix.c_str(), it->first.c_str(), it->second.c_str());
+ net::AddMultipartValueForUpload(kPrinterTagValue, msg, mime_boundary,
+ std::string(), &post_data);
+ }
+ std::string tags_hash_msg = base::StringPrintf("%s=%s",
+ tags_hash_tag_name.c_str(),
+ HashPrinterTags(printer_tags_prepared).c_str());
+ net::AddMultipartValueForUpload(kPrinterTagValue, tags_hash_msg,
+ mime_boundary, std::string(), &post_data);
+ return post_data;
+}
+
+std::string GetCloudPrintAuthHeader(const std::string& auth_token) {
+ return base::StringPrintf("Authorization: OAuth %s", auth_token.c_str());
+}
+
+} // namespace cloud_print
diff --git a/chromium/chrome/common/cloud_print/cloud_print_helpers.h b/chromium/chrome/common/cloud_print/cloud_print_helpers.h
new file mode 100644
index 00000000000..904f934ec1b
--- /dev/null
+++ b/chromium/chrome/common/cloud_print/cloud_print_helpers.h
@@ -0,0 +1,86 @@
+// 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 CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_HELPERS_H_
+#define CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_HELPERS_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+class GURL;
+
+namespace base {
+class Value;
+}
+
+// Helper consts and methods for both cloud print and chrome browser.
+namespace cloud_print {
+
+// A map representing printer tags.
+typedef std::map<std::string, std::string> PrinterTags;
+
+// Appends a relative path to the url making sure to append a '/' if the
+// URL's path does not end with a slash. It is assumed that |path| does not
+// begin with a '/'.
+// NOTE: Since we ALWAYS want to append here, we simply append the path string
+// instead of calling url::ResolveRelative. The input |url| may or may not
+// contain a '/' at the end.
+std::string AppendPathToUrl(const GURL& url, const std::string& path);
+
+GURL GetUrlForSearch(const GURL& cloud_print_server_url);
+GURL GetUrlForSubmit(const GURL& cloud_print_server_url);
+GURL GetUrlForPrinterList(const GURL& cloud_print_server_url,
+ const std::string& proxy_id);
+GURL GetUrlForPrinterRegistration(const GURL& cloud_print_server_url);
+GURL GetUrlForPrinterUpdate(const GURL& cloud_print_server_url,
+ const std::string& printer_id);
+GURL GetUrlForPrinterDelete(const GURL& cloud_print_server_url,
+ const std::string& printer_id,
+ const std::string& reason);
+GURL GetUrlForJobFetch(const GURL& cloud_print_server_url,
+ const std::string& printer_id,
+ const std::string& reason);
+GURL GetUrlForJobCjt(const GURL& cloud_print_server_url,
+ const std::string& job_id,
+ const std::string& reason);
+GURL GetUrlForJobDelete(const GURL& cloud_print_server_url,
+ const std::string& job_id);
+GURL GetUrlForJobStatusUpdate(const GURL& cloud_print_server_url,
+ const std::string& job_id,
+ const std::string& status_string,
+ int connector_code);
+GURL GetUrlForUserMessage(const GURL& cloud_print_server_url,
+ const std::string& message_id);
+GURL GetUrlForGetAuthCode(const GURL& cloud_print_server_url,
+ const std::string& oauth_client_id,
+ const std::string& proxy_id);
+
+// Parses the response data for any cloud print server request. The method
+// returns none Value if there was an error in parsing the JSON. The |succeeded|
+// parameters returns the value of the "success" value in the response JSON.
+// Returns the response as a dictionary value on success.
+base::Value ParseResponseJSON(const std::string& response_data,
+ bool* succeeded);
+
+// Returns the MIME type of multipart with |mime_boundary|.
+std::string GetMultipartMimeType(const std::string& mime_boundary);
+
+// Returns an MD5 hash for |printer_tags| and the default required tags.
+std::string GetHashOfPrinterTags(const PrinterTags& printer_tags);
+
+// Returns the post data for |printer_tags| and the default required tags.
+std::string GetPostDataForPrinterTags(
+ const PrinterTags& printer_tags,
+ const std::string& mime_boundary,
+ const std::string& proxy_tag_prefix,
+ const std::string& tags_hash_tag_name);
+
+// Get the cloud print auth header from |auth_token|.
+std::string GetCloudPrintAuthHeader(const std::string& auth_token);
+
+} // namespace cloud_print
+
+#endif // CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_HELPERS_H_
diff --git a/chromium/chrome/common/cloud_print/cloud_print_helpers_unittest.cc b/chromium/chrome/common/cloud_print/cloud_print_helpers_unittest.cc
new file mode 100644
index 00000000000..cfd1b650f0f
--- /dev/null
+++ b/chromium/chrome/common/cloud_print/cloud_print_helpers_unittest.cc
@@ -0,0 +1,131 @@
+// 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 "chrome/common/cloud_print/cloud_print_helpers.h"
+
+#include "base/hash/md5.h"
+#include "base/strings/stringprintf.h"
+#include "base/system/sys_info.h"
+#include "chrome/common/channel_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace cloud_print {
+
+namespace {
+
+void CheckURLs(const GURL& server_base_url) {
+ std::string expected_url_base = server_base_url.spec();
+ if (expected_url_base.back() != '/')
+ expected_url_base += "/";
+
+ EXPECT_EQ(base::StringPrintf("%ssearch", expected_url_base.c_str()),
+ GetUrlForSearch(server_base_url).spec());
+
+ EXPECT_EQ(base::StringPrintf("%ssubmit", expected_url_base.c_str()),
+ GetUrlForSubmit(server_base_url).spec());
+
+ EXPECT_EQ(base::StringPrintf("%slist?proxy=demoproxy",
+ expected_url_base.c_str()),
+ GetUrlForPrinterList(
+ server_base_url, std::string("demoproxy")).spec());
+
+ EXPECT_EQ(base::StringPrintf("%sregister", expected_url_base.c_str()),
+ GetUrlForPrinterRegistration(server_base_url).spec());
+
+ EXPECT_EQ(base::StringPrintf("%supdate?printerid=printeridfoo",
+ expected_url_base.c_str()),
+ GetUrlForPrinterUpdate(server_base_url, "printeridfoo").spec());
+
+ EXPECT_EQ(base::StringPrintf("%sdelete?printerid=printeridbar&reason=deleted",
+ expected_url_base.c_str()),
+ GetUrlForPrinterDelete(
+ server_base_url, "printeridbar", "deleted").spec());
+
+ EXPECT_EQ(base::StringPrintf("%sfetch?printerid=myprinter&deb=nogoodreason",
+ expected_url_base.c_str()),
+ GetUrlForJobFetch(
+ server_base_url, "myprinter", "nogoodreason").spec());
+
+ EXPECT_EQ(base::StringPrintf("%sdeletejob?jobid=myprinter",
+ expected_url_base.c_str()),
+ GetUrlForJobDelete(server_base_url, "myprinter").spec());
+
+ EXPECT_EQ(base::StringPrintf(
+ "%scontrol?jobid=myprinter&status=s1&connector_code=0",
+ expected_url_base.c_str()),
+ GetUrlForJobStatusUpdate(
+ server_base_url, "myprinter", "s1", 0).spec());
+
+ EXPECT_EQ(base::StringPrintf("%smessage?code=testmsg",
+ expected_url_base.c_str()),
+ GetUrlForUserMessage(server_base_url, "testmsg").spec());
+
+ EXPECT_EQ(base::StringPrintf(
+ "%screaterobot?oauth_client_id=democlientid&proxy=demoproxy",
+ expected_url_base.c_str()),
+ GetUrlForGetAuthCode(
+ server_base_url, "democlientid", "demoproxy").spec());
+}
+
+} // namespace
+
+TEST(CloudPrintHelpersTest, GetURLs) {
+ CheckURLs(GURL("https://www.google.com/cloudprint"));
+ CheckURLs(GURL("https://www.google.com/cloudprint/"));
+ CheckURLs(GURL("http://www.myprinterserver.com"));
+ CheckURLs(GURL("http://www.myprinterserver.com/"));
+}
+
+TEST(CloudPrintHelpersTest, GetHashOfPrinterTags) {
+ PrinterTags printer_tags;
+ printer_tags["tag1"] = std::string("value1");
+ printer_tags["tag2"] = std::string("value2");
+
+ std::string expected_list_string = base::StringPrintf(
+ "chrome_version%ssystem_name%ssystem_version%stag1value1tag2value2",
+ chrome::GetVersionString().c_str(),
+ base::SysInfo::OperatingSystemName().c_str(),
+ base::SysInfo::OperatingSystemVersion().c_str());
+ EXPECT_EQ(base::MD5String(expected_list_string),
+ GetHashOfPrinterTags(printer_tags));
+}
+
+TEST(CloudPrintHelpersTest, GetPostDataForPrinterTags) {
+ PrinterTags printer_tags;
+ printer_tags["tag1"] = std::string("value1");
+ printer_tags["tag2"] = std::string("value2");
+
+ std::string expected = base::StringPrintf(
+ "--test_mime_boundary\r\nContent-Disposition: form-data; name=\"tag\""
+ "\r\n\r\n__test__chrome_version=%s\r\n"
+ "--test_mime_boundary\r\nContent-Disposition: form-data; name=\"tag\""
+ "\r\n\r\n__test__system_name=%s\r\n"
+ "--test_mime_boundary\r\nContent-Disposition: form-data; name=\"tag\""
+ "\r\n\r\n__test__system_version=%s\r\n"
+ "--test_mime_boundary\r\nContent-Disposition: form-data; name=\"tag\""
+ "\r\n\r\n__test__tag1=value1\r\n"
+ "--test_mime_boundary\r\nContent-Disposition: form-data; name=\"tag\""
+ "\r\n\r\n__test__tag2=value2\r\n"
+ "--test_mime_boundary\r\nContent-Disposition: form-data; name=\"tag\""
+ "\r\n\r\n__test__tagshash=%s\r\n",
+ chrome::GetVersionString().c_str(),
+ base::SysInfo::OperatingSystemName().c_str(),
+ base::SysInfo::OperatingSystemVersion().c_str(),
+ GetHashOfPrinterTags(printer_tags).c_str());
+
+ EXPECT_EQ(expected, GetPostDataForPrinterTags(
+ printer_tags,
+ std::string("test_mime_boundary"),
+ std::string("__test__"),
+ std::string("__test__tagshash")));
+}
+
+TEST(CloudPrintHelpersTest, GetCloudPrintAuthHeader) {
+ std::string test_auth("testauth");
+ EXPECT_EQ("Authorization: OAuth testauth",
+ GetCloudPrintAuthHeader(test_auth));
+}
+
+} // namespace cloud_print
diff --git a/chromium/chrome/common/cloud_print/cloud_print_proxy_info.cc b/chromium/chrome/common/cloud_print/cloud_print_proxy_info.cc
new file mode 100644
index 00000000000..6e38663cb3b
--- /dev/null
+++ b/chromium/chrome/common/cloud_print/cloud_print_proxy_info.cc
@@ -0,0 +1,14 @@
+// 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 "chrome/common/cloud_print/cloud_print_proxy_info.h"
+
+namespace cloud_print {
+
+CloudPrintProxyInfo::CloudPrintProxyInfo() : enabled(false) {
+}
+
+CloudPrintProxyInfo::~CloudPrintProxyInfo() {}
+
+} // namespace cloud_print
diff --git a/chromium/chrome/common/cloud_print/cloud_print_proxy_info.h b/chromium/chrome/common/cloud_print/cloud_print_proxy_info.h
new file mode 100644
index 00000000000..2b97378bd72
--- /dev/null
+++ b/chromium/chrome/common/cloud_print/cloud_print_proxy_info.h
@@ -0,0 +1,24 @@
+// 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 CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_PROXY_INFO_H_
+#define CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_PROXY_INFO_H_
+
+#include <string>
+
+namespace cloud_print {
+
+// This struct is used for ServiceHostMsg_CloudPrint_Info IPC message.
+struct CloudPrintProxyInfo {
+ CloudPrintProxyInfo();
+ ~CloudPrintProxyInfo();
+
+ bool enabled;
+ std::string email;
+ std::string proxy_id;
+};
+
+} // namespace cloud_print
+
+#endif // CHROME_COMMON_CLOUD_PRINT_CLOUD_PRINT_PROXY_INFO_H_
diff --git a/chromium/chrome/common/common.vsprops b/chromium/chrome/common/common.vsprops
new file mode 100644
index 00000000000..a8343918f4a
--- /dev/null
+++ b/chromium/chrome/common/common.vsprops
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="common (chrome)"
+ InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\third_party\icu\build\using_icu.vsprops;$(SolutionDir)..\third_party\zlib\using_zlib.vsprops;$(SolutionDir)..\third_party\libpng\using_libpng.vsprops;$(SolutionDir)..\skia\using_skia.vsprops;$(SolutionDir)..\tools\grit\build\using_generated_resources.vsprops;$(SolutionDir)..\third_party\libxml\build\using_libxml.vsprops;$(SolutionDir)..\third_party\npapi\using_npapi.vsprops;$(SolutionDir)..\chrome\third_party\wtl\using_wtl.vsprops;$(SolutionDir)\common\extra_defines.vsprops"
+ >
+</VisualStudioPropertySheet>
diff --git a/chromium/chrome/common/common_message_generator.cc b/chromium/chrome/common/common_message_generator.cc
new file mode 100644
index 00000000000..f2dd63b8714
--- /dev/null
+++ b/chromium/chrome/common/common_message_generator.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/common_message_generator.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "chrome/common/safe_browsing/ipc_protobuf_message_null_macros.h"
+#include "chrome/common/common_message_generator.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+#include "chrome/common/safe_browsing/protobuf_message_write_macros.h"
+namespace IPC {
+#include "chrome/common/common_message_generator.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+#include "chrome/common/safe_browsing/protobuf_message_read_macros.h"
+namespace IPC {
+#include "chrome/common/common_message_generator.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+#include "chrome/common/safe_browsing/protobuf_message_log_macros.h"
+namespace IPC {
+#include "chrome/common/common_message_generator.h"
+} // namespace IPC
diff --git a/chromium/chrome/common/common_message_generator.h b/chromium/chrome/common/common_message_generator.h
new file mode 100644
index 00000000000..c16905baf6f
--- /dev/null
+++ b/chromium/chrome/common/common_message_generator.h
@@ -0,0 +1,51 @@
+// 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.
+
+// Multiply-included file, hence no include guard.
+
+#include "chrome/common/common_param_traits_macros.h"
+#include "chrome/common/instant_mojom_traits.h"
+#include "services/network/public/cpp/p2p_param_traits.h"
+#undef CHROME_COMMON_MAC_APP_SHIM_PARAM_TRAITS_H_
+#include "chrome/common/mac/app_shim_param_traits.h"
+#ifndef CHROME_COMMON_MAC_APP_SHIM_PARAM_TRAITS_H_
+#error "Failed to include header chrome/common/mac/app_shim_param_traits.h"
+#endif
+#undef CHROME_COMMON_PRERENDER_MESSAGES_H_
+#include "chrome/common/prerender_messages.h"
+#ifndef CHROME_COMMON_PRERENDER_MESSAGES_H_
+#error "Failed to include header chrome/common/prerender_messages.h"
+#endif
+#undef CHROME_COMMON_RENDER_MESSAGES_H_
+#include "chrome/common/render_messages.h"
+#ifndef CHROME_COMMON_RENDER_MESSAGES_H_
+#error "Failed to include header chrome/common/render_messages.h"
+#endif
+#include "components/safe_browsing/buildflags.h"
+#include "content/public/common/common_param_traits.h"
+#include "content/public/common/common_param_traits_macros.h"
+#include "extensions/buildflags/buildflags.h"
+#include "media/media_buildflags.h"
+#include "printing/buildflags/buildflags.h"
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#undef CHROME_COMMON_CAST_MESSAGES_H_
+#include "chrome/common/cast_messages.h"
+#ifndef CHROME_COMMON_CAST_MESSAGES_H_
+#error "Failed to include header chrome/common/cast_messages.h"
+#endif
+#endif
+
+#if BUILDFLAG(ENABLE_PRINTING)
+#undef CHROME_COMMON_CHROME_UTILITY_PRINTING_MESSAGES_H_
+#include "chrome/common/chrome_utility_printing_messages.h"
+#ifndef CHROME_COMMON_CHROME_UTILITY_PRINTING_MESSAGES_H_
+#error \
+ "Failed to include header chrome/common/chrome_utility_printing_messages.h"
+#endif
+#endif
+
+#if BUILDFLAG(FULL_SAFE_BROWSING)
+#include "chrome/services/file_util/public/mojom/safe_archive_analyzer_param_traits.h"
+#endif
diff --git a/chromium/chrome/common/common_param_traits.cc b/chromium/chrome/common/common_param_traits.cc
new file mode 100644
index 00000000000..466cfde6da8
--- /dev/null
+++ b/chromium/chrome/common/common_param_traits.cc
@@ -0,0 +1,27 @@
+// 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.
+
+// Get basic type definitions.
+#include "chrome/common/common_param_traits.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#undef CHROME_COMMON_COMMON_PARAM_TRAITS_MACROS_H_
+#include "chrome/common/common_param_traits_macros.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#undef CHROME_COMMON_COMMON_PARAM_TRAITS_MACROS_H_
+#include "chrome/common/common_param_traits_macros.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#undef CHROME_COMMON_COMMON_PARAM_TRAITS_MACROS_H_
+#include "chrome/common/common_param_traits_macros.h"
+} // namespace IPC
diff --git a/chromium/chrome/common/common_param_traits.h b/chromium/chrome/common/common_param_traits.h
new file mode 100644
index 00000000000..9a05b2bf99e
--- /dev/null
+++ b/chromium/chrome/common/common_param_traits.h
@@ -0,0 +1,13 @@
+// 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 CHROME_COMMON_COMMON_PARAM_TRAITS_H_
+#define CHROME_COMMON_COMMON_PARAM_TRAITS_H_
+
+// This file provides declarations of IPC serialization macros that are used
+// in more than one IPC message file.
+
+#include "chrome/common/common_param_traits_macros.h"
+
+#endif // CHROME_COMMON_COMMON_PARAM_TRAITS_H_
diff --git a/chromium/chrome/common/common_param_traits_macros.h b/chromium/chrome/common/common_param_traits_macros.h
new file mode 100644
index 00000000000..f6b91ccd276
--- /dev/null
+++ b/chromium/chrome/common/common_param_traits_macros.h
@@ -0,0 +1,16 @@
+// 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.
+
+// Singly or multiply-included shared traits file depending upon circumstances.
+// This allows the use of IPC serialization macros in more than one IPC message
+// file.
+#ifndef CHROME_COMMON_COMMON_PARAM_TRAITS_MACROS_H_
+#define CHROME_COMMON_COMMON_PARAM_TRAITS_MACROS_H_
+
+#include "components/content_settings/core/common/content_settings_types.h"
+#include "ipc/ipc_message_macros.h"
+
+IPC_ENUM_TRAITS_MAX_VALUE(ContentSettingsType, CONTENT_SETTINGS_NUM_TYPES - 1)
+
+#endif // CHROME_COMMON_COMMON_PARAM_TRAITS_MACROS_H_
diff --git a/chromium/chrome/common/component_flash_hint_file_linux.cc b/chromium/chrome/common/component_flash_hint_file_linux.cc
new file mode 100644
index 00000000000..8e90d1f7a98
--- /dev/null
+++ b/chromium/chrome/common/component_flash_hint_file_linux.cc
@@ -0,0 +1,229 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/component_flash_hint_file_linux.h"
+
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/mman.h>
+
+#include <memory>
+
+#include "base/base64.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/important_file_writer.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/files/scoped_file.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/path_service.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "chrome/common/chrome_paths.h"
+#include "crypto/secure_hash.h"
+#include "crypto/secure_util.h"
+#include "crypto/sha2.h"
+
+namespace component_flash_hint_file {
+
+namespace {
+
+// The current version of the hints file.
+const int kCurrentHintFileVersion = 0x10;
+// The earliest version of the hints file.
+const int kEarliestHintFileVersion = 0x10;
+// The Version field in the JSON encoded file.
+const char kVersionField[] = "Version";
+// The HashAlgorithm field in the JSON encoded file.
+const char kHashAlgoField[] = "HashAlgorithm";
+// The Hash field in the JSON encoded file.
+const char kHashField[] = "Hash";
+// The PluginPath field in the JSON encoded file.
+const char kPluginPath[] = "PluginPath";
+// The PluginVersion field in the JSON encoded file.
+const char kPluginVersion[] = "PluginVersion";
+// For use with the scoped_ptr of an mmap-ed buffer
+struct MmapDeleter {
+ explicit MmapDeleter(size_t map_size) : map_size_(map_size) { }
+ inline void operator()(uint8_t* ptr) const {
+ if (ptr != MAP_FAILED)
+ munmap(ptr, map_size_);
+ }
+
+ private:
+ size_t map_size_;
+};
+
+// Hashes the plugin file and returns the result in the out params.
+// |mapped_file| is the file to be hashed.
+// |result| is the buffer, which must be of size crypto::kSHA256Length, which
+// will contain the hash.
+// |len| is the size of the buffer, which must be crypto::kSHA256Length.
+void SHA256Hash(const base::MemoryMappedFile& mapped_file,
+ void* result,
+ size_t len) {
+ CHECK_EQ(crypto::kSHA256Length, len);
+ std::unique_ptr<crypto::SecureHash> secure_hash(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ secure_hash->Update(mapped_file.data(), mapped_file.length());
+ secure_hash->Finish(result, len);
+}
+
+// This will serialize the file to disk as JSON. The format is:
+// {
+// "Version": 0x10,
+// "HashAlgorithm": SecureHash::SHA256,
+// "Hash": <Base64 Encoded Hash>,
+// "PluginPath": /path/to/component/updated/flash.so,
+// "PluginVersion": "1.0.0.1"
+// }
+bool WriteToDisk(const int version,
+ const crypto::SecureHash::Algorithm algorithm,
+ const std::string& hash,
+ const base::FilePath& plugin_path,
+ const std::string& flash_version) {
+ base::FilePath hint_file_path;
+ if (!base::PathService::Get(chrome::FILE_COMPONENT_FLASH_HINT,
+ &hint_file_path))
+ return false;
+
+ std::string encoded_hash;
+ base::Base64Encode(hash, &encoded_hash);
+
+ // Now construct a Value object to convert to JSON.
+ base::DictionaryValue dict;
+ dict.SetInteger(kVersionField, version);
+ dict.SetInteger(kHashAlgoField, crypto::SecureHash::SHA256);
+ dict.SetString(kHashField, encoded_hash);
+ dict.SetString(kPluginPath, plugin_path.value());
+ dict.SetString(kPluginVersion, flash_version);
+ // Do the serialization of the DictionaryValue to JSON.
+ std::string json_string;
+ JSONStringValueSerializer serializer(&json_string);
+ if (!serializer.Serialize(dict))
+ return false;
+
+ return base::ImportantFileWriter::WriteFileAtomically(hint_file_path,
+ json_string);
+}
+
+} // namespace
+
+bool TestExecutableMapping(const base::FilePath& path) {
+ const base::ScopedFD fd(
+ HANDLE_EINTR(open(path.value().c_str(), O_RDONLY | O_CLOEXEC)));
+ if (!fd.is_valid())
+ return false;
+ const size_t map_size = sizeof(uint8_t);
+ const MmapDeleter deleter(map_size);
+ std::unique_ptr<uint8_t, MmapDeleter> buf_ptr(
+ reinterpret_cast<uint8_t*>(mmap(nullptr, map_size, PROT_READ | PROT_EXEC,
+ MAP_PRIVATE, fd.get(), 0)),
+ deleter);
+ return buf_ptr.get() != MAP_FAILED;
+}
+
+bool RecordFlashUpdate(const base::FilePath& unpacked_plugin,
+ const base::FilePath& moved_plugin,
+ const std::string& version) {
+ base::MemoryMappedFile mapped_file;
+ if (!mapped_file.Initialize(unpacked_plugin))
+ return false;
+
+ std::string hash(crypto::kSHA256Length, 0);
+ SHA256Hash(mapped_file, base::data(hash), hash.size());
+
+ return WriteToDisk(kCurrentHintFileVersion,
+ crypto::SecureHash::Algorithm::SHA256, hash, moved_plugin,
+ version);
+}
+
+bool DoesHintFileExist() {
+ base::FilePath hint_file_path;
+ if (!base::PathService::Get(chrome::FILE_COMPONENT_FLASH_HINT,
+ &hint_file_path))
+ return false;
+ return base::PathExists(hint_file_path);
+}
+
+bool VerifyAndReturnFlashLocation(base::FilePath* path,
+ std::string* flash_version) {
+ base::FilePath hint_file_path;
+ if (!base::PathService::Get(chrome::FILE_COMPONENT_FLASH_HINT,
+ &hint_file_path))
+ return false;
+
+ std::string json_string;
+ if (!base::ReadFileToString(hint_file_path, &json_string))
+ return false;
+
+ int error_code;
+ std::string error_message;
+ JSONStringValueDeserializer deserializer(json_string);
+ const std::unique_ptr<base::Value> value =
+ deserializer.Deserialize(&error_code, &error_message);
+
+ if (!value) {
+ LOG(ERROR)
+ << "Could not deserialize the component updated Flash hint file. Error "
+ << error_code << ": " << error_message;
+ return false;
+ }
+
+ base::DictionaryValue* dict = nullptr;
+ if (!value->GetAsDictionary(&dict))
+ return false;
+
+ int version;
+ if (!dict->GetInteger(kVersionField, &version))
+ return false;
+ if (version < kEarliestHintFileVersion || version > kCurrentHintFileVersion)
+ return false;
+
+ int hash_algorithm;
+ if (!dict->GetInteger(kHashAlgoField, &hash_algorithm))
+ return false;
+ if (hash_algorithm != crypto::SecureHash::SHA256)
+ return false;
+
+ std::string hash;
+ if (!dict->GetString(kHashField, &hash))
+ return false;
+
+ std::string plugin_path_str;
+ if (!dict->GetString(kPluginPath, &plugin_path_str))
+ return false;
+
+ std::string plugin_version_str;
+ if (!dict->GetString(kPluginVersion, &plugin_version_str))
+ return false;
+
+ std::string decoded_hash;
+ if (!base::Base64Decode(hash, &decoded_hash))
+ return false;
+
+ const base::FilePath plugin_path(plugin_path_str);
+ base::MemoryMappedFile plugin_file;
+ if (!plugin_file.Initialize(plugin_path))
+ return false;
+
+ std::vector<uint8_t> file_hash(crypto::kSHA256Length, 0);
+ SHA256Hash(plugin_file, &file_hash[0], file_hash.size());
+ if (!crypto::SecureMemEqual(base::data(file_hash), base::data(decoded_hash),
+ crypto::kSHA256Length)) {
+ LOG(ERROR)
+ << "The hash recorded in the component flash hint file does not "
+ "match the actual hash of the flash plugin found on disk. The "
+ "component flash plugin will not be loaded.";
+ return false;
+ }
+
+ *path = plugin_path;
+ flash_version->assign(plugin_version_str);
+ return true;
+}
+
+} // namespace component_flash_hint_file
diff --git a/chromium/chrome/common/component_flash_hint_file_linux.h b/chromium/chrome/common/component_flash_hint_file_linux.h
new file mode 100644
index 00000000000..85694ce4284
--- /dev/null
+++ b/chromium/chrome/common/component_flash_hint_file_linux.h
@@ -0,0 +1,49 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_COMPONENT_FLASH_HINT_FILE_LINUX_H_
+#define CHROME_COMMON_COMPONENT_FLASH_HINT_FILE_LINUX_H_
+
+#include "build/build_config.h"
+
+#if !defined(OS_LINUX)
+#error "This file only applies to the Linux component update of Flash."
+#endif // !defined(OS_LINUX)
+
+#include <string>
+
+namespace base {
+class FilePath;
+}
+
+// The APIs in this namespace wraps the component updated flash hint file, which
+// lives inside the PepperFlash folder of the user-data-dir, so that the Linux
+// zygote process can preload the right version of flash.
+namespace component_flash_hint_file {
+
+// Records a new flash update into the hint file.
+// |unpacked_plugin| is the current location of the plugin.
+// |moved_plugin| is the location where the plugin will be loaded from.
+bool RecordFlashUpdate(const base::FilePath& unpacked_plugin,
+ const base::FilePath& moved_plugin,
+ const std::string& version);
+
+// Reports whether or not a hints file exists.
+bool DoesHintFileExist();
+
+// Return the path of the component updated flash plugin, only if the file has
+// the correct hash sum.
+// |path| will be populated with the path to the flash plugin.
+// |version| will be populated with the version of the flash plugin.
+bool VerifyAndReturnFlashLocation(base::FilePath* path, std::string* version);
+
+// Test if the specified plugin file can be mapped executable.
+// This is useful to test if the flash plugin is in a directory mounted
+// noexec, in which case Chrome will not be able to load and use the plugin.
+// |path| is the path of the flash plugin that will mapped executable.
+bool TestExecutableMapping(const base::FilePath& path);
+
+} // namespace component_flash_hint_file
+
+#endif // CHROME_COMMON_COMPONENT_FLASH_HINT_FILE_LINUX_H_
diff --git a/chromium/chrome/common/component_flash_hint_file_linux_unittest.cc b/chromium/chrome/common/component_flash_hint_file_linux_unittest.cc
new file mode 100644
index 00000000000..ca550f46a9f
--- /dev/null
+++ b/chromium/chrome/common/component_flash_hint_file_linux_unittest.cc
@@ -0,0 +1,168 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/component_flash_hint_file_linux.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/process/kill.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/scoped_path_override.h"
+#include "base/test/test_timeouts.h"
+#include "chrome/common/chrome_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace chrome {
+
+class ComponentFlashHintFileTest : public base::MultiProcessTest {};
+
+TEST_F(ComponentFlashHintFileTest, ExistsTest) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+ EXPECT_FALSE(component_flash_hint_file::DoesHintFileExist());
+}
+
+TEST_F(ComponentFlashHintFileTest, InstallTest) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+ EXPECT_FALSE(component_flash_hint_file::DoesHintFileExist());
+
+ base::FilePath flash_dir;
+ ASSERT_TRUE(base::PathService::Get(
+ chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN, &flash_dir));
+
+ base::File::Error error;
+ ASSERT_TRUE(base::CreateDirectoryAndGetError(flash_dir, &error));
+
+ // Write out a fixed byte array as the flash file.
+ uint8_t file[] = {0x4c, 0x65, 0x74, 0x20, 0x75, 0x73,
+ 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x67};
+ flash_dir = flash_dir.Append("libflash.so");
+ const std::string flash_version = "1.0.0.1";
+ ASSERT_EQ(static_cast<int>(sizeof(file)),
+ base::WriteFile(flash_dir, reinterpret_cast<const char*>(file),
+ sizeof(file)));
+ ASSERT_TRUE(component_flash_hint_file::RecordFlashUpdate(flash_dir, flash_dir,
+ flash_version));
+ ASSERT_TRUE(component_flash_hint_file::DoesHintFileExist());
+
+ // Confirm that the flash plugin can be verified and returned.
+ base::FilePath returned_flash_path;
+ std::string version;
+ ASSERT_TRUE(component_flash_hint_file::VerifyAndReturnFlashLocation(
+ &returned_flash_path, &version));
+ ASSERT_EQ(returned_flash_path, flash_dir);
+ ASSERT_EQ(version, flash_version);
+
+ // Now "corrupt" the flash file and make sure the checksum fails and nothing
+ // is returned.
+ file[0] = 0xAA;
+ ASSERT_TRUE(base::WriteFile(flash_dir, reinterpret_cast<const char*>(file),
+ sizeof(file)) == sizeof(file));
+ base::FilePath empty_path;
+ std::string empty_version;
+ ASSERT_FALSE(component_flash_hint_file::VerifyAndReturnFlashLocation(
+ &empty_path, &empty_version));
+ ASSERT_NE(empty_path, flash_dir);
+ ASSERT_FALSE(empty_version == flash_version);
+}
+
+TEST_F(ComponentFlashHintFileTest, CorruptionTest) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+ EXPECT_FALSE(component_flash_hint_file::DoesHintFileExist());
+
+ base::FilePath flash_dir;
+ ASSERT_TRUE(base::PathService::Get(
+ chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN, &flash_dir));
+
+ base::File::Error error;
+ ASSERT_TRUE(base::CreateDirectoryAndGetError(flash_dir, &error));
+ flash_dir = flash_dir.Append("libflash.so");
+
+ const uint8_t file[] = {0x56, 0x61, 0x20, 0x67, 0x75, 0x76,
+ 0x66, 0x20, 0x62, 0x61, 0x72, 0x20};
+ ASSERT_TRUE(base::WriteFile(flash_dir, reinterpret_cast<const char*>(file),
+ sizeof(file)) == sizeof(file));
+ const std::string flash_version = "1.0.0.1";
+ ASSERT_TRUE(component_flash_hint_file::RecordFlashUpdate(flash_dir, flash_dir,
+ flash_version));
+ ASSERT_TRUE(component_flash_hint_file::DoesHintFileExist());
+
+ // Now write out a new flash version that will not be moved into place.
+ const uint8_t updated_file[] = {0x43, 0x72, 0x62, 0x63, 0x79, 0x72,
+ 0x20, 0x66, 0x7a, 0x76, 0x79, 0x76};
+ base::FilePath flash_dir_update;
+ ASSERT_TRUE(base::PathService::Get(
+ chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN, &flash_dir_update));
+ flash_dir_update = flash_dir_update.Append("other_flash.so");
+ ASSERT_TRUE(base::WriteFile(flash_dir_update,
+ reinterpret_cast<const char*>(updated_file),
+ sizeof(updated_file)) == sizeof(updated_file));
+ ASSERT_TRUE(component_flash_hint_file::RecordFlashUpdate(
+ flash_dir_update, flash_dir, flash_version));
+ // |flash_dir_update| needs to be moved to |flash_dir|, but this test
+ // deliberately skips that step, so VerifyAndReturnFlashLocation should fail.
+ base::FilePath failed_flash_dir;
+ std::string failed_version;
+ ASSERT_FALSE(component_flash_hint_file::VerifyAndReturnFlashLocation(
+ &failed_flash_dir, &failed_version));
+}
+
+TEST_F(ComponentFlashHintFileTest, ExecTest1) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath file_path = temp_dir.GetPath().Append("plugin.so");
+ const uint8_t file[] = {0x55, 0x62, 0x79, 0x71, 0x20,
+ 0x6c, 0x62, 0x68, 0x65, 0x20};
+
+ ASSERT_TRUE(base::WriteFile(file_path, reinterpret_cast<const char*>(file),
+ sizeof(file)) == sizeof(file));
+ ASSERT_TRUE(component_flash_hint_file::TestExecutableMapping(file_path));
+}
+
+MULTIPROCESS_TEST_MAIN(NoExecMountTest) {
+ if (unshare(CLONE_NEWUSER | CLONE_NEWNS) != 0) {
+ LOG(ERROR) << "This kernel does not support unprivileged namespaces. "
+ "ExecTest2 will succeed without running.";
+ return 0;
+ }
+ // Now mount a NOEXEC fs.
+ const unsigned long tmpfs_flags = MS_NODEV | MS_NOSUID | MS_NOEXEC;
+ base::ScopedTempDir temp_dir;
+ CHECK(temp_dir.CreateUniqueTempDir());
+ CHECK_EQ(0, mount("tmpfs", temp_dir.GetPath().value().c_str(), "tmpfs",
+ tmpfs_flags, nullptr));
+ const base::FilePath file_path = temp_dir.GetPath().Append("plugin.so");
+ const uint8_t file[] = {0x56, 0x61, 0x20, 0x67, 0x75, 0x72,
+ 0x20, 0x70, 0x76, 0x67, 0x6c, 0x20};
+ bool test_exec = false;
+ bool file_written =
+ base::WriteFile(file_path, reinterpret_cast<const char*>(file),
+ sizeof(file)) == static_cast<int>(sizeof(file));
+ if (file_written)
+ test_exec = component_flash_hint_file::TestExecutableMapping(file_path);
+
+ if (umount(temp_dir.GetPath().value().c_str()) != 0)
+ LOG(ERROR) << "Could not unmount directory " << temp_dir.GetPath().value();
+
+ CHECK(file_written);
+ CHECK(!test_exec);
+ return 0;
+}
+
+TEST_F(ComponentFlashHintFileTest, ExecTest2) {
+ base::Process process = SpawnChild("NoExecMountTest");
+ ASSERT_TRUE(process.IsValid());
+ int exit_code = 42;
+ ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
+ &exit_code));
+ EXPECT_EQ(0, exit_code);
+}
+
+} // namespace chrome
diff --git a/chromium/chrome/common/conflicts/OWNERS b/chromium/chrome/common/conflicts/OWNERS
new file mode 100644
index 00000000000..070d64169b2
--- /dev/null
+++ b/chromium/chrome/common/conflicts/OWNERS
@@ -0,0 +1,8 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+chrisha@chromium.org
+pmonette@chromium.org
+
+# COMPONENT: Internals>PlatformIntegration
+# TEAM: windows-third-party@chromium.org
diff --git a/chromium/chrome/common/conflicts/module_watcher_win.cc b/chromium/chrome/common/conflicts/module_watcher_win.cc
new file mode 100644
index 00000000000..994b1056ff3
--- /dev/null
+++ b/chromium/chrome/common/conflicts/module_watcher_win.cc
@@ -0,0 +1,266 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/conflicts/module_watcher_win.h"
+
+#include <windows.h>
+#include <tlhelp32.h>
+#include <winternl.h> // For UNICODE_STRING.
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/win/scoped_handle.h"
+
+// These structures and functions are documented in MSDN, see
+// http://msdn.microsoft.com/en-us/library/gg547638(v=vs.85).aspx
+// there are however no headers or import libraries available in the
+// Platform SDK. They are declared outside of the anonymous namespace to
+// allow them to be forward declared in the header file.
+enum {
+ // The DLL was loaded. The NotificationData parameter points to a
+ // LDR_DLL_LOADED_NOTIFICATION_DATA structure.
+ LDR_DLL_NOTIFICATION_REASON_LOADED = 1,
+ // The DLL was unloaded. The NotificationData parameter points to a
+ // LDR_DLL_UNLOADED_NOTIFICATION_DATA structure.
+ LDR_DLL_NOTIFICATION_REASON_UNLOADED = 2,
+};
+
+// Structure that is used for module load notifications.
+struct LDR_DLL_LOADED_NOTIFICATION_DATA {
+ // Reserved.
+ ULONG Flags;
+ // The full path name of the DLL module.
+ PCUNICODE_STRING FullDllName;
+ // The base file name of the DLL module.
+ PCUNICODE_STRING BaseDllName;
+ // A pointer to the base address for the DLL in memory.
+ PVOID DllBase;
+ // The size of the DLL image, in bytes.
+ ULONG SizeOfImage;
+};
+using PLDR_DLL_LOADED_NOTIFICATION_DATA = LDR_DLL_LOADED_NOTIFICATION_DATA*;
+
+// Structure that is used for module unload notifications.
+struct LDR_DLL_UNLOADED_NOTIFICATION_DATA {
+ // Reserved.
+ ULONG Flags;
+ // The full path name of the DLL module.
+ PCUNICODE_STRING FullDllName;
+ // The base file name of the DLL module.
+ PCUNICODE_STRING BaseDllName;
+ // A pointer to the base address for the DLL in memory.
+ PVOID DllBase;
+ // The size of the DLL image, in bytes.
+ ULONG SizeOfImage;
+};
+using PLDR_DLL_UNLOADED_NOTIFICATION_DATA = LDR_DLL_UNLOADED_NOTIFICATION_DATA*;
+
+// Union that is used for notifications.
+union LDR_DLL_NOTIFICATION_DATA {
+ LDR_DLL_LOADED_NOTIFICATION_DATA Loaded;
+ LDR_DLL_UNLOADED_NOTIFICATION_DATA Unloaded;
+};
+using PLDR_DLL_NOTIFICATION_DATA = LDR_DLL_NOTIFICATION_DATA*;
+
+// Signature of the notification callback function.
+using PLDR_DLL_NOTIFICATION_FUNCTION =
+ VOID(CALLBACK*)(ULONG notification_reason,
+ const LDR_DLL_NOTIFICATION_DATA* notification_data,
+ PVOID context);
+
+// Signatures of the functions used for registering DLL notification callbacks.
+using LdrRegisterDllNotificationFunc =
+ NTSTATUS(NTAPI*)(ULONG flags,
+ PLDR_DLL_NOTIFICATION_FUNCTION notification_function,
+ PVOID context,
+ PVOID* cookie);
+using LdrUnregisterDllNotificationFunc = NTSTATUS(NTAPI*)(PVOID cookie);
+
+namespace {
+
+// Global lock for ensuring synchronization of destruction and notifications.
+//
+// Warning: Since this lock is acquired inside the DLL notification callbacks,
+// it must never be held when calling into any functions that may
+// acquire the Loader Lock, as this is a lock order violation that will
+// cause a deadlock. A noteworthy example in this file are the
+// LdrRegisterDllNotification and LdrUnregisterDllNotification
+// functions.
+base::LazyInstance<base::Lock>::Leaky g_module_watcher_lock =
+ LAZY_INSTANCE_INITIALIZER;
+// Global pointer to the singleton ModuleWatcher, if one exists. Under
+// |module_watcher_lock|.
+ModuleWatcher* g_module_watcher_instance = nullptr;
+
+// Names of the DLL notification registration functions. These are exported by
+// ntdll.
+constexpr wchar_t kNtDll[] = L"ntdll.dll";
+constexpr char kLdrRegisterDllNotification[] = "LdrRegisterDllNotification";
+constexpr char kLdrUnregisterDllNotification[] = "LdrUnregisterDllNotification";
+
+// Helper function for converting a UNICODE_STRING to a FilePath.
+base::FilePath ToFilePath(const UNICODE_STRING* str) {
+ return base::FilePath(
+ base::StringPiece16(str->Buffer, str->Length / sizeof(wchar_t)));
+}
+
+template <typename NotificationDataType>
+void OnModuleEvent(ModuleWatcher::ModuleEventType event_type,
+ const NotificationDataType& notification_data,
+ const ModuleWatcher::OnModuleEventCallback& callback) {
+ ModuleWatcher::ModuleEvent event(
+ event_type, ToFilePath(notification_data.FullDllName),
+ notification_data.DllBase, notification_data.SizeOfImage);
+ callback.Run(event);
+}
+
+} // namespace
+
+// static
+std::unique_ptr<ModuleWatcher> ModuleWatcher::Create(
+ OnModuleEventCallback callback) {
+ {
+ base::AutoLock lock(g_module_watcher_lock.Get());
+ // If a ModuleWatcher already exists then bail out.
+ if (g_module_watcher_instance)
+ return nullptr;
+ g_module_watcher_instance = new ModuleWatcher();
+ }
+
+ // Initialization mustn't occur while holding |g_module_watcher_lock|.
+ g_module_watcher_instance->Initialize(std::move(callback));
+ return base::WrapUnique(g_module_watcher_instance);
+}
+
+ModuleWatcher::~ModuleWatcher() {
+ // Done before acquiring |g_module_watcher_lock|.
+ UnregisterDllNotificationCallback();
+
+ // As soon as |g_module_watcher_instance| is null any dispatched callbacks
+ // will be silently absorbed by LoaderNotificationCallback.
+ base::AutoLock lock(g_module_watcher_lock.Get());
+ DCHECK_EQ(g_module_watcher_instance, this);
+ g_module_watcher_instance = nullptr;
+}
+
+ModuleWatcher::ModuleWatcher() {}
+
+// Initializes the ModuleWatcher instance.
+void ModuleWatcher::Initialize(OnModuleEventCallback callback) {
+ callback_ = std::move(callback);
+ RegisterDllNotificationCallback();
+
+ // The enumeration of modules is done on a background task to make sure it
+ // doesn't slow down startup.
+ base::PostTask(
+ FROM_HERE,
+ {base::ThreadPool(), base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+ base::BindOnce(&ModuleWatcher::EnumerateAlreadyLoadedModules,
+ base::SequencedTaskRunnerHandle::Get(),
+ base::BindRepeating(&ModuleWatcher::RunCallback,
+ weak_ptr_factory_.GetWeakPtr())));
+}
+
+void ModuleWatcher::RegisterDllNotificationCallback() {
+ // It's safe to pass the return value of ::GetModuleHandle() directly to
+ // ::GetProcAddress() because ntdll is guaranteed to be loaded.
+ LdrRegisterDllNotificationFunc reg_fn =
+ reinterpret_cast<LdrRegisterDllNotificationFunc>(::GetProcAddress(
+ ::GetModuleHandle(kNtDll), kLdrRegisterDllNotification));
+ if (reg_fn)
+ reg_fn(0, &LoaderNotificationCallback, this, &dll_notification_cookie_);
+}
+
+void ModuleWatcher::UnregisterDllNotificationCallback() {
+ // It's safe to pass the return value of ::GetModuleHandle() directly to
+ // ::GetProcAddress() because ntdll is guaranteed to be loaded.
+ LdrUnregisterDllNotificationFunc unreg_fn =
+ reinterpret_cast<LdrUnregisterDllNotificationFunc>(::GetProcAddress(
+ ::GetModuleHandle(kNtDll), kLdrUnregisterDllNotification));
+ if (unreg_fn)
+ unreg_fn(dll_notification_cookie_);
+}
+
+// static
+void ModuleWatcher::EnumerateAlreadyLoadedModules(
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ OnModuleEventCallback callback) {
+ // Get all modules in the current process. According to MSDN,
+ // CreateToolhelp32Snapshot should be retried as long as its returning
+ // ERROR_BAD_LENGTH. To avoid locking up here a retry limit is enforced.
+ base::win::ScopedHandle snap;
+ DWORD process_id = ::GetCurrentProcessId();
+ for (int i = 0; i < 5; ++i) {
+ snap.Set(::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32,
+ process_id));
+ if (snap.IsValid())
+ break;
+ if (::GetLastError() != ERROR_BAD_LENGTH)
+ return;
+ }
+ if (!snap.IsValid())
+ return;
+
+ // Walk the module list.
+ MODULEENTRY32 module = {sizeof(module)};
+ for (BOOL result = ::Module32First(snap.Get(), &module); result != FALSE;
+ result = ::Module32Next(snap.Get(), &module)) {
+ ModuleEvent event(ModuleEventType::kModuleAlreadyLoaded,
+ base::FilePath(module.szExePath), module.modBaseAddr,
+ module.modBaseSize);
+ task_runner->PostTask(FROM_HERE, base::BindOnce(callback, event));
+ }
+}
+
+// static
+ModuleWatcher::OnModuleEventCallback ModuleWatcher::GetCallbackForContext(
+ void* context) {
+ base::AutoLock lock(g_module_watcher_lock.Get());
+ if (context != g_module_watcher_instance)
+ return OnModuleEventCallback();
+ return g_module_watcher_instance->callback_;
+}
+
+// static
+void __stdcall ModuleWatcher::LoaderNotificationCallback(
+ unsigned long notification_reason,
+ const LDR_DLL_NOTIFICATION_DATA* notification_data,
+ void* context) {
+ auto callback = GetCallbackForContext(context);
+ if (!callback)
+ return;
+
+ switch (notification_reason) {
+ case LDR_DLL_NOTIFICATION_REASON_LOADED:
+ OnModuleEvent(ModuleEventType::kModuleLoaded, notification_data->Loaded,
+ callback);
+ break;
+
+ case LDR_DLL_NOTIFICATION_REASON_UNLOADED:
+ // Intentionally ignored.
+ break;
+
+ default:
+ // This is unexpected, but not a reason to crash.
+ NOTREACHED() << "Unknown LDR_DLL_NOTIFICATION_REASON: "
+ << notification_reason;
+ }
+}
+
+void ModuleWatcher::RunCallback(const ModuleEvent& event) {
+ callback_.Run(event);
+}
diff --git a/chromium/chrome/common/conflicts/module_watcher_win.h b/chromium/chrome/common/conflicts/module_watcher_win.h
new file mode 100644
index 00000000000..b050fdf028a
--- /dev/null
+++ b/chromium/chrome/common/conflicts/module_watcher_win.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 CHROME_COMMON_CONFLICTS_MODULE_WATCHER_WIN_H_
+#define CHROME_COMMON_CONFLICTS_MODULE_WATCHER_WIN_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+
+class ModuleWatcherTest;
+
+union LDR_DLL_NOTIFICATION_DATA;
+
+// This class observes modules as they are loaded into a process's address
+// space.
+//
+// This class is safe to be created on any thread. Similarly, it is safe to be
+// destroyed on any thread, independent of the thread on which the instance was
+// created.
+class ModuleWatcher {
+ public:
+ // The types of module events that can occur.
+ enum class ModuleEventType {
+ // A module was already loaded, but its presence is being observed.
+ kModuleAlreadyLoaded,
+ // A module is in the process of being loaded.
+ kModuleLoaded,
+ };
+
+ // Houses information about a module event, and some module metadata.
+ struct ModuleEvent {
+ ModuleEvent() = default;
+ ModuleEvent(const ModuleEvent& other) = default;
+ ModuleEvent(ModuleEventType event_type,
+ const base::FilePath& module_path,
+ void* module_load_address,
+ size_t module_size)
+ : event_type(event_type),
+ module_path(module_path),
+ module_load_address(module_load_address),
+ module_size(module_size) {}
+
+ // The type of module event.
+ ModuleEventType event_type;
+ // The full path to the module on disk.
+ base::FilePath module_path;
+ // The load address of the module. Careful consideration must be made before
+ // accessing memory at this address. See the comment for
+ // OnModuleEventCallback.
+ void* module_load_address;
+ // The size of the module in memory.
+ size_t module_size;
+ };
+
+ // The type of callback that will be invoked for each module event. This
+ // callback may be run from any thread in the process, and may be invoked
+ // during initialization (while iterating over already loaded modules) or in
+ // response to LdrDllNotifications received from the loader. As such, keep the
+ // amount of work performed here to an absolute minimum.
+ //
+ // MODULE_LOADED events are always dispatched directly from the loader while
+ // under the loader's lock, so the module is guaranteed to be loaded in memory
+ // (it is safe to access module_load_address).
+ //
+ // If the event is of type MODULE_ALREADY_LOADED, then the module data comes
+ // from a snapshot and it is possible that its |module_load_address| is
+ // invalid by the time the event is sent.
+ //
+ // Note that it is possible for this callback to be invoked after the
+ // destruction of the watcher.
+ using OnModuleEventCallback =
+ base::RepeatingCallback<void(const ModuleEvent& event)>;
+
+ // Creates and starts a watcher. This enumerates all loaded modules
+ // synchronously on the current thread during construction, and provides
+ // synchronous notifications as modules are loaded. The callback is invoked in
+ // the context of the thread that is loading a module, and as such may be
+ // invoked on any thread in the process. Note that it is possible to receive
+ // two notifications for some modules as the initial loaded module enumeration
+ // races briefly with the callback mechanism. In this case both a
+ // MODULE_LOADED and a MODULE_ALREADY_LOADED event will be received for the
+ // same module. Since the callback is installed first no modules can be
+ // missed, however. This factory function may be called on any thread.
+ //
+ // Only a single instance of a watcher may exist at any moment. This will
+ // return nullptr when trying to create a second watcher.
+ static std::unique_ptr<ModuleWatcher> Create(OnModuleEventCallback callback);
+
+ // This can be called on any thread. After destruction the |callback|
+ // provided to the constructor will no longer be invoked with module events.
+ ~ModuleWatcher();
+
+ private:
+ // For unittesting.
+ friend class ModuleWatcherTest;
+
+ // Private to enforce Singleton semantics. See Create above.
+ ModuleWatcher();
+
+ // Initializes the ModuleWatcher instance.
+ void Initialize(OnModuleEventCallback callback);
+
+ // Registers a DllNotification callback with the OS. Modifies
+ // |dll_notification_cookie_|. Can be called on any thread.
+ void RegisterDllNotificationCallback();
+
+ // Removes the installed DllNotification callback. Modifies
+ // |dll_notification_cookie_|. Can be called on any thread.
+ void UnregisterDllNotificationCallback();
+
+ // Enumerates all currently loaded modules, synchronously invoking callbacks
+ // on the current thread. Can be called on any thread.
+ static void EnumerateAlreadyLoadedModules(
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ OnModuleEventCallback callback);
+
+ // Helper function for retrieving the callback associated with a given
+ // LdrNotification context.
+ static OnModuleEventCallback GetCallbackForContext(void* context);
+
+ // The loader notification callback. This is actually
+ // void CALLBACK LoaderNotificationCallback(
+ // DWORD, const LDR_DLL_NOTIFICATION_DATA*, PVOID)
+ // Not using CALLBACK/DWORD/PVOID allows skipping the windows.h header from
+ // this file.
+ static void __stdcall LoaderNotificationCallback(
+ unsigned long notification_reason,
+ const LDR_DLL_NOTIFICATION_DATA* notification_data,
+ void* context);
+
+ // Used to bind the |callback_| to a WeakPtr.
+ void RunCallback(const ModuleEvent& event);
+
+ // The current callback. Can end up being invoked on any thread.
+ OnModuleEventCallback callback_;
+ // Used by the DllNotification mechanism.
+ void* dll_notification_cookie_ = nullptr;
+
+ base::WeakPtrFactory<ModuleWatcher> weak_ptr_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(ModuleWatcher);
+};
+
+#endif // CHROME_COMMON_CONFLICTS_MODULE_WATCHER_WIN_H_
diff --git a/chromium/chrome/common/conflicts/module_watcher_win_unittest.cc b/chromium/chrome/common/conflicts/module_watcher_win_unittest.cc
new file mode 100644
index 00000000000..8de1eb13161
--- /dev/null
+++ b/chromium/chrome/common/conflicts/module_watcher_win_unittest.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 "chrome/common/conflicts/module_watcher_win.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/test/task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include <windows.h>
+
+class ModuleWatcherTest : public testing::Test {
+ protected:
+ ModuleWatcherTest()
+ : module_(nullptr),
+ module_event_count_(0),
+ module_already_loaded_event_count_(0),
+ module_loaded_event_count_(0) {}
+
+ void OnModuleEvent(const ModuleWatcher::ModuleEvent& event) {
+ ++module_event_count_;
+ switch (event.event_type) {
+ case ModuleWatcher::ModuleEventType::kModuleAlreadyLoaded:
+ ++module_already_loaded_event_count_;
+ break;
+ case ModuleWatcher::ModuleEventType::kModuleLoaded:
+ ++module_loaded_event_count_;
+ break;
+ }
+ }
+
+ void TearDown() override { UnloadModule(); }
+
+ void LoadModule() {
+ if (module_)
+ return;
+ // This module should not be a static dependency of the unit-test
+ // executable, but should be a build-system dependency or a module that is
+ // present on any Windows machine.
+ static constexpr wchar_t kModuleName[] = L"conflicts_dll.dll";
+ // The module should not already be loaded.
+ ASSERT_FALSE(::GetModuleHandle(kModuleName));
+ // It should load successfully.
+ module_ = ::LoadLibrary(kModuleName);
+ ASSERT_TRUE(module_);
+ }
+
+ void UnloadModule() {
+ if (!module_)
+ return;
+ ::FreeLibrary(module_);
+ module_ = nullptr;
+ }
+
+ void RunUntilIdle() { task_environment_.RunUntilIdle(); }
+
+ std::unique_ptr<ModuleWatcher> Create() {
+ return ModuleWatcher::Create(
+ base::Bind(&ModuleWatcherTest::OnModuleEvent, base::Unretained(this)));
+ }
+
+ base::test::TaskEnvironment task_environment_;
+
+ // Holds a handle to a loaded module.
+ HMODULE module_;
+ // Total number of module events seen.
+ int module_event_count_;
+ // Total number of MODULE_ALREADY_LOADED events seen.
+ int module_already_loaded_event_count_;
+ // Total number of MODULE_LOADED events seen.
+ int module_loaded_event_count_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ModuleWatcherTest);
+};
+
+TEST_F(ModuleWatcherTest, SingleModuleWatcherOnly) {
+ std::unique_ptr<ModuleWatcher> mw1(Create());
+ EXPECT_TRUE(mw1.get());
+
+ std::unique_ptr<ModuleWatcher> mw2(Create());
+ EXPECT_FALSE(mw2.get());
+}
+
+TEST_F(ModuleWatcherTest, ModuleEvents) {
+ // Create the module watcher. This should immediately enumerate all already
+ // loaded modules on a background task.
+ std::unique_ptr<ModuleWatcher> mw(Create());
+ RunUntilIdle();
+
+ EXPECT_LT(0, module_event_count_);
+ EXPECT_LT(0, module_already_loaded_event_count_);
+ EXPECT_EQ(0, module_loaded_event_count_);
+
+ // Dynamically load a module and ensure a notification is received for it.
+ int previous_module_loaded_event_count = module_loaded_event_count_;
+ LoadModule();
+ EXPECT_LT(previous_module_loaded_event_count, module_loaded_event_count_);
+
+ UnloadModule();
+
+ // Dynamically load a module and ensure a notification is received for it.
+ previous_module_loaded_event_count = module_loaded_event_count_;
+ LoadModule();
+ EXPECT_LT(previous_module_loaded_event_count, module_loaded_event_count_);
+
+ UnloadModule();
+
+ // Destroy the module watcher.
+ mw.reset();
+
+ // Load the module and ensure no notification is received this time.
+ previous_module_loaded_event_count = module_loaded_event_count_;
+ LoadModule();
+ EXPECT_EQ(previous_module_loaded_event_count, module_loaded_event_count_);
+}
diff --git a/chromium/chrome/common/conflicts/remote_module_watcher_win.cc b/chromium/chrome/common/conflicts/remote_module_watcher_win.cc
new file mode 100644
index 00000000000..0a28e9e11cf
--- /dev/null
+++ b/chromium/chrome/common/conflicts/remote_module_watcher_win.cc
@@ -0,0 +1,84 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/conflicts/remote_module_watcher_win.h"
+
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+
+namespace {
+
+// Note: Can be called on any threads, even those not owned by the task
+// scheduler.
+void OnModuleEvent(
+ scoped_refptr<base::SequencedTaskRunner> task_runner,
+ const ModuleWatcher::OnModuleEventCallback& on_module_event_callback,
+ const ModuleWatcher::ModuleEvent& event) {
+ task_runner->PostTask(FROM_HERE,
+ base::BindOnce(on_module_event_callback, event));
+}
+
+} // namespace
+
+// static
+constexpr base::TimeDelta RemoteModuleWatcher::kIdleDelay;
+
+RemoteModuleWatcher::~RemoteModuleWatcher() = default;
+
+// static
+RemoteModuleWatcher::UniquePtr RemoteModuleWatcher::Create(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ mojo::PendingRemote<mojom::ModuleEventSink> remote_sink) {
+ auto remote_module_watcher =
+ UniquePtr(new RemoteModuleWatcher(task_runner),
+ base::OnTaskRunnerDeleter(task_runner));
+
+ // Because |remote_module_watcher| will be sent for deletion on |task_runner|,
+ // using an unretained pointer to it is safe as the initialization is
+ // guaranteed to be run before the destructor.
+ task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&RemoteModuleWatcher::InitializeOnTaskRunner,
+ base::Unretained(remote_module_watcher.get()),
+ std::move(remote_sink)));
+
+ return remote_module_watcher;
+}
+
+RemoteModuleWatcher::RemoteModuleWatcher(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : task_runner_(task_runner),
+ delay_timer_(FROM_HERE,
+ kIdleDelay,
+ this,
+ &RemoteModuleWatcher::OnTimerFired) {}
+
+void RemoteModuleWatcher::InitializeOnTaskRunner(
+ mojo::PendingRemote<mojom::ModuleEventSink> remote_sink) {
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
+
+ module_event_sink_.Bind(std::move(remote_sink));
+ module_watcher_ = ModuleWatcher::Create(base::BindRepeating(
+ &OnModuleEvent, task_runner_,
+ base::BindRepeating(&RemoteModuleWatcher::HandleModuleEvent,
+ weak_ptr_factory_.GetWeakPtr())));
+}
+
+void RemoteModuleWatcher::HandleModuleEvent(
+ const ModuleWatcher::ModuleEvent& event) {
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
+
+ // Accumulate events. They will be sent when the |delay_timer_| fires.
+ module_load_addresses_.push_back(
+ reinterpret_cast<uintptr_t>(event.module_load_address));
+
+ // Ensure the timer is running.
+ delay_timer_.Reset();
+}
+
+void RemoteModuleWatcher::OnTimerFired() {
+ DCHECK(task_runner_->RunsTasksInCurrentSequence());
+
+ module_event_sink_->OnModuleEvents(module_load_addresses_);
+ module_load_addresses_.clear();
+}
diff --git a/chromium/chrome/common/conflicts/remote_module_watcher_win.h b/chromium/chrome/common/conflicts/remote_module_watcher_win.h
new file mode 100644
index 00000000000..45909f17dc1
--- /dev/null
+++ b/chromium/chrome/common/conflicts/remote_module_watcher_win.h
@@ -0,0 +1,87 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_CONFLICTS_REMOTE_MODULE_WATCHER_WIN_H_
+#define CHROME_COMMON_CONFLICTS_REMOTE_MODULE_WATCHER_WIN_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "chrome/common/conflicts/module_event_sink_win.mojom.h"
+#include "chrome/common/conflicts/module_watcher_win.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+struct OnTaskRunnerDeleter;
+} // namespace base
+
+// This class is used to instantiate a ModuleWatcher instance in a child
+// process that forwards all the module events to the browser process via the
+// mojom::ModuleEventSink interface.
+class RemoteModuleWatcher {
+ public:
+ // Provided for convenience.
+ using UniquePtr =
+ std::unique_ptr<RemoteModuleWatcher, base::OnTaskRunnerDeleter>;
+
+ // The amount of time this class waits before sending all the received module
+ // events in one batch to the browser process.
+ static constexpr base::TimeDelta kIdleDelay = base::TimeDelta::FromSeconds(5);
+
+ ~RemoteModuleWatcher();
+
+ // Creates a RemoteModuleWatcher instance and initializes it on |task_runner|.
+ // The instance lives on that task runner and will be destroyed there when the
+ // UniquePtr is destroyed.
+ static UniquePtr Create(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ mojo::PendingRemote<mojom::ModuleEventSink> remote_sink);
+
+ private:
+ explicit RemoteModuleWatcher(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+ // Initializes this instance by connecting the |module_event_sink_| instance
+ // and starting the |module_watcher_|. Called on |task_runner_|.
+ void InitializeOnTaskRunner(
+ mojo::PendingRemote<mojom::ModuleEventSink> remote_sink);
+
+ // Receives module load events from the |module_watcher_| and forwards them to
+ // the |module_event_sink_|.
+ void HandleModuleEvent(const ModuleWatcher::ModuleEvent& event);
+
+ // Sends all accumulated module events in |module_load_addresses_| to the
+ // |module_event_sink_| in one batch.
+ void OnTimerFired();
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ // Module events from |module_watcher_| are forwarded to the browser process
+ // through this sink.
+ mojo::Remote<mojom::ModuleEventSink> module_event_sink_;
+
+ // Observes module load events.
+ std::unique_ptr<ModuleWatcher> module_watcher_;
+
+ // Accumulates module events. They will be sent to the browser process when
+ // |delay_timer_| fires.
+ std::vector<uint64_t> module_load_addresses_;
+
+ // This timer is used to delay the sending of module events until none have
+ // been received for |kIdleDelay| amount of time.
+ base::DelayTimer delay_timer_;
+
+ base::WeakPtrFactory<RemoteModuleWatcher> weak_ptr_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteModuleWatcher);
+};
+
+#endif // CHROME_COMMON_CONFLICTS_REMOTE_MODULE_WATCHER_WIN_H_
diff --git a/chromium/chrome/common/conflicts/remote_module_watcher_win_unittest.cc b/chromium/chrome/common/conflicts/remote_module_watcher_win_unittest.cc
new file mode 100644
index 00000000000..ca99ee16a84
--- /dev/null
+++ b/chromium/chrome/common/conflicts/remote_module_watcher_win_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/conflicts/remote_module_watcher_win.h"
+
+#include <windows.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/test/task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "chrome/common/conflicts/module_event_sink_win.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class RemoteModuleWatcherTest : public testing::Test,
+ public mojom::ModuleEventSink {
+ public:
+ RemoteModuleWatcherTest() = default;
+ ~RemoteModuleWatcherTest() override = default;
+
+ mojo::PendingRemote<mojom::ModuleEventSink> Bind() {
+ return receiver_.BindNewPipeAndPassRemote();
+ }
+
+ // mojom::ModuleEventSink:
+ void OnModuleEvents(
+ const std::vector<uint64_t>& module_load_addresses) override {
+ module_event_count_ += module_load_addresses.size();
+ }
+
+ void LoadModule() {
+ if (module_handle_)
+ return;
+ // This module should not be a static dependency of the unit-test
+ // executable, but should be a build-system dependency or a module that is
+ // present on any Windows machine.
+ static constexpr wchar_t kModuleName[] = L"conflicts_dll.dll";
+ // The module should not already be loaded.
+ ASSERT_FALSE(::GetModuleHandle(kModuleName));
+ // It should load successfully.
+ module_handle_ = ::LoadLibrary(kModuleName);
+ ASSERT_TRUE(module_handle_);
+ }
+
+ void UnloadModule() {
+ if (!module_handle_)
+ return;
+ ::FreeLibrary(module_handle_);
+ module_handle_ = nullptr;
+ }
+
+ // Runs the task scheduler until no tasks are running.
+ void RunUntilIdle() { task_environment_.RunUntilIdle(); }
+ void FastForwardByIdleDelay() {
+ task_environment_.FastForwardBy(RemoteModuleWatcher::kIdleDelay);
+ }
+
+ HMODULE module_handle() { return module_handle_; }
+
+ int module_event_count() { return module_event_count_; }
+
+ private:
+ // Must be first.
+ base::test::TaskEnvironment task_environment_{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+
+ // Binds a ModuleEventSinkRequest to this implementation of ModuleEventSink.
+ mojo::Receiver<mojom::ModuleEventSink> receiver_{this};
+
+ // Holds a handle to a loaded module.
+ HMODULE module_handle_ = nullptr;
+
+ // Total number of module events seen.
+ int module_event_count_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteModuleWatcherTest);
+};
+
+} // namespace
+
+TEST_F(RemoteModuleWatcherTest, ModuleEvents) {
+ auto remote_module_watcher =
+ RemoteModuleWatcher::Create(base::ThreadTaskRunnerHandle::Get(), Bind());
+
+ // Wait until the watcher is initialized and events for already loaded modules
+ // are received.
+ RunUntilIdle();
+ // Now wait for the timer used to batch events to expire.
+ FastForwardByIdleDelay();
+
+ EXPECT_GT(module_event_count(), 0);
+
+ // Dynamically load a module and ensure a notification is received for it.
+ int previous_module_event_count = module_event_count();
+ LoadModule();
+ FastForwardByIdleDelay();
+ EXPECT_GT(module_event_count(), previous_module_event_count);
+
+ UnloadModule();
+
+ // Destroy the module watcher.
+ remote_module_watcher = nullptr;
+ RunUntilIdle();
+
+ // Load the module and ensure no notification is received this time.
+ previous_module_event_count = module_event_count();
+ LoadModule();
+ FastForwardByIdleDelay();
+
+ EXPECT_EQ(module_event_count(), previous_module_event_count);
+
+ UnloadModule();
+}
diff --git a/chromium/chrome/common/crash_keys.cc b/chromium/chrome/common/crash_keys.cc
new file mode 100644
index 00000000000..4b9d1c36537
--- /dev/null
+++ b/chromium/chrome/common/crash_keys.cc
@@ -0,0 +1,118 @@
+// 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 "chrome/common/crash_keys.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.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"
+#include "build/build_config.h"
+#include "chrome/common/chrome_switches.h"
+#include "components/crash/core/common/crash_key.h"
+#include "components/crash/core/common/crash_keys.h"
+#include "components/flags_ui/flags_ui_switches.h"
+#include "content/public/common/content_switches.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/common/chrome_switches.h"
+#include "components/crash/content/app/crash_switches.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "ui/gl/gl_switches.h"
+#endif
+
+namespace crash_keys {
+
+// Return true if we DON'T want to upload this flag to the crash server.
+static bool IsBoringSwitch(const std::string& flag) {
+ static const char* const kIgnoreSwitches[] = {
+ switches::kEnableLogging,
+ switches::kFlagSwitchesBegin,
+ switches::kFlagSwitchesEnd,
+ switches::kLoggingLevel,
+ switches::kProcessType,
+ switches::kV,
+ switches::kVModule,
+#if defined(OS_MACOSX)
+ switches::kMetricsClientID,
+#elif defined(OS_CHROMEOS)
+ // --crash-loop-before is a "boring" switch because it is redundant;
+ // crash_reporter separately informs the crash server if it is doing
+ // crash-loop handling.
+ crash_reporter::switches::kCrashLoopBefore,
+ switches::kPpapiFlashArgs,
+ switches::kPpapiFlashPath,
+ switches::kRegisterPepperPlugins,
+ switches::kUseGL,
+ switches::kUserDataDir,
+ // Cros/CC flags are specified as raw strings to avoid dependency.
+ "child-wallpaper-large",
+ "child-wallpaper-small",
+ "default-wallpaper-large",
+ "default-wallpaper-small",
+ "guest-wallpaper-large",
+ "guest-wallpaper-small",
+ "enterprise-enable-forced-re-enrollment",
+ "enterprise-enrollment-initial-modulus",
+ "enterprise-enrollment-modulus-limit",
+ "login-profile",
+ "login-user",
+ "use-cras",
+#endif
+ };
+
+#if defined(OS_WIN)
+ // Just about everything has this, don't bother.
+ if (base::StartsWith(flag, "/prefetch:", base::CompareCase::SENSITIVE))
+ return true;
+#endif
+
+ if (!base::StartsWith(flag, "--", base::CompareCase::SENSITIVE))
+ return false;
+ size_t end = flag.find("=");
+ size_t len = (end == std::string::npos) ? flag.length() - 2 : end - 2;
+ for (size_t i = 0; i < base::size(kIgnoreSwitches); ++i) {
+ if (flag.compare(2, len, kIgnoreSwitches[i]) == 0)
+ return true;
+ }
+ return false;
+}
+
+void SetCrashKeysFromCommandLine(const base::CommandLine& command_line) {
+ return SetSwitchesFromCommandLine(command_line, &IsBoringSwitch);
+}
+
+void SetActiveExtensions(const std::set<std::string>& extensions) {
+ static crash_reporter::CrashKeyString<4> num_extensions("num-extensions");
+ num_extensions.Set(base::NumberToString(extensions.size()));
+
+ using ExtensionIDKey = crash_reporter::CrashKeyString<64>;
+ static ExtensionIDKey extension_ids[] = {
+ {"extension-1", ExtensionIDKey::Tag::kArray},
+ {"extension-2", ExtensionIDKey::Tag::kArray},
+ {"extension-3", ExtensionIDKey::Tag::kArray},
+ {"extension-4", ExtensionIDKey::Tag::kArray},
+ {"extension-5", ExtensionIDKey::Tag::kArray},
+ {"extension-6", ExtensionIDKey::Tag::kArray},
+ {"extension-7", ExtensionIDKey::Tag::kArray},
+ {"extension-8", ExtensionIDKey::Tag::kArray},
+ {"extension-9", ExtensionIDKey::Tag::kArray},
+ {"extension-10", ExtensionIDKey::Tag::kArray},
+ };
+
+ auto it = extensions.begin();
+ for (size_t i = 0; i < base::size(extension_ids); ++i) {
+ if (it == extensions.end()) {
+ extension_ids[i].Clear();
+ } else {
+ extension_ids[i].Set(*it);
+ ++it;
+ }
+ }
+}
+
+} // namespace crash_keys
diff --git a/chromium/chrome/common/crash_keys.h b/chromium/chrome/common/crash_keys.h
new file mode 100644
index 00000000000..bcf172e645a
--- /dev/null
+++ b/chromium/chrome/common/crash_keys.h
@@ -0,0 +1,34 @@
+// 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 CHROME_COMMON_CRASH_KEYS_H_
+#define CHROME_COMMON_CRASH_KEYS_H_
+
+#include <set>
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+class CommandLine;
+}
+
+namespace crash_keys {
+
+// Sets the kNumSwitches key and the set of keys named using kSwitchFormat based
+// on the given |command_line|.
+void SetCrashKeysFromCommandLine(const base::CommandLine& command_line);
+
+// Sets the list of "active" extensions in this process. We overload "active" to
+// mean different things depending on the process type:
+// - browser: all enabled extensions
+// - renderer: the unique set of extension ids from all content scripts
+// - extension: the id of each extension running in this process (there can be
+// multiple because of process collapsing).
+void SetActiveExtensions(const std::set<std::string>& extensions);
+
+} // namespace crash_keys
+
+#endif // CHROME_COMMON_CRASH_KEYS_H_
diff --git a/chromium/chrome/common/crash_keys_unittest.cc b/chromium/chrome/common/crash_keys_unittest.cc
new file mode 100644
index 00000000000..80b1781a84d
--- /dev/null
+++ b/chromium/chrome/common/crash_keys_unittest.cc
@@ -0,0 +1,111 @@
+// 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 "chrome/common/crash_keys.h"
+
+#include <set>
+#include <string>
+
+#include "base/command_line.h"
+#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
+#include "components/crash/core/common/crash_key.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using crash_reporter::GetCrashKeyValue;
+
+class CrashKeysTest : public testing::Test {
+ public:
+ void SetUp() override {
+ crash_reporter::ResetCrashKeysForTesting();
+ crash_reporter::InitializeCrashKeys();
+ }
+
+ void TearDown() override {
+ crash_reporter::ResetCrashKeysForTesting();
+ }
+};
+
+TEST_F(CrashKeysTest, Extensions) {
+ // Set three extensions.
+ {
+ std::set<std::string> extensions;
+ extensions.insert("ext.1");
+ extensions.insert("ext.2");
+ extensions.insert("ext.3");
+
+ crash_keys::SetActiveExtensions(extensions);
+
+ extensions.erase(GetCrashKeyValue("extension-1"));
+ extensions.erase(GetCrashKeyValue("extension-2"));
+ extensions.erase(GetCrashKeyValue("extension-3"));
+ EXPECT_EQ(0u, extensions.size());
+
+ EXPECT_EQ("3", GetCrashKeyValue("num-extensions"));
+ EXPECT_TRUE(GetCrashKeyValue("extension-4").empty());
+ }
+
+ // Set more than the max switches.
+ {
+ std::set<std::string> extensions;
+ const int kMax = 12;
+ for (int i = 1; i <= kMax; ++i)
+ extensions.insert(base::StringPrintf("ext.%d", i));
+ crash_keys::SetActiveExtensions(extensions);
+
+ for (int i = 1; i <= kMax; ++i) {
+ extensions.erase(GetCrashKeyValue(base::StringPrintf("extension-%d", i)));
+ }
+ EXPECT_EQ(2u, extensions.size());
+
+ EXPECT_EQ("12", GetCrashKeyValue("num-extensions"));
+ EXPECT_TRUE(GetCrashKeyValue("extension-13").empty());
+ EXPECT_TRUE(GetCrashKeyValue("extension-14").empty());
+ }
+
+ // Set fewer to ensure that old ones are erased.
+ {
+ std::set<std::string> extensions;
+ for (int i = 1; i <= 5; ++i)
+ extensions.insert(base::StringPrintf("ext.%d", i));
+ crash_keys::SetActiveExtensions(extensions);
+
+ extensions.erase(GetCrashKeyValue("extension-1"));
+ extensions.erase(GetCrashKeyValue("extension-2"));
+ extensions.erase(GetCrashKeyValue("extension-3"));
+ extensions.erase(GetCrashKeyValue("extension-4"));
+ extensions.erase(GetCrashKeyValue("extension-5"));
+ EXPECT_EQ(0u, extensions.size());
+
+ EXPECT_EQ("5", GetCrashKeyValue("num-extensions"));
+ for (int i = 6; i < 20; ++i) {
+ std::string key = base::StringPrintf("extension-%d", i);
+ EXPECT_TRUE(GetCrashKeyValue(key).empty()) << key;
+ }
+ }
+}
+
+TEST_F(CrashKeysTest, IgnoreBoringFlags) {
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ command_line.AppendSwitch("--enable-logging");
+ command_line.AppendSwitch("--v=1");
+
+ command_line.AppendSwitch("--vv=1");
+ command_line.AppendSwitch("--vvv");
+ command_line.AppendSwitch("--enable-multi-profiles");
+ command_line.AppendSwitch("--device-management-url=https://foo/bar");
+#if defined(OS_CHROMEOS)
+ command_line.AppendSwitch("--user-data-dir=/tmp");
+ command_line.AppendSwitch("--default-wallpaper-small=test.png");
+#endif
+
+ crash_keys::SetCrashKeysFromCommandLine(command_line);
+
+ EXPECT_EQ("--vv=1", GetCrashKeyValue("switch-1"));
+ EXPECT_EQ("--vvv", GetCrashKeyValue("switch-2"));
+ EXPECT_EQ("--enable-multi-profiles", GetCrashKeyValue("switch-3"));
+ EXPECT_EQ("--device-management-url=https://foo/bar",
+ GetCrashKeyValue("switch-4"));
+ EXPECT_TRUE(GetCrashKeyValue("switch-5").empty());
+}
diff --git a/chromium/chrome/common/env_vars.cc b/chromium/chrome/common/env_vars.cc
new file mode 100644
index 00000000000..f880adbab66
--- /dev/null
+++ b/chromium/chrome/common/env_vars.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 "chrome/common/env_vars.h"
+
+namespace env_vars {
+
+// We call running in unattended mode (for automated testing) "headless".
+// This mode can be enabled using this variable or by the kNoErrorDialogs
+// switch.
+const char kHeadless[] = "CHROME_HEADLESS";
+
+// The name of the log file.
+const char kLogFileName[] = "CHROME_LOG_FILE";
+
+// Flag indicating if metro viewer is connected to browser instance.
+// As of now there is only one metro viewer instance per browser.
+const char kMetroConnected[] = "CHROME_METRO_CONNECTED";
+
+// The name of the session log directory when logged in to ChromeOS.
+const char kSessionLogDir[] = "CHROMEOS_SESSION_LOG_DIR";
+
+// CHROME_CRASHED exists if a previous instance of chrome has crashed. This
+// triggers the 'restart chrome' dialog. CHROME_RESTART contains the strings
+// that are needed to show the dialog.
+const char kShowRestart[] = "CHROME_CRASHED";
+const char kRestartInfo[] = "CHROME_RESTART";
+
+// The strings RIGHT_TO_LEFT and LEFT_TO_RIGHT indicate the locale direction.
+// For example, for Hebrew and Arabic locales, we use RIGHT_TO_LEFT so that the
+// dialog is displayed using the right orientation.
+const char kRtlLocale[] = "RIGHT_TO_LEFT";
+const char kLtrLocale[] = "LEFT_TO_RIGHT";
+
+} // namespace env_vars
diff --git a/chromium/chrome/common/env_vars.h b/chromium/chrome/common/env_vars.h
new file mode 100644
index 00000000000..847335623de
--- /dev/null
+++ b/chromium/chrome/common/env_vars.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.
+
+// Defines all the environment variables used by Chrome.
+
+#ifndef CHROME_COMMON_ENV_VARS_H__
+#define CHROME_COMMON_ENV_VARS_H__
+
+namespace env_vars {
+
+extern const char kHeadless[];
+extern const char kLogFileName[];
+extern const char kMetroConnected[];
+extern const char kSessionLogDir[];
+extern const char kShowRestart[];
+extern const char kRestartInfo[];
+extern const char kRtlLocale[];
+extern const char kLtrLocale[];
+
+} // namespace env_vars
+
+#endif // CHROME_COMMON_ENV_VARS_H__
diff --git a/chromium/chrome/common/extensions/DEPS b/chromium/chrome/common/extensions/DEPS
new file mode 100644
index 00000000000..6a5a42e5aeb
--- /dev/null
+++ b/chromium/chrome/common/extensions/DEPS
@@ -0,0 +1,18 @@
+include_rules = [
+ "+ash/keyboard/ui/resources", # For virtual keyboard
+ "+components/policy/core/common",
+ "+extensions/grit",
+ "+extensions/strings/grit",
+ "+extensions/test",
+ "+ppapi/c", # For various types.
+ "+skia",
+]
+
+specific_include_rules = {
+ # The extensions client interface is the master arbiter of which
+ # API schemas exist, so it needs to know about app APIs.
+ "chrome_extensions_client\.cc": [
+ "+apps/common/api/generated_schemas.h",
+ "+services/network/public/mojom/cors_origin_pattern.mojom.h",
+ ],
+}
diff --git a/chromium/chrome/common/extensions/OWNERS b/chromium/chrome/common/extensions/OWNERS
new file mode 100644
index 00000000000..fe353c7aa3b
--- /dev/null
+++ b/chromium/chrome/common/extensions/OWNERS
@@ -0,0 +1,13 @@
+file://extensions/OWNERS
+
+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
+
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+
+# COMPONENT: Platform>Extensions
+# TEAM: chromium-extensions@chromium.org
diff --git a/chromium/chrome/common/extensions/PRESUBMIT.py b/chromium/chrome/common/extensions/PRESUBMIT.py
new file mode 100644
index 00000000000..1b0d113938c
--- /dev/null
+++ b/chromium/chrome/common/extensions/PRESUBMIT.py
@@ -0,0 +1,169 @@
+# 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.
+
+"""Presubmit script for changes affecting extensions.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+import fnmatch
+import os
+import re
+
+EXTENSIONS_PATH = os.path.join('chrome', 'common', 'extensions')
+DOCS_PATH = os.path.join(EXTENSIONS_PATH, 'docs')
+SERVER2_PATH = os.path.join(DOCS_PATH, 'server2')
+API_PATH = os.path.join(EXTENSIONS_PATH, 'api')
+TEMPLATES_PATH = os.path.join(DOCS_PATH, 'templates')
+PRIVATE_TEMPLATES_PATH = os.path.join(TEMPLATES_PATH, 'private')
+PUBLIC_TEMPLATES_PATH = os.path.join(TEMPLATES_PATH, 'public')
+INTROS_PATH = os.path.join(TEMPLATES_PATH, 'intros')
+ARTICLES_PATH = os.path.join(TEMPLATES_PATH, 'articles')
+
+LOCAL_PUBLIC_TEMPLATES_PATH = os.path.join('docs',
+ 'templates',
+ 'public')
+
+EXTENSIONS_TO_REMOVE_FOR_CLEAN_URLS = ('.md', '.html')
+
+def _ReadFile(filename):
+ with open(filename) as f:
+ return f.read()
+
+def _ListFilesInPublic():
+ all_files = []
+ for path, dirs, files in os.walk(LOCAL_PUBLIC_TEMPLATES_PATH):
+ all_files.extend(
+ os.path.join(path, filename)[len(LOCAL_PUBLIC_TEMPLATES_PATH + os.sep):]
+ for filename in files)
+ return all_files
+
+def _UnixName(name):
+ name = os.path.splitext(name)[0]
+ s1 = re.sub('([a-z])([A-Z])', r'\1_\2', name)
+ s2 = re.sub('([A-Z]+)([A-Z][a-z])', r'\1_\2', s1)
+ return s2.replace('.', '_').lower()
+
+def _FindMatchingTemplates(template_name, template_path_list):
+ matches = []
+ unix_name = _UnixName(template_name)
+ for template in template_path_list:
+ if unix_name == _UnixName(template.split(os.sep)[-1]):
+ basename, ext = os.path.splitext(template)
+ # The docserver expects clean (extensionless) template URLs, so we
+ # strip some extensions here when generating the list of matches.
+ if ext in EXTENSIONS_TO_REMOVE_FOR_CLEAN_URLS:
+ matches.append(basename)
+ else:
+ matches.append(template)
+ return matches
+
+def _SanitizeAPIName(name, api_path):
+ if not api_path.endswith(os.sep):
+ api_path += os.sep
+ filename = os.path.splitext(name)[0][len(api_path):].replace(os.sep, '_')
+ if 'experimental' in filename:
+ filename = 'experimental_' + filename.replace('experimental_', '')
+ return filename
+
+def _CreateIntegrationTestArgs(affected_files):
+ if (any(fnmatch.fnmatch(name, '%s*.py' % SERVER2_PATH)
+ for name in affected_files) or
+ any(fnmatch.fnmatch(name, '%s*' % PRIVATE_TEMPLATES_PATH)
+ for name in affected_files)):
+ return ['-a']
+ args = []
+ for name in affected_files:
+ if (fnmatch.fnmatch(name, '%s*' % PUBLIC_TEMPLATES_PATH) or
+ fnmatch.fnmatch(name, '%s*' % INTROS_PATH) or
+ fnmatch.fnmatch(name, '%s*' % ARTICLES_PATH)):
+ args.extend(_FindMatchingTemplates(name.split(os.sep)[-1],
+ _ListFilesInPublic()))
+ if fnmatch.fnmatch(name, '%s*' % API_PATH):
+ args.extend(_FindMatchingTemplates(_SanitizeAPIName(name, API_PATH),
+ _ListFilesInPublic()))
+ return args
+
+def _CheckHeadingIDs(input_api):
+ ids_re = re.compile('<h[23].*id=.*?>')
+ headings_re = re.compile('<h[23].*?>')
+ bad_files = []
+ for name in input_api.AbsoluteLocalPaths():
+ if not os.path.exists(name):
+ continue
+ if (fnmatch.fnmatch(name, '*%s*' % INTROS_PATH) or
+ fnmatch.fnmatch(name, '*%s*' % ARTICLES_PATH)):
+ contents = input_api.ReadFile(name)
+ if (len(re.findall(headings_re, contents)) !=
+ len(re.findall(ids_re, contents))):
+ bad_files.append(name)
+ return bad_files
+
+def _CheckLinks(input_api, output_api, results):
+ for affected_file in input_api.AffectedFiles():
+ name = affected_file.LocalPath()
+ absolute_path = affected_file.AbsoluteLocalPath()
+ if not os.path.exists(absolute_path):
+ continue
+ if (fnmatch.fnmatch(name, '%s*' % PUBLIC_TEMPLATES_PATH) or
+ fnmatch.fnmatch(name, '%s*' % INTROS_PATH) or
+ fnmatch.fnmatch(name, '%s*' % ARTICLES_PATH) or
+ fnmatch.fnmatch(name, '%s*' % API_PATH)):
+ contents = _ReadFile(absolute_path)
+ args = []
+ if input_api.platform == 'win32':
+ args = [input_api.python_executable]
+ args.extend([os.path.join('docs', 'server2', 'link_converter.py'),
+ '-o',
+ '-f',
+ absolute_path])
+ output = input_api.subprocess.check_output(
+ args,
+ cwd=input_api.PresubmitLocalPath(),
+ universal_newlines=True)
+ if output != contents:
+ changes = ''
+ for i, (line1, line2) in enumerate(
+ zip(contents.split('\n'), output.split('\n'))):
+ if line1 != line2:
+ changes = ('%s\nLine %d:\n-%s\n+%s\n' %
+ (changes, i + 1, line1, line2))
+ if changes:
+ results.append(output_api.PresubmitPromptWarning(
+ 'File %s may have an old-style <a> link to an API page. Please '
+ 'run docs/server2/link_converter.py to convert the link[s], or '
+ 'convert them manually.\n\nSuggested changes are: %s' %
+ (name, changes)))
+
+def _CheckChange(input_api, output_api):
+ results = [
+ output_api.PresubmitError('File %s needs an id for each heading.' % name)
+ for name in _CheckHeadingIDs(input_api)]
+ try:
+ integration_test = []
+ # From depot_tools/presubmit_canned_checks.py:529
+ if input_api.platform == 'win32':
+ integration_test = [input_api.python_executable]
+ integration_test.append(
+ os.path.join('docs', 'server2', 'integration_test.py'))
+ integration_test.extend(_CreateIntegrationTestArgs(input_api.LocalPaths()))
+ input_api.subprocess.check_call(integration_test,
+ cwd=input_api.PresubmitLocalPath())
+ except input_api.subprocess.CalledProcessError:
+ results.append(output_api.PresubmitError('IntegrationTest failed!'))
+
+ # TODO(kalman): Re-enable this check, or decide to delete it forever. Now
+ # that we have multiple directories it no longer works.
+ # See http://crbug.com/297178.
+ #_CheckLinks(input_api, output_api, results)
+
+ return results
+
+def CheckChangeOnUpload(input_api, output_api):
+ results = []
+ results += _CheckChange(input_api, output_api)
+ return results
+
+def CheckChangeOnCommit(input_api, output_api):
+ return _CheckChange(input_api, output_api)
diff --git a/chromium/chrome/common/extensions/PRESUBMIT_test.py b/chromium/chrome/common/extensions/PRESUBMIT_test.py
new file mode 100755
index 00000000000..7ac79b06820
--- /dev/null
+++ b/chromium/chrome/common/extensions/PRESUBMIT_test.py
@@ -0,0 +1,75 @@
+#!/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.
+
+import os
+import unittest
+
+import PRESUBMIT
+
+EXTENSIONS_PATH = os.path.join('chrome', 'common', 'extensions')
+DOCS_PATH = os.path.join(EXTENSIONS_PATH, 'docs')
+SERVER2_PATH = os.path.join(DOCS_PATH, 'server2')
+PUBLIC_PATH = os.path.join(DOCS_PATH, 'templates', 'public')
+PRIVATE_PATH = os.path.join(DOCS_PATH, 'templates', 'private')
+INTROS_PATH = os.path.join(DOCS_PATH, 'templates', 'intros')
+ARTICLES_PATH = os.path.join(DOCS_PATH, 'templates', 'articles')
+
+class PRESUBMITTest(unittest.TestCase):
+ def testCreateIntegrationTestArgs(self):
+ input_files = [
+ os.path.join(EXTENSIONS_PATH, 'test.cc'),
+ os.path.join(EXTENSIONS_PATH, 'test2.cc'),
+ os.path.join('test', 'test.py')
+ ]
+ expected_files = []
+ self.assertEqual(expected_files,
+ PRESUBMIT._CreateIntegrationTestArgs(input_files))
+ expected_files.append(os.path.join('apps', 'fileSystem.html'))
+ input_files.append(os.path.join(EXTENSIONS_PATH, 'api', 'file_system.idl'))
+ self.assertEqual(expected_files,
+ PRESUBMIT._CreateIntegrationTestArgs(input_files))
+ expected_files.append(os.path.join('extensions', 'alarms.html'))
+ expected_files.append(os.path.join('apps', 'alarms.html'))
+ input_files.append(os.path.join(EXTENSIONS_PATH, 'api', 'alarms.json'))
+ self.assertEqual(expected_files,
+ PRESUBMIT._CreateIntegrationTestArgs(input_files))
+ expected_files.append('extensions/devtools_network.html')
+ input_files.append(os.path.join(EXTENSIONS_PATH,
+ 'api',
+ 'devtools',
+ 'network.json'))
+ self.assertEqual(expected_files,
+ PRESUBMIT._CreateIntegrationTestArgs(input_files))
+ expected_files.append(os.path.join('extensions', 'docs.html'))
+ expected_files.append(os.path.join('apps', 'docs.html'))
+ input_files.append(os.path.join(PUBLIC_PATH, 'extensions', 'docs.html'))
+ self.assertEqual(expected_files,
+ PRESUBMIT._CreateIntegrationTestArgs(input_files))
+ expected_files.append(os.path.join('extensions', 'bookmarks.html'))
+ input_files.append(os.path.join(INTROS_PATH, 'bookmarks.html'))
+ self.assertEqual(expected_files,
+ PRESUBMIT._CreateIntegrationTestArgs(input_files))
+ expected_files.append(os.path.join('extensions', 'i18n.html'))
+ expected_files.append(os.path.join('apps', 'i18n.html'))
+ input_files.append(os.path.join(INTROS_PATH, 'i18n.html'))
+ self.assertEqual(expected_files,
+ PRESUBMIT._CreateIntegrationTestArgs(input_files))
+ expected_files.append(os.path.join('apps', 'about_apps.html'))
+ input_files.append(os.path.join(ARTICLES_PATH, 'about_apps.html'))
+ self.assertEqual(expected_files,
+ PRESUBMIT._CreateIntegrationTestArgs(input_files))
+ input_files.append(os.path.join(PRIVATE_PATH, 'type.html'))
+ self.assertEqual([ '-a' ],
+ PRESUBMIT._CreateIntegrationTestArgs(input_files))
+ input_files.pop()
+ input_files.append(os.path.join(SERVER2_PATH, 'test.txt'))
+ self.assertEqual(expected_files,
+ PRESUBMIT._CreateIntegrationTestArgs(input_files))
+ input_files.append(os.path.join(SERVER2_PATH, 'handler.py'))
+ self.assertEqual([ '-a' ],
+ PRESUBMIT._CreateIntegrationTestArgs(input_files))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/chromium/chrome/common/extensions/chrome_extensions_api_provider.cc b/chromium/chrome/common/extensions/chrome_extensions_api_provider.cc
new file mode 100644
index 00000000000..17c0c89d83d
--- /dev/null
+++ b/chromium/chrome/common/extensions/chrome_extensions_api_provider.cc
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/chrome_extensions_api_provider.h"
+
+#include "chrome/common/extensions/api/api_features.h"
+#include "chrome/common/extensions/api/generated_schemas.h"
+#include "chrome/common/extensions/api/manifest_features.h"
+#include "chrome/common/extensions/api/permission_features.h"
+#include "chrome/common/extensions/chrome_manifest_handlers.h"
+#include "chrome/common/extensions/permissions/chrome_api_permissions.h"
+#include "chrome/grit/common_resources.h"
+#include "extensions/common/features/json_feature_provider_source.h"
+#include "extensions/common/permissions/permissions_info.h"
+
+namespace extensions {
+
+ChromeExtensionsAPIProvider::ChromeExtensionsAPIProvider() {}
+ChromeExtensionsAPIProvider::~ChromeExtensionsAPIProvider() = default;
+
+void ChromeExtensionsAPIProvider::AddAPIFeatures(FeatureProvider* provider) {
+ AddChromeAPIFeatures(provider);
+}
+
+void ChromeExtensionsAPIProvider::AddManifestFeatures(
+ FeatureProvider* provider) {
+ AddChromeManifestFeatures(provider);
+}
+
+void ChromeExtensionsAPIProvider::AddPermissionFeatures(
+ FeatureProvider* provider) {
+ AddChromePermissionFeatures(provider);
+}
+
+void ChromeExtensionsAPIProvider::AddBehaviorFeatures(
+ FeatureProvider* provider) {
+ // Note: No chrome-specific behavior features.
+}
+
+void ChromeExtensionsAPIProvider::AddAPIJSONSources(
+ JSONFeatureProviderSource* json_source) {
+ json_source->LoadJSON(IDR_CHROME_EXTENSION_API_FEATURES);
+}
+
+bool ChromeExtensionsAPIProvider::IsAPISchemaGenerated(
+ const std::string& name) {
+ return api::ChromeGeneratedSchemas::IsGenerated(name);
+}
+
+base::StringPiece ChromeExtensionsAPIProvider::GetAPISchema(
+ const std::string& name) {
+ return api::ChromeGeneratedSchemas::Get(name);
+}
+
+void ChromeExtensionsAPIProvider::RegisterPermissions(
+ PermissionsInfo* permissions_info) {
+ permissions_info->RegisterPermissions(
+ chrome_api_permissions::GetPermissionInfos(),
+ chrome_api_permissions::GetPermissionAliases());
+}
+
+void ChromeExtensionsAPIProvider::RegisterManifestHandlers() {
+ RegisterChromeManifestHandlers();
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/chrome_extensions_api_provider.h b/chromium/chrome/common/extensions/chrome_extensions_api_provider.h
new file mode 100644
index 00000000000..e3595d5536e
--- /dev/null
+++ b/chromium/chrome/common/extensions/chrome_extensions_api_provider.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_CHROME_EXTENSIONS_API_PROVIDER_H_
+#define CHROME_COMMON_EXTENSIONS_CHROME_EXTENSIONS_API_PROVIDER_H_
+
+#include "base/macros.h"
+#include "extensions/common/extensions_api_provider.h"
+
+namespace extensions {
+
+class ChromeExtensionsAPIProvider : public ExtensionsAPIProvider {
+ public:
+ ChromeExtensionsAPIProvider();
+ ~ChromeExtensionsAPIProvider() override;
+
+ // ExtensionsAPIProvider:
+ void AddAPIFeatures(FeatureProvider* provider) override;
+ void AddManifestFeatures(FeatureProvider* provider) override;
+ void AddPermissionFeatures(FeatureProvider* provider) override;
+ void AddBehaviorFeatures(FeatureProvider* provider) override;
+ void AddAPIJSONSources(JSONFeatureProviderSource* json_source) override;
+ bool IsAPISchemaGenerated(const std::string& name) override;
+ base::StringPiece GetAPISchema(const std::string& name) override;
+ void RegisterPermissions(PermissionsInfo* permissions_info) override;
+ void RegisterManifestHandlers() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ChromeExtensionsAPIProvider);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_CHROME_EXTENSIONS_API_PROVIDER_H_
diff --git a/chromium/chrome/common/extensions/chrome_extensions_client.cc b/chromium/chrome/common/extensions/chrome_extensions_client.cc
new file mode 100644
index 00000000000..a57d93fed58
--- /dev/null
+++ b/chromium/chrome/common/extensions/chrome_extensions_client.cc
@@ -0,0 +1,257 @@
+// 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 "chrome/common/extensions/chrome_extensions_client.h"
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/api/extension_action/action_info.h"
+#include "chrome/common/extensions/chrome_extensions_api_provider.h"
+#include "chrome/common/extensions/manifest_handlers/theme_handler.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/common/webui_url_constants.h"
+#include "chrome/grit/chromium_strings.h"
+#include "components/version_info/version_info.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/core_extensions_api_provider.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_api.h"
+#include "extensions/common/extension_icon_set.h"
+#include "extensions/common/extension_urls.h"
+#include "extensions/common/features/feature_channel.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/icons_handler.h"
+#include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/common/url_pattern.h"
+#include "extensions/common/url_pattern_set.h"
+#include "services/network/public/mojom/cors_origin_pattern.mojom.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+namespace {
+
+// TODO(battre): Delete the HTTP URL once the blacklist is downloaded via HTTPS.
+const char kExtensionBlocklistUrlPrefix[] =
+ "http://www.gstatic.com/chrome/extensions/blacklist";
+const char kExtensionBlocklistHttpsUrlPrefix[] =
+ "https://www.gstatic.com/chrome/extensions/blacklist";
+
+const char kThumbsWhiteListedExtension[] = "khopmbdjffemhegeeobelklnbglcdgfh";
+
+} // namespace
+
+ChromeExtensionsClient::ChromeExtensionsClient() {
+ AddAPIProvider(std::make_unique<ChromeExtensionsAPIProvider>());
+ AddAPIProvider(std::make_unique<CoreExtensionsAPIProvider>());
+}
+
+ChromeExtensionsClient::~ChromeExtensionsClient() {
+}
+
+void ChromeExtensionsClient::Initialize() {
+ // Set up the scripting whitelist.
+ // Whitelist ChromeVox, an accessibility extension from Google that needs
+ // the ability to script webui pages. This is temporary and is not
+ // meant to be a general solution.
+ // TODO(dmazzoni): remove this once we have an extension API that
+ // allows any extension to request read-only access to webui pages.
+ scripting_whitelist_.push_back(extension_misc::kChromeVoxExtensionId);
+ InitializeWebStoreUrls(base::CommandLine::ForCurrentProcess());
+}
+
+void ChromeExtensionsClient::InitializeWebStoreUrls(
+ base::CommandLine* command_line) {
+ if (command_line->HasSwitch(switches::kAppsGalleryURL)) {
+ webstore_base_url_ =
+ GURL(command_line->GetSwitchValueASCII(switches::kAppsGalleryURL));
+ } else {
+ webstore_base_url_ = GURL(extension_urls::kChromeWebstoreBaseURL);
+ }
+ if (command_line->HasSwitch(switches::kAppsGalleryUpdateURL)) {
+ webstore_update_url_ = GURL(
+ command_line->GetSwitchValueASCII(switches::kAppsGalleryUpdateURL));
+ } else {
+ webstore_update_url_ = GURL(extension_urls::GetDefaultWebstoreUpdateUrl());
+ }
+}
+
+const PermissionMessageProvider&
+ChromeExtensionsClient::GetPermissionMessageProvider() const {
+ return permission_message_provider_;
+}
+
+const std::string ChromeExtensionsClient::GetProductName() {
+ return l10n_util::GetStringUTF8(IDS_PRODUCT_NAME);
+}
+
+void ChromeExtensionsClient::FilterHostPermissions(
+ const URLPatternSet& hosts,
+ URLPatternSet* new_hosts,
+ PermissionIDSet* permissions) const {
+ // When editing this function, be sure to add the same functionality to
+ // FilterHostPermissions() above.
+ for (auto i = hosts.begin(); i != hosts.end(); ++i) {
+ // Filters out every URL pattern that matches chrome:// scheme.
+ if (i->scheme() == content::kChromeUIScheme) {
+ // chrome://favicon is the only URL for chrome:// scheme that we
+ // want to support. We want to deprecate the "chrome" scheme.
+ // We should not add any additional "host" here.
+ if (GURL(chrome::kChromeUIFaviconURL).host() != i->host())
+ continue;
+ permissions->insert(APIPermission::kFavicon);
+ } else {
+ new_hosts->AddPattern(*i);
+ }
+ }
+}
+
+void ChromeExtensionsClient::SetScriptingWhitelist(
+ const ExtensionsClient::ScriptingWhitelist& whitelist) {
+ scripting_whitelist_ = whitelist;
+}
+
+const ExtensionsClient::ScriptingWhitelist&
+ChromeExtensionsClient::GetScriptingWhitelist() const {
+ return scripting_whitelist_;
+}
+
+URLPatternSet ChromeExtensionsClient::GetPermittedChromeSchemeHosts(
+ const Extension* extension,
+ const APIPermissionSet& api_permissions) const {
+ URLPatternSet hosts;
+ // Regular extensions are only allowed access to chrome://favicon.
+ hosts.AddPattern(URLPattern(URLPattern::SCHEME_CHROMEUI,
+ chrome::kChromeUIFaviconURL));
+
+ // Experimental extensions are also allowed chrome://thumb.
+ //
+ // TODO: A public API should be created for retrieving thumbnails.
+ // See http://crbug.com/222856. A temporary hack is implemented here to
+ // make chrome://thumbs available to NTP Russia extension as
+ // non-experimental.
+ if ((api_permissions.find(APIPermission::kExperimental) !=
+ api_permissions.end()) ||
+ (extension->id() == kThumbsWhiteListedExtension &&
+ extension->from_webstore())) {
+ hosts.AddPattern(URLPattern(URLPattern::SCHEME_CHROMEUI,
+ chrome::kChromeUIThumbnailURL));
+ }
+ return hosts;
+}
+
+bool ChromeExtensionsClient::IsScriptableURL(
+ const GURL& url, std::string* error) const {
+ // The gallery is special-cased as a restricted URL for scripting to prevent
+ // access to special JS bindings we expose to the gallery (and avoid things
+ // like extensions removing the "report abuse" link).
+ // TODO(erikkay): This seems like the wrong test. Shouldn't we we testing
+ // against the store app extent?
+ GURL store_url(extension_urls::GetWebstoreLaunchURL());
+ if (url.DomainIs(store_url.host())) {
+ if (error)
+ *error = manifest_errors::kCannotScriptGallery;
+ return false;
+ }
+ return true;
+}
+
+const GURL& ChromeExtensionsClient::GetWebstoreBaseURL() const {
+ return webstore_base_url_;
+}
+
+const GURL& ChromeExtensionsClient::GetWebstoreUpdateURL() const {
+ return webstore_update_url_;
+}
+
+bool ChromeExtensionsClient::IsBlacklistUpdateURL(const GURL& url) const {
+ // The extension blacklist URL is returned from the update service and
+ // therefore not determined by Chromium. If the location of the blacklist file
+ // ever changes, we need to update this function. A DCHECK in the
+ // ExtensionUpdater ensures that we notice a change. This is the full URL
+ // of a blacklist:
+ // http://www.gstatic.com/chrome/extensions/blacklist/l_0_0_0_7.txt
+ return base::StartsWith(url.spec(), kExtensionBlocklistUrlPrefix,
+ base::CompareCase::SENSITIVE) ||
+ base::StartsWith(url.spec(), kExtensionBlocklistHttpsUrlPrefix,
+ base::CompareCase::SENSITIVE);
+}
+
+std::set<base::FilePath> ChromeExtensionsClient::GetBrowserImagePaths(
+ const Extension* extension) {
+ std::set<base::FilePath> image_paths =
+ ExtensionsClient::GetBrowserImagePaths(extension);
+
+ // Theme images
+ const base::DictionaryValue* theme_images = ThemeInfo::GetImages(extension);
+ if (theme_images) {
+ for (base::DictionaryValue::Iterator it(*theme_images); !it.IsAtEnd();
+ it.Advance()) {
+ base::FilePath::StringType path;
+ if (it.value().GetAsString(&path))
+ image_paths.insert(base::FilePath(path));
+ }
+ }
+
+ const ActionInfo* action = ActionInfo::GetAnyActionInfo(extension);
+ if (action && !action->default_icon.empty())
+ action->default_icon.GetPaths(&image_paths);
+
+ return image_paths;
+}
+
+bool ChromeExtensionsClient::ExtensionAPIEnabledInExtensionServiceWorkers()
+ const {
+ return GetCurrentChannel() <=
+ extension_misc::kMinChannelForServiceWorkerBasedExtension;
+}
+
+void ChromeExtensionsClient::AddOriginAccessPermissions(
+ const Extension& extension,
+ bool is_extension_active,
+ std::vector<network::mojom::CorsOriginPatternPtr>* origin_patterns) const {
+ // Allow component extensions to access chrome://theme/.
+ //
+ // We don't want to grant these permissions to inactive component extensions,
+ // to avoid granting them in "unblessed" (non-extension) processes. If a
+ // component extension somehow starts as inactive and becomes active later,
+ // we'll re-init the origin permissions, so there's no danger in being
+ // conservative. Components shouldn't be subject to enterprise policy controls
+ // or blocking access to the webstore so they get the highest priority
+ // allowlist entry.
+ if (extensions::Manifest::IsComponentLocation(extension.location()) &&
+ is_extension_active) {
+ origin_patterns->push_back(network::mojom::CorsOriginPattern::New(
+ content::kChromeUIScheme, chrome::kChromeUIThemeHost, /*port=*/0,
+ network::mojom::CorsDomainMatchMode::kDisallowSubdomains,
+ network::mojom::CorsPortMatchMode::kAllowAnyPort,
+ network::mojom::CorsOriginAccessMatchPriority::kMaxPriority));
+ }
+
+ // TODO(jstritar): We should try to remove this special case. Also, these
+ // whitelist entries need to be updated when the kManagement permission
+ // changes.
+ if (is_extension_active && extension.permissions_data()->HasAPIPermission(
+ extensions::APIPermission::kManagement)) {
+ origin_patterns->push_back(network::mojom::CorsOriginPattern::New(
+ content::kChromeUIScheme, chrome::kChromeUIExtensionIconHost,
+ /*port=*/0, network::mojom::CorsDomainMatchMode::kDisallowSubdomains,
+ network::mojom::CorsPortMatchMode::kAllowAnyPort,
+ network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority));
+ }
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/chrome_extensions_client.h b/chromium/chrome/common/extensions/chrome_extensions_client.h
new file mode 100644
index 00000000000..737c9708922
--- /dev/null
+++ b/chromium/chrome/common/extensions/chrome_extensions_client.h
@@ -0,0 +1,70 @@
+// 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 CHROME_COMMON_EXTENSIONS_CHROME_EXTENSIONS_CLIENT_H_
+#define CHROME_COMMON_EXTENSIONS_CHROME_EXTENSIONS_CLIENT_H_
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
+#include "extensions/common/extensions_client.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+// The implementation of ExtensionsClient for Chrome, which encapsulates the
+// global knowledge of features, permissions, and manifest fields.
+class ChromeExtensionsClient : public ExtensionsClient {
+ public:
+ ChromeExtensionsClient();
+ ~ChromeExtensionsClient() override;
+
+ void Initialize() override;
+
+ void InitializeWebStoreUrls(base::CommandLine* command_line) override;
+
+ const PermissionMessageProvider& GetPermissionMessageProvider()
+ const override;
+ const std::string GetProductName() override;
+ void FilterHostPermissions(const URLPatternSet& hosts,
+ URLPatternSet* new_hosts,
+ PermissionIDSet* permissions) const override;
+ void SetScriptingWhitelist(const ScriptingWhitelist& whitelist) override;
+ const ScriptingWhitelist& GetScriptingWhitelist() const override;
+ URLPatternSet GetPermittedChromeSchemeHosts(
+ const Extension* extension,
+ const APIPermissionSet& api_permissions) const override;
+ bool IsScriptableURL(const GURL& url, std::string* error) const override;
+ const GURL& GetWebstoreBaseURL() const override;
+ const GURL& GetWebstoreUpdateURL() const override;
+ bool IsBlacklistUpdateURL(const GURL& url) const override;
+ std::set<base::FilePath> GetBrowserImagePaths(
+ const Extension* extension) override;
+ bool ExtensionAPIEnabledInExtensionServiceWorkers() const override;
+ void AddOriginAccessPermissions(
+ const Extension& extension,
+ bool is_extension_active,
+ std::vector<network::mojom::CorsOriginPatternPtr>* origin_patterns)
+ const override;
+
+ private:
+ const ChromePermissionMessageProvider permission_message_provider_;
+
+ // A whitelist of extensions that can script anywhere. Do not add to this
+ // list (except in tests) without consulting the Extensions team first.
+ // Note: Component extensions have this right implicitly and do not need to be
+ // added to this list.
+ ScriptingWhitelist scripting_whitelist_;
+
+ GURL webstore_base_url_;
+ GURL webstore_update_url_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeExtensionsClient);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_CHROME_EXTENSIONS_CLIENT_H_
diff --git a/chromium/chrome/common/extensions/chrome_extensions_client_unittest.cc b/chromium/chrome/common/extensions/chrome_extensions_client_unittest.cc
new file mode 100644
index 00000000000..5f5c47e710b
--- /dev/null
+++ b/chromium/chrome/common/extensions/chrome_extensions_client_unittest.cc
@@ -0,0 +1,93 @@
+// 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 "chrome/common/extensions/chrome_extensions_client.h"
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/path_service.h"
+#include "chrome/common/chrome_paths.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/file_util.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_handler.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+class ChromeExtensionsClientTest : public testing::Test {
+ public:
+ void SetUp() override {
+ extensions_client_.reset(new ChromeExtensionsClient());
+ ExtensionsClient::Set(extensions_client_.get());
+ }
+
+ private:
+ std::unique_ptr<ChromeExtensionsClient> extensions_client_;
+};
+
+// Test that a browser action extension returns a path to an icon.
+TEST_F(ChromeExtensionsClientTest, GetBrowserImagePaths) {
+ base::FilePath install_dir;
+ ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+ install_dir = install_dir.AppendASCII("extensions")
+ .AppendASCII("api_test")
+ .AppendASCII("browser_action")
+ .AppendASCII("basics");
+
+ std::string error;
+ scoped_refptr<Extension> extension(file_util::LoadExtension(
+ install_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error));
+ ASSERT_TRUE(extension.get());
+
+ // The extension contains one icon.
+ std::set<base::FilePath> paths =
+ ExtensionsClient::Get()->GetBrowserImagePaths(extension.get());
+ ASSERT_EQ(1u, paths.size());
+ EXPECT_EQ("icon.png", paths.begin()->BaseName().AsUTF8Unsafe());
+}
+
+// Test that extensions with zero-length action icons will not load.
+TEST_F(ChromeExtensionsClientTest, CheckZeroLengthActionIconFiles) {
+ base::FilePath install_dir;
+ ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+
+ // Try to install an extension with a zero-length browser action icon file.
+ base::FilePath ext_dir = install_dir.AppendASCII("extensions")
+ .AppendASCII("bad")
+ .AppendASCII("Extensions")
+ .AppendASCII("gggggggggggggggggggggggggggggggg");
+
+ std::string error;
+ scoped_refptr<Extension> extension2(file_util::LoadExtension(
+ ext_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error));
+ EXPECT_FALSE(extension2.get());
+ EXPECT_STREQ("Could not load icon 'icon.png' for browser action.",
+ error.c_str());
+
+ // Try to install an extension with a zero-length page action icon file.
+ ext_dir = install_dir.AppendASCII("extensions")
+ .AppendASCII("bad")
+ .AppendASCII("Extensions")
+ .AppendASCII("hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh");
+
+ scoped_refptr<Extension> extension3(file_util::LoadExtension(
+ ext_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error));
+ EXPECT_FALSE(extension3.get());
+ EXPECT_STREQ("Could not load icon 'icon.png' for page action.",
+ error.c_str());
+}
+
+// Test that the ManifestHandlerRegistry handler map hasn't overflowed.
+// If this test fails, increase ManifestHandlerRegistry::kHandlerMax.
+TEST_F(ChromeExtensionsClientTest, CheckManifestHandlerRegistryForOverflow) {
+ ManifestHandlerRegistry* registry = ManifestHandlerRegistry::Get();
+ ASSERT_TRUE(registry);
+ ASSERT_LT(0u, registry->handlers_.size());
+ EXPECT_LE(registry->handlers_.size(), ManifestHandlerRegistry::kHandlerMax);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/chrome_manifest_handlers.cc b/chromium/chrome/common/extensions/chrome_manifest_handlers.cc
new file mode 100644
index 00000000000..89b30325e30
--- /dev/null
+++ b/chromium/chrome/common/extensions/chrome_manifest_handlers.cc
@@ -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.
+
+#include "chrome/common/extensions/chrome_manifest_handlers.h"
+
+#include <memory>
+
+#include "build/build_config.h"
+#include "chrome/common/extensions/api/commands/commands_handler.h"
+#include "chrome/common/extensions/api/omnibox/omnibox_handler.h"
+#include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h"
+#include "chrome/common/extensions/api/spellcheck/spellcheck_handler.h"
+#include "chrome/common/extensions/api/storage/storage_schema_manifest_handler.h"
+#include "chrome/common/extensions/api/system_indicator/system_indicator_handler.h"
+#include "chrome/common/extensions/api/url_handlers/url_handlers_parser.h"
+#include "chrome/common/extensions/chrome_manifest_url_handlers.h"
+#include "chrome/common/extensions/manifest_handlers/app_icon_color_info.h"
+#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
+#include "chrome/common/extensions/manifest_handlers/app_theme_color_info.h"
+#include "chrome/common/extensions/manifest_handlers/extension_action_handler.h"
+#include "chrome/common/extensions/manifest_handlers/linked_app_icons.h"
+#include "chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.h"
+#include "chrome/common/extensions/manifest_handlers/natively_connectable_handler.h"
+#include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
+#include "chrome/common/extensions/manifest_handlers/theme_handler.h"
+#include "chrome/common/extensions/manifest_handlers/ui_overrides_handler.h"
+#include "extensions/common/manifest_handlers/app_isolation_info.h"
+#include "extensions/common/manifest_handlers/automation.h"
+#include "extensions/common/manifest_handlers/options_page_info.h"
+#include "extensions/common/manifest_url_handlers.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h"
+#include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
+#include "chrome/common/extensions/api/input_ime/input_components_handler.h"
+#endif
+
+namespace extensions {
+
+void RegisterChromeManifestHandlers() {
+ // TODO(devlin): Pass in |registry| rather than Get()ing it.
+ ManifestHandlerRegistry* registry = ManifestHandlerRegistry::Get();
+
+ DCHECK(!ManifestHandler::IsRegistrationFinalized());
+
+ registry->RegisterHandler(std::make_unique<AboutPageHandler>());
+ registry->RegisterHandler(std::make_unique<AppIconColorHandler>());
+ registry->RegisterHandler(std::make_unique<AppThemeColorHandler>());
+ registry->RegisterHandler(std::make_unique<AppIsolationHandler>());
+ registry->RegisterHandler(std::make_unique<AppLaunchManifestHandler>());
+ registry->RegisterHandler(std::make_unique<AutomationHandler>());
+ registry->RegisterHandler(std::make_unique<CommandsHandler>());
+ registry->RegisterHandler(std::make_unique<DevToolsPageHandler>());
+ registry->RegisterHandler(std::make_unique<ExtensionActionHandler>());
+ registry->RegisterHandler(std::make_unique<HomepageURLHandler>());
+ registry->RegisterHandler(std::make_unique<LinkedAppIconsHandler>());
+ registry->RegisterHandler(std::make_unique<MinimumChromeVersionChecker>());
+ registry->RegisterHandler(std::make_unique<NativelyConnectableHandler>());
+ registry->RegisterHandler(std::make_unique<OmniboxHandler>());
+ registry->RegisterHandler(std::make_unique<OptionsPageManifestHandler>());
+ registry->RegisterHandler(std::make_unique<SettingsOverridesHandler>());
+ registry->RegisterHandler(std::make_unique<SpellcheckHandler>());
+ registry->RegisterHandler(std::make_unique<StorageSchemaManifestHandler>());
+ registry->RegisterHandler(std::make_unique<SystemIndicatorHandler>());
+ registry->RegisterHandler(std::make_unique<ThemeHandler>());
+ registry->RegisterHandler(std::make_unique<TtsEngineManifestHandler>());
+ registry->RegisterHandler(std::make_unique<UIOverridesHandler>());
+ registry->RegisterHandler(std::make_unique<UrlHandlersParser>());
+ registry->RegisterHandler(std::make_unique<URLOverridesHandler>());
+#if defined(OS_CHROMEOS)
+ registry->RegisterHandler(std::make_unique<FileBrowserHandlerParser>());
+ registry->RegisterHandler(
+ std::make_unique<FileSystemProviderCapabilitiesHandler>());
+ registry->RegisterHandler(std::make_unique<InputComponentsHandler>());
+#endif
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/chrome_manifest_handlers.h b/chromium/chrome/common/extensions/chrome_manifest_handlers.h
new file mode 100644
index 00000000000..03d9a5fbb71
--- /dev/null
+++ b/chromium/chrome/common/extensions/chrome_manifest_handlers.h
@@ -0,0 +1,16 @@
+// 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 CHROME_COMMON_EXTENSIONS_CHROME_MANIFEST_HANDLERS_H_
+#define CHROME_COMMON_EXTENSIONS_CHROME_MANIFEST_HANDLERS_H_
+
+namespace extensions {
+
+// Registers all manifest handlers used in Chrome. Should be called
+// once in each process. See also extensions/common/common_manifest_handlers.h.
+void RegisterChromeManifestHandlers();
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_CHROME_MANIFEST_HANDLERS_H_
diff --git a/chromium/chrome/common/extensions/chrome_manifest_url_handlers.cc b/chromium/chrome/common/extensions/chrome_manifest_url_handlers.cc
new file mode 100644
index 00000000000..00126be870a
--- /dev/null
+++ b/chromium/chrome/common/extensions/chrome_manifest_url_handlers.cc
@@ -0,0 +1,187 @@
+// 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 "chrome/common/extensions/chrome_manifest_url_handlers.h"
+
+#include <memory>
+
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/url_constants.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/file_util.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/permissions_parser.h"
+#include "extensions/common/manifest_handlers/shared_module_info.h"
+#include "extensions/common/manifest_url_handlers.h"
+#include "extensions/common/permissions/api_permission.h"
+
+#if defined(OS_CHROMEOS)
+#include "ash/keyboard/ui/resources/keyboard_resource_util.h"
+#endif
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+namespace {
+
+const char kOverrideExtentUrlPatternFormat[] = "chrome://%s/*";
+
+} // namespace
+
+namespace chrome_manifest_urls {
+const GURL& GetDevToolsPage(const Extension* extension) {
+ return ManifestURL::Get(extension, keys::kDevToolsPage);
+}
+}
+
+URLOverrides::URLOverrides() {
+}
+
+URLOverrides::~URLOverrides() {
+}
+
+static base::LazyInstance<URLOverrides::URLOverrideMap>::DestructorAtExit
+ g_empty_url_overrides = LAZY_INSTANCE_INITIALIZER;
+
+// static
+const URLOverrides::URLOverrideMap& URLOverrides::GetChromeURLOverrides(
+ const Extension* extension) {
+ URLOverrides* url_overrides = static_cast<URLOverrides*>(
+ extension->GetManifestData(keys::kChromeURLOverrides));
+ return url_overrides ? url_overrides->chrome_url_overrides_
+ : g_empty_url_overrides.Get();
+}
+
+DevToolsPageHandler::DevToolsPageHandler() {
+}
+
+DevToolsPageHandler::~DevToolsPageHandler() {
+}
+
+bool DevToolsPageHandler::Parse(Extension* extension, base::string16* error) {
+ std::unique_ptr<ManifestURL> manifest_url(new ManifestURL);
+ std::string devtools_str;
+ if (!extension->manifest()->GetString(keys::kDevToolsPage, &devtools_str)) {
+ *error = base::ASCIIToUTF16(errors::kInvalidDevToolsPage);
+ return false;
+ }
+ manifest_url->url_ = extension->GetResourceURL(devtools_str);
+ extension->SetManifestData(keys::kDevToolsPage, std::move(manifest_url));
+ PermissionsParser::AddAPIPermission(extension, APIPermission::kDevtools);
+ return true;
+}
+
+base::span<const char* const> DevToolsPageHandler::Keys() const {
+ static constexpr const char* kKeys[] = {keys::kDevToolsPage};
+ return kKeys;
+}
+
+URLOverridesHandler::URLOverridesHandler() {
+}
+
+URLOverridesHandler::~URLOverridesHandler() {
+}
+
+bool URLOverridesHandler::Parse(Extension* extension, base::string16* error) {
+ const base::DictionaryValue* overrides = NULL;
+ if (!extension->manifest()->GetDictionary(keys::kChromeURLOverrides,
+ &overrides)) {
+ *error = base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
+ return false;
+ }
+ std::unique_ptr<URLOverrides> url_overrides(new URLOverrides);
+ // Validate that the overrides are all strings
+ for (base::DictionaryValue::Iterator iter(*overrides); !iter.IsAtEnd();
+ iter.Advance()) {
+ const std::string& page = iter.key();
+ std::string val;
+ // Restrict override pages to a list of supported URLs.
+ bool is_allowed_host = page == chrome::kChromeUINewTabHost ||
+ page == chrome::kChromeUIBookmarksHost ||
+ page == chrome::kChromeUIHistoryHost;
+#if defined(OS_CHROMEOS)
+ is_allowed_host = is_allowed_host ||
+ page == chrome::kChromeUIActivationMessageHost ||
+ page == keyboard::kKeyboardHost;
+#endif
+
+ if (!is_allowed_host || !iter.value().GetAsString(&val)) {
+ *error = base::ASCIIToUTF16(errors::kInvalidChromeURLOverrides);
+ return false;
+ }
+ // Replace the entry with a fully qualified chrome-extension:// URL.
+ url_overrides->chrome_url_overrides_[page] = extension->GetResourceURL(val);
+
+ // For component extensions, add override URL to extent patterns.
+ if (extension->is_legacy_packaged_app() &&
+ extension->location() == Manifest::COMPONENT) {
+ URLPattern pattern(URLPattern::SCHEME_CHROMEUI);
+ std::string url =
+ base::StringPrintf(kOverrideExtentUrlPatternFormat, page.c_str());
+ if (pattern.Parse(url) != URLPattern::ParseResult::kSuccess) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidURLPatternError, url);
+ return false;
+ }
+ extension->AddWebExtentPattern(pattern);
+ }
+ }
+
+ // An extension may override at most one page.
+ if (overrides->size() > 1) {
+ *error = base::ASCIIToUTF16(errors::kMultipleOverrides);
+ return false;
+ }
+
+ // If this is an NTP override extension, add the NTP override permission.
+ if (url_overrides->chrome_url_overrides_.count(chrome::kChromeUINewTabHost)) {
+ PermissionsParser::AddAPIPermission(extension,
+ APIPermission::kNewTabPageOverride);
+ }
+
+ extension->SetManifestData(keys::kChromeURLOverrides,
+ std::move(url_overrides));
+
+ return true;
+}
+
+bool URLOverridesHandler::Validate(
+ const Extension* extension,
+ std::string* error,
+ std::vector<InstallWarning>* warnings) const {
+ const URLOverrides::URLOverrideMap& overrides =
+ URLOverrides::GetChromeURLOverrides(extension);
+ if (overrides.empty())
+ return true;
+
+ for (const auto& entry : overrides) {
+ base::FilePath relative_path =
+ file_util::ExtensionURLToRelativeFilePath(entry.second);
+ base::FilePath resource_path =
+ extension->GetResource(relative_path).GetFilePath();
+ if (resource_path.empty() || !base::PathExists(resource_path)) {
+ *error = ErrorUtils::FormatErrorMessage(errors::kFileNotFound,
+ relative_path.AsUTF8Unsafe());
+ return false;
+ }
+ }
+ return true;
+}
+
+base::span<const char* const> URLOverridesHandler::Keys() const {
+ static constexpr const char* kKeys[] = {keys::kChromeURLOverrides};
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/chrome_manifest_url_handlers.h b/chromium/chrome/common/extensions/chrome_manifest_url_handlers.h
new file mode 100644
index 00000000000..bacd703425a
--- /dev/null
+++ b/chromium/chrome/common/extensions/chrome_manifest_url_handlers.h
@@ -0,0 +1,70 @@
+// 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 CHROME_COMMON_EXTENSIONS_CHROME_MANIFEST_URL_HANDLERS_H_
+#define CHROME_COMMON_EXTENSIONS_CHROME_MANIFEST_URL_HANDLERS_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handler.h"
+
+// Chrome-specific extension manifest URL handlers.
+
+namespace extensions {
+
+namespace chrome_manifest_urls {
+const GURL& GetDevToolsPage(const Extension* extension);
+}
+
+// Stores Chrome URL overrides specified in extensions manifests.
+struct URLOverrides : public Extension::ManifestData {
+ typedef std::map<const std::string, GURL> URLOverrideMap;
+
+ URLOverrides();
+ ~URLOverrides() override;
+
+ static const URLOverrideMap& GetChromeURLOverrides(
+ const Extension* extension);
+
+ // A map of chrome:// hostnames (newtab, downloads, etc.) to Extension URLs
+ // which override the handling of those URLs. (see ExtensionOverrideUI).
+ URLOverrideMap chrome_url_overrides_;
+};
+
+// Parses the "devtools_page" manifest key.
+class DevToolsPageHandler : public ManifestHandler {
+ public:
+ DevToolsPageHandler();
+ ~DevToolsPageHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+
+ private:
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(DevToolsPageHandler);
+};
+
+// Parses the "chrome_url_overrides" manifest key.
+class URLOverridesHandler : public ManifestHandler {
+ public:
+ URLOverridesHandler();
+ ~URLOverridesHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+ bool Validate(const Extension* extension,
+ std::string* error,
+ std::vector<InstallWarning>* warnings) const override;
+
+ private:
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(URLOverridesHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_CHROME_MANIFEST_URL_HANDLERS_H_
diff --git a/chromium/chrome/common/extensions/chrome_manifest_url_handlers_unittest.cc b/chromium/chrome/common/extensions/chrome_manifest_url_handlers_unittest.cc
new file mode 100644
index 00000000000..458d6782520
--- /dev/null
+++ b/chromium/chrome/common/extensions/chrome_manifest_url_handlers_unittest.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.
+
+#include "base/files/scoped_temp_dir.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/file_util.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/value_builder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+TEST(ChromeURLOverridesHandlerTest, TestFileMissing) {
+ DictionaryBuilder manifest;
+ manifest.Set("name", "ntp override");
+ manifest.Set("version", "0.1");
+ manifest.Set("manifest_version", 2);
+ manifest.Set("description", "description");
+ manifest.Set("chrome_url_overrides",
+ DictionaryBuilder().Set("newtab", "newtab.html").Build());
+ std::unique_ptr<base::DictionaryValue> manifest_value = manifest.Build();
+ std::string error;
+ std::vector<InstallWarning> warnings;
+ base::ScopedTempDir dir;
+ ASSERT_TRUE(dir.CreateUniqueTempDir());
+ scoped_refptr<Extension> extension =
+ Extension::Create(dir.GetPath(), Manifest::INTERNAL, *manifest_value,
+ Extension::NO_FLAGS, std::string(), &error);
+ ASSERT_TRUE(extension);
+ EXPECT_FALSE(
+ file_util::ValidateExtension(extension.get(), &error, &warnings));
+ EXPECT_EQ(ErrorUtils::FormatErrorMessage(manifest_errors::kFileNotFound,
+ "newtab.html"),
+ error);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/command.cc b/chromium/chrome/common/extensions/command.cc
new file mode 100644
index 00000000000..aba488f8c64
--- /dev/null
+++ b/chromium/chrome/common/extensions/command.cc
@@ -0,0 +1,542 @@
+// 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 "chrome/common/extensions/command.h"
+
+#include <stddef.h>
+
+#include "base/logging.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 "base/values.h"
+#include "build/build_config.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_constants.h"
+#include "ui/base/accelerators/media_keys_listener.h"
+
+namespace extensions {
+
+namespace errors = manifest_errors;
+namespace keys = manifest_keys;
+namespace values = manifest_values;
+
+namespace {
+
+static const char kMissing[] = "Missing";
+
+static const char kCommandKeyNotSupported[] =
+ "Command key is not supported. Note: Ctrl means Command on Mac";
+
+#if defined(OS_CHROMEOS)
+// ChromeOS supports an additional modifier 'Search', which can result in longer
+// sequences.
+static const int kMaxTokenSize = 4;
+#else
+static const int kMaxTokenSize = 3;
+#endif // OS_CHROMEOS
+
+Command::Type GetCommandType(const std::string& command_name) {
+ if (command_name == values::kPageActionCommandEvent)
+ return Command::Type::kPageAction;
+ if (command_name == values::kBrowserActionCommandEvent)
+ return Command::Type::kBrowserAction;
+ return Command::Type::kNamed;
+}
+
+bool IsNamedCommand(const std::string& command_name) {
+ return GetCommandType(command_name) == Command::Type::kNamed;
+}
+
+bool DoesRequireModifier(const std::string& accelerator) {
+ return accelerator != values::kKeyMediaNextTrack &&
+ accelerator != values::kKeyMediaPlayPause &&
+ accelerator != values::kKeyMediaPrevTrack &&
+ accelerator != values::kKeyMediaStop;
+}
+
+// Parse an |accelerator| for a given platform (specified by |platform_key|) and
+// return the result as a ui::Accelerator if successful, or VKEY_UNKNOWN if not.
+// |index| is used when constructing an |error| messages to show which command
+// in the manifest is failing and |should_parse_media_keys| specifies whether
+// media keys are to be considered for parsing.
+// Note: If the parsing rules here are changed, make sure to update the
+// corresponding extension_command_list.js validation, which validates the user
+// input for chrome://extensions/configureCommands.
+ui::Accelerator ParseImpl(const std::string& accelerator,
+ const std::string& platform_key,
+ int index,
+ bool should_parse_media_keys,
+ base::string16* error) {
+ error->clear();
+ if (platform_key != values::kKeybindingPlatformWin &&
+ platform_key != values::kKeybindingPlatformMac &&
+ platform_key != values::kKeybindingPlatformChromeOs &&
+ platform_key != values::kKeybindingPlatformLinux &&
+ platform_key != values::kKeybindingPlatformDefault) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidKeyBindingUnknownPlatform, base::NumberToString(index),
+ platform_key);
+ return ui::Accelerator();
+ }
+
+ std::vector<std::string> tokens = base::SplitString(
+ accelerator, "+", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ if (tokens.size() == 0 ||
+ (tokens.size() == 1 && DoesRequireModifier(accelerator)) ||
+ tokens.size() > kMaxTokenSize) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidKeyBinding,
+ base::NumberToString(index),
+ platform_key, accelerator);
+ return ui::Accelerator();
+ }
+
+ // Now, parse it into an accelerator.
+ int modifiers = ui::EF_NONE;
+ ui::KeyboardCode key = ui::VKEY_UNKNOWN;
+ for (size_t i = 0; i < tokens.size(); i++) {
+ if (tokens[i] == values::kKeyCtrl) {
+ modifiers |= ui::EF_CONTROL_DOWN;
+ } else if (tokens[i] == values::kKeyCommand) {
+ if (platform_key == values::kKeybindingPlatformMac) {
+ // Either the developer specified Command+foo in the manifest for Mac or
+ // they specified Ctrl and it got normalized to Command (to get Ctrl on
+ // Mac the developer has to specify MacCtrl). Therefore we treat this
+ // as Command.
+ modifiers |= ui::EF_COMMAND_DOWN;
+#if defined(OS_MACOSX)
+ } else if (platform_key == values::kKeybindingPlatformDefault) {
+ // If we see "Command+foo" in the Default section it can mean two
+ // things, depending on the platform:
+ // The developer specified "Ctrl+foo" for Default and it got normalized
+ // on Mac to "Command+foo". This is fine. Treat it as Command.
+ modifiers |= ui::EF_COMMAND_DOWN;
+#endif
+ } else {
+ // No other platform supports Command.
+ key = ui::VKEY_UNKNOWN;
+ break;
+ }
+ } else if (tokens[i] == values::kKeySearch) {
+ // Search is a special modifier only on ChromeOS and maps to 'Command'.
+ if (platform_key == values::kKeybindingPlatformChromeOs) {
+ modifiers |= ui::EF_COMMAND_DOWN;
+ } else {
+ // No other platform supports Search.
+ key = ui::VKEY_UNKNOWN;
+ break;
+ }
+ } else if (tokens[i] == values::kKeyAlt) {
+ modifiers |= ui::EF_ALT_DOWN;
+ } else if (tokens[i] == values::kKeyShift) {
+ modifiers |= ui::EF_SHIFT_DOWN;
+ } else if (tokens[i].size() == 1 || // A-Z, 0-9.
+ tokens[i] == values::kKeyComma ||
+ tokens[i] == values::kKeyPeriod ||
+ tokens[i] == values::kKeyUp ||
+ tokens[i] == values::kKeyDown ||
+ tokens[i] == values::kKeyLeft ||
+ tokens[i] == values::kKeyRight ||
+ tokens[i] == values::kKeyIns ||
+ tokens[i] == values::kKeyDel ||
+ tokens[i] == values::kKeyHome ||
+ tokens[i] == values::kKeyEnd ||
+ tokens[i] == values::kKeyPgUp ||
+ tokens[i] == values::kKeyPgDwn ||
+ tokens[i] == values::kKeySpace ||
+ tokens[i] == values::kKeyTab ||
+ tokens[i] == values::kKeyMediaNextTrack ||
+ tokens[i] == values::kKeyMediaPlayPause ||
+ tokens[i] == values::kKeyMediaPrevTrack ||
+ tokens[i] == values::kKeyMediaStop) {
+ if (key != ui::VKEY_UNKNOWN) {
+ // Multiple key assignments.
+ key = ui::VKEY_UNKNOWN;
+ break;
+ }
+
+ if (tokens[i] == values::kKeyComma) {
+ key = ui::VKEY_OEM_COMMA;
+ } else if (tokens[i] == values::kKeyPeriod) {
+ key = ui::VKEY_OEM_PERIOD;
+ } else if (tokens[i] == values::kKeyUp) {
+ key = ui::VKEY_UP;
+ } else if (tokens[i] == values::kKeyDown) {
+ key = ui::VKEY_DOWN;
+ } else if (tokens[i] == values::kKeyLeft) {
+ key = ui::VKEY_LEFT;
+ } else if (tokens[i] == values::kKeyRight) {
+ key = ui::VKEY_RIGHT;
+ } else if (tokens[i] == values::kKeyIns) {
+ key = ui::VKEY_INSERT;
+ } else if (tokens[i] == values::kKeyDel) {
+ key = ui::VKEY_DELETE;
+ } else if (tokens[i] == values::kKeyHome) {
+ key = ui::VKEY_HOME;
+ } else if (tokens[i] == values::kKeyEnd) {
+ key = ui::VKEY_END;
+ } else if (tokens[i] == values::kKeyPgUp) {
+ key = ui::VKEY_PRIOR;
+ } else if (tokens[i] == values::kKeyPgDwn) {
+ key = ui::VKEY_NEXT;
+ } else if (tokens[i] == values::kKeySpace) {
+ key = ui::VKEY_SPACE;
+ } else if (tokens[i] == values::kKeyTab) {
+ key = ui::VKEY_TAB;
+ } else if (tokens[i] == values::kKeyMediaNextTrack &&
+ should_parse_media_keys) {
+ key = ui::VKEY_MEDIA_NEXT_TRACK;
+ } else if (tokens[i] == values::kKeyMediaPlayPause &&
+ should_parse_media_keys) {
+ key = ui::VKEY_MEDIA_PLAY_PAUSE;
+ } else if (tokens[i] == values::kKeyMediaPrevTrack &&
+ should_parse_media_keys) {
+ key = ui::VKEY_MEDIA_PREV_TRACK;
+ } else if (tokens[i] == values::kKeyMediaStop &&
+ should_parse_media_keys) {
+ key = ui::VKEY_MEDIA_STOP;
+ } else if (tokens[i].size() == 1 && base::IsAsciiUpper(tokens[i][0])) {
+ key = static_cast<ui::KeyboardCode>(ui::VKEY_A + (tokens[i][0] - 'A'));
+ } else if (tokens[i].size() == 1 && base::IsAsciiDigit(tokens[i][0])) {
+ key = static_cast<ui::KeyboardCode>(ui::VKEY_0 + (tokens[i][0] - '0'));
+ } else {
+ key = ui::VKEY_UNKNOWN;
+ break;
+ }
+ } else {
+ *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidKeyBinding,
+ base::NumberToString(index),
+ platform_key, accelerator);
+ return ui::Accelerator();
+ }
+ }
+
+ bool command = (modifiers & ui::EF_COMMAND_DOWN) != 0;
+ bool ctrl = (modifiers & ui::EF_CONTROL_DOWN) != 0;
+ bool alt = (modifiers & ui::EF_ALT_DOWN) != 0;
+ bool shift = (modifiers & ui::EF_SHIFT_DOWN) != 0;
+
+ // We support Ctrl+foo, Alt+foo, Ctrl+Shift+foo, Alt+Shift+foo, but not
+ // Ctrl+Alt+foo and not Shift+foo either. For a more detailed reason why we
+ // don't support Ctrl+Alt+foo see this article:
+ // http://blogs.msdn.com/b/oldnewthing/archive/2004/03/29/101121.aspx.
+ // On Mac Command can also be used in combination with Shift or on its own,
+ // as a modifier.
+ if (key == ui::VKEY_UNKNOWN || (ctrl && alt) || (command && alt) ||
+ (shift && !ctrl && !alt && !command)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidKeyBinding,
+ base::NumberToString(index),
+ platform_key, accelerator);
+ return ui::Accelerator();
+ }
+
+ if (ui::MediaKeysListener::IsMediaKeycode(key) &&
+ (shift || ctrl || alt || command)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidKeyBindingMediaKeyWithModifier,
+ base::NumberToString(index), platform_key, accelerator);
+ return ui::Accelerator();
+ }
+
+ return ui::Accelerator(key, modifiers);
+}
+
+// For Mac, we convert "Ctrl" to "Command" and "MacCtrl" to "Ctrl". Other
+// platforms leave the shortcut untouched.
+std::string NormalizeShortcutSuggestion(const std::string& suggestion,
+ const std::string& platform) {
+ bool normalize = false;
+ if (platform == values::kKeybindingPlatformMac) {
+ normalize = true;
+ } else if (platform == values::kKeybindingPlatformDefault) {
+#if defined(OS_MACOSX)
+ normalize = true;
+#endif
+ }
+
+ if (!normalize)
+ return suggestion;
+
+ std::vector<base::StringPiece> tokens = base::SplitStringPiece(
+ suggestion, "+", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ for (size_t i = 0; i < tokens.size(); i++) {
+ if (tokens[i] == values::kKeyCtrl)
+ tokens[i] = values::kKeyCommand;
+ else if (tokens[i] == values::kKeyMacCtrl)
+ tokens[i] = values::kKeyCtrl;
+ }
+ return base::JoinString(tokens, "+");
+}
+
+} // namespace
+
+Command::Command() : global_(false), type_(Type::kNamed) {}
+
+Command::Command(const std::string& command_name,
+ const base::string16& description,
+ const std::string& accelerator,
+ bool global)
+ : command_name_(command_name),
+ description_(description),
+ global_(global),
+ type_(GetCommandType(command_name)) {
+ base::string16 error;
+ accelerator_ = ParseImpl(accelerator, CommandPlatform(), 0,
+ type_ == Type::kNamed, &error);
+}
+
+Command::Command(const Command& other) = default;
+
+Command::~Command() {}
+
+// static
+std::string Command::CommandPlatform() {
+#if defined(OS_WIN)
+ return values::kKeybindingPlatformWin;
+#elif defined(OS_MACOSX)
+ return values::kKeybindingPlatformMac;
+#elif defined(OS_CHROMEOS)
+ return values::kKeybindingPlatformChromeOs;
+#elif defined(OS_LINUX)
+ return values::kKeybindingPlatformLinux;
+#else
+ return "";
+#endif
+}
+
+// static
+ui::Accelerator Command::StringToAccelerator(const std::string& accelerator,
+ const std::string& command_name) {
+ base::string16 error;
+ ui::Accelerator parsed =
+ ParseImpl(accelerator, Command::CommandPlatform(), 0,
+ IsNamedCommand(command_name), &error);
+ return parsed;
+}
+
+// static
+std::string Command::AcceleratorToString(const ui::Accelerator& accelerator) {
+ std::string shortcut;
+
+ // Ctrl and Alt are mutually exclusive.
+ if (accelerator.IsCtrlDown())
+ shortcut += values::kKeyCtrl;
+ else if (accelerator.IsAltDown())
+ shortcut += values::kKeyAlt;
+ if (!shortcut.empty())
+ shortcut += values::kKeySeparator;
+
+ if (accelerator.IsCmdDown()) {
+#if defined(OS_CHROMEOS)
+ // Chrome OS treats the Search key like the Command key.
+ shortcut += values::kKeySearch;
+#else
+ shortcut += values::kKeyCommand;
+#endif
+ shortcut += values::kKeySeparator;
+ }
+
+ if (accelerator.IsShiftDown()) {
+ shortcut += values::kKeyShift;
+ shortcut += values::kKeySeparator;
+ }
+
+ if (accelerator.key_code() >= ui::VKEY_0 &&
+ accelerator.key_code() <= ui::VKEY_9) {
+ shortcut += '0' + (accelerator.key_code() - ui::VKEY_0);
+ } else if (accelerator.key_code() >= ui::VKEY_A &&
+ accelerator.key_code() <= ui::VKEY_Z) {
+ shortcut += 'A' + (accelerator.key_code() - ui::VKEY_A);
+ } else {
+ switch (accelerator.key_code()) {
+ case ui::VKEY_OEM_COMMA:
+ shortcut += values::kKeyComma;
+ break;
+ case ui::VKEY_OEM_PERIOD:
+ shortcut += values::kKeyPeriod;
+ break;
+ case ui::VKEY_UP:
+ shortcut += values::kKeyUp;
+ break;
+ case ui::VKEY_DOWN:
+ shortcut += values::kKeyDown;
+ break;
+ case ui::VKEY_LEFT:
+ shortcut += values::kKeyLeft;
+ break;
+ case ui::VKEY_RIGHT:
+ shortcut += values::kKeyRight;
+ break;
+ case ui::VKEY_INSERT:
+ shortcut += values::kKeyIns;
+ break;
+ case ui::VKEY_DELETE:
+ shortcut += values::kKeyDel;
+ break;
+ case ui::VKEY_HOME:
+ shortcut += values::kKeyHome;
+ break;
+ case ui::VKEY_END:
+ shortcut += values::kKeyEnd;
+ break;
+ case ui::VKEY_PRIOR:
+ shortcut += values::kKeyPgUp;
+ break;
+ case ui::VKEY_NEXT:
+ shortcut += values::kKeyPgDwn;
+ break;
+ case ui::VKEY_SPACE:
+ shortcut += values::kKeySpace;
+ break;
+ case ui::VKEY_TAB:
+ shortcut += values::kKeyTab;
+ break;
+ case ui::VKEY_MEDIA_NEXT_TRACK:
+ shortcut += values::kKeyMediaNextTrack;
+ break;
+ case ui::VKEY_MEDIA_PLAY_PAUSE:
+ shortcut += values::kKeyMediaPlayPause;
+ break;
+ case ui::VKEY_MEDIA_PREV_TRACK:
+ shortcut += values::kKeyMediaPrevTrack;
+ break;
+ case ui::VKEY_MEDIA_STOP:
+ shortcut += values::kKeyMediaStop;
+ break;
+ default:
+ return "";
+ }
+ }
+ return shortcut;
+}
+
+// static
+bool Command::IsMediaKey(const ui::Accelerator& accelerator) {
+ if (accelerator.modifiers() != 0)
+ return false;
+
+ return ui::MediaKeysListener::IsMediaKeycode(accelerator.key_code());
+}
+
+bool Command::Parse(const base::DictionaryValue* command,
+ const std::string& command_name,
+ int index,
+ base::string16* error) {
+ DCHECK(!command_name.empty());
+
+ base::string16 description;
+ if (IsNamedCommand(command_name)) {
+ if (!command->GetString(keys::kDescription, &description) ||
+ description.empty()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidKeyBindingDescription, base::NumberToString(index));
+ return false;
+ }
+ }
+
+ // We'll build up a map of platform-to-shortcut suggestions.
+ typedef std::map<const std::string, std::string> SuggestionMap;
+ SuggestionMap suggestions;
+
+ // First try to parse the |suggested_key| as a dictionary.
+ const base::DictionaryValue* suggested_key_dict;
+ if (command->GetDictionary(keys::kSuggestedKey, &suggested_key_dict)) {
+ for (base::DictionaryValue::Iterator iter(*suggested_key_dict);
+ !iter.IsAtEnd(); iter.Advance()) {
+ // For each item in the dictionary, extract the platforms specified.
+ std::string suggested_key_string;
+ if (iter.value().GetAsString(&suggested_key_string) &&
+ !suggested_key_string.empty()) {
+ // Found a platform, add it to the suggestions list.
+ suggestions[iter.key()] = suggested_key_string;
+ } else {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidKeyBinding, base::NumberToString(index),
+ keys::kSuggestedKey, kMissing);
+ return false;
+ }
+ }
+ } else {
+ // No dictionary was found, fall back to using just a string, so developers
+ // don't have to specify a dictionary if they just want to use one default
+ // for all platforms.
+ std::string suggested_key_string;
+ if (command->GetString(keys::kSuggestedKey, &suggested_key_string) &&
+ !suggested_key_string.empty()) {
+ // If only a single string is provided, it must be default for all.
+ suggestions[values::kKeybindingPlatformDefault] = suggested_key_string;
+ } else {
+ suggestions[values::kKeybindingPlatformDefault] = "";
+ }
+ }
+
+ // Check if this is a global or a regular shortcut.
+ bool global = false;
+ command->GetBoolean(keys::kGlobal, &global);
+
+ // Normalize the suggestions.
+ for (auto iter = suggestions.begin(); iter != suggestions.end(); ++iter) {
+ // Before we normalize Ctrl to Command we must detect when the developer
+ // specified Command in the Default section, which will work on Mac after
+ // normalization but only fail on other platforms when they try it out on
+ // other platforms, which is not what we want.
+ if (iter->first == values::kKeybindingPlatformDefault &&
+ iter->second.find("Command+") != std::string::npos) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidKeyBinding, base::NumberToString(index),
+ keys::kSuggestedKey, kCommandKeyNotSupported);
+ return false;
+ }
+
+ suggestions[iter->first] = NormalizeShortcutSuggestion(iter->second,
+ iter->first);
+ }
+
+ std::string platform = CommandPlatform();
+ std::string key = platform;
+ if (suggestions.find(key) == suggestions.end())
+ key = values::kKeybindingPlatformDefault;
+ if (suggestions.find(key) == suggestions.end()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidKeyBindingMissingPlatform, base::NumberToString(index),
+ keys::kSuggestedKey, platform);
+ return false; // No platform specified and no fallback. Bail.
+ }
+
+ // For developer convenience, we parse all the suggestions (and complain about
+ // errors for platforms other than the current one) but use only what we need.
+ std::map<const std::string, std::string>::const_iterator iter =
+ suggestions.begin();
+ for ( ; iter != suggestions.end(); ++iter) {
+ ui::Accelerator accelerator;
+ if (!iter->second.empty()) {
+ // Note that we pass iter->first to pretend we are on a platform we're not
+ // on.
+ accelerator = ParseImpl(iter->second, iter->first, index,
+ IsNamedCommand(command_name), error);
+ if (accelerator.key_code() == ui::VKEY_UNKNOWN) {
+ if (error->empty()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidKeyBinding, base::NumberToString(index),
+ iter->first, iter->second);
+ }
+ return false;
+ }
+ }
+
+ if (iter->first == key) {
+ // This platform is our platform, so grab this key.
+ accelerator_ = accelerator;
+ command_name_ = command_name;
+ description_ = description;
+ global_ = global;
+ type_ = GetCommandType(command_name);
+ }
+ }
+ return true;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/command.h b/chromium/chrome/common/extensions/command.h
new file mode 100644
index 00000000000..11a86fbfb4f
--- /dev/null
+++ b/chromium/chrome/common/extensions/command.h
@@ -0,0 +1,87 @@
+// 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 CHROME_COMMON_EXTENSIONS_COMMAND_H_
+#define CHROME_COMMON_EXTENSIONS_COMMAND_H_
+
+#include <map>
+#include <string>
+
+#include "base/strings/string16.h"
+#include "ui/base/accelerators/accelerator.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace extensions {
+
+class Command {
+ public:
+ enum class Type {
+ kBrowserAction,
+ kPageAction,
+ kNamed,
+ };
+
+ Command();
+ Command(const std::string& command_name,
+ const base::string16& description,
+ const std::string& accelerator,
+ bool global);
+ Command(const Command& other);
+ ~Command();
+
+ // The platform value for the Command.
+ static std::string CommandPlatform();
+
+ // Parse a string as an accelerator. If the accelerator is unparsable then
+ // a generic ui::Accelerator object will be returns (with key_code Unknown).
+ static ui::Accelerator StringToAccelerator(const std::string& accelerator,
+ const std::string& command_name);
+
+ // Returns the string representation of an accelerator without localizing the
+ // shortcut text (like accelerator::GetShortcutText() does).
+ static std::string AcceleratorToString(const ui::Accelerator& accelerator);
+
+ // Return true if the specified accelerator is one of the following multimedia
+ // keys: Next Track key, Previous Track key, Stop Media key, Play/Pause Media
+ // key, without any modifiers.
+ static bool IsMediaKey(const ui::Accelerator& accelerator);
+
+ // Parse the command.
+ bool Parse(const base::DictionaryValue* command,
+ const std::string& command_name,
+ int index,
+ base::string16* error);
+
+ // Accessors:
+ const std::string& command_name() const { return command_name_; }
+ const ui::Accelerator& accelerator() const { return accelerator_; }
+ const base::string16& description() const { return description_; }
+ bool global() const { return global_; }
+ Type type() const { return type_; }
+
+ // Setter:
+ void set_accelerator(const ui::Accelerator& accelerator) {
+ accelerator_ = accelerator;
+ }
+ void set_global(bool global) {
+ global_ = global;
+ }
+
+ private:
+ std::string command_name_;
+ ui::Accelerator accelerator_;
+ base::string16 description_;
+ bool global_;
+ Type type_;
+};
+
+// A mapping of command name (std::string) to a command object.
+typedef std::map<std::string, Command> CommandMap;
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_COMMAND_H_
diff --git a/chromium/chrome/common/extensions/command_unittest.cc b/chromium/chrome/common/extensions/command_unittest.cc
new file mode 100644
index 00000000000..adc18072fab
--- /dev/null
+++ b/chromium/chrome/common/extensions/command_unittest.cc
@@ -0,0 +1,348 @@
+// 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 "chrome/common/extensions/command.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/optional.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+using CommandTest = testing::Test;
+
+struct ConstCommandsTestData {
+ bool expected_result;
+ ui::Accelerator accelerator;
+ const char* command_name;
+ const char* key;
+ const char* description;
+ base::Optional<Command::Type> type;
+};
+
+// Checks the |suggested_key| value parses into a command when specified as a
+// string or dictionary of platform specific keys. If
+// |platform_specific_only| is true, only the latter is tested. |platforms|
+// specifies all platforms to use when populating the |suggested_key|
+// dictionary.
+void CheckParse(const ConstCommandsTestData& data,
+ int i,
+ bool platform_specific_only,
+ std::vector<std::string>& platforms) {
+ SCOPED_TRACE(std::string("Command name: |") + data.command_name + "| key: |" +
+ data.key + "| description: |" + data.description +
+ "| index: " + base::NumberToString(i));
+
+ extensions::Command command;
+ std::unique_ptr<base::DictionaryValue> input(new base::DictionaryValue);
+ base::string16 error;
+
+ // First, test the parse of a string suggested_key value.
+ input->SetString("suggested_key", data.key);
+ input->SetString("description", data.description);
+
+ if (!platform_specific_only) {
+ bool result = command.Parse(input.get(), data.command_name, i, &error);
+ EXPECT_EQ(data.expected_result, result);
+ if (result) {
+ EXPECT_STREQ(data.description,
+ base::UTF16ToASCII(command.description()).c_str());
+ EXPECT_STREQ(data.command_name, command.command_name().c_str());
+ EXPECT_EQ(data.accelerator, command.accelerator());
+ }
+ }
+
+ // Now, test the parse of a platform dictionary suggested_key value.
+ if (data.key[0] != '\0') {
+ std::string current_platform = extensions::Command::CommandPlatform();
+ if (platform_specific_only &&
+ !base::Contains(platforms, current_platform)) {
+ // Given a |current_platform| without a |suggested_key|, |default| is
+ // used. However, some keys, such as Search on Chrome OS, are only valid
+ // for platform specific entries. Skip the test in this case.
+ return;
+ }
+
+ input.reset(new base::DictionaryValue);
+ auto key_dict = std::make_unique<base::DictionaryValue>();
+
+ for (size_t j = 0; j < platforms.size(); ++j)
+ key_dict->SetString(platforms[j], data.key);
+
+ input->Set("suggested_key", std::move(key_dict));
+ input->SetString("description", data.description);
+
+ bool result = command.Parse(input.get(), data.command_name, i, &error);
+ EXPECT_EQ(data.expected_result, result);
+
+ if (result) {
+ EXPECT_STREQ(data.description,
+ base::UTF16ToASCII(command.description()).c_str());
+ EXPECT_STREQ(data.command_name, command.command_name().c_str());
+ EXPECT_EQ(data.accelerator, command.accelerator());
+ ASSERT_TRUE(data.type) << "Parsed commands must specify an expected type";
+ EXPECT_EQ(*data.type, command.type());
+ }
+ }
+}
+
+TEST(CommandTest, ExtensionCommandParsing) {
+ const ui::Accelerator none = ui::Accelerator();
+ const ui::Accelerator shift_f = ui::Accelerator(ui::VKEY_F,
+ ui::EF_SHIFT_DOWN);
+#if defined(OS_MACOSX)
+ int ctrl = ui::EF_COMMAND_DOWN;
+#else
+ int ctrl = ui::EF_CONTROL_DOWN;
+#endif
+
+ const ui::Accelerator ctrl_f = ui::Accelerator(ui::VKEY_F, ctrl);
+ const ui::Accelerator alt_f = ui::Accelerator(ui::VKEY_F, ui::EF_ALT_DOWN);
+ const ui::Accelerator ctrl_shift_f =
+ ui::Accelerator(ui::VKEY_F, ctrl | ui::EF_SHIFT_DOWN);
+ const ui::Accelerator alt_shift_f =
+ ui::Accelerator(ui::VKEY_F, ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN);
+ const ui::Accelerator ctrl_1 = ui::Accelerator(ui::VKEY_1, ctrl);
+ const ui::Accelerator ctrl_comma = ui::Accelerator(ui::VKEY_OEM_COMMA, ctrl);
+ const ui::Accelerator ctrl_dot = ui::Accelerator(ui::VKEY_OEM_PERIOD, ctrl);
+ const ui::Accelerator ctrl_left = ui::Accelerator(ui::VKEY_LEFT, ctrl);
+ const ui::Accelerator ctrl_right = ui::Accelerator(ui::VKEY_RIGHT, ctrl);
+ const ui::Accelerator ctrl_up = ui::Accelerator(ui::VKEY_UP, ctrl);
+ const ui::Accelerator ctrl_down = ui::Accelerator(ui::VKEY_DOWN, ctrl);
+ const ui::Accelerator ctrl_ins = ui::Accelerator(ui::VKEY_INSERT, ctrl);
+ const ui::Accelerator ctrl_del = ui::Accelerator(ui::VKEY_DELETE, ctrl);
+ const ui::Accelerator ctrl_home = ui::Accelerator(ui::VKEY_HOME, ctrl);
+ const ui::Accelerator ctrl_end = ui::Accelerator(ui::VKEY_END, ctrl);
+ const ui::Accelerator ctrl_pgup = ui::Accelerator(ui::VKEY_PRIOR, ctrl);
+ const ui::Accelerator ctrl_pgdwn = ui::Accelerator(ui::VKEY_NEXT, ctrl);
+ const ui::Accelerator next_track =
+ ui::Accelerator(ui::VKEY_MEDIA_NEXT_TRACK, ui::EF_NONE);
+ const ui::Accelerator prev_track =
+ ui::Accelerator(ui::VKEY_MEDIA_PREV_TRACK, ui::EF_NONE);
+ const ui::Accelerator play_pause =
+ ui::Accelerator(ui::VKEY_MEDIA_PLAY_PAUSE, ui::EF_NONE);
+ const ui::Accelerator stop =
+ ui::Accelerator(ui::VKEY_MEDIA_STOP, ui::EF_NONE);
+
+ ConstCommandsTestData kTests[] = {
+ // Negative test (one or more missing required fields). We don't need to
+ // test |command_name| being blank as it is used as a key in the manifest,
+ // so it can't be blank (and we CHECK() when it is). A blank shortcut is
+ // permitted.
+ {false, none, "command", "", ""},
+ {false, none, "command", "Ctrl+f", ""},
+ // Ctrl+Alt is not permitted, see MSDN link in comments in Parse function.
+ {false, none, "command", "Ctrl+Alt+F", "description"},
+ // Unsupported shortcuts/too many, or missing modifier.
+ {false, none, "command", "A", "description"},
+ {false, none, "command", "F10", "description"},
+ {false, none, "command", "Ctrl+F+G", "description"},
+ {false, none, "command", "Ctrl+Alt+Shift+G", "description"},
+ // Shift on its own is not supported.
+ {false, shift_f, "command", "Shift+F", "description"},
+ {false, shift_f, "command", "F+Shift", "description"},
+ // Basic tests.
+ {true, none, "command", "", "description", Command::Type::kNamed},
+ {true, ctrl_f, "command", "Ctrl+F", "description", Command::Type::kNamed},
+ {true, alt_f, "command", "Alt+F", "description", Command::Type::kNamed},
+ {true, ctrl_shift_f, "command", "Ctrl+Shift+F", "description",
+ Command::Type::kNamed},
+ {true, alt_shift_f, "command", "Alt+Shift+F", "description",
+ Command::Type::kNamed},
+ {true, ctrl_1, "command", "Ctrl+1", "description", Command::Type::kNamed},
+ // Shortcut token order tests.
+ {true, ctrl_f, "command", "F+Ctrl", "description", Command::Type::kNamed},
+ {true, alt_f, "command", "F+Alt", "description", Command::Type::kNamed},
+ {true, ctrl_shift_f, "command", "F+Ctrl+Shift", "description",
+ Command::Type::kNamed},
+ {true, ctrl_shift_f, "command", "F+Shift+Ctrl", "description",
+ Command::Type::kNamed},
+ {true, alt_shift_f, "command", "F+Alt+Shift", "description",
+ Command::Type::kNamed},
+ {true, alt_shift_f, "command", "F+Shift+Alt", "description",
+ Command::Type::kNamed},
+ // Case insensitivity is not OK.
+ {false, ctrl_f, "command", "Ctrl+f", "description"},
+ {false, ctrl_f, "command", "cTrL+F", "description"},
+ // Skipping description is OK for browser- and pageActions.
+ {true, ctrl_f, "_execute_browser_action", "Ctrl+F", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_f, "_execute_page_action", "Ctrl+F", "",
+ Command::Type::kPageAction},
+ // Home, End, Arrow keys, etc.
+ {true, ctrl_comma, "_execute_browser_action", "Ctrl+Comma", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_dot, "_execute_browser_action", "Ctrl+Period", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_left, "_execute_browser_action", "Ctrl+Left", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_right, "_execute_browser_action", "Ctrl+Right", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_up, "_execute_browser_action", "Ctrl+Up", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_down, "_execute_browser_action", "Ctrl+Down", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_ins, "_execute_browser_action", "Ctrl+Insert", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_del, "_execute_browser_action", "Ctrl+Delete", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_home, "_execute_browser_action", "Ctrl+Home", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_end, "_execute_browser_action", "Ctrl+End", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_pgup, "_execute_browser_action", "Ctrl+PageUp", "",
+ Command::Type::kBrowserAction},
+ {true, ctrl_pgdwn, "_execute_browser_action", "Ctrl+PageDown", "",
+ Command::Type::kBrowserAction},
+ // Media keys.
+ {true, next_track, "command", "MediaNextTrack", "description",
+ Command::Type::kNamed},
+ {true, play_pause, "command", "MediaPlayPause", "description",
+ Command::Type::kNamed},
+ {true, prev_track, "command", "MediaPrevTrack", "description",
+ Command::Type::kNamed},
+ {true, stop, "command", "MediaStop", "description",
+ Command::Type::kNamed},
+ {false, none, "_execute_browser_action", "MediaNextTrack", ""},
+ {false, none, "_execute_page_action", "MediaPrevTrack", ""},
+ {false, none, "command", "Ctrl+Shift+MediaPrevTrack", "description"},
+ };
+ std::vector<std::string> all_platforms;
+ all_platforms.push_back("default");
+ all_platforms.push_back("chromeos");
+ all_platforms.push_back("linux");
+ all_platforms.push_back("mac");
+ all_platforms.push_back("windows");
+
+ for (size_t i = 0; i < base::size(kTests); ++i)
+ CheckParse(kTests[i], i, false, all_platforms);
+}
+
+TEST(CommandTest, ExtensionCommandParsingFallback) {
+ std::string description = "desc";
+ std::string command_name = "foo";
+
+ // Test that platform specific keys are honored on each platform, despite
+ // fallback being given.
+ std::unique_ptr<base::DictionaryValue> input(new base::DictionaryValue);
+ input->SetString("description", description);
+ base::DictionaryValue* key_dict = input->SetDictionary(
+ "suggested_key", std::make_unique<base::DictionaryValue>());
+ key_dict->SetString("default", "Ctrl+Shift+D");
+ key_dict->SetString("windows", "Ctrl+Shift+W");
+ key_dict->SetString("mac", "Ctrl+Shift+M");
+ key_dict->SetString("linux", "Ctrl+Shift+L");
+ key_dict->SetString("chromeos", "Ctrl+Shift+C");
+
+ extensions::Command command;
+ base::string16 error;
+ EXPECT_TRUE(command.Parse(input.get(), command_name, 0, &error));
+ EXPECT_STREQ(description.c_str(),
+ base::UTF16ToASCII(command.description()).c_str());
+ EXPECT_STREQ(command_name.c_str(), command.command_name().c_str());
+
+#if defined(OS_WIN)
+ ui::Accelerator accelerator(ui::VKEY_W,
+ ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
+#elif defined(OS_MACOSX)
+ ui::Accelerator accelerator(ui::VKEY_M,
+ ui::EF_SHIFT_DOWN | ui::EF_COMMAND_DOWN);
+#elif defined(OS_CHROMEOS)
+ ui::Accelerator accelerator(ui::VKEY_C,
+ ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
+#elif defined(OS_LINUX)
+ ui::Accelerator accelerator(ui::VKEY_L,
+ ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
+#else
+ ui::Accelerator accelerator(ui::VKEY_D,
+ ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
+#endif
+ EXPECT_EQ(accelerator, command.accelerator());
+
+ // Misspell a platform.
+ key_dict->SetString("windosw", "Ctrl+M");
+ EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
+ EXPECT_TRUE(key_dict->Remove("windosw", NULL));
+
+ // Now remove platform specific keys (leaving just "default") and make sure
+ // every platform falls back to the default.
+ EXPECT_TRUE(key_dict->Remove("windows", NULL));
+ EXPECT_TRUE(key_dict->Remove("mac", NULL));
+ EXPECT_TRUE(key_dict->Remove("linux", NULL));
+ EXPECT_TRUE(key_dict->Remove("chromeos", NULL));
+ EXPECT_TRUE(command.Parse(input.get(), command_name, 0, &error));
+ EXPECT_EQ(ui::VKEY_D, command.accelerator().key_code());
+
+ // Now remove "default", leaving no option but failure. Or, in the words of
+ // the immortal Adam Savage: "Failure is always an option".
+ EXPECT_TRUE(key_dict->Remove("default", NULL));
+ EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
+
+ // Make sure Command is not supported for non-Mac platforms.
+ key_dict->SetString("default", "Command+M");
+ EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
+ EXPECT_TRUE(key_dict->Remove("default", NULL));
+ key_dict->SetString("windows", "Command+M");
+ EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
+ EXPECT_TRUE(key_dict->Remove("windows", NULL));
+
+ // Now add only a valid platform that we are not running on to make sure devs
+ // are notified of errors on other platforms.
+#if defined(OS_WIN)
+ key_dict->SetString("mac", "Ctrl+Shift+M");
+#else
+ key_dict->SetString("windows", "Ctrl+Shift+W");
+#endif
+ EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
+
+ // Make sure Mac specific keys are not processed on other platforms.
+#if !defined(OS_MACOSX)
+ key_dict->SetString("windows", "Command+Shift+M");
+ EXPECT_FALSE(command.Parse(input.get(), command_name, 0, &error));
+#endif
+}
+
+TEST(CommandTest, ExtensionCommandParsingPlatformSpecific) {
+ ui::Accelerator search_a(ui::VKEY_A, ui::EF_COMMAND_DOWN);
+ ui::Accelerator search_shift_z(ui::VKEY_Z,
+ ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN);
+
+ ConstCommandsTestData kChromeOsTests[] = {
+ {true, search_shift_z, "command", "Search+Shift+Z", "description",
+ Command::Type::kNamed},
+ {true, search_a, "command", "Search+A", "description",
+ Command::Type::kNamed},
+ // Command is not valid on Chrome OS.
+ {false, search_shift_z, "command", "Command+Shift+Z", "description"},
+ };
+
+ std::vector<std::string> chromeos;
+ chromeos.push_back("chromeos");
+ for (size_t i = 0; i < base::size(kChromeOsTests); ++i)
+ CheckParse(kChromeOsTests[i], i, true, chromeos);
+
+ ConstCommandsTestData kNonChromeOsSearchTests[] = {
+ {false, search_shift_z, "command", "Search+Shift+Z", "description"},
+ };
+ std::vector<std::string> non_chromeos;
+ non_chromeos.push_back("default");
+ non_chromeos.push_back("windows");
+ non_chromeos.push_back("mac");
+ non_chromeos.push_back("linux");
+
+ for (size_t i = 0; i < base::size(kNonChromeOsSearchTests); ++i)
+ CheckParse(kNonChromeOsSearchTests[i], i, true, non_chromeos);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/docs/examples/api/bookmarks/basic/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/bookmarks/basic/manifest.json
deleted file mode 100644
index 2135c3cbf6b..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/bookmarks/basic/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "My Bookmarks",
- "version": "1.1",
- "description": "A browser action with a popup dump of all bookmarks, including search, add, edit and delete.",
- "permissions": [
- "bookmarks"
- ],
- "browser_action": {
- "default_title": "My Bookmarks",
- "default_icon": "icon.png",
- "default_popup": "popup.html"
- },
- "manifest_version": 2,
- "content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'"
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/browserAction/make_page_red/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/browserAction/make_page_red/manifest.json
deleted file mode 100644
index b901108730c..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/browserAction/make_page_red/manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "Page Redder",
- "description": "Make the current page red",
- "version": "2.0",
- "permissions": [
- "activeTab"
- ],
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "browser_action": {
- "default_title": "Make this page red"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/browserAction/print/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/browserAction/print/manifest.json
deleted file mode 100644
index e6feef42c6a..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/browserAction/print/manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "Print this page",
- "description": "Adds a print button to the browser.",
- "version": "1.2",
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "permissions": [
- "activeTab"
- ],
- "browser_action": {
- "default_title": "Print this page",
- "default_icon": "print_16x16.png"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/browserAction/set_icon_path/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/browserAction/set_icon_path/manifest.json
deleted file mode 100644
index 597e0036a1e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/browserAction/set_icon_path/manifest.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "name": "A browser action which changes its icon when clicked",
- "description": "Click browser action icon to change color!",
- "version": "1.3",
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "permissions": ["storage"],
- "browser_action": {
- "name": "Click to change the icon's color"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/browserAction/set_page_color/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/browserAction/set_page_color/manifest.json
deleted file mode 100644
index cecb2bccd11..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/browserAction/set_page_color/manifest.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "name": "A browser action with a popup that changes the page color",
- "description": "Change the current page color",
- "version": "1.0",
- "permissions": [
- "activeTab"
- ],
- "browser_action": {
- "default_title": "Set this page's color.",
- "default_icon": "icon.png",
- "default_popup": "popup.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/browsingData/basic/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/browsingData/basic/manifest.json
deleted file mode 100644
index d2287292ddf..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/browsingData/basic/manifest.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name" : "BrowsingData API: Basics",
- "version" : "1.1",
- "description" : "A trivial usage example.",
- "permissions": [
- "browsingData"
- ],
- "browser_action": {
- "default_icon": "icon.png",
- "default_popup": "popup.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/commands/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/commands/manifest.json
deleted file mode 100644
index a22622c85a2..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/commands/manifest.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "Sample Extension Commands extension",
- "description": "Press Ctrl+Shift+F to open the browser action popup, press Ctrl+Shift+Y to send an event.",
- "version": "1.0",
- "manifest_version": 2,
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "browser_action": {
- "default_popup": "browser_action.html"
- },
- "commands": {
- "toggle-feature": {
- "suggested_key": {
- "default": "Ctrl+Shift+Y",
- "mac": "MacCtrl+Shift+Y"
- },
- "description": "Send a 'toggle-feature' event to the extension"
- },
- "_execute_browser_action": {
- "suggested_key": {
- "default": "Ctrl+Shift+F",
- "mac": "MacCtrl+Shift+F"
- }
- }
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/contentSettings/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/contentSettings/manifest.json
deleted file mode 100644
index adf1daefb52..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/contentSettings/manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name" : "Content settings",
- "version" : "0.2",
- "description" : "Shows the content settings for the current site.",
- "permissions": [ "contentSettings", "tabs" ],
- "browser_action": {
- "default_icon": "contentSettings.png",
- "default_popup": "popup.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/contextMenus/basic/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/contextMenus/basic/manifest.json
deleted file mode 100644
index c59cec18d17..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/contextMenus/basic/manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "Context Menus Sample",
- "description": "Shows some of the features of the Context Menus API",
- "version": "0.6",
- "permissions": ["contextMenus"],
- "background": {
- "scripts": ["sample.js"]
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/contextMenus/event_page/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/contextMenus/event_page/manifest.json
deleted file mode 100644
index 8279823db8d..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/contextMenus/event_page/manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name": "Context Menus Sample (with Event Page)",
- "description": "Shows some of the features of the Context Menus API using an event page",
- "version": "0.7",
- "permissions": ["contextMenus"],
- "background": {
- "persistent": false,
- "scripts": ["sample.js"]
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/contextMenus/global_context_search/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/contextMenus/global_context_search/manifest.json
deleted file mode 100644
index df745d53022..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/contextMenus/global_context_search/manifest.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "Global Google Search",
- "description": "Use the context menu to search a different country's Google",
- "version": "1.0",
- "manifest_version": 2,
- "options_page": "options.html",
- "permissions": ["contextMenus", "storage"],
- "background": {
- "scripts": [ "locales.js", "background.js"],
- "persistent": false
- },
- "browser_action": {
- "default_popup": "options.html"
- },
- "icons": {
- "16": "globalGoogle16.png",
- "48": "globalGoogle48.png",
- "128": "globalGoogle128.png"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/cookies/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/cookies/manifest.json
deleted file mode 100644
index eb7da26d259..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/cookies/manifest.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "name" : "Cookie API Test Extension",
- "version" : "0.8",
- "description" : "Testing Cookie API",
- "permissions": [ "cookies", "tabs", "http://*/*", "https://*/*" ],
- "icons": { "16": "cookie.png", "48": "cookie.png", "128": "cookie.png" },
- "browser_action": {
- "default_icon": "cookie.png"
- },
- "background": {
- "scripts": ["background.js"]
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/debugger/live-headers/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/debugger/live-headers/manifest.json
deleted file mode 100644
index 19b6554da4b..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/debugger/live-headers/manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "Live HTTP headers",
- "description": "Displays the live log with the http requests headers",
- "version": "0.7",
- "permissions": [
- "debugger"
- ],
- "background": {
- "scripts": ["background.js"]
- },
- "browser_action": {
- "default_icon": "icon.png",
- "default_title": "Live HTTP headers"
- },
- "manifest_version": 2
-}
-
diff --git a/chromium/chrome/common/extensions/docs/examples/api/debugger/pause-resume/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/debugger/pause-resume/manifest.json
deleted file mode 100644
index fdc7e3d6475..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/debugger/pause-resume/manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "JavaScript pause/resume",
- "description": "Pauses / resumes JavaScript execution",
- "version": "0.7",
- "permissions": [
- "debugger"
- ],
- "background": {
- "scripts": ["background.js"]
- },
- "browser_action": {
- "default_icon": "debuggerPause.png",
- "default_title": "Pause JavaScript"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/default_command_override/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/default_command_override/manifest.json
deleted file mode 100644
index 803f2b9c9fd..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/default_command_override/manifest.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "name": "Tab Flipper",
- "description": "Press Ctrl+Shift+Right or Ctrl+Shift+Left (Command+Shift+Right or Command+Shift+Left on a Mac) to flip through window tabs",
- "version": "1.0",
- "manifest_version": 2,
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "browser_action": {
- "default_icon": "images/tabFlipper16.png",
- "default_title": "Press Ctrl(Win)/Command(Mac)+Shift+ Left or Right to Flip Tabs"
- },
- "commands": {
- "flip-tabs-forward": {
- "suggested_key": {
- "default": "Ctrl+Shift+Right",
- "mac": "Command+Shift+Right"
- },
- "description": "Flip tabs forward"
- },
- "flip-tabs-backwards": {
- "suggested_key": {
- "default": "Ctrl+Shift+Left",
- "mac": "Command+Shift+Left"
- },
- "description": "Flip tabs backwards"
- }
- },
- "icons": {
- "16": "images/tabFlipper16.png",
- "32": "images/tabFlipper32.png",
- "48": "images/tabFlipper48.png",
- "128": "images/tabFlipper128.png"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/desktopCapture/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/desktopCapture/manifest.json
deleted file mode 100644
index 6a59859120b..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/desktopCapture/manifest.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjd3VZe2un2t/ju5HGcZrbD862LLhtukwtXeySPzbQaq9zEyFzr+pVd1EeAW7ZPUA86K9/mpWiDycoSMMj9hpm+QQqBnQDrPPtBJfogkFvWsgDQaw6SXZmErTlzz1wukn/0YLQrPLJ7JPj3zGzWcoVj9AhOjQeDpq2E9P3lz85mHwG0RrxgpknP1wGNNkXl/y4WDaWHZyoX1zgcn2r3bzTdb77RWiA9pduXSn6d14GA9B9CdQA4bTDmc9HY1WaVGK0oDX2A2eJEllHqdeBJmpqPqds4cIhm0Gq6lKvxB61I2UZlbCaSIMfTTxBnt+r7NPgpxHBKJIF1xOCpuGtWuc0wIDAQAB",
- "name": "Desktop Capture Example",
- "description": "Show desktop media picker UI",
- "version": "1",
- "manifest_version": 3,
- "icons": {
- "16": "icon.png",
- "128": "icon.png"
- },
- "app": {
- "background": {
- "scripts": ["background.js"]
- }
- },
- "permissions": [
- "desktopCapture"
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/deviceInfo/basic/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/deviceInfo/basic/manifest.json
deleted file mode 100644
index 4d376d84c52..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/deviceInfo/basic/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "My Devices",
- "version": "1.1",
- "description": "A browser action with a popup dump of all devices signed into the same account as the current profile.",
- "permissions": [
- "signedInDevices"
- ],
- "browser_action": {
- "default_title": "My Devices",
- "default_icon": "icon.png",
- "default_popup": "popup.html"
- },
- "manifest_version": 2,
- "content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'"
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/devtools/network/chrome-firephp/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/devtools/network/chrome-firephp/manifest.json
deleted file mode 100644
index 275dced7431..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/devtools/network/chrome-firephp/manifest.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name": "FirePHP for Chrome",
- "version": "1.1",
- "minimum_chrome_version": "10.0",
- "description": "Extends the Developer Tools, adding support for parsing FirePHP messages from server",
- "devtools_page": "devtools.html",
- "background": { "scripts": ["background.js"] },
- "permissions": [
- "http://*/*",
- "https://*/*"
- ],
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/devtools/panels/chrome-query/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/devtools/panels/chrome-query/manifest.json
deleted file mode 100644
index a60485d7fbf..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/devtools/panels/chrome-query/manifest.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": "Chrome Query",
- "version": "1.1",
- "description": "Extends the Developer Tools, adding a sidebar that displays the jQuery data associated with the selected DOM element.",
- "devtools_page": "devtools.html",
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/displaySource/tabCast/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/displaySource/tabCast/manifest.json
deleted file mode 100644
index b3fc8aa1e89..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/displaySource/tabCast/manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "tabCast",
- "version": "0.1",
- "manifest_version": 2,
- "description": "Creates a WiFi Display Session from the captured tab media stream using chrome.displaySource API.",
- "permissions": [
- "tabCapture", "tabs", "displaySource"
- ],
- "browser_action": {
- "default_title": "Tab cast",
- "default_popup": "main.html"
- },
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/document_scan/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/document_scan/manifest.json
deleted file mode 100644
index 8f788d3aa0b..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/document_scan/manifest.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name": "Document Scanning API Sample",
- "version": "0.1",
- "manifest_version": 2,
- "minimum_chrome_version": "37",
- "app": {
- "background": {
- "scripts": ["background.js"]
- }
- },
- "permissions": [],
- "optional_permissions": [ "documentScan" ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/manifest.json
deleted file mode 100644
index 6bdb58ecb65..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_filename_controller/manifest.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{"name": "Download Filename Controller",
- "description": "Download Filename Controller",
- "version": "0.1",
- "background": {"scripts": ["bg.js"], "persistent": false},
- "options_page": "options.html",
- "permissions": ["downloads"],
- "content_security_policy": "script-src 'self'; default-src 'self'",
- "manifest_version": 2}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_links/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/downloads/download_links/manifest.json
deleted file mode 100644
index f252f0decc0..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_links/manifest.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "name": "Download Selected Links",
- "description": "Select links on a page and download them.",
- "version": "0.1",
- "minimum_chrome_version": "16.0.884",
- "permissions": ["downloads", "<all_urls>"],
- "browser_action": {"default_popup": "popup.html"},
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json
deleted file mode 100644
index 83d05e7bf55..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_manager/_locales/en/messages.json
+++ /dev/null
@@ -1,290 +0,0 @@
-{"extName": {
- "message": "Download Manager Button",
- "description": "Extension name"},
- "extDesc": {
- "message": "Browser Action Download Manager User Interface for Google Chrome",
- "description": "Extension description"},
- "badChromeVersion": {
- "message": "The downloads API is only available on the canary, dev, and beta channels.",
- "description": ""},
- "tabTitle": {
- "message": "Downloads",
- "description": "tab title"},
- "searchPlaceholder": {
- "message": "Search Downloads",
- "description": ""},
- "clearAllTitle": {
- "message": "Erase All Visible Downloads",
- "description": ""},
- "openDownloadsFolderTitle": {
- "message": "Open Downloads Folder",
- "description": ""},
- "zeroItems": {
- "message": "There are zero download items.",
- "description": ""},
- "searching": {
- "message": "Teleporting lots of goats...",
- "description": ""},
- "zeroSearchResults": {
- "message": "Zero matches",
- "description": ""},
- "managementPermissionInfo": {
- "message": "Some files were downloaded by an extension.",
- "description": ""},
- "grantManagementPermission": {
- "message": "Show links to extensions that download files.",
- "description": ""},
- "showOlderDownloads": {
- "message": "Show Older Downloads",
- "description": ""},
- "loadingOlderDownloads": {
- "message": "Loading Older Downloads...",
- "description": ""},
- "openTitle": {
- "message": "Open",
- "description": ""},
- "pauseTitle": {
- "message": "Pause",
- "description": ""},
- "resumeTitle": {
- "message": "Resume",
- "description": ""},
- "cancelTitle": {
- "message": "Cancel",
- "description": ""},
- "removeFileTitle": {
- "message": "Remove file",
- "description": ""},
- "eraseTitle": {
- "message": "Erase",
- "description": ""},
- "retryTitle": {
- "message": "Retry",
- "description": ""},
- "referrerTitle": {
- "message": "Referrer",
- "description": ""},
- "month0abbr": {"message": "Jan","description": ""},
- "month1abbr": {"message": "Feb","description": ""},
- "month2abbr": {"message": "Mar","description": ""},
- "month3abbr": {"message": "Apr","description": ""},
- "month4abbr": {"message": "May","description": ""},
- "month5abbr": {"message": "Jun","description": ""},
- "month6abbr": {"message": "Jul","description": ""},
- "month7abbr": {"message": "Aug","description": ""},
- "month8abbr": {"message": "Sep","description": ""},
- "month9abbr": {"message": "Oct","description": ""},
- "month10abbr": {"message": "Nov","description": ""},
- "month11abbr": {"message": "Dec","description": ""},
- "openWhenCompleteFinishing": {
- "message": "Opening in just a moment",
- "description": ""},
- "timeLeftFinishing": {
- "message": "finishing...",
- "description": ""},
- "openWhenCompleteDays": {
- "message": "Opening in $days$d $hours$h",
- "description": "",
- "placeholders": {
- "days": {
- "content": "$1",
- "example": "2"},
- "hours": {
- "content": "$2",
- "example": "23"}}},
- "timeLeftDays": {
- "message": "$days$d $hours$h left",
- "description": "",
- "placeholders": {
- "days": {
- "content": "$1",
- "example": "2"},
- "hours": {
- "content": "$2",
- "example": "23"}}},
- "openWhenCompleteHours": {
- "message": "Opening in $hours$h $mins$m",
- "description": "",
- "placeholders": {
- "hours": {
- "content": "$1",
- "example": "23"},
- "mins": {
- "content": "$2",
- "example": "59"}}},
- "timeLeftHours": {
- "message": "$hours$h $mins$m left",
- "description": "",
- "placeholders": {
- "hours": {
- "content": "$1",
- "example": "23"},
- "mins": {
- "content": "$2",
- "example": "59"}}},
- "openWhenCompleteMinutes": {
- "message": "Opening in $mins$m $sec$s",
- "description": "",
- "placeholders": {
- "mins": {
- "content": "$1",
- "example": "59"},
- "sec": {
- "content": "$2",
- "example": "59"}}},
- "timeLeftMinutes": {
- "message": "$mins$m $sec$s left",
- "description": "",
- "placeholders": {
- "mins": {
- "content": "$1",
- "example": "59"},
- "sec": {
- "content": "$2",
- "example": "59"}}},
- "openWhenCompleteSeconds": {
- "message": "Opening in $sec$s",
- "description": "",
- "placeholders": {
- "sec": {
- "content": "$1",
- "example": "59"}}},
- "timeLeftSeconds": {
- "message": "$sec$s left",
- "description": "",
- "placeholders": {
- "sec": {
- "content": "$1",
- "example": "59"}}},
- "error_FILE_FAILED": {
- "message": "File Failed",
- "description": ""},
- "error_FILE_ACCESS_DENIED": {
- "message": "File-System Access Denied",
- "description": ""},
- "error_FILE_NO_SPACE": {
- "message": "No Space On Disk",
- "description": ""},
- "error_FILE_NAME_TOO_LONG": {
- "message": "Filename Too Long",
- "description": ""},
- "error_FILE_TOO_LARGE": {
- "message": "File Too Large",
- "description": ""},
- "error_FILE_VIRUS_INFECTED": {
- "message": "Virus Infected",
- "description": ""},
- "error_FILE_TRANSIENT_ERROR": {
- "message": "Transient File-System Error",
- "description": ""},
- "error_FILE_BLOCKED": {
- "message": "File Blocked",
- "description": ""},
- "error_FILE_SECURITY_CHECK_FAILED": {
- "message": "Security Check Failed",
- "description": ""},
- "error_FILE_TOO_SHORT": {
- "message": "File Too Short",
- "description": ""},
- "error_NETWORK_FAILED": {
- "message": "Network Failure",
- "description": ""},
- "error_NETWORK_TIMEOUT": {
- "message": "Network Timeout",
- "description": ""},
- "error_NETWORK_DISCONNECTED": {
- "message": "Network Disconnected",
- "description": ""},
- "error_NETWORK_SERVER_DOWN": {
- "message": "Server Down",
- "description": ""},
- "error_SERVER_FAILED": {
- "message": "Server Failure",
- "description": ""},
- "error_SERVER_NO_RANGE": {
- "message": "Server No Range",
- "description": ""},
- "error_SERVER_PRECONDITION": {
- "message": "Server Precondition Failure",
- "description": ""},
- "error_SERVER_BAD_CONTENT": {
- "message": "Bad Content",
- "description": ""},
- "error_USER_CANCELED": {
- "message": "Cancelled",
- "description": ""},
- "error_USER_SHUTDOWN": {
- "message": "Cancelled",
- "description": ""},
- "error_CRASH": {
- "message": "Crash",
- "description": ""},
- "error_1": {
- "message": "File Failed",
- "description": ""},
- "error_2": {
- "message": "File-System Access Denied",
- "description": ""},
- "error_3": {
- "message": "No Space On Disk",
- "description": ""},
- "error_5": {
- "message": "Filename Too Long",
- "description": ""},
- "error_6": {
- "message": "File Too Large",
- "description": ""},
- "error_7": {
- "message": "Virus Infected",
- "description": ""},
- "error_10": {
- "message": "Transient File-System Error",
- "description": ""},
- "error_11": {
- "message": "File Blocked",
- "description": ""},
- "error_12": {
- "message": "Security Check Failed",
- "description": ""},
- "error_13": {
- "message": "File Too Short",
- "description": ""},
- "error_20": {
- "message": "Network Failure",
- "description": ""},
- "error_21": {
- "message": "Network Timeout",
- "description": ""},
- "error_22": {
- "message": "Network Disconnected",
- "description": ""},
- "error_23": {
- "message": "Server Down",
- "description": ""},
- "error_30": {
- "message": "Server Failure",
- "description": ""},
- "error_31": {
- "message": "Server No Range",
- "description": ""},
- "error_32": {
- "message": "Server Precondition Failure",
- "description": ""},
- "error_33": {
- "message": "Bad Content",
- "description": ""},
- "error_40": {
- "message": "Cancelled",
- "description": ""},
- "error_41": {
- "message": "Cancelled",
- "description": ""},
- "error_50": {
- "message": "Crash",
- "description": ""},
- "errorRemoved": {
- "message": "Removed",
- "description": ""},
- "showInFolderTitle": {
- "message": "Show in Folder",
- "description": "Alt text for show in folder icon"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json
deleted file mode 100644
index 156e69c124f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{"name": "__MSG_extName__",
- "version": "0.3",
- "manifest_version": 2,
- "description": "__MSG_extDesc__",
- "icons": {"128": "icon128.png"},
- "browser_action": {
- "default_icon": {
- "19": "icon19.png",
- "38": "icon38.png"},
- "default_title": "__MSG_extName__",
- "default_popup": "popup.html"},
- "background": {"persistent": false, "scripts": ["background.js"]},
- "default_locale": "en",
- "optional_permissions": ["management"],
- "permissions": ["downloads", "downloads.open", "downloads.shelf"]}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_open/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/api/downloads/download_open/_locales/en/messages.json
deleted file mode 100644
index eae1fbe9a55..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_open/_locales/en/messages.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{"extName": {
- "message": "Download and Open Button",
- "description": "Extension name"},
- "extDesc": {
- "message": "Download and Open Context Menu Button",
- "description": "Extension description"},
- "openContextMenuTitle": {
- "message": "Download and Open",
- "description": "context menu button text"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_open/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/downloads/download_open/manifest.json
deleted file mode 100644
index 98a49ab74e4..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/downloads/download_open/manifest.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{"name": "__MSG_extName__",
- "version": "0.1",
- "manifest_version": 2,
- "description": "__MSG_extDesc__",
- "icons": {"16": "icon16.png", "128": "icon128.png"},
- "background": {"persistent": false, "scripts": ["background.js"]},
- "default_locale": "en",
- "permissions": ["contextMenus", "downloads", "downloads.open"]}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/downloads/downloads_overwrite/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/downloads/downloads_overwrite/manifest.json
deleted file mode 100644
index c1f8999dd8d..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/downloads/downloads_overwrite/manifest.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "name": "Downloads Overwrite Existing Files",
- "description": "All downloads overwrite existing files instead of adding ' (1)', ' (2)', etc.",
- "version": "1",
- "minimum_chrome_version": "26.0.1428",
- "background": {
- "scripts": ["bg.js"],
- "persistent": false
- },
- "permissions": [
- "downloads"
- ],
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/eventPage/basic/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/eventPage/basic/manifest.json
deleted file mode 100644
index 7a6e1f43d87..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/eventPage/basic/manifest.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "name": "Event Page Example",
- "description": "Demonstrates usage and features of the event page",
- "version": "1.0",
- "manifest_version": 2,
- "permissions": ["alarms", "tabs", "bookmarks", "declarativeWebRequest", "*://*/*"],
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "browser_action": {
- "default_icon" : "icon.png",
- "default_title": "Start Event Page"
- },
- "commands": {
- "open-google": {
- "description": "Open a tab to google.com",
- "suggested_key": { "default": "Ctrl+Shift+L" }
- },
- "_execute_browser_action": {
- "suggested_key": { "default": "Ctrl+Shift+K" }
- }
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/manifest.json
deleted file mode 100644
index 66241fc37bf..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name" : "`extension.isAllowedFileSchemeAccess` and `extension.isAllowedIncognitoAccess` Example",
- "version" : "1.0.0",
- "description" : "Demonstrates the `extension.isAllowedFileSchemeAccess` and `extesion.isAllowedIncognitoAccess` APIs",
- "permissions" : [ "file://*" ],
- "browser_action" : {
- "default_popup": "popup.html",
- "default_icon" : "sample-19.png"
- },
- "icons" : {
- "16" : "sample-16.png",
- "48" : "sample-48.png",
- "128" : "sample-128.png"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/fileSystemProvider/archive/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/fileSystemProvider/archive/manifest.json
deleted file mode 100644
index 025b5d3b62e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/fileSystemProvider/archive/manifest.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "Fake Archive Handler App",
- "version": "0.1",
- "manifest_version": 2,
- "description": "Demonstrate File System Provider API usage for apps.",
- "permissions": [
- "fileSystemProvider",
- {"fileSystem": ["retainEntries"]},
- "storage"
- ],
- "file_handlers": {
- "fake": {
- "types": ["application/fake"],
- "extensions": ["fake"]
- }
- },
- "file_system_provider_capabilities": {
- "multiple_mounts": true,
- "source": "file"
- },
- "app": {
- "background": {
- "scripts": [
- "background.js"
- ]
- }
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/fileSystemProvider/basic/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/fileSystemProvider/basic/manifest.json
deleted file mode 100644
index fcb281cddf7..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/fileSystemProvider/basic/manifest.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "File System Provider API Extension Example",
- "version": "0.1",
- "manifest_version": 2,
- "description":
- "Demonstrate features of the API like mounting, listing directories, etc for extensions.",
- "permissions": [
- "fileSystemProvider"
- ],
- "file_system_provider_capabilities": {
- "source": "network"
- },
- "background": {
- "scripts": [
- "background.js"
- ]
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/fontSettings/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/fontSettings/manifest.json
deleted file mode 100644
index 2829fecb424..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/fontSettings/manifest.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "Advanced Font Settings",
- "version": "0.67",
- "manifest_version": 2,
- "description": "Customize per-script font settings.",
- "options_page": "options.html",
- "icons": {
- "16": "fonts16.png",
- "128": "fonts128.png"
- },
- "permissions": ["fontSettings"]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/history/historyOverride/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/history/historyOverride/manifest.json
deleted file mode 100644
index bb44e22eed0..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/history/historyOverride/manifest.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "manifest_version": 2,
- "name": "History Override",
- "description": "Overrides the History Page",
- "version": "1.0",
- "chrome_url_overrides" : {
- "history": "history.html"
- },
- "browser_action": {
- "default_title": "History"
- },
- "permissions": [
- "history",
- "chrome://favicon/"
- ],
- "icons": {
- "16": "history16.png",
- "32": "history32.png",
- "48": "history48.png",
- "128": "history128.png"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/history/showHistory/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/history/showHistory/manifest.json
deleted file mode 100644
index b4aa6ffe3bf..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/history/showHistory/manifest.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name": "Typed URL History",
- "version": "1.2",
- "description": "Reads your history, and shows the top ten pages you go to by typing the URL.",
- "permissions": [
- "history"
- ],
- "browser_action": {
- "default_popup": "typedUrls.html",
- "default_icon": "clock.png"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/i18n/cld/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/i18n/cld/manifest.json
deleted file mode 100644
index 4b242cf319f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/i18n/cld/manifest.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "CLD",
- "description": "Displays the language of a tab",
- "version": "0.3",
- "background": {
- "scripts": ["background.js"]
- },
- "browser_action": {
- "default_name": "Page Language"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/i18n/detectLanguage/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/i18n/detectLanguage/manifest.json
deleted file mode 100644
index beceb3305c1..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/i18n/detectLanguage/manifest.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "Detect Language",
- "description": "Detects up to 3 languages and their percentages of the provided string",
- "version": "1.0",
-
- "browser_action": {
- "default_icon": "icon.png",
- "default_popup": "popup.html"
- },
-
- "manifest_version": 2
-} \ No newline at end of file
diff --git a/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/en_US/messages.json b/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/en_US/messages.json
deleted file mode 100644
index b33d2f0a2c1..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/en_US/messages.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "chrome_extension_name": {
- "message": "AcceptLanguage"
- },
- "chrome_extension_description": {
- "message": "Returns accept languages of the browser"
- },
- "click_here": {
- "message": "Left click to list acceptLanguages."
- },
- "browser_action_title": {
- "message": "Click Me"
- },
- "chrome_accept_languages": {
- "message": "$CHROME$ accepts $languages$ languages",
- "placeholders": {
- "chrome": {
- "content": "Chrome",
- "example": "Chrome"
- },
- "languages": {
- "content": "$1",
- "example": "en-US,sr,de"
- }
- }
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/es/messages.json b/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/es/messages.json
deleted file mode 100644
index 0e1a7ef43e0..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/es/messages.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "chrome_extension_name": {
- "message": "AcceptLanguage"
- },
- "chrome_extension_description": {
- "message": "Devuelve los idiomas aceptados por el navegador"
- },
- "click_here": {
- "message": "Click con botón izquierdo para mostrar la lista de acceptLanguages."
- },
- "browser_action_title": {
- "message": "Haz click aquí"
- },
- "chrome_accept_languages": {
- "message": "$CHROME$ acepta los idiomas $languages$",
- "placeholders": {
- "chrome": {
- "content": "Chrome",
- "example": "Chrome"
- },
- "languages": {
- "content": "$1",
- "example": "en-US,sr,de"
- }
- }
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/sr/messages.json b/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/sr/messages.json
deleted file mode 100644
index 30bd958eedd..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/_locales/sr/messages.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "chrome_extension_name": {
- "message": "Прихватљиви језици"
- },
- "chrome_extension_description": {
- "message": "Језици које прегледач прихвата"
- },
- "click_here": {
- "message": "Кликните да излистате дозвољене језике."
- },
- "chrome_accept_languages": {
- "message": "$CHROME$ прихвата $languages$ језике.",
- "placeholders": {
- "chrome": {
- "content": "Chrome",
- "example": "Chrome"
- },
- "languages": {
- "content": "$1",
- "example": "en-US,sr,de"
- }
- }
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/manifest.json
deleted file mode 100644
index 52997f29891..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/i18n/getMessage/manifest.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "__MSG_chrome_extension_name__",
- "description": "__MSG_chrome_extension_description__",
- "version": "0.2",
- "default_locale": "en_US",
- "browser_action": {
- "default_title": "__MSG_browser_action_title__",
- "default_icon": "icon.png",
- "default_popup": "popup.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/_locales/de/messages.json b/chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/_locales/de/messages.json
deleted file mode 100644
index 0d8e2f7757c..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/_locales/de/messages.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "application_title": {
- "message": "Eine lokalisierte gehostete Beispielanwendung"
- },
- "application_description": {
- "message": "Hier steht eine Beschreibung der Applikation, die im Web Store auftauchen wird."
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/_locales/en/messages.json
deleted file mode 100644
index ed87abfbf9c..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/_locales/en/messages.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "application_title": {
- "message": "Minimal Localized Hosted App",
- "description": "The title of the application, displayed in the web store."
- },
- "application_description": {
- "message": "This is the minimal set of data required to upload a localized hosted application to the web store.",
- "description": "The description of the application, displayed in the web store."
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/manifest.json
deleted file mode 100644
index 9cb94fd72db..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/i18n/localizedHostedApp/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "__MSG_application_title__",
- "description": "__MSG_application_description__",
- "version": "0.2",
- "default_locale": "en",
- "app": {
- "launch": {
- "web_url": "http://example.com/"
- }
- },
- "icons": {
- "128": "icon128.png"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/idle/idle_simple/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/idle/idle_simple/manifest.json
deleted file mode 100644
index b6fba2a4d6b..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/idle/idle_simple/manifest.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name" : "Idle - Simple Example",
- "version" : "1.0.1",
- "description" : "Demonstrates the Idle API",
- "background" : {
- "scripts": ["background.js"]
- },
- "permissions" : [ "idle" ],
- "browser_action" : {
- "default_icon" : "sample-19.png"
- },
- "icons" : {
- "16" : "sample-16.png",
- "48" : "sample-48.png",
- "128" : "sample-128.png"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/input.ime/basic/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/input.ime/basic/manifest.json
deleted file mode 100644
index e21aec11562..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/input.ime/basic/manifest.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "Test IME",
- "version": "1.0",
- "manifest_version": 2,
- "description": "A simple IME that converts all keystrokes to upper case.",
- "background": {
- "scripts": ["main.js"]
- },
- "permissions": [
- "input"
- ],
- "input_components": [
- {
- "name": "Test IME",
- "type": "ime",
- "id": "test",
- "description": "Test IME", // A user visible description
- "language": "en-US", // The primary language this IME is used for
- "layouts": ["us::eng"] // The supported keyboard layouts for this IME
- }
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/messaging/timer/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/messaging/timer/manifest.json
deleted file mode 100644
index 76d6907a3b1..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/messaging/timer/manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "Message Timer",
- "version": "1.3",
- "description": "Times how long it takes to send a message to a content script and back.",
- "content_scripts": [
- {
- "matches": ["http://*/*", "https://*/*"],
- "js": ["page.js"]
- }
- ],
- "browser_action": {
- "default_title": "Time to current page",
- "default_icon": "clock.png",
- "default_popup": "popup.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/app/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/app/manifest.json
deleted file mode 100644
index a339e11dade..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/app/manifest.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- // Extension ID: knldjmfmopnpolahpmmgbagdohdnhkik
- "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcBHwzDvyBQ6bDppkIs9MP4ksKqCMyXQ/A52JivHZKh4YO/9vJsT3oaYhSpDCE9RPocOEQvwsHsFReW2nUEc6OLLyoCFFxIb7KkLGsmfakkut/fFdNJYh0xOTbSN8YvLWcqph09XAY2Y/f0AL7vfO1cuCqtkMt8hFrBGWxDdf9CQIDAQAB",
- "name": "Native Messaging Example",
- "version": "1.0",
- "manifest_version": 2,
- "description": "Send a message to a native application.",
- "app": {
- "launch": {
- "local_path": "main.html"
- }
- },
- "icons": {
- "128": "icon-128.png"
- },
- "permissions": [
- "nativeMessaging"
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/host/com.google.chrome.example.echo-win.json b/chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/host/com.google.chrome.example.echo-win.json
deleted file mode 100644
index 84e544847dd..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/host/com.google.chrome.example.echo-win.json
+++ /dev/null
@@ -1,13 +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.
-
-{
- "name": "com.google.chrome.example.echo",
- "description": "Chrome Native Messaging API Example Host",
- "path": "native-messaging-example-host.bat",
- "type": "stdio",
- "allowed_origins": [
- "chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/host/com.google.chrome.example.echo.json b/chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/host/com.google.chrome.example.echo.json
deleted file mode 100644
index dfeae04f627..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/nativeMessaging/host/com.google.chrome.example.echo.json
+++ /dev/null
@@ -1,13 +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.
-
-{
- "name": "com.google.chrome.example.echo",
- "description": "Chrome Native Messaging API Example Host",
- "path": "HOST_PATH",
- "type": "stdio",
- "allowed_origins": [
- "chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/notifications/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/notifications/manifest.json
deleted file mode 100644
index 1f77d635210..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/notifications/manifest.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "Notification Demo",
- "version": "1.1",
- "description":
- "Shows off desktop notifications, which are \"toast\" windows that pop up on the desktop.",
- "icons": {"16": "16.png", "48": "48.png", "128": "128.png"},
- "permissions": [
- "notifications"
- ],
- "options_page": "options.html",
- "background": { "scripts": ["background.js"] },
- "manifest_version": 2,
-
- // crbug.com/134315
- "web_accessible_resources": [
- "48.png"
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/omnibox/newtab_search/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/omnibox/newtab_search/manifest.json
deleted file mode 100644
index 5d1c2ffbd4f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/omnibox/newtab_search/manifest.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "name": "Omnibox New Tab Search",
- "description": "Type 'nt' plus a search term into the Omnibox to open search in new tab.",
- "version": "1.0",
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "omnibox": { "keyword" : "nt" },
- "manifest_version": 2,
- "browser_action": {
- "default_icon": {
- "16": "newtab_search16.png",
- "32": "newtab_search32.png"
- }
- },
- "icons": {
- "16": "newtab_search16.png",
- "32": "newtab_search32.png",
- "48": "newtab_search48.png",
- "128": "newtab_search128.png"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/omnibox/simple-example/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/omnibox/simple-example/manifest.json
deleted file mode 100644
index eafc95a7ee3..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/omnibox/simple-example/manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name": "Omnibox Example",
- "description" : "To use, type 'omnix' plus a search term into the Omnibox.",
- "version": "1.1",
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "omnibox": { "keyword" : "omnix" },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/override/blank_ntp/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/override/blank_ntp/manifest.json
deleted file mode 100644
index 9efcc231540..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/override/blank_ntp/manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "Blank new tab page",
- "description": "Override the new tab page with a blank one",
- "version": "0.2",
- "incognito": "split",
- "chrome_url_overrides": {
- "newtab": "blank.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/override/override_igoogle/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/override/override_igoogle/manifest.json
deleted file mode 100644
index 927faa3c1d6..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/override/override_igoogle/manifest.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "name": "iGoogle new tab page",
- "description": "Override the new tab page with iGoogle",
- "version": "0.2",
- "chrome_url_overrides": {
- "newtab": "redirect.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/pageAction/pageaction_by_content/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/pageAction/pageaction_by_content/manifest.json
deleted file mode 100644
index 79134a72efa..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/pageAction/pageaction_by_content/manifest.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name" : "Page action by content",
- "version" : "1.1",
- "description" : "Shows a page action for HTML pages containing a video",
- "background" : {
- "scripts": ["background.js"],
- "persistent": false
- },
- "page_action" :
- {
- "default_icon" : "video-19.png",
- "default_title" : "There's a <video> in this page!"
- },
- "permissions": [ "declarativeContent" ],
- "icons" : {
- "48" : "video-48.png",
- "128" : "video-128.png"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/pageAction/pageaction_by_url/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/pageAction/pageaction_by_url/manifest.json
deleted file mode 100644
index 5c20902fd4e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/pageAction/pageaction_by_url/manifest.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "Page action by URL",
- "version": "1.0",
- "description": "Shows a page action for urls which have the letter 'g' in them.",
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "page_action" :
- {
- "default_icon" : "icon-19.png",
- "default_title" : "There's a 'G' in this URL!"
- },
- "permissions" : [
- "declarativeContent"
- ],
- "icons" : {
- "48" : "icon-48.png",
- "128" : "icon-128.png"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/pageAction/set_icon/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/pageAction/set_icon/manifest.json
deleted file mode 100644
index 115b8d0124a..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/pageAction/set_icon/manifest.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "Animated Page Action",
- "description": "This extension adds an animated browser action to the toolbar.",
- "version": "1.2",
- "background": {
- "page": "background.html"
- },
- "page_action": {
- "default_title": "First icon"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/permissions/extension-questions/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/permissions/extension-questions/manifest.json
deleted file mode 100644
index 2d8647edc30..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/permissions/extension-questions/manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "Top Chrome Extension Questions",
- "version": "0.3",
- "description": "Sample demonstration of the optional permissions API.",
- "icons": {
- "128": "images/icon.png",
- "48": "images/icon.png",
- "16": "images/icon.png"
- },
- "browser_action": {
- "default_icon": "images/icon.png",
- "default_popup": "popup.html"
- },
- "options_page": "options.html",
- "optional_permissions": ["http://api.stackoverflow.com/"],
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/power/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/api/power/_locales/en/messages.json
deleted file mode 100644
index ef50944de10..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/power/_locales/en/messages.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "extensionName": {
- "message": "Keep Awake",
- "description": "Extension name."
- },
- "extensionDescription": {
- "message": "Override system power-saving settings.",
- "description": "Extension description."
- },
- "disabledTitle": {
- "message": "Default power-saving settings",
- "description": "Browser action title when disabled."
- },
- "displayTitle": {
- "message": "Screen will be kept on",
- "description": "Browser action title when preventing screen-off."
- },
- "systemTitle": {
- "message": "System will stay awake",
- "description": "Browser action title when preventing system sleep."
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/power/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/power/manifest.json
deleted file mode 100644
index dd90842bd1c..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/power/manifest.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "manifest_version": 2,
-
- "name": "__MSG_extensionName__",
- "description": "__MSG_extensionDescription__",
- "version": "1.9",
- "icons": {
- "16": "images/icon-16.png",
- "48": "images/icon-48.png",
- "128": "images/icon-128.png"
- },
-
- "permissions": [
- "power",
- "storage"
- ],
- "browser_action": {
- "default_title": "__MSG_disabledTitle__",
- "default_icon": {
- "19": "images/night-19.png",
- "38": "images/night-38.png"
- }
- },
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
-
- "default_locale": "en"
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/preferences/allowThirdPartyCookies/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/preferences/allowThirdPartyCookies/manifest.json
deleted file mode 100644
index 25114067490..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/preferences/allowThirdPartyCookies/manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name" : "Block/allow third-party cookies API example extension",
- "version" : "0.1",
- "description" : "Sample extension which demonstrates how to access a preference.",
- "permissions": [ "privacy" ],
- "browser_action": {
- "default_icon": "advicedog.jpg",
- "default_popup": "popup.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json
deleted file mode 100644
index c72e8959829..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name" : "Block/allow referrer API example extension",
- "version" : "0.1",
- "description" : "Sample extension which demonstrates how to access a preference.",
- "permissions": [ "privacy" ],
- "browser_action": {
- "default_icon": "advicedog.jpg",
- "default_popup": "popup.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/processes/process_monitor/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/processes/process_monitor/manifest.json
deleted file mode 100644
index 2c1836a6f4a..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/processes/process_monitor/manifest.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "name": "Process Monitor",
- "version": "1.2",
- "description": "Adds a browser action that monitors resource usage of all browser processes.",
- "permissions": [
- "processes"
- ],
- "browser_action": {
- "default_title": "Process Monitor",
- "default_icon": "icon.png",
- "default_popup": "popup.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/processes/show_tabs/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/processes/show_tabs/manifest.json
deleted file mode 100644
index bdbdb1e2254..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/processes/show_tabs/manifest.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "name": "Show Tabs in Process",
- "version": "1.0",
- "description": "Adds a browser action showing which tabs share the current tab's process.",
- "permissions": [
- "processes", "tabs", "chrome://favicon/*"
- ],
- "browser_action": {
- "default_title": "Show Tabs in this Process",
- "default_icon": "icon.png",
- "default_popup": "popup.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/storage/stylizr/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/storage/stylizr/manifest.json
deleted file mode 100644
index 1c0b9cebf0d..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/storage/stylizr/manifest.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "Stylizr",
- "description": "Spruce up your pages with custom CSS.",
- "version": "1.0",
-
- "permissions": [
- "activeTab",
- "storage"
- ],
-
- "options_page": "options.html",
-
- "browser_action": {
- "default_icon": "icon.png",
- "default_title": "Stylize!",
- "default_popup": "popup.html"
- },
-
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/tabCapture/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/tabCapture/manifest.json
deleted file mode 100644
index 777e1e256e3..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/tabCapture/manifest.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "Tab Capture Example",
- "description": "Capture a tab and play in a <video> element in a separate tab.",
- "version": "1",
- "manifest_version": 2,
- "background": {
- "scripts": ["eventPage.js"],
- "persistent": false
- },
- "browser_action": {
- "default_icon": "icon.png"
- },
- "options_ui": {
- "page": "options.html",
- "open_in_tab": false
- },
- "permissions": [
- "storage",
- "tabs",
- "tabCapture"
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/tabs/inspector/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/tabs/inspector/manifest.json
deleted file mode 100644
index 68b7728ec3f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/tabs/inspector/manifest.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "name": "Tab Inspector",
- "description": "Utility for working with the extension tabs api",
- "version": "0.3",
- "permissions": ["tabs"],
- "background": {
- "persistent": false,
- "scripts": ["background.js"]
- },
- "browser_action": {
- "default_title": "show tab inspector"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/tabs/pin/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/tabs/pin/manifest.json
deleted file mode 100644
index 3154c8c9368..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/tabs/pin/manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name": "Keyboard Pin",
- "version": "0.3",
- "description": "Creates a keyboard shortcut (Alt + Shift + P) to toggle the pinned state of the currently selected tab",
- "background": {
- "persistent": false,
- "scripts": ["background.js"]
- },
- "commands": {
- "toggle-pin": {
- "suggested_key": { "default": "Alt+Shift+P" },
- "description": "Toggle tab pin"
- }
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/tabs/screenshot/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/tabs/screenshot/manifest.json
deleted file mode 100644
index 2fae69d1e5e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/tabs/screenshot/manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "Test Screenshot Extension",
- "version": "1.3",
- "description": "Demonstrate screenshot functionality in the chrome.tabs api.",
- "background": {
- "persistent": false,
- "scripts": ["background.js"]
- },
- "browser_action": {
- "default_icon": "camera.png",
- "default_title": "Take a screen shot!"
- },
- "permissions": [
- "activeTab"
- ],
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/tabs/zoom/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/tabs/zoom/manifest.json
deleted file mode 100644
index 51db85b6d40..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/tabs/zoom/manifest.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "manifest_version": 2,
-
- "name": "Tabs Zoom API Demo",
- "description": "This extension allows the user to explore features of the new tabs zoom api.",
-
- "version": "0.1",
-
- "icons": {
- "16": "zoom16.png",
- "48": "zoom48.png"
- },
-
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
-
- "browser_action": {
- "default_icon": "zoom19.png",
- "default_title": "Zoom Extension Demo",
- "default_popup": "popup.html"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/topsites/basic/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/topsites/basic/manifest.json
deleted file mode 100644
index c042c095a4e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/topsites/basic/manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name": "Top Sites",
- "version": "1.2",
- "description": "Shows the top sites in a browser action",
- "permissions": ["topSites"],
- "browser_action": {
- "default_icon": "icon.png",
- "default_popup": "popup.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/topsites/magic8ball/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/topsites/magic8ball/manifest.json
deleted file mode 100644
index 84f12ac5aae..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/topsites/magic8ball/manifest.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name": "NTP prototyping extension",
- "version": "1.1",
- "description": "extension to prototype new NTP designs",
- "chrome_url_overrides" : {
- "newtab": "newTab.html"
- },
- "permissions": [
- "topSites",
- "chrome://favicon/"
- ],
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/ttsEngine/console_tts_engine/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/ttsEngine/console_tts_engine/manifest.json
deleted file mode 100644
index 35be832ec8f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/ttsEngine/console_tts_engine/manifest.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "Console TTS Engine",
- "manifest_version": 2,
- "version": "2.1",
- "description": "A \"silent\" TTS engine that prints text to a small window rather than synthesizing speech.",
- "permissions": ["ttsEngine", "tabs"],
- "background": {
- "persistent": false,
- "scripts": ["console_tts_engine.js"]
- },
- "tts_engine": {
- "voices": [
- {
- "voice_name": "Console",
- "event_types": ["start", "word", "sentence", "end"]
- }
- ]
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/water_alarm_notification/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/water_alarm_notification/manifest.json
deleted file mode 100644
index a4832da210f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/water_alarm_notification/manifest.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "name": "Drink Water Event Popup",
- "description": "Demonstrates usage and features of the event page by reminding user to drink water",
- "version": "1.0",
- "manifest_version": 2,
- "permissions": ["alarms", "notifications", "storage"],
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "browser_action": {
- "default_title": "Drink Water Event",
- "default_popup": "popup.html"
- },
- "icons": {
- "16": "drink_water16.png",
- "32": "drink_water32.png",
- "48": "drink_water48.png",
- "128": "drink_water128.png"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json
deleted file mode 100644
index e639880d7c4..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "extName": {
- "message": "WebNavigation Tech Demo",
- "description": "The extension name."
- },
- "extDescription": {
- "message": "Demonstration of the WebNavigation extension API.",
- "description": "The extension description."
- },
-
- "navigationDescription": {
- "message": ", requested $NUM$ times. Loaded in an average of $LOAD$ miliseconds.",
- "description": "The message posted in the popup for each stored navigation.",
- "placeholders": {
- "NUM": {
- "content": "$1",
- "example": "4 (The number of times this URL was accessed.)"
- },
- "LOAD": {
- "content": "$2",
- "example": "12.345 (The average load time in miliseconds.)"
- }
- }
- },
-
- "inHandler": {
- "message": "In webNavigation[`%s`] handler: %o",
- "description": "Notification displayed for each webNavigation event."
- },
-
- "inHandlerError": {
- "message": "In webNavigation[`%s`] handler: No data!",
- "description": "Notification displayed in a webNavigation event handler without data!"
- },
-
- "errorCommittedWithoutPending": {
- "message": "Wha? `onCommitted` for `%s` called, though it's not pending: %o",
- "description": "Error logged when `onCommitted` is triggered on a non-pending request."
- },
- "errorCompletedWithoutPending": {
- "message": "Wha? `onCompleted` for `%s` called, though it's not pending: %o",
- "description": "Error logged when `onCompleted` is triggered on a non-pending request."
- },
- "errorErrorOccurredWithoutPending": {
- "message": "Wha? `onErrorOccurred` for `%s` called, though it's not pending: %o",
- "description": "Error logged when `onErrorOccurred` is triggered on a non-pending request."
- },
- "errorCommittedWithoutPending": {
- "message": "Wha? `onCompleted` for `%s` called, though it's not pending: %o",
- "description": "Error logged when `onCompleted` is triggered on a non-pending request."
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json
deleted file mode 100644
index 2c0d43519dc..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "__MSG_extName__",
- "version": "0.2",
- "description": "__MSG_extDescription__",
- "default_locale": "en",
- "background": {
- "persistent": false,
- "scripts": ["navigation_collector.js", "background.js"]
- },
- "browser_action": {
- "default_icon": "icon.png",
- "default_popup": "popup.html"
- },
- "permissions": [
- "webNavigation", "storage"
- ],
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/webview/capturevisibleregion/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/webview/capturevisibleregion/manifest.json
deleted file mode 100644
index 6b27ec4102f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/webview/capturevisibleregion/manifest.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "manifest_version": 2,
- "name": "Webview transparency",
- "description": "Sample of the webview.captureVisibleRegion api",
- "version": "1",
- "app": {
- "background": {
- "scripts": ["main.js"]
- }
- },
- "permissions": [
- "webview"
- ],
- "webview": {
- "partitions": [
- {
- "name": "partition",
- "accessible_resources": [ "test2.html" ]
- }
- ]
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/webview/comm_demo_app/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/webview/comm_demo_app/manifest.json
deleted file mode 100644
index 340d590139a..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/webview/comm_demo_app/manifest.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "manifest_version": 2,
- "name": "WebView Extension Communications Demo: App",
- "version": "1",
- "app": {
- "background": {
- "scripts": ["main.js"]
- }
- },
- "permissions": ["webview"],
- "webview": {
- "partitions": [
- {
- "name": "partition",
- "accessible_resources": [""]
- }
- ]
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/webview/comm_demo_ext/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/webview/comm_demo_ext/manifest.json
deleted file mode 100644
index 0869009b022..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/webview/comm_demo_ext/manifest.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "manifest_version": 2,
-
- "name": "WebView Extension Communications Demo: Extension",
- "description": "Provides content scripts to an app hosting a WebView.",
- "version": "1.0",
-
- "background": {
- "scripts": ["background.js"]
- },
- "permissions": [
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/api/windows/merge_windows/manifest.json b/chromium/chrome/common/extensions/docs/examples/api/windows/merge_windows/manifest.json
deleted file mode 100644
index b5b51737667..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/api/windows/merge_windows/manifest.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "Merge Windows",
- "version": "1.0.2",
- "description": "Merges all of the browser's windows into the current window",
- "icons": {
- "48": "merge_windows_48.png",
- "128": "merge_windows_128.png"
- },
- "background": {
- "persistent": false,
- "scripts": ["background.js"]
- },
- "browser_action": {
- "default_icon": "arrow_in.png",
- "default_title": "Merge Windows"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/apps/background-simple/manifest.json b/chromium/chrome/common/extensions/docs/examples/apps/background-simple/manifest.json
deleted file mode 100644
index 086138459e6..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/apps/background-simple/manifest.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "Simple Background App",
- "version": "0.2",
- "app": {
- "urls": [ "http://SOME_SITE_WITHOUT_PORT_NUMBERS/SOME_PATH/" ],
- "launch": {
- "web_url": "http://SOME_SITE/SOME_PATH/index.html"
- }
- },
- "permissions": ["background", "notifications"],
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/apps/calculator/app/manifest.json b/chromium/chrome/common/extensions/docs/examples/apps/calculator/app/manifest.json
deleted file mode 100644
index 09b249e0d8c..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/apps/calculator/app/manifest.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "Calculator",
- "description": "A simple calculator.",
- "manifest_version": 2,
- "minimum_chrome_version": "23",
- "version": "1.3.3",
- "app": {"background": {"scripts": ["model.js", "view.js", "controller.js"]}},
- "icons": {
- "16": "images/icon-16x16.png",
- "128": "images/icon-128x128.png"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/app_launcher/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/app_launcher/manifest.json
deleted file mode 100644
index 78e0c92406e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/app_launcher/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "App Launcher",
- "description": "Get access to your apps in a browser action",
- "version": "0.7.3",
- "permissions": ["management"],
- "browser_action": {
- "default_icon": "browser_action_icon.png",
- "default_title": "App Launcher",
- "default_popup": "popup.html"
- },
- "icons": {
- "48": "icon.png"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/buildbot/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/buildbot/manifest.json
deleted file mode 100644
index 0d86bcb620b..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/buildbot/manifest.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "name": "Chromium Buildbot Monitor",
- "version": "0.9.0",
- "description": "Displays the status of the Chromium buildbot in the toolbar. Click to see more detailed status in a popup.",
- "icons": { "128": "icon.png" },
- "background": {
- "scripts": ["utils.js",
- "prefs.js",
- "try_status.js",
- "active_issues.js",
- "bg.js"]
- },
- "permissions": [
- "notifications",
- "storage",
- "http://build.chromium.org/",
- "http://chromium-status.appspot.com/",
- "https://codereview.chromium.org/"
- ],
- "browser_action": {
- "default_title": "",
- "default_icon": "chromium.png",
- "default_popup": "popup.html"
- },
- "options_page": "options.html",
- "options_ui": {
- "chrome_style": true,
- "page": "options.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ar/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ar/messages.json
deleted file mode 100644
index 3fd46a01d4d..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ar/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (\u062a\u062f\u0639\u0645\u0647\u0627 Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"\u064a\u0645\u0643\u0646\u0643 \u0628\u0633\u0631\u0639\u0629 \u0627\u0644\u062a\u0639\u0631\u0641 \u0639\u0644\u0649 \u0627\u0644\u0648\u0642\u062a \u0627\u0644\u0645\u062a\u0628\u0642\u064a \u0644\u0643 \u0625\u0644\u0649 \u0623\u0646 \u064a\u062d\u064a\u0646 \u0645\u0648\u0639\u062f \u0627\u062c\u062a\u0645\u0627\u0639\u0643 \u0627\u0644\u062a\u0627\u0644\u064a \u0645\u0646 \u0623\u064a \u062a\u0642\u0648\u064a\u0645 \u0645\u0646 \u062a\u0642\u0627\u0648\u064a\u0645\u0643. \u0627\u0646\u0642\u0631 \u0639\u0644\u0649 \u0627\u0644\u0632\u0631 \u0644\u064a\u062a\u0645 \u0646\u0642\u0644\u0643 \u0625\u0644\u0649 \u0627\u0644\u062a\u0642\u0648\u064a\u0645."},"direction":{"message":"rtl"},"notitle":{"message":"(\u0644\u064a\u0633 \u0647\u0646\u0627\u0643 \u0623\u064a \u0639\u0646\u0648\u0627\u0646)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 \u062f\u0642\u064a\u0642\u0629","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 \u0633\u0627\u0639\u0629","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 \u064a\u0648\u0645","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\u062f\u0639\u0645 \u0645\u062a\u0639\u062f\u062f \u0644\u0644\u062a\u0642\u0648\u064a\u0645"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u062a\u0645 \u062d\u0641\u0638 \u0627\u0644\u0625\u0639\u062f\u0627\u062f\u0627\u062a."},"status_saving":{"message":"\u062c\u0627\u0631\u0650 \u0627\u0644\u062d\u0641\u0638..."},"multicalendartooltip":{"message":"\u0627\u0644\u0631\u062c\u0627\u0621 \u062a\u062d\u062f\u064a\u062f \u0627\u0644\u0645\u0631\u0628\u0639 \u0644\u062a\u0645\u0643\u064a\u0646 \u0627\u0644\u062f\u0639\u0645 \u0627\u0644\u0645\u062a\u0639\u062f\u062f \u0644\u0644\u062a\u0642\u0648\u064a\u0645."},"imagetooltip":{"message":"\u062a\u0642\u0648\u064a\u0645 Google"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/bg/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/bg/messages.json
deleted file mode 100644
index e7dc1a674d5..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/bg/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (by Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"\u0412\u0438\u0436\u0442\u0435 \u0431\u044a\u0440\u0437\u043e \u043a\u043e\u043b\u043a\u043e \u0432\u0440\u0435\u043c\u0435 \u0432\u0438 \u043e\u0441\u0442\u0430\u0432\u0430 \u0434\u043e \u0441\u043b\u0435\u0434\u0432\u0430\u0449\u0430\u0442\u0430 \u0432\u0438 \u0441\u0440\u0435\u0449\u0430 \u043e\u0442 \u0432\u0441\u0435\u043a\u0438 \u0441\u0432\u043e\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440. \u041a\u043b\u0438\u043a\u043d\u0435\u0442\u0435 \u0432\u044a\u0440\u0445\u0443 \u0431\u0443\u0442\u043e\u043d\u0430, \u0437\u0430 \u0434\u0430 \u0433\u043e \u043e\u0442\u0432\u043e\u0440\u0438\u0442\u0435."},"direction":{"message":"ltr"},"notitle":{"message":"(\u0411\u0435\u0437 \u0437\u0430\u0433\u043b\u0430\u0432\u0438\u0435)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 \u043c","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 \u0447","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 \u0434","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\u041f\u043e\u0434\u0434\u0440\u044a\u0436\u043a\u0430 \u043d\u0430 \u043d\u044f\u043a\u043e\u043b\u043a\u043e \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0430"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435 \u0441\u0430 \u0437\u0430\u043f\u0430\u0437\u0435\u043d\u0438."},"status_saving":{"message":"\u0417\u0430\u043f\u0430\u0437\u0432\u0430 \u0441\u0435...."},"multicalendartooltip":{"message":"\u041c\u043e\u043b\u044f, \u043f\u043e\u0441\u0442\u0430\u0432\u0435\u0442\u0435 \u043e\u0442\u043c\u0435\u0442\u043a\u0430 \u0432 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0447\u0435\u0442\u043e, \u0437\u0430 \u0434\u0430 \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u0430\u0442\u0435 \u043f\u043e\u0434\u0434\u0440\u044a\u0436\u043a\u0430\u0442\u0430 \u043d\u0430 \u043d\u044f\u043a\u043e\u043b\u043a\u043e \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0430"},"imagetooltip":{"message":"Google \u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ca/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ca/messages.json
deleted file mode 100644
index b0ab0c644da..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ca/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (de Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Comproveu r\u00e0pidament el temps que falta per a la propera reuni\u00f3 a qualsevol dels vostres calendaris. Feu clic al bot\u00f3 per anar-hi."},"direction":{"message":"ltr"},"notitle":{"message":"(Sense t\u00edtol)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 min","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 dies","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Compatibilitat amb m\u00faltiples calendaris"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"S'ha desat la configuraci\u00f3."},"status_saving":{"message":"S'est\u00e0 desant..."},"multicalendartooltip":{"message":"Activeu la casella per activar la compatibilitat amb m\u00faltiples calendaris"},"imagetooltip":{"message":"Google Calendar"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/cs/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/cs/messages.json
deleted file mode 100644
index 6e31a42ee17..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/cs/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Kontrola Kalend\u00e1\u0159e Google (od spole\u010dnosti Google)"},"title":{"message":"Kontrola Kalend\u00e1\u0159e Google"},"description":{"message":"Umo\u017e\u0148uje rychle zobrazit \u010das, kter\u00fd zb\u00fdv\u00e1 do dal\u0161\u00ed sch\u016fzky napl\u00e1novan\u00e9 v kter\u00e9mkoli z va\u0161ich kalend\u00e1\u0159\u016f. Kliknut\u00edm na tla\u010d\u00edtko p\u0159ejdete do kalend\u00e1\u0159e."},"direction":{"message":"ltr"},"notitle":{"message":"(Bez n\u00e1zvu)"},"optionstitle":{"message":"Kontrola Kalend\u00e1\u0159e Google"},"minutes":{"message":"$1 min","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Podpora n\u011bkolika kalend\u00e1\u0159\u016f"},"extensionname":{"message":"Kontrola Kalend\u00e1\u0159e Google"},"status_saved":{"message":"Nastaven\u00ed byla ulo\u017eena."},"status_saving":{"message":"Ukl\u00e1d\u00e1n\u00ed...."},"multicalendartooltip":{"message":"Za\u0161krtnut\u00edm pol\u00ed\u010dka pros\u00edm povolte podporu v\u00edce kalend\u00e1\u0159\u016f"},"imagetooltip":{"message":"Kalend\u00e1\u0159 Google"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/da/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/da/messages.json
deleted file mode 100644
index 209b6d90568..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/da/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (fra Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Tjek hurtigt hvor lang tid der er til n\u00e6ste m\u00f8de i en af dine kalendre. Klik p\u00e5 knappen for at \u00e5bne din kalender."},"direction":{"message":"ltr"},"notitle":{"message":"(Ingen titel)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 t","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Support til flere kalendere"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Indstillingerne er gemt."},"status_saving":{"message":"Gemmer..."},"multicalendartooltip":{"message":"S\u00e6t kryds i feltet for at aktivere support til flere kalendere"},"imagetooltip":{"message":"Google Kalender"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/de/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/de/messages.json
deleted file mode 100644
index 3892f3975a2..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/de/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Werfen Sie schnell einen Blick auf die verbleibende Zeit bis zum n\u00e4chsten Termin in einem Ihrer Kalender. Klicken Sie zum \u00d6ffnen Ihres Kalenders auf die Schaltfl\u00e4che."},"direction":{"message":"ltr"},"notitle":{"message":"(Kein Titel)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 Min.","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 Std.","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 Tage","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Unterst\u00fctzung mehrerer Kalender"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Einstellungen gespeichert"},"status_saving":{"message":"Speichern...."},"multicalendartooltip":{"message":"Aktivieren Sie das Kontrollk\u00e4stchen, um die Unterst\u00fctzung mehrerer Kalender einzuschalten."},"imagetooltip":{"message":"Google Kalender"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/el/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/el/messages.json
deleted file mode 100644
index 9cd461d443e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/el/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (\u03b1\u03c0\u03cc \u03c4\u03b7\u03bd Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"\u0394\u03b5\u03af\u03c4\u03b5 \u03b3\u03c1\u03ae\u03b3\u03bf\u03c1\u03b1 \u03c0\u03cc\u03c4\u03b5 \u03b5\u03af\u03bd\u03b1\u03b9 \u03b7 \u03b5\u03c0\u03cc\u03bc\u03b5\u03bd\u03b7 \u03c3\u03c5\u03bd\u03ac\u03bd\u03c4\u03b7\u03c3\u03ae \u03c3\u03b1\u03c2 \u03b1\u03c0\u03cc \u03bf\u03c0\u03bf\u03b9\u03bf\u03b4\u03ae\u03c0\u03bf\u03c4\u03b5 \u03b1\u03c0\u03cc \u03c4\u03b1 \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03ac \u03c3\u03b1\u03c2. \u039a\u03ac\u03bd\u03c4\u03b5 \u03ba\u03bb\u03b9\u03ba \u03c3\u03c4\u03bf \u03ba\u03bf\u03c5\u03bc\u03c0\u03af \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03bc\u03b5\u03c4\u03b1\u03c6\u03b5\u03c1\u03b8\u03b5\u03af\u03c4\u03b5 \u03c3\u03c4\u03bf \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03cc \u03c3\u03b1\u03c2."},"direction":{"message":"ltr"},"notitle":{"message":"(\u03a7\u03c9\u03c1\u03af\u03c2 \u03c4\u03af\u03c4\u03bb\u03bf)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1\u03bb","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1\u03c9","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1\u03b7","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\u03a5\u03c0\u03bf\u03c3\u03c4\u03ae\u03c1\u03b9\u03be\u03b7 \u03c0\u03bf\u03bb\u03bb\u03ce\u03bd \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03c9\u03bd"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u039f\u03b9 \u03c1\u03c5\u03b8\u03bc\u03af\u03c3\u03b5\u03b9\u03c2 \u03b1\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03cd\u03c4\u03b7\u03ba\u03b1\u03bd."},"status_saving":{"message":"\u0391\u03c0\u03bf\u03b8\u03ae\u03ba\u03b5\u03c5\u03c3\u03b7...."},"multicalendartooltip":{"message":"\u0395\u03c0\u03b9\u03bb\u03ad\u03be\u03c4\u03b5 \u03c4\u03bf \u03c0\u03bb\u03b1\u03af\u03c3\u03b9\u03bf \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03b5\u03bd\u03b5\u03c1\u03b3\u03bf\u03c0\u03bf\u03b9\u03ae\u03c3\u03b5\u03c4\u03b5 \u03c4\u03b7\u03bd \u03c5\u03c0\u03bf\u03c3\u03c4\u03ae\u03c1\u03b9\u03be\u03b7 \u03c0\u03bf\u03bb\u03bb\u03ce\u03bd \u03b7\u03bc\u03b5\u03c1\u03bf\u03bb\u03bf\u03b3\u03af\u03c9\u03bd"},"imagetooltip":{"message":"\u0397\u03bc\u03b5\u03c1\u03bf\u03bb\u03cc\u03b3\u03b9\u03bf Google"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/en/messages.json
deleted file mode 100644
index 2b19e00a5f3..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/en/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (by Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Quickly see the time until your next meeting from any of your calendars. Click on the button to be taken to your calendar."},"direction":{"message":"ltr"},"notitle":{"message":"(No Title)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Multi Calendar Support"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Settings Saved."},"status_saving":{"message":"Saving...."},"multicalendartooltip":{"message":"Please check the box to enable multiple calendar support"},"imagetooltip":{"message":"Google Calendar"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/en_GB/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/en_GB/messages.json
deleted file mode 100644
index 87ef60e9d36..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/en_GB/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (by Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Quickly see the time until your next meeting from any of your calendars. Click the button to be taken to your calendar."},"direction":{"message":"ltr"},"notitle":{"message":"(No Title)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Multi-Calendar Support"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Settings Saved."},"status_saving":{"message":"Saving...."},"multicalendartooltip":{"message":"Please tick the box to enable multiple calendar support"},"imagetooltip":{"message":"Google Calendar"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/es/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/es/messages.json
deleted file mode 100644
index 03d60100222..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/es/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (de Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Consulta r\u00e1pidamente cu\u00e1nto tiempo falta para tu pr\u00f3xima reuni\u00f3n en cualquiera de tus calendarios. Haz clic en el bot\u00f3n para acceder al calendario."},"direction":{"message":"ltr"},"notitle":{"message":"(Sin t\u00edtulo)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1min","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Compatibilidad con varios calendarios"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Se ha guardado la configuraci\u00f3n."},"status_saving":{"message":"Guardando...."},"multicalendartooltip":{"message":"Selecciona la casilla para habilitar la compatibilidad con varios calendarios"},"imagetooltip":{"message":"Google Calendar"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/es_419/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/es_419/messages.json
deleted file mode 100644
index e7b2536a293..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/es_419/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (de Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"F\u00edjate r\u00e1pidamente cu\u00e1nto tiempo falta para tu pr\u00f3xima reuni\u00f3n en alguno de tus calendarios. Haz clic en el bot\u00f3n para que te lleve hasta tu calendario."},"direction":{"message":"ltr"},"notitle":{"message":"(Sin t\u00edtulo)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1\u00a0m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1\u00a0h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Ayuda de Multi Calendar"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Configuraciones guardadas"},"status_saving":{"message":"Guardando...."},"multicalendartooltip":{"message":"Marca el casillero para habilitar la ayuda del calendario m\u00faltiple."},"imagetooltip":{"message":"Google Calendar"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/et/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/et/messages.json
deleted file mode 100644
index 5828ccd7569..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/et/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Vaadake kiiresti oma j\u00e4rgmise koosolekuni j\u00e4\u00e4nud aega \u00fcksk\u00f5ik millisest oma kalendrist. Kalendrisse minekuks kl\u00f5psake nupul."},"direction":{"message":"ltr"},"notitle":{"message":"(Pealkiri puudub)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 min","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 p\u00e4ev(a)","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Multi-Calendari tugi"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Seaded salvestatud."},"status_saving":{"message":"Salvestamine ..."},"multicalendartooltip":{"message":"Mitme kalendri toe lubamiseks m\u00e4rkige ruut"},"imagetooltip":{"message":"Google'i kalender"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fi/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fi/messages.json
deleted file mode 100644
index ddc20889a7e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fi/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (Googlen tekem\u00e4)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"N\u00e4et nopeasti ajan seuraavaan tapaamiseesi mist\u00e4 tahansa kalenteristasi. Siirryt kalenteriin napsauttamalla painiketta."},"direction":{"message":"ltr"},"notitle":{"message":"(Ei nime\u00e4)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 min","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 t","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 pv","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Useiden kalentereiden tuki"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Asetukset tallennettu."},"status_saving":{"message":"Tallennetaan..."},"multicalendartooltip":{"message":"Ota useiden kalentereiden tuki k\u00e4ytt\u00f6\u00f6n valitsemalla valintaruutu"},"imagetooltip":{"message":"Google-kalenteri"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fil/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fil/messages.json
deleted file mode 100644
index 16cdebaed25..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fil/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (mula sa Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Mabilisang tingnan ang oras hanggang sa iyong susunod na pagpupulong mula sa alinman sa iyong mga kalendaryo. Mag-click sa pindutan upang mapunta sa iyong kalendaryo."},"direction":{"message":"ltr"},"notitle":{"message":"(Walang Pamagat)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1o","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1a","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Suporta sa Maramihang Kalendaryo"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Na-save ang Mga Setting."},"status_saving":{"message":"Sine-save...."},"multicalendartooltip":{"message":"Pakilagyan ng check ang kahon upang paganahin ang suporta sa maramihang kalendaryo"},"imagetooltip":{"message":"Google Calendar"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fr/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fr/messages.json
deleted file mode 100644
index f8e413af922..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/fr/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google\u00a0Calendar Checker (par Google)"},"title":{"message":"Google\u00a0Calendar Checker"},"description":{"message":"V\u00e9rifiez rapidement dans vos agendas le temps qu'il vous reste avant votre prochaine r\u00e9union. Cliquez sur le bouton pour ouvrir l'agenda correspondant."},"direction":{"message":"ltr"},"notitle":{"message":"(Sans titre)"},"optionstitle":{"message":"Google\u00a0Calendar Checker"},"minutes":{"message":"$1\u00a0mn","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1\u00a0h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1\u00a0j","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Prise en charge multi-agendas"},"extensionname":{"message":"Google\u00a0Calendar Checker"},"status_saved":{"message":"Param\u00e8tres enregistr\u00e9s"},"status_saving":{"message":"Enregistrement...."},"multicalendartooltip":{"message":"Cocher la case pour activer la prise en charge multi-agendas"},"imagetooltip":{"message":"Google\u00a0Agenda"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/he/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/he/messages.json
deleted file mode 100644
index 09f16548158..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/he/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (\u05de\u05d0\u05ea Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"\u05e8\u05d0\u05d4 \u05d1\u05de\u05d4\u05d9\u05e8\u05d5\u05ea \u05db\u05de\u05d4 \u05d6\u05de\u05df \u05d9\u05e9 \u05dc\u05da \u05e2\u05d3 \u05d4\u05e4\u05d2\u05d9\u05e9\u05d4 \u05d4\u05d1\u05d0\u05d4 \u05e9\u05dc\u05da \u05de\u05db\u05dc \u05dc\u05d5\u05d7 \u05e9\u05e0\u05d4 \u05e9\u05dc\u05da. \u05dc\u05d7\u05e5 \u05e2\u05dc \u05d4\u05dc\u05d7\u05e6\u05df \u05db\u05d3\u05d9 \u05dc\u05e2\u05d1\u05d5\u05e8 \u05dc\u05dc\u05d5\u05d7 \u05d4\u05e9\u05e0\u05d4 \u05e9\u05dc\u05da."},"direction":{"message":"rtl"},"notitle":{"message":"(\u05dc\u05dc\u05d0 \u05db\u05d5\u05ea\u05e8\u05ea)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1\u05d3'","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1\u05e9'","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1\u05d9'","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\u05ea\u05de\u05d9\u05db\u05d4 \u05d1\u05d9\u05d5\u05de\u05e0\u05d9\u05dd \u05de\u05e8\u05d5\u05d1\u05d9\u05dd"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u05d4\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea \u05e0\u05e9\u05de\u05e8\u05d5."},"status_saving":{"message":"\u05e9\u05d5\u05de\u05e8...."},"multicalendartooltip":{"message":"\u05e1\u05de\u05df \u05d0\u05ea \u05d4\u05ea\u05d9\u05d1\u05d4 \u05db\u05d3\u05d9 \u05dc\u05d4\u05e4\u05d5\u05da \u05d0\u05ea \u05d4\u05ea\u05de\u05d9\u05db\u05d4 \u05d1\u05d9\u05d5\u05de\u05e0\u05d9\u05dd \u05de\u05e8\u05d5\u05d1\u05d9\u05dd \u05dc\u05e4\u05e2\u05d9\u05dc\u05d4"},"imagetooltip":{"message":"\u05d9\u05d5\u05de\u05df Google"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hi/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hi/messages.json
deleted file mode 100644
index 2b19e00a5f3..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hi/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (by Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Quickly see the time until your next meeting from any of your calendars. Click on the button to be taken to your calendar."},"direction":{"message":"ltr"},"notitle":{"message":"(No Title)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Multi Calendar Support"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Settings Saved."},"status_saving":{"message":"Saving...."},"multicalendartooltip":{"message":"Please check the box to enable multiple calendar support"},"imagetooltip":{"message":"Google Calendar"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hr/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hr/messages.json
deleted file mode 100644
index f2ab5e5ce8e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hr/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (od Googlea)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Brzo pogledajte koliko imate vremena do idu\u0107eg sastanka iz svih svojih kalendara. Kliknite gumb koji \u0107e vas odvesti u va\u0161 kalendar."},"direction":{"message":"ltr"},"notitle":{"message":"(Nema naslova)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Podr\u0161ka za vi\u0161e kalendara"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Postavke su spremljene."},"status_saving":{"message":"Spremanje...."},"multicalendartooltip":{"message":"Uklju\u010dite potvrdni okvir za omogu\u0107avanje podr\u0161ke za vi\u0161e kalendara"},"imagetooltip":{"message":"Google Kalendar"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hu/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hu/messages.json
deleted file mode 100644
index 6be01dc6fdb..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/hu/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (a Google-t\u00f3l)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Gyorsan megn\u00e9zheti b\u00e1rmelyik napt\u00e1r\u00e1ban, hogy mennyi ideje van m\u00e9g a k\u00f6vetkez\u0151 tal\u00e1lkoz\u00f3ig. Kattintson a gombra a napt\u00e1r megtekint\u00e9s\u00e9hez."},"direction":{"message":"ltr"},"notitle":{"message":"(Nincs c\u00edm)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1p","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1\u00f3","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1nap","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"T\u00f6bb napt\u00e1r t\u00e1mogat\u00e1sa"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Be\u00e1ll\u00edt\u00e1sok elmentve."},"status_saving":{"message":"Ment\u00e9s..."},"multicalendartooltip":{"message":"K\u00e9rj\u00fck, jel\u00f6lje be a jel\u00f6l\u0151n\u00e9gyzetet t\u00f6bb napt\u00e1r t\u00e1mogat\u00e1s\u00e1nak enged\u00e9lyez\u00e9s\u00e9hez"},"imagetooltip":{"message":"Google Napt\u00e1r"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/id/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/id/messages.json
deleted file mode 100644
index 37056ba89e6..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/id/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Pemeriksa Google Kalender (oleh Google)"},"title":{"message":"Pemeriksa Google Kalender"},"description":{"message":"Lihat waktu dengan cepat sampai pertemuan berikutnya dari kalender apa pun. Klik tombol untuk diarahkan ke kalender Anda."},"direction":{"message":"ltr"},"notitle":{"message":"(Tanpa Judul)"},"optionstitle":{"message":"Pemeriksa Google Kalender"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1j","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Dukungan Multi-Kalender"},"extensionname":{"message":"Pemeriksa Google Kalender"},"status_saved":{"message":"Setelan Disimpan."},"status_saving":{"message":"Menyimpan..."},"multicalendartooltip":{"message":"Harap periksa kotak untuk mengaktifkan dukungan multi-kalender"},"imagetooltip":{"message":"Google Kalender"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/it/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/it/messages.json
deleted file mode 100644
index 90e8dafa8f1..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/it/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (di Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Usa uno dei tuoi calendari per controllare rapidamente quanto manca alla prossima riunione. Fai clic sul pulsante per accedere al calendario."},"direction":{"message":"ltr"},"notitle":{"message":"(Nessun titolo)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 g","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Supporto di pi\u00f9 calendari"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Impostazioni salvate."},"status_saving":{"message":"Salvataggio in corso..."},"multicalendartooltip":{"message":"Seleziona la casella per attivare il supporto di pi\u00f9 calendari"},"imagetooltip":{"message":"Google Calendar"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ja/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ja/messages.json
deleted file mode 100644
index 30cdf0bbbb6..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ja/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker\uff08by Google\uff09"},"title":{"message":"Google Calendar Checker"},"description":{"message":"\u3069\u306e\u30ab\u30ec\u30f3\u30c0\u30fc\u304b\u3089\u3067\u3082\u6b21\u306e\u4f1a\u8b70\u307e\u3067\u306e\u6642\u9593\u3092\u3059\u3070\u3084\u304f\u30c1\u30a7\u30c3\u30af\u3002\u30dc\u30bf\u30f3\u3092\u30af\u30ea\u30c3\u30af\u3059\u308b\u3068\u30ab\u30ec\u30f3\u30c0\u30fc\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u3059\u3002"},"direction":{"message":"ltr"},"notitle":{"message":"\uff08\u30bf\u30a4\u30c8\u30eb\u306a\u3057\uff09"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\u8907\u6570\u306e\u30ab\u30ec\u30f3\u30c0\u30fc\u306b\u5bfe\u5fdc"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u8a2d\u5b9a\u304c\u4fdd\u5b58\u3055\u308c\u307e\u3057\u305f\u3002"},"status_saving":{"message":"\u4fdd\u5b58\u3057\u3066\u3044\u307e\u3059..."},"multicalendartooltip":{"message":"\u8907\u6570\u306e\u30ab\u30ec\u30f3\u30c0\u30fc\u3092\u4f7f\u7528\u3067\u304d\u308b\u3088\u3046\u306b\u3059\u308b\u306b\u306f\u30c1\u30a7\u30c3\u30af\u30dc\u30c3\u30af\u30b9\u3092\u30aa\u30f3\u306b\u3057\u3066\u304f\u3060\u3055\u3044"},"imagetooltip":{"message":"Google \u30ab\u30ec\u30f3\u30c0\u30fc"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ko/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ko/messages.json
deleted file mode 100644
index 4e381a8cdce..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ko/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google \uce98\ub9b0\ub354 \uccb4\ud06c \ub3c4\uc6b0\ubbf8(Google \uc81c\uacf5)"},"title":{"message":"Google \uce98\ub9b0\ub354 \uccb4\ud06c \ub3c4\uc6b0\ubbf8"},"description":{"message":"\uce98\ub9b0\ub354 \uc5b4\ub514\uc5d0\uc11c\ub098 \ub2e4\uc74c \ubaa8\uc784\uae4c\uc9c0 \ub0a8\uc740 \uc2dc\uac04\uc744 \uc2e0\uc18d\ud558\uac8c \uc0b4\ud3b4\ubcfc \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uce98\ub9b0\ub354\ub85c \uc774\ub3d9\ud558\ub824\uba74 \ubc84\ud2bc\uc744 \ud074\ub9ad\ud558\uc138\uc694."},"direction":{"message":"ltr"},"notitle":{"message":"(\uc81c\ubaa9 \uc5c6\uc74c)"},"optionstitle":{"message":"Google \uce98\ub9b0\ub354 \uccb4\ud06c \ub3c4\uc6b0\ubbf8"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\uc5ec\ub7ec \uce98\ub9b0\ub354 \uc9c0\uc6d0"},"extensionname":{"message":"Google \uce98\ub9b0\ub354 \uccb4\ud06c \ub3c4\uc6b0\ubbf8"},"status_saved":{"message":"\uc124\uc815\uc744 \uc800\uc7a5\ud588\uc2b5\ub2c8\ub2e4."},"status_saving":{"message":"\uc800\uc7a5 \uc911..."},"multicalendartooltip":{"message":"\uc5ec\ub7ec \uce98\ub9b0\ub354 \uc9c0\uc6d0\uc744 \uc0ac\uc6a9\ud558\ub3c4\ub85d \uc124\uc815\ud558\ub824\uba74 \ud655\uc778\ub780\uc744 \uc120\ud0dd\ud558\uc138\uc694."},"imagetooltip":{"message":"Google \uce98\ub9b0\ub354"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/lt/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/lt/messages.json
deleted file mode 100644
index aac503ff0f1..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/lt/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Bet kuriame i\u0161 savo kalendori\u0173 greitai \u017ei\u016br\u0117kite, kiek laiko liko iki kito susitikimo. Jei norite patekti \u012f kalendori\u0173, spustel\u0117kite mygtuk\u0105."},"direction":{"message":"ltr"},"notitle":{"message":"(N\u0117ra pavadinimo)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 min.","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 val.","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 d.","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Keli\u0173 kalendori\u0173 palaikymas"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Nustatymai i\u0161saugoti."},"status_saving":{"message":"I\u0161saugoma..."},"multicalendartooltip":{"message":"Kad \u012fgalintum\u0117te keli\u0173 kalendori\u0173 palaikym\u0105, pa\u017eym\u0117kite laukel\u012f"},"imagetooltip":{"message":"\u201eGoogle\u201c kalendorius"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/lv/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/lv/messages.json
deleted file mode 100644
index be331835676..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/lv/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (nodro\u0161ina Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Varat \u0101tri skat\u012bt, cik daudz laika atlicis l\u012bdz n\u0101kamajai sapulcei, izmantojot jebkuru no saviem kalend\u0101riem. Lai atv\u0113rtu kalend\u0101ru, nospiediet pogu."},"direction":{"message":"ltr"},"notitle":{"message":"(Bez nosaukuma)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1\u00a0min","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1\u00a0h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1\u00a0d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Vair\u0101ku kalend\u0101ru atbalsts"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Iestat\u012bjumi ir saglab\u0101ti."},"status_saving":{"message":"Notiek saglab\u0101\u0161ana..."},"multicalendartooltip":{"message":"L\u016bdzu, atz\u012bm\u0113jiet lodzi\u0146u, lai iesp\u0113jotu vair\u0101ku kalend\u0101ru atbalstu."},"imagetooltip":{"message":"Google kalend\u0101rs"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/nb/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/nb/messages.json
deleted file mode 100644
index 666df6e58c2..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/nb/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (laget av Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Finn ut raskt hvor lenge det er til neste m\u00f8te fra alle kalendrene dine. Klikk p\u00e5 knappen for \u00e5 g\u00e5 videre til kalenderen."},"direction":{"message":"ltr"},"notitle":{"message":"(Ingen tittel)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 min","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 t","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"St\u00f8tte for flere kalendere"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Innstillinger lagret."},"status_saving":{"message":"Lagrer \u2026"},"multicalendartooltip":{"message":"Merk av i ruten for \u00e5 aktivere st\u00f8tte for flere kalendere"},"imagetooltip":{"message":"Google Kalender"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/nl/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/nl/messages.json
deleted file mode 100644
index 9ffa2224652..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/nl/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (van Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Snel in al uw agenda's bekijken hoe lang het nog duurt voordat uw volgende vergadering begint. Klik op de knop om naar uw agenda te gaan."},"direction":{"message":"ltr"},"notitle":{"message":"(Naamloos)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 u","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Ondersteuning voor meerdere agenda's"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Instellingen zijn opgeslagen."},"status_saving":{"message":"Opslaan..."},"multicalendartooltip":{"message":"Vink het selectievakje aan om de ondersteuning voor meerdere agenda's in te schakelen"},"imagetooltip":{"message":"Google Agenda"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pl/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pl/messages.json
deleted file mode 100644
index 2a3d471d2a7..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pl/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (by Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Szybko sprawd\u017a w dowolnym kalendarzu, ile masz czasu do nast\u0119pnego zebrania. Kliknij przycisk, aby przej\u015b\u0107 do kalendarza."},"direction":{"message":"ltr"},"notitle":{"message":"(Bez tytu\u0142u)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1g","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Obs\u0142uga wielu kalendarzy"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Zapisano ustawienia."},"status_saving":{"message":"Zapisywanie..."},"multicalendartooltip":{"message":"Zaznacz pole, aby w\u0142\u0105czy\u0107 obs\u0142ug\u0119 wielu kalendarzy"},"imagetooltip":{"message":"Kalendarz Google"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pt_BR/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pt_BR/messages.json
deleted file mode 100644
index 3a79f1ddd6d..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pt_BR/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (do Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Veja rapidamente quanto tempo voc\u00ea tem at\u00e9 seu pr\u00f3ximo compromisso. Clique no bot\u00e3o para abrir sua agenda."},"direction":{"message":"ltr"},"notitle":{"message":"(Sem t\u00edtulo)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Suporte para v\u00e1rias agendas"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Configura\u00e7\u00f5es salvas."},"status_saving":{"message":"Salvando..."},"multicalendartooltip":{"message":"Marque a caixa para ativar o suporte para v\u00e1rias agendas"},"imagetooltip":{"message":"Google Agenda"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pt_PT/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pt_PT/messages.json
deleted file mode 100644
index 53f249fa8a4..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/pt_PT/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (do Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Veja rapidamente quanto tempo falta para a sua pr\u00f3xima reuni\u00e3o a partir de qualquer um dos seus calend\u00e1rios. Clique no bot\u00e3o para aceder ao calend\u00e1rio."},"direction":{"message":"ltr"},"notitle":{"message":"(Sem t\u00edtulo)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Suporte para v\u00e1rios calend\u00e1rios"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Defini\u00e7\u00f5es guardadas."},"status_saving":{"message":"A guardar..."},"multicalendartooltip":{"message":"Marque a caixa para permitir o suporte de v\u00e1rios calend\u00e1rios."},"imagetooltip":{"message":"Calend\u00e1rio Google"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ro/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ro/messages.json
deleted file mode 100644
index 3540609401b..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ro/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (de la Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Vede\u0163i rapid timpul p\u00e2n\u0103 la urm\u0103toarea \u00eent\u00e2lnire, din oricare dintre calendarele dvs. Face\u0163i clic pe buton pentru a accesa calendarul."},"direction":{"message":"ltr"},"notitle":{"message":"(F\u0103r\u0103 titlu)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 z","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Asisten\u0163\u0103 pentru mai multe calendare"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Set\u0103rile au fost salvate."},"status_saving":{"message":"Se salveaz\u0103..."},"multicalendartooltip":{"message":"Bifa\u0163i caseta pentru a activa asisten\u0163a pentru mai multe calendare"},"imagetooltip":{"message":"Google Calendar"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ru/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ru/messages.json
deleted file mode 100644
index 343632602bd..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/ru/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043e \u0432 Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"\u041e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0439\u0442\u0435 \u0432\u0440\u0435\u043c\u044f \u0434\u043e \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0433\u043e \u043c\u0435\u0440\u043e\u043f\u0440\u0438\u044f\u0442\u0438\u044f. \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0435\u0439. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043d\u0443\u0436\u043d\u044b\u0439 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c."},"direction":{"message":"ltr"},"notitle":{"message":"(\u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1\u043c.","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1\u0447.","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1\u0434.","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\u041f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0435\u0439"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b."},"status_saving":{"message":"\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435...."},"multicalendartooltip":{"message":"\u041d\u0435 \u0437\u0430\u0431\u0443\u0434\u044c\u0442\u0435 \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0444\u043b\u0430\u0436\u043e\u043a, \u0447\u0442\u043e\u0431\u044b \u0430\u043a\u0442\u0438\u0432\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0435\u0439"},"imagetooltip":{"message":"\u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044c Google"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sk/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sk/messages.json
deleted file mode 100644
index 65257bf2c7c..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sk/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Kontrola Kalend\u00e1ra Google (od spolo\u010dnosti Google)"},"title":{"message":"Kontrola Kalend\u00e1ra Google"},"description":{"message":"V \u013eubovo\u013enom z va\u0161ich kalend\u00e1rov si v r\u00fdchlosti si zobrazte, ko\u013eko \u010dasu m\u00e1te do \u010fal\u0161ej sch\u00f4dzky. Kliknut\u00edm na tla\u010didlo prejdete do svojho kalend\u00e1ra."},"direction":{"message":"ltr"},"notitle":{"message":"(Bez n\u00e1zvu)"},"optionstitle":{"message":"Kontrola Kalend\u00e1ra Google"},"minutes":{"message":"$1 min","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Podpora viacer\u00fdch Kalend\u00e1rov"},"extensionname":{"message":"Kontrola Kalend\u00e1ra Google"},"status_saved":{"message":"Nastavenia boli ulo\u017een\u00e9."},"status_saving":{"message":"Prebieha ukladanie...."},"multicalendartooltip":{"message":"Ak chcete povoli\u0165 podporu viacer\u00fdch kalend\u00e1rov, za\u010diarknite toto pol\u00ed\u010dko"},"imagetooltip":{"message":"Kalend\u00e1r Google"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sl/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sl/messages.json
deleted file mode 100644
index 09a2113dd39..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sl/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Hitro preverite, koliko je \u0161e do naslednjega sestanka v katerem koli od va\u0161ih koledarjev. Kliknite gumb, da odprete koledar."},"direction":{"message":"ltr"},"notitle":{"message":"(Brez naslova)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 min","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Podpora za ve\u010d koledarjev"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Nastavitve shranjene."},"status_saving":{"message":"Shranjevanje ..."},"multicalendartooltip":{"message":"Potrdite polje, da omogo\u010dite podporo za ve\u010d koledarjev."},"imagetooltip":{"message":"Google Koledar"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sr/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sr/messages.json
deleted file mode 100644
index d55c41b7777..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sr/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (\u043e\u0434 Google-\u0430)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"\u0411\u0440\u0437\u043e \u043f\u043e\u0433\u043b\u0435\u0434\u0430\u0458\u0442\u0435 \u043a\u043e\u043b\u0438\u043a\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0430 \u0438\u043c\u0430\u0442\u0435 \u0434\u043e \u0441\u043b\u0435\u0434\u0435\u045b\u0435\u0433 \u0441\u0430\u0441\u0442\u0430\u043d\u043a\u0430 \u0443 \u0431\u0438\u043b\u043e \u043a\u043e\u043c \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0443. \u041a\u043b\u0438\u043a\u043d\u0438\u0442\u0435 \u043d\u0430 \u0434\u0443\u0433\u043c\u0435 \u0434\u0430 \u0431\u0438\u0441\u0442\u0435 \u043e\u0442\u0432\u043e\u0440\u0438\u043b\u0438 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440."},"direction":{"message":"ltr"},"notitle":{"message":"(\u0411\u0435\u0437 \u043d\u0430\u0441\u043b\u043e\u0432\u0430)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 \u043c\u0438\u043d","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 \u0441","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 \u0434","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\u041f\u043e\u0434\u0440\u0448\u043a\u0430 \u0437\u0430 \u0432\u0438\u0448\u0435 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0430"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u041f\u043e\u0434\u0435\u0448\u0430\u0432\u0430\u045a\u0430 \u0441\u0443 \u0441\u0430\u0447\u0443\u0432\u0430\u043d\u0430."},"status_saving":{"message":"\u0427\u0443\u0432\u0430\u045a\u0435...."},"multicalendartooltip":{"message":"\u041f\u043e\u0442\u0432\u0440\u0434\u0438\u0442\u0435 \u0438\u0437\u0431\u043e\u0440 \u0443 \u043f\u043e\u0459\u0443 \u0437\u0430 \u043f\u043e\u0442\u0432\u0440\u0434\u0443 \u0434\u0430 \u0431\u0438\u0441\u0442\u0435 \u043e\u043c\u043e\u0433\u0443\u045b\u0438\u043b\u0438 \u043f\u043e\u0434\u0440\u0448\u043a\u0443 \u0437\u0430 \u0432\u0438\u0448\u0435 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0430"},"imagetooltip":{"message":"Google \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sv/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sv/messages.json
deleted file mode 100644
index edb0193ea9c..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/sv/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (fr\u00e5n Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Se snabbt i dina kalendrar hur l\u00e4nge det \u00e4r till n\u00e4sta m\u00f6te. Klicka p\u00e5 knappen s\u00e5 kommer du till kalendern."},"direction":{"message":"ltr"},"notitle":{"message":"(Namnl\u00f6s)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1min","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1tim","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Support f\u00f6r flera kalendrar"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Inst\u00e4llningarna har sparats."},"status_saving":{"message":"Sparar..."},"multicalendartooltip":{"message":"Aktivera support f\u00f6r flera kalendrar genom att markera rutan"},"imagetooltip":{"message":"Google Kalender"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/th/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/th/messages.json
deleted file mode 100644
index c9680f1ca0d..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/th/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (\u0e42\u0e14\u0e22 Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"\u0e14\u0e39\u0e40\u0e27\u0e25\u0e32\u0e17\u0e35\u0e48\u0e04\u0e38\u0e13\u0e21\u0e35\u0e01\u0e48\u0e2d\u0e19\u0e16\u0e36\u0e07\u0e01\u0e32\u0e23\u0e1b\u0e23\u0e30\u0e0a\u0e38\u0e21\u0e04\u0e23\u0e31\u0e49\u0e07\u0e15\u0e48\u0e2d\u0e44\u0e1b\u0e44\u0e14\u0e49\u0e08\u0e32\u0e01\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e43\u0e14\u0e46 \u0e01\u0e47\u0e44\u0e14\u0e49\u0e02\u0e2d\u0e07\u0e04\u0e38\u0e13 \u0e43\u0e2b\u0e49\u0e04\u0e25\u0e34\u0e01\u0e17\u0e35\u0e48\u0e1b\u0e38\u0e48\u0e21\u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e44\u0e1b\u0e17\u0e35\u0e48\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e02\u0e2d\u0e07\u0e04\u0e38\u0e13"},"direction":{"message":"ltr"},"notitle":{"message":"(\u0e44\u0e21\u0e48\u0e21\u0e35\u0e0a\u0e37\u0e48\u0e2d)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\u0e01\u0e32\u0e23\u0e2a\u0e19\u0e31\u0e1a\u0e2a\u0e19\u0e38\u0e19\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e2b\u0e25\u0e32\u0e22\u0e23\u0e30\u0e1a\u0e1a"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01\u0e01\u0e32\u0e23\u0e15\u0e31\u0e49\u0e07\u0e04\u0e48\u0e32\u0e41\u0e25\u0e49\u0e27"},"status_saving":{"message":"\u0e01\u0e33\u0e25\u0e31\u0e07\u0e1a\u0e31\u0e19\u0e17\u0e36\u0e01...."},"multicalendartooltip":{"message":"\u0e42\u0e1b\u0e23\u0e14\u0e40\u0e25\u0e37\u0e2d\u0e01\u0e0a\u0e48\u0e2d\u0e07\u0e17\u0e33\u0e40\u0e04\u0e23\u0e37\u0e48\u0e2d\u0e07\u0e2b\u0e21\u0e32\u0e22 \u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e40\u0e1b\u0e34\u0e14\u0e43\u0e0a\u0e49\u0e07\u0e32\u0e19\u0e01\u0e32\u0e23\u0e2a\u0e19\u0e31\u0e1a\u0e2a\u0e19\u0e38\u0e19\u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19\u0e2b\u0e25\u0e32\u0e22\u0e23\u0e30\u0e1a\u0e1a"},"imagetooltip":{"message":"Google \u0e1b\u0e0f\u0e34\u0e17\u0e34\u0e19"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/tr/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/tr/messages.json
deleted file mode 100644
index a54371eb347..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/tr/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (Google'dan)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Takvimlerinizden herhangi birine bakarak bir sonraki toplant\u0131n\u0131za ne kadar zaman kald\u0131\u011f\u0131n\u0131 hemen g\u00f6r\u00fcn. Takviminizi a\u00e7mak i\u00e7in d\u00fc\u011fmeyi t\u0131klay\u0131n."},"direction":{"message":"ltr"},"notitle":{"message":"(Ba\u015fl\u0131ks\u0131z)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1s","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1g","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"Birden Fazla Takvim Deste\u011fi"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"Ayarlar Kaydedildi."},"status_saving":{"message":"Kaydediliyor..."},"multicalendartooltip":{"message":"Birden fazla takvim deste\u011fini etkinle\u015ftirmek i\u00e7in l\u00fctfen kutuyu i\u015faretleyin"},"imagetooltip":{"message":"Google Takvim"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/uk/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/uk/messages.json
deleted file mode 100644
index 21c7514d060..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/uk/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (\u0432\u0456\u0434 Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"\u0428\u0432\u0438\u0434\u043a\u043e \u043f\u0435\u0440\u0435\u0433\u043b\u044f\u0434\u0430\u0439\u0442\u0435 \u0441\u0432\u043e\u0457 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0456, \u0449\u043e\u0431 \u0434\u0456\u0437\u043d\u0430\u0442\u0438\u0441\u044f, \u0441\u043a\u0456\u043b\u044c\u043a\u0438 \u0447\u0430\u0441\u0443 \u0437\u0430\u043b\u0438\u0448\u0438\u043b\u043e\u0441\u044f \u0434\u043e \u043d\u0430\u0441\u0442\u0443\u043f\u043d\u043e\u0457 \u0437\u0443\u0441\u0442\u0440\u0456\u0447\u0456. \u041d\u0430\u0442\u0438\u0441\u043d\u0456\u0442\u044c \u0446\u044e \u043a\u043d\u043e\u043f\u043a\u0443, \u0449\u043e\u0431 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u0434\u043e \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u044f."},"direction":{"message":"ltr"},"notitle":{"message":"(\u0411\u0435\u0437 \u043d\u0430\u0437\u0432\u0438)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1 \u0445\u0432.","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1 \u0433\u043e\u0434.","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1 \u0434\u043d.","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\u041f\u0456\u0434\u0442\u0440\u0438\u043c\u043a\u0430 \u0434\u0435\u043a\u0456\u043b\u044c\u043a\u043e\u0445 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0456\u0432"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u041d\u0430\u043b\u0430\u0448\u0442\u0443\u0432\u0430\u043d\u043d\u044f \u0437\u0431\u0435\u0440\u0435\u0436\u0435\u043d\u043e."},"status_saving":{"message":"\u0417\u0431\u0435\u0440\u0456\u0433\u0430\u043d\u043d\u044f...."},"multicalendartooltip":{"message":"\u041f\u043e\u0441\u0442\u0430\u0432\u0442\u0435 \u043f\u0440\u0430\u043f\u043e\u0440\u0435\u0446\u044c, \u0449\u043e\u0431 \u0443\u0432\u0456\u043c\u043a\u043d\u0443\u0442\u0438 \u043f\u0456\u0434\u0442\u0440\u0438\u043c\u043a\u0443 \u0434\u0435\u043a\u0456\u043b\u044c\u043a\u043e\u0445 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0456\u0432"},"imagetooltip":{"message":"\u041a\u0430\u043b\u0435\u043d\u0434\u0430\u0440 Google"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/vi/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/vi/messages.json
deleted file mode 100644
index a54d48b6e0f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/vi/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (c\u1ee7a Google)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"Xem nhanh th\u1eddi gian tr\u01b0\u1edbc khi \u0111\u1ebfn cu\u1ed9c h\u1ecdp ti\u1ebfp theo t\u1eeb b\u1ea5t k\u1ef3 l\u1ecbch n\u00e0o c\u1ee7a b\u1ea1n. H\u00e3y nh\u1ea5p v\u00e0o n\u00fat \u0111\u1ec3 \u0111\u01b0\u1ee3c \u0111\u01b0a \u0111\u1ebfn l\u1ecbch c\u1ee7a b\u1ea1n."},"direction":{"message":"ltr"},"notitle":{"message":"(Kh\u00f4ng c\u00f3 ti\u00eau \u0111\u1ec1)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"H\u1ed7 tr\u1ee3 nhi\u1ec1u l\u1ecbch"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u0110\u00e3 l\u01b0u c\u00e0i \u0111\u1eb7t."},"status_saving":{"message":"\u0110ang l\u01b0u...."},"multicalendartooltip":{"message":"Vui l\u00f2ng ch\u1ecdn h\u1ed9p n\u00e0y \u0111\u1ec3 b\u1eadt t\u00ednh n\u0103ng h\u1ed7 tr\u1ee3 nhi\u1ec1u l\u1ecbch"},"imagetooltip":{"message":"L\u1ecbch Google"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/zh_CN/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/zh_CN/messages.json
deleted file mode 100644
index 7c2ecea0c70..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/zh_CN/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker\uff08\u7531 Google \u63d0\u4f9b\uff09"},"title":{"message":"Google Calendar Checker"},"description":{"message":"\u5feb\u901f\u67e5\u770b\u79bb\u60a8\u7684\u4efb\u610f\u65e5\u5386\u4e2d\u4e0b\u4e00\u6b21\u4f1a\u8bae\u8fd8\u6709\u591a\u957f\u65f6\u95f4\u3002\u60a8\u53ea\u9700\u70b9\u51fb\u8be5\u6309\u94ae\u5373\u53ef\u8fdb\u5165\u81ea\u5df1\u7684\u65e5\u5386\u3002"},"direction":{"message":"ltr"},"notitle":{"message":"\uff08\u65e0\u6807\u9898\uff09"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\u591a\u65e5\u5386\u652f\u6301"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u8bbe\u7f6e\u5df2\u4fdd\u5b58\u3002"},"status_saving":{"message":"\u6b63\u5728\u4fdd\u5b58..."},"multicalendartooltip":{"message":"\u8bf7\u9009\u4e2d\u6b64\u6846\u4ee5\u542f\u7528\u591a\u65e5\u5386\u652f\u6301"},"imagetooltip":{"message":"Google \u65e5\u5386"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/zh_TW/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/zh_TW/messages.json
deleted file mode 100644
index 5c99aba52f1..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/_locales/zh_TW/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"name":{"message":"Google Calendar Checker (\u7531 Google \u63d0\u4f9b)"},"title":{"message":"Google Calendar Checker"},"description":{"message":"\u5f9e\u4efb\u4f55\u65e5\u66c6\u7686\u53ef\u8fc5\u901f\u67e5\u770b\u8ddd\u96e2\u4e0b\u6b21\u6703\u8b70\u9084\u5269\u4e0b\u591a\u5c11\u6642\u9593\u3002\u6309\u4e00\u4e0b\u6309\u9215\u5373\u53ef\u524d\u5f80\u60a8\u7684\u65e5\u66c6\u3002"},"direction":{"message":"ltr"},"notitle":{"message":"(\u7121\u6a19\u984c)"},"optionstitle":{"message":"Google Calendar Checker"},"minutes":{"message":"$1m","placeholders":{"1":{"content":"$1"}}},"hours":{"message":"$1h","placeholders":{"1":{"content":"$1"}}},"days":{"message":"$1d","placeholders":{"1":{"content":"$1"}}},"multicalendartext":{"message":"\u591a\u91cd\u65e5\u66c6\u652f\u63f4"},"extensionname":{"message":"Google Calendar Checker"},"status_saved":{"message":"\u8a2d\u5b9a\u5df2\u5132\u5b58\u3002"},"status_saving":{"message":"\u5132\u5b58\u4e2d...."},"multicalendartooltip":{"message":"\u8acb\u52fe\u9078\u6b64\u65b9\u584a\uff0c\u4ee5\u555f\u7528\u591a\u91cd\u65e5\u66c6\u652f\u63f4\u529f\u80fd"},"imagetooltip":{"message":"Google \u65e5\u66c6"}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/calendar/manifest.json
deleted file mode 100644
index 51ee7441e17..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/calendar/manifest.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "name": "__MSG_name__",
- "description": "__MSG_description__",
- "manifest_version": 2,
- "default_locale":"en",
- "options_page": "views/options.html",
- "options_ui": {
- "page": "views/options.html",
- "chrome_style": true
- },
- "version": "2.0.0",
- "background": {
- "scripts": ["javascript/background.js"],
- "persistent": false
- },
- "permissions": [
- "notifications"
- ],
- "browser_action": {
- "default_icon": {
- "19": "images/icon-19.png",
- "38": "images/icon-38.png"
- },
- "default_title": "__MSG_title__"
- },
- "icons": {
- "128": "images/icon-128.png",
- "48": "images/icon-48.png",
- "16":"images/icon-16.png"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/catblock/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/catblock/manifest.json
deleted file mode 100644
index e775432add4..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/catblock/manifest.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "CatBlock",
- "version": "1.0",
- "description": "I can't has cheezburger!",
- "permissions": ["webRequest", "webRequestBlocking",
- "https://i.chzbgr.com/*"],
- "background": {
- "scripts": ["loldogs.js", "background.js"]
- },
-
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/catifier/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/catifier/manifest.json
deleted file mode 100644
index ba372527a89..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/catifier/manifest.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "Catifier",
- "version": "1.0",
- "description": "Moar cats!",
- "permissions": ["declarativeWebRequest", "<all_urls>"],
- "background": {
- "scripts": ["event_page.js"],
- "persistent": false
- },
-
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json
deleted file mode 100644
index 771783b91fc..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/chrome_search/manifest.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "background": {
- "scripts": ["background.js"]
- },
- "description": "Add support to the omnibox to search the Chromium source code.",
- "name": "Chromium Search",
- "omnibox": { "keyword" : "src" },
- "permissions": [ "http://www.google.com/" ],
- "version": "6.1",
- "minimum_chrome_version": "9",
-
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/constant_context/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/constant_context/manifest.json
deleted file mode 100644
index ebccaa57ed1..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/constant_context/manifest.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "Constant Context",
- "description" : "Highlights elements with keywords on developer.chrome",
- "version": "1.0",
- "page_action": {
- "default_icon": {
- "16": "images/cc16.png",
- "32": "images/cc32.png"
- },
- "default_popup": "popup.html"
- },
- "icons": {
- "16": "images/cc16.png",
- "48": "images/cc48.png",
- "32": "images/cc32.png",
- "128": "images/cc128.png"
- },
- "permissions": [
- "https://developer.chrome.com/*",
- "storage",
- "declarativeContent"
- ],
- "manifest_version": 2,
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "web_accessible_resources": ["style.css"],
- "content_scripts": [
- {
- "all_frames": true,
- "js": ["content_script.js"],
- "matches": ["https://developer.chrome.com/*"],
- "run_at": "document_idle"
- }
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/download_images/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/download_images/manifest.json
deleted file mode 100644
index 58fd910b1f8..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/download_images/manifest.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "name": "Download Images",
- "description" : "Displays all webpage images and allows user to download",
- "version": "1.0",
- "manifest_version": 2,
- "page_action": {
- "default_popup": "popup.html",
- "default_icon": {
- "16": "/images/download_image16.png",
- "32": "/images/download_image32.png",
- "48": "/images/download_image48.png",
- "128": "/images/download_image128.png"
- }
- },
- "icons": {
- "16": "/images/download_image16.png",
- "32": "/images/download_image32.png",
- "48": "/images/download_image48.png",
- "128": "/images/download_image128.png"
- },
- "permissions": [
- "downloads",
- "storage",
- "activeTab",
- "declarativeContent"
- ],
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "options_page": "options.html"
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/email_this_page/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/email_this_page/manifest.json
deleted file mode 100644
index 3801b87910a..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/email_this_page/manifest.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "Email this page (by Google)",
- "description": "This extension adds an email button to the toolbar which allows you to email the page link using your default mail client or Gmail.",
- "version": "1.2.6",
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "icons": { "128": "mail_128x128.png" },
- "options_page": "options.html",
- "permissions": [
- "tabs", "http://*/*", "https://*/*"
- ],
- "browser_action": {
- "default_title": "Email this page",
- "default_icon": "email_16x16.png"
- },
-
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/fx/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/fx/manifest.json
deleted file mode 100644
index 962c5eec6d2..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/fx/manifest.json
+++ /dev/null
@@ -1,22 +0,0 @@
-{
- "name": "Chrome Sounds",
- "version": "1.2",
- "description": "Enjoy a more magical and immersive experience when browsing the web using the power of sound.",
- "background": {
- "scripts": ["bg.js"]
- },
- "options_page": "options.html",
- "icons": { "128": "icon.png" },
- "permissions": [
- "tabs",
- "bookmarks",
- "http://*/*",
- "https://*/*"
- ],
- "content_scripts": [ {
- "matches": ["http://*/*", "https://*/*"],
- "js": ["content.js"],
- "all_frames": true
- }],
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gdocs/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/gdocs/manifest.json
deleted file mode 100644
index 03d17586f12..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gdocs/manifest.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "name": "Google Document List Viewer",
- "version": "1.0.2",
- "icons": {
- "48": "img/docs_spreadsheets-48.gif",
- "128": "img/docs_spreadsheets-128.gif"
- },
- "description": "Demonstrates how to use OAuth to connect the Google Documents List Data API.",
- "background": {
- "page": "background.html"
- },
- "options_page": "options.html",
- "browser_action": {
- "default_title": "List your Google Docs",
- "default_icon": "img/docs_spreadsheets-32.gif",
- "default_popup": "popup.html"
- },
- "permissions": [
- "tabs",
- "https://docs.google.com/feeds/*",
- "https://www.google.com/accounts/OAuthGetRequestToken",
- "https://www.google.com/accounts/OAuthAuthorizeToken",
- "https://www.google.com/accounts/OAuthGetAccessToken"
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ar/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ar/messages.json
deleted file mode 100644
index 87faf6490f2..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ar/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"\u0644\u0639\u0631\u0636 \u0639\u062f\u062f \u0627\u0644\u0631\u0633\u0627\u0626\u0644 \u063a\u064a\u0631 \u0627\u0644\u0645\u0642\u0631\u0648\u0621\u0629 \u0641\u064a \u0627\u0644\u0628\u0631\u064a\u062f \u0627\u0644\u0648\u0627\u0631\u062f \u0641\u064a Google Mail. \u0643\u0645\u0627 \u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0646\u0642\u0631 \u0639\u0644\u0649 \u0627\u0644\u0632\u0631 \u0644\u0641\u062a\u062d \u0628\u0631\u064a\u062f\u0643 \u0627\u0644\u0648\u0627\u0631\u062f."},"gmailcheck_node_error":{"message":"\u062e\u0637\u0623: \u062a\u0645 \u0627\u0633\u062a\u0631\u062f\u0627\u062f \u0627\u0644\u062e\u0644\u0627\u0635\u0629\u060c \u0648\u0644\u0643\u0646 \u0644\u0645 \u064a\u062a\u0645 \u0627\u0644\u0639\u062b\u0648\u0631 \u0639\u0644\u0649 &lt;fullcount&gt; \u0645\u0646 \u0627\u0644\u0639\u064f\u0642\u062f"},"gmailcheck_exception":{"message":"\u0627\u0633\u062a\u062b\u0646\u0627\u0621: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/bg/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/bg/messages.json
deleted file mode 100644
index 0903503a6e5..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/bg/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u043f\u043e\u0449\u0430\u0442\u0430"},"gmailcheck_description":{"message":"\u041f\u043e\u043a\u0430\u0437\u0432\u0430 \u0431\u0440\u043e\u044f \u043d\u0435\u043f\u0440\u043e\u0447\u0435\u0442\u0435\u043d\u0438 \u0441\u044a\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432\u044a\u0432 \u0432\u0445\u043e\u0434\u044f\u0449\u0430\u0442\u0430 \u0432\u0438 \u043f\u043e\u0449\u0430 \u0432 Google Mail. \u041c\u043e\u0436\u0435\u0442\u0435 \u0441\u044a\u0449\u043e \u0434\u0430 \u043a\u043b\u0438\u043a\u043d\u0435\u0442\u0435 \u0432\u044a\u0440\u0445\u0443 \u0431\u0443\u0442\u043e\u043d\u0430, \u0437\u0430 \u0434\u0430 \u044f \u043e\u0442\u0432\u043e\u0440\u0438\u0442\u0435."},"gmailcheck_node_error":{"message":"\u0413\u0440\u0435\u0448\u043a\u0430: \u0415\u043c\u0438\u0441\u0438\u044f\u0442\u0430 \u0431\u0435 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0430, \u043d\u043e \u043d\u044f\u043c\u0430 \u043d\u0430\u043c\u0435\u0440\u0435\u043d \u0432\u044a\u0437\u0435\u043b &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"\u0438\u0437\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ca/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ca/messages.json
deleted file mode 100644
index 6c2b1b2769e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ca/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Verificador de Google Mail"},"gmailcheck_description":{"message":"Mostra el nombre de missatges no llegits que hi ha a la vostra safata d'entrada de Google Mail. Tamb\u00e9 podeu fer clic al bot\u00f3 per obrir la safata d'entrada."},"gmailcheck_node_error":{"message":"Error: s'ha recuperat el feed, per\u00f2 no s'ha trobat cap node &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"excepci\u00f3: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/cs/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/cs/messages.json
deleted file mode 100644
index 394e6addd6e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/cs/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Kontrola e-mailu Google"},"gmailcheck_description":{"message":"Zobraz\u00ed po\u010det nep\u0159e\u010dten\u00fdch zpr\u00e1v ve slo\u017ece Doru\u010den\u00e1 po\u0161ta slu\u017eby Google Mail. Kliknut\u00edm na tla\u010d\u00edtko tuto slo\u017eku otev\u0159ete."},"gmailcheck_node_error":{"message":"Chyba: Zdroj byl na\u010dten, nebyl v\u0161ak nalezen \u017e\u00e1dn\u00fd uzel &lt;fullcount&gt;."},"gmailcheck_exception":{"message":"v\u00fdjimka: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/da/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/da/messages.json
deleted file mode 100644
index e1c2f82737f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/da/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google E-mail-t\u00e6ller"},"gmailcheck_description":{"message":"Viser antallet af ul\u00e6ste meddelelser i din Google Mail-indbakke. Du kan ogs\u00e5 klikke p\u00e5 knappen for at \u00e5bne din indbakke."},"gmailcheck_node_error":{"message":"Fejl: Feedet blev hentet, men der blev ikke fundet nogen &lt;fullcount&gt;-node"},"gmailcheck_exception":{"message":"undtagelse: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/de/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/de/messages.json
deleted file mode 100644
index 6c2188616c0..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/de/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail-Checker"},"gmailcheck_description":{"message":"Zeigt die Anzahl ungelesener Nachrichten in Ihrem Google Mail-Posteingang an. Sie k\u00f6nnen auch auf diese Schaltfl\u00e4che klicken, um Ihren Posteingang zu \u00f6ffnen."},"gmailcheck_node_error":{"message":"Fehler: Feed abgerufen, aber kein &lt;fullcount&gt; Knoten gefunden"},"gmailcheck_exception":{"message":"Ausnahme: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/el/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/el/messages.json
deleted file mode 100644
index 7db27143e6c..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/el/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"\u0388\u03bb\u03b5\u03b3\u03c7\u03bf\u03c2 \u03c4\u03bf\u03c5 Google Mail"},"gmailcheck_description":{"message":"\u0395\u03bc\u03c6\u03b1\u03bd\u03af\u03b6\u03b5\u03b9 \u03c4\u03bf\u03bd \u03b1\u03c1\u03b9\u03b8\u03bc\u03cc \u03c4\u03c9\u03bd \u03bc\u03b7 \u03b1\u03bd\u03b1\u03b3\u03bd\u03c9\u03c3\u03bc\u03ad\u03bd\u03c9\u03bd \u03bc\u03b7\u03bd\u03c5\u03bc\u03ac\u03c4\u03c9\u03bd \u03c3\u03c4\u03b1 \u03b5\u03b9\u03c3\u03b5\u03c1\u03c7\u03cc\u03bc\u03b5\u03bd\u03b1 \u03c4\u03bf\u03c5 Google Mail \u03c3\u03b1\u03c2. \u039c\u03c0\u03bf\u03c1\u03b5\u03af\u03c4\u03b5 \u03b5\u03c0\u03af\u03c3\u03b7\u03c2 \u03bd\u03b1 \u03ba\u03ac\u03bd\u03b5\u03c4\u03b5 \u03ba\u03bb\u03b9\u03ba \u03c3\u03c4\u03bf \u03ba\u03bf\u03c5\u03bc\u03c0\u03af \u03b3\u03b9\u03b1 \u03bd\u03b1 \u03b1\u03bd\u03bf\u03af\u03be\u03b5\u03c4\u03b5 \u03c4\u03b1 \u03b5\u03b9\u03c3\u03b5\u03c1\u03c7\u03cc\u03bc\u03b5\u03bd\u03ac \u03c3\u03b1\u03c2."},"gmailcheck_node_error":{"message":"\u03a3\u03c6\u03ac\u03bb\u03bc\u03b1: \u03ad\u03b3\u03b9\u03bd\u03b5 \u03b1\u03bd\u03ac\u03ba\u03c4\u03b7\u03c3\u03b7 \u03c1\u03bf\u03ae\u03c2, \u03b1\u03bb\u03bb\u03ac \u03b4\u03b5\u03bd \u03b2\u03c1\u03ad\u03b8\u03b7\u03ba\u03b5 \u03ba\u03cc\u03bc\u03b2\u03bf\u03c2 &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"\u03b5\u03be\u03b1\u03af\u03c1\u03b5\u03c3\u03b7: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/en/messages.json
deleted file mode 100644
index 063b9ca02a4..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/en/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Displays the number of unread messages in your Google Mail inbox. You can also click the button to open your inbox."},"gmailcheck_node_error":{"message":"Error: feed retrieved, but no &lt;fullcount&gt; node found"},"gmailcheck_exception":{"message":"exception: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/en_GB/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/en_GB/messages.json
deleted file mode 100644
index d3fa3a3a1d8..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/en_GB/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Displays the number of unread messages in your Google Mail inbox. You can also click the button to open your inbox."},"gmailcheck_node_error":{"message":"Error: Feed retrieved, but no &lt;fullcount&gt; node found"},"gmailcheck_exception":{"message":"exception: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/es/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/es/messages.json
deleted file mode 100644
index 4d8364f7a0d..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/es/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Permite ver el n\u00famero de mensajes sin leer en la bandeja de entrada de Google Mail. Tambi\u00e9n puedes hacer clic en el bot\u00f3n para abrir la bandeja de entrada."},"gmailcheck_node_error":{"message":"Se ha producido un error: el feed se ha recuperado, pero no se ha encontrado ning\u00fan nodo &lt;fullcount&gt;."},"gmailcheck_exception":{"message":"excepci\u00f3n: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/es_419/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/es_419/messages.json
deleted file mode 100644
index 54bf27032ec..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/es_419/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Muestra el n\u00famero de mensajes sin leer en tu bandeja de entrada de Google Mail. Tambi\u00e9n puedes hacer clic en el bot\u00f3n para abrir tu bandeja de entrada."},"gmailcheck_node_error":{"message":"Error: se recuper\u00f3 el feed, pero no se encontr\u00f3 el nodo &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"excepci\u00f3n: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/et/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/et/messages.json
deleted file mode 100644
index 20b1e844d81..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/et/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google'i meilikontrollija"},"gmailcheck_description":{"message":"Kuvab Google Maili postkastis olevate lugemata s\u00f5numite arvu. V\u00f5ite kl\u00f5psata ka nupul ja avada postkasti."},"gmailcheck_node_error":{"message":"Viga: voog vastuv\u00f5etud, kuid \u00fchtki &lt;fullcount&gt; s\u00f5lme ei leitud"},"gmailcheck_exception":{"message":"erand: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fi/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fi/messages.json
deleted file mode 100644
index f9da2c15ae9..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fi/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google-s\u00e4hk\u00f6postin tarkistus"},"gmailcheck_description":{"message":"N\u00e4ytt\u00e4\u00e4, kuinka monta lukematonta viesti\u00e4 Google Mail -postilaatikossasi on. Voit my\u00f6s avata postilaatikkosi napsauttamalla painiketta."},"gmailcheck_node_error":{"message":"Virhe: sy\u00f6te haettiin, mutta &lt;fullcount&gt;-solmua ei l\u00f6ytynyt"},"gmailcheck_exception":{"message":"poikkeus: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fil/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fil/messages.json
deleted file mode 100644
index 1a019a60d93..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fil/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Ipinapakita ang bilang ng mga hindi pa nababasang mensahe sa inbox ng iyong Google Mail. Maaari mo ring i-click ang pindutan upang buksan ang iyong inbox."},"gmailcheck_node_error":{"message":"Error: nakuha ang feed, ngunit walang &lt;fullcount&gt; node na natagpuan"},"gmailcheck_exception":{"message":"pagbubukod: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fr/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fr/messages.json
deleted file mode 100644
index 2900819e1c2..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/fr/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"V\u00e9rificateur de messages Google"},"gmailcheck_description":{"message":"Affiche le nombre de messages non lus dans votre bo\u00eete de r\u00e9ception Google\u00a0Mail. Vous avez \u00e9galement la possibilit\u00e9 de cliquer sur ce bouton pour ouvrir cette derni\u00e8re."},"gmailcheck_node_error":{"message":"Erreur\u00a0: flux r\u00e9cup\u00e9r\u00e9, mais aucun n\u0153ud &lt;fullcount&gt; trouv\u00e9"},"gmailcheck_exception":{"message":"exception\u00a0: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/he/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/he/messages.json
deleted file mode 100644
index c32e98298ab..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/he/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"\u05de\u05e6\u05d9\u05d2 \u05d0\u05ea \u05de\u05e1\u05e4\u05e8 \u05d4\u05d4\u05d5\u05d3\u05e2\u05d5\u05ea \u05e9\u05dc\u05d0 \u05e0\u05e7\u05e8\u05d0\u05d5 \u05d1\u05ea\u05d9\u05d1\u05ea \u05d4\u05d3\u05d5\u05d0\u05e8 \u05d4\u05e0\u05db\u05e0\u05e1 \u05e9\u05dc\u05da \u05d1-Google Mail. \u05d1\u05e0\u05d5\u05e1\u05e3, \u05ea\u05d5\u05db\u05dc \u05dc\u05dc\u05d7\u05d5\u05e5 \u05e2\u05dc \u05d4\u05dc\u05d7\u05e6\u05df \u05db\u05d3\u05d9 \u05dc\u05e4\u05ea\u05d5\u05d7 \u05d0\u05ea \u05ea\u05d9\u05d1\u05ea \u05d4\u05d3\u05d5\u05d0\u05e8 \u05d4\u05e0\u05db\u05e0\u05e1."},"gmailcheck_node_error":{"message":"\u05e9\u05d2\u05d9\u05d0\u05d4: \u05d4\u05e2\u05d3\u05db\u05d5\u05df \u05d0\u05d5\u05d7\u05d6\u05e8, \u05d0\u05da \u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05e6\u05de\u05ea\u05d9\u05dd \u05e9\u05dc &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"\u05d7\u05e8\u05d9\u05d2: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hi/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hi/messages.json
deleted file mode 100644
index 0056c565f25..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hi/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google \u092e\u0947\u0932 \u091c\u093e\u0902\u091a\u0915\u0930\u094d\u0924\u093e"},"gmailcheck_description":{"message":"\u0906\u092a\u0915\u0947 Google \u092e\u0947\u0932 \u0907\u0928\u092c\u0949\u0915\u094d\u0938 \u092e\u0947\u0902 \u0928 \u092a\u095d\u0947 \u0917\u090f \u0938\u0902\u0926\u0947\u0936\u094b\u0902 \u0915\u0940 \u0938\u0902\u0916\u094d\u092f\u093e \u092a\u094d\u0930\u0926\u0930\u094d\u0936\u093f\u0924 \u0915\u0930\u0924\u093e \u0939\u0948. \u0906\u092a \u0905\u092a\u0928\u093e \u0907\u0928\u092c\u0949\u0915\u094d\u0938 \u0916\u094b\u0932\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f \u092c\u091f\u0928 \u0915\u094d\u0932\u093f\u0915 \u092d\u0940 \u0915\u0930 \u0938\u0915\u0924\u0947 \u0939\u0948\u0902."},"gmailcheck_node_error":{"message":"\u0924\u094d\u0930\u0941\u091f\u093f: \u095e\u0940\u0921 \u092a\u0941\u0928\u0930\u094d\u092a\u094d\u0930\u093e\u092a\u094d\u0924 \u0915\u0940 \u0917\u0908, \u0932\u0947\u0915\u093f\u0928 \u0915\u094b\u0908 &lt;fullcount&gt; \u0928\u094b\u0921 \u0928\u0939\u0940\u0902 \u092e\u093f\u0932\u093e"},"gmailcheck_exception":{"message":"\u0905\u092a\u0935\u093e\u0926: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hr/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hr/messages.json
deleted file mode 100644
index 94dce1c1ae4..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hr/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Provjera po\u0161te"},"gmailcheck_description":{"message":"Prikazuje broj nepro\u010ditanih poruka u ulaznom pretincu usluge Google Mail. Mo\u017eete tako\u0111er kliknuti gumb za otvaranje ulazne po\u0161te."},"gmailcheck_node_error":{"message":"Pogre\u0161ka: Feed je dohva\u0107en, ali nije prona\u0111eno \u010dvori\u0161te &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"izuzetak: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hu/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hu/messages.json
deleted file mode 100644
index 8b3e6c967ca..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/hu/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Lev\u00e9lfigyel\u0151"},"gmailcheck_description":{"message":"Megjelen\u00edti az olvasatlan \u00fczeneteket a Google Mail be\u00e9rkez\u0151 levelei k\u00f6z\u00f6tt. A gombra kattintva is megnyithatja a be\u00e9rkez\u0151 leveleit."},"gmailcheck_node_error":{"message":"Hiba: h\u00edrcsatorna leh\u00edvva, de a csom\u00f3pont (&lt;fullcount&gt;) hi\u00e1nyzik"},"gmailcheck_exception":{"message":"kiv\u00e9tel: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/id/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/id/messages.json
deleted file mode 100644
index 4a8d09c247f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/id/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Menampilkan jumlah pesan yang belum dibaca dalam kotak masuk Google Mail. Anda juga dapat mengeklik tombol ini untuk membuka kotak masuk."},"gmailcheck_node_error":{"message":"Galat: umpan diperoleh, tetapi tidak ada &lt;fullcount&gt; node yang ditemukan"},"gmailcheck_exception":{"message":"pengecualian: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/it/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/it/messages.json
deleted file mode 100644
index 13b6e78749a..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/it/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Avvisi email"},"gmailcheck_description":{"message":"Visualizza il numero di messaggi da leggere nella posta in arrivo di Google Mail. Puoi anche fare clic sul pulsante per aprire la tua posta in arrivo."},"gmailcheck_node_error":{"message":"Errore: feed recuperato ma non sono stati trovati nodi &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"eccezione: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ja/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ja/messages.json
deleted file mode 100644
index 3ce2669b789..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ja/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Google Mail \u306e\u53d7\u4fe1\u30c8\u30ec\u30a4\u306b\u3042\u308b\u672a\u8aad\u306e\u30e1\u30fc\u30eb\u6570\u3092\u8868\u793a\u3057\u307e\u3059\u3002\u3053\u306e\u30dc\u30bf\u30f3\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u53d7\u4fe1\u30c8\u30ec\u30a4\u3092\u958b\u304f\u3053\u3068\u3082\u3067\u304d\u307e\u3059\u3002"},"gmailcheck_node_error":{"message":"\u30a8\u30e9\u30fc: \u53d6\u5f97\u3057\u305f\u30d5\u30a3\u30fc\u30c9\u306b &lt;fullcount&gt; \u30ce\u30fc\u30c9\u304c\u3042\u308a\u307e\u305b\u3093"},"gmailcheck_exception":{"message":"\u4f8b\u5916: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ko/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ko/messages.json
deleted file mode 100644
index 934e49e4f01..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ko/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Gmaill \ubc1b\uc740\ud3b8\uc9c0\ud568\uc5d0\uc11c \uc77d\uc9c0 \uc54a\uc740 \uba54\uc77c\uc758 \uc218\ub97c \ub098\ud0c0\ub0c5\ub2c8\ub2e4. \ub610\ud55c \ubc84\ud2bc\uc744 \ud074\ub9ad\ud558\uc5ec \ubc1b\uc740\ud3b8\uc9c0\ud568\uc744 \uc5f4 \uc218\ub3c4 \uc788\uc2b5\ub2c8\ub2e4."},"gmailcheck_node_error":{"message":"\uc624\ub958: \ud53c\ub4dc\ub97c \uac80\uc0c9\ud588\uc73c\ub098 \ucd1d &lt;fullcount&gt;\uac1c\uc758 \ub178\ub4dc\ub97c \ucc3e\uc9c0 \ubabb\ud588\uc2b5\ub2c8\ub2e4."},"gmailcheck_exception":{"message":"\uc608\uc678: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/lt/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/lt/messages.json
deleted file mode 100644
index 7da57e1c76c..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/lt/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"\u201eGoogle\u201c pa\u0161to tikrintuvas"},"gmailcheck_description":{"message":"Pateikiamas \u201eGoogle\u201c pa\u0161to gaut\u0173 lai\u0161k\u0173 aplanke esan\u010di\u0173 neperskaityt\u0173 prane\u0161im\u0173 skai\u010dius. Be to, jei norite atidaryti gaut\u0173 lai\u0161k\u0173 aplank\u0105, galite spustel\u0117ti mygtuk\u0105."},"gmailcheck_node_error":{"message":"Klaida: sklaidos kanalas nuskaitytas, ta\u010diau nerastas joks &lt;fullcount&gt; mazgas"},"gmailcheck_exception":{"message":"i\u0161imtis: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/lv/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/lv/messages.json
deleted file mode 100644
index 52f2ca3e792..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/lv/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Tiek r\u0101d\u012bts nelas\u012bto zi\u0146ojumu skaits Google Mail ies\u016btn\u0113. Varat ar\u012b noklik\u0161\u0137in\u0101t uz pogas, lai atv\u0113rtu ies\u016btni."},"gmailcheck_node_error":{"message":"K\u013c\u016bda: pl\u016bsma ir izg\u016bta, ta\u010du netika atrasts neviens &lt;fullcount&gt; mezgls"},"gmailcheck_exception":{"message":"iz\u0146\u0113mums: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/nb/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/nb/messages.json
deleted file mode 100644
index ad8a09df4ba..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/nb/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google e-post-sjekker"},"gmailcheck_description":{"message":"Viser antallet uleste meldinger i innboksen for Google Mail. Du kan ogs\u00e5 klikke p\u00e5 knappen for \u00e5 \u00e5pne innboksen."},"gmailcheck_node_error":{"message":"Feil: innmating hentet, men finner ingen &lt;fullcount&gt;-node"},"gmailcheck_exception":{"message":"unntak: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/nl/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/nl/messages.json
deleted file mode 100644
index c40d81fa105..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/nl/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Hiermee wordt het aantal ongelezen berichten in uw Postvak IN van Gmail weergegeven. U kunt ook op de knop klikken om het Postvak IN te openen."},"gmailcheck_node_error":{"message":"Fout: feed opgehaald, maar het knooppunt &lt;fullcount&gt; is niet gevonden"},"gmailcheck_exception":{"message":"uitzondering: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pl/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pl/messages.json
deleted file mode 100644
index d607a06d280..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pl/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Sprawdzanie poczty Google"},"gmailcheck_description":{"message":"Wy\u015bwietla liczb\u0119 nieprzeczytanych wiadomo\u015bci w Twojej skrzynce odbiorczej Google Mail. Mo\u017cesz te\u017c klikn\u0105\u0107 przycisk, aby otworzy\u0107 swoj\u0105 skrzynk\u0119 odbiorcz\u0105."},"gmailcheck_node_error":{"message":"B\u0142\u0105d: pobrano kana\u0142, ale nie odnaleziono w\u0119z\u0142a &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"wyj\u0105tek: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pt_BR/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pt_BR/messages.json
deleted file mode 100644
index 1175d0c822e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pt_BR/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Verificador de mensagens do Google"},"gmailcheck_description":{"message":"Exibe o n\u00famero de mensagens n\u00e3o lidas na sua Caixa de entrada do Gmail. Voc\u00ea tamb\u00e9m pode clicar no bot\u00e3o para abrir a sua caixa de entrada."},"gmailcheck_node_error":{"message":"Erro: feed recuperado, mas nenhum n\u00f3 &lt;fullcount&gt; encontrado"},"gmailcheck_exception":{"message":"exce\u00e7\u00e3o: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pt_PT/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pt_PT/messages.json
deleted file mode 100644
index e6d8992af23..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/pt_PT/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Verificador do Google Mail"},"gmailcheck_description":{"message":"Apresenta o n\u00famero de mensagens n\u00e3o lidas existentes na sua caixa de entrada do Google Mail. Pode tamb\u00e9m clicar no bot\u00e3o para abrir a caixa de entrada."},"gmailcheck_node_error":{"message":"Erro: obteve-se o feed, mas n\u00e3o foi encontrado nenhum n\u00f3 &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"excep\u00e7\u00e3o: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ro/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ro/messages.json
deleted file mode 100644
index d0d5838ce51..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ro/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Verificator de e-mail"},"gmailcheck_description":{"message":"Afi\u015feaz\u0103 num\u0103rul mesajelor necitite din folderul Mesaje primite al contului Google Mail. De asemenea, pute\u0163i s\u0103 face\u0163i clic pe buton pentru a deschide folderul Mesaje primite."},"gmailcheck_node_error":{"message":"Eroare: s-a preluat feedul, dar nu s-a g\u0103sit niciun nod &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"excep\u0163ie: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ru/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ru/messages.json
deleted file mode 100644
index dedaef1344b..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/ru/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043d\u0435\u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0432 \u043f\u043e\u0447\u0442\u043e\u0432\u043e\u043c \u044f\u0449\u0438\u043a\u0435 Google Mail. \u041c\u043e\u0436\u043d\u043e \u0442\u0430\u043a\u0436\u0435 \u043d\u0430\u0436\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043f\u0430\u043f\u043a\u0443 \"\u0412\u0445\u043e\u0434\u044f\u0449\u0438\u0435\"."},"gmailcheck_node_error":{"message":"\u041e\u0448\u0438\u0431\u043a\u0430: \u0444\u0438\u0434 \u0431\u044b\u043b \u043f\u043e\u043b\u0443\u0447\u0435\u043d, \u043d\u043e \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0439\u0442\u0438 \u0443\u0437\u0435\u043b &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"\u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sk/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sk/messages.json
deleted file mode 100644
index 13d902a78c7..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sk/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Kontrola po\u0161ty Google"},"gmailcheck_description":{"message":"Zobraz\u00ed po\u010det nepre\u010d\u00edtan\u00fdch spr\u00e1v v prie\u010dinku doru\u010denej po\u0161ty v slu\u017ebe Gmail. Kliknut\u00edm na tla\u010didlo prie\u010dinok doru\u010denej po\u0161ty otvor\u00edte."},"gmailcheck_node_error":{"message":"Chyba: informa\u010dn\u00fd kan\u00e1l bol na\u010d\u00edtan\u00fd, nena\u0161iel sa v\u0161ak \u017eiadny uzol &lt;fullcount&gt;."},"gmailcheck_exception":{"message":"v\u00fdnimka: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sl/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sl/messages.json
deleted file mode 100644
index 962a8c6efb4..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sl/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Preverjevalnik za Google Mail"},"gmailcheck_description":{"message":"Prika\u017ee \u0161tevilo neprebranih sporo\u010dil v nabiralniku storitve Google Mail. Nabiralnik lahko odprete tudi s klikom gumba."},"gmailcheck_node_error":{"message":"Napaka: vir prejet, vendar ni bilo najdeno nobeno vozli\u0161\u010de &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"izjema: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sr/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sr/messages.json
deleted file mode 100644
index a2cfdb417e6..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sr/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google \u043f\u0440\u043e\u0432\u0435\u0440\u0430 \u043f\u043e\u0448\u0442\u0435"},"gmailcheck_description":{"message":"\u041f\u0440\u0438\u043a\u0430\u0437\u0443\u0458\u0435 \u0431\u0440\u043e\u0458 \u043d\u0435\u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d\u0438\u0445 \u043f\u0440\u0438\u043c\u0459\u0435\u043d\u0438\u0445 \u043f\u043e\u0440\u0443\u043a\u0430 Google Mail-\u0430. \u041c\u043e\u0436\u0435\u0442\u0435 \u0438 \u0434\u0430 \u043a\u043b\u0438\u043a\u043d\u0435\u0442\u0435 \u043d\u0430 \u0434\u0443\u0433\u043c\u0435 \u0438 \u043e\u0442\u0432\u043e\u0440\u0438\u0442\u0435 \u043f\u0440\u0438\u043c\u0459\u0435\u043d\u0435 \u043f\u043e\u0440\u0443\u043a\u0435."},"gmailcheck_node_error":{"message":"\u0413\u0440\u0435\u0448\u043a\u0430: \u0424\u0438\u0434 \u0458\u0435 \u043f\u0440\u0435\u0443\u0437\u0435\u0442, \u0430\u043b\u0438 \u0447\u0432\u043e\u0440 &lt;fullcount&gt; \u043d\u0438\u0458\u0435 \u043f\u0440\u043e\u043d\u0430\u0452\u0435\u043d"},"gmailcheck_exception":{"message":"\u0438\u0437\u0443\u0437\u0435\u0442\u0430\u043a: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sv/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sv/messages.json
deleted file mode 100644
index b4359f35bd1..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/sv/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Visar hur m\u00e5nga ol\u00e4sta meddelanden du har i inkorgen i Google Mail. Du kan ocks\u00e5 klicka p\u00e5 knappen om du vill \u00f6ppna inkorgen."},"gmailcheck_node_error":{"message":"Fel: feeden h\u00e4mtades, men ingen &lt;fullcount&gt;-nod hittades"},"gmailcheck_exception":{"message":"undantag: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/th/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/th/messages.json
deleted file mode 100644
index e5bef6cd04b..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/th/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"\u0e41\u0e2a\u0e14\u0e07\u0e08\u0e33\u0e19\u0e27\u0e19\u0e02\u0e2d\u0e07\u0e02\u0e49\u0e2d\u0e04\u0e27\u0e32\u0e21\u0e17\u0e35\u0e48\u0e22\u0e31\u0e07\u0e44\u0e21\u0e48\u0e44\u0e14\u0e49\u0e2d\u0e48\u0e32\u0e19\u0e43\u0e19\u0e01\u0e25\u0e48\u0e2d\u0e07\u0e08\u0e14\u0e2b\u0e21\u0e32\u0e22 Google Mail \u0e02\u0e2d\u0e07\u0e04\u0e38\u0e13 \u0e41\u0e25\u0e30\u0e04\u0e38\u0e13\u0e2a\u0e32\u0e21\u0e32\u0e23\u0e16\u0e04\u0e25\u0e34\u0e01\u0e1b\u0e38\u0e48\u0e21\u0e40\u0e1e\u0e37\u0e48\u0e2d\u0e40\u0e1b\u0e34\u0e14\u0e01\u0e25\u0e48\u0e2d\u0e07\u0e08\u0e14\u0e2b\u0e21\u0e32\u0e22\u0e02\u0e2d\u0e07\u0e04\u0e38\u0e13\u0e44\u0e14\u0e49\u0e40\u0e0a\u0e48\u0e19\u0e01\u0e31\u0e19"},"gmailcheck_node_error":{"message":"\u0e02\u0e49\u0e2d\u0e1c\u0e34\u0e14\u0e1e\u0e25\u0e32\u0e14: \u0e40\u0e23\u0e35\u0e22\u0e01\u0e04\u0e37\u0e19\u0e1f\u0e35\u0e14\u0e41\u0e25\u0e49\u0e27 \u0e41\u0e15\u0e48\u0e44\u0e21\u0e48\u0e1e\u0e1a\u0e42\u0e2b\u0e19\u0e14 &lt;fullcount&gt;"},"gmailcheck_exception":{"message":"\u0e02\u0e49\u0e2d\u0e22\u0e01\u0e40\u0e27\u0e49\u0e19: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/tr/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/tr/messages.json
deleted file mode 100644
index 593057dc79f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/tr/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"Google Mail gelen kutunuzdaki okunmam\u0131\u015f iletilerin say\u0131s\u0131n\u0131 g\u00f6r\u00fcnt\u00fcler. Ayr\u0131ca, d\u00fc\u011fmeyi t\u0131klayarak gelen kutunuzu da a\u00e7abilirsiniz."},"gmailcheck_node_error":{"message":"Hata: yay\u0131n al\u0131nd\u0131, ancak &lt;fullcount&gt; d\u00fc\u011f\u00fcm\u00fc bulunamad\u0131"},"gmailcheck_exception":{"message":"\u00f6zel durum: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/uk/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/uk/messages.json
deleted file mode 100644
index 0d196cc2503..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/uk/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"\u041f\u0435\u0440\u0435\u0432\u0456\u0440\u043a\u0430 \u043f\u043e\u0448\u0442\u0438 Google"},"gmailcheck_description":{"message":"\u0412\u0456\u0434\u043e\u0431\u0440\u0430\u0436\u0430\u0454 \u043a\u0456\u043b\u044c\u043a\u0456\u0441\u0442\u044c \u043d\u0435\u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d\u0438\u0445 \u043f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u044c \u0443 \u043f\u0430\u043f\u0446\u0456 \u0437 \u0432\u0445\u0456\u0434\u043d\u0438\u043c\u0438 \u043f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u043d\u044f\u043c\u0438 \u0441\u043b\u0443\u0436\u0431\u0438 Google Mail. \u0429\u043e\u0431 \u0432\u0456\u0434\u043a\u0440\u0438\u0442\u0438 \u043f\u0430\u043f\u043a\u0443 \u0437 \u0432\u0445\u0456\u0434\u043d\u0438\u043c\u0438 \u043f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u043d\u044f\u043c\u0438, \u043c\u043e\u0436\u043d\u0430 \u0442\u0430\u043a\u043e\u0436 \u043d\u0430\u0442\u0438\u0441\u043d\u0443\u0442\u0438 \u0446\u044e \u043a\u043d\u043e\u043f\u043a\u0443."},"gmailcheck_node_error":{"message":"\u041f\u043e\u043c\u0438\u043b\u043a\u0430: \u043a\u0430\u043d\u0430\u043b \u0432\u0456\u0434\u043d\u043e\u0432\u043b\u0435\u043d\u043e, \u0430\u043b\u0435 \u0436\u043e\u0434\u043d\u043e\u0433\u043e \u0432\u0443\u0437\u043b\u0430 &lt;fullcount&gt; \u043d\u0435 \u0437\u043d\u0430\u0439\u0434\u0435\u043d\u043e"},"gmailcheck_exception":{"message":"\u0432\u0438\u043d\u044f\u0442\u043e\u043a: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/vi/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/vi/messages.json
deleted file mode 100644
index d26050fb329..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/vi/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Tr\u00ecnh Ki\u1ec3m tra Th\u01b0 c\u1ee7a Google"},"gmailcheck_description":{"message":"Hi\u1ec3n th\u1ecb s\u1ed1 th\u01b0 ch\u01b0a \u0111\u1ecdc trong h\u1ed9p th\u01b0 \u0111\u1ebfn Gmail c\u1ee7a b\u1ea1n. B\u1ea1n c\u0169ng c\u00f3 th\u1ec3 nh\u1ea5p v\u00e0o n\u00fat \u0111\u1ec3 m\u1edf h\u1ed9p th\u01b0 \u0111\u1ebfn c\u1ee7a m\u00ecnh."},"gmailcheck_node_error":{"message":"L\u1ed7i: ngu\u1ed3n c\u1ea5p d\u1eef li\u1ec7u \u0111\u00e3 \u0111\u01b0\u1ee3c truy xu\u1ea5t nh\u01b0ng kh\u00f4ng t\u00ecm th\u1ea5y n\u00fat &lt;fullcount&gt; n\u00e0o"},"gmailcheck_exception":{"message":"ngo\u1ea1i l\u1ec7: $1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/zh_CN/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/zh_CN/messages.json
deleted file mode 100644
index ae6227f379e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/zh_CN/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"\u663e\u793a Google Mail \u6536\u4ef6\u7bb1\u4e2d\u7684\u672a\u8bfb\u90ae\u4ef6\u6570\u3002\u70b9\u51fb\u8be5\u6309\u94ae\u8fd8\u53ef\u4ee5\u6253\u5f00\u60a8\u7684\u6536\u4ef6\u7bb1\u3002"},"gmailcheck_node_error":{"message":"\u9519\u8bef\uff1a\u7cfb\u7edf\u5df2\u68c0\u7d22\u4f9b\u7a3f\uff0c\u4f46\u672a\u53d1\u73b0 &lt;fullcount&gt; \u8282\u70b9"},"gmailcheck_exception":{"message":"\u5f02\u5e38\uff1a$1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/zh_TW/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/zh_TW/messages.json
deleted file mode 100644
index 4c317934892..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/_locales/zh_TW/messages.json
+++ /dev/null
@@ -1 +0,0 @@
-{"gmailcheck_name":{"message":"Google Mail Checker"},"gmailcheck_description":{"message":"\u5728 Google Mail \u6536\u4ef6\u5323\u4e2d\u986f\u793a\u672a\u8b80\u90f5\u4ef6\u7684\u6578\u76ee\u3002\u6309\u4e00\u4e0b\u6309\u9215\u4e5f\u53ef\u4ee5\u958b\u555f\u6536\u4ef6\u5323\u3002"},"gmailcheck_node_error":{"message":"\u932f\u8aa4\uff1a\u64f7\u53d6\u5230\u8cc7\u8a0a\u63d0\u4f9b\uff0c\u4f46\u627e\u4e0d\u5230 &lt;fullcount&gt; \u7bc0\u9ede"},"gmailcheck_exception":{"message":"\u4f8b\u5916\u72c0\u6cc1\uff1a$1","placeholders":{"1":{"content":"$1"}}}}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/gmail/manifest.json
deleted file mode 100644
index c181dcd3ca4..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/gmail/manifest.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "background": {
- "persistent": false,
- "page": "background.html"
- },
- "browser_action": {
- "default_icon": "gmail_not_logged_in.png"
- },
- "default_locale": "en",
- "description": "__MSG_gmailcheck_description__",
- "icons": {
- "128": "icon_128.png"
- },
- "name": "__MSG_gmailcheck_name__",
- "permissions": [
- "alarms",
- "tabs",
- "webNavigation",
- "*://*.google.com/"
- ],
- "version": "4.4.0",
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/imageinfo/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/imageinfo/manifest.json
deleted file mode 100644
index ecda1b16800..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/imageinfo/manifest.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name" : "Imageinfo",
- "version" : "1.0.1",
- "description" : "Get image info for images, including EXIF data",
- "background" : { "scripts": ["background.js"] },
- "permissions" : [
- "contextMenus",
- "tabs",
- "http://*/*",
- "https://*/*"
- ],
- "minimum_chrome_version" : "6.0.0.0",
- "icons" : {
- "16" : "imageinfo-16.png",
- "48" : "imageinfo-48.png",
- "128" : "imageinfo-128.png"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/irc/app/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/irc/app/manifest.json
deleted file mode 100644
index 9c6b31e67b0..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/irc/app/manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name": "Chromium IRC App",
- "version": "0.1",
- "app": {
- "launch" : {
- "url": "http://localhost:8080"
- },
- "origins": ["http://localhost:8080"]
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/_locales/en/messages.json
deleted file mode 100644
index 958f7866477..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/_locales/en/messages.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "extName": {
- "message": "Managed Bookmarks",
- "description": "The extension name."
- },
- "extDescription": {
- "message": "Adds bookmarks configured by your system administrator to Chrome.",
- "description": "The extension description."
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/manifest.json
deleted file mode 100644
index 6ee3f29bfb4..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/manifest.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "__MSG_extName__",
- "description": "__MSG_extDescription__",
- "default_locale": "en",
- "version": "1.0",
- "manifest_version": 2,
- "minimum_chrome_version": "33",
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "permissions": [
- "bookmarks"
- ],
- "storage": {
- "managed_schema": "schema.json"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/schema.json b/chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/schema.json
deleted file mode 100644
index 11e7aeb544b..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/managed_bookmarks/schema.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "type": "object",
- "properties": {
- "Bookmarks Bar": {
- "title": "Bookmarks in the Bookmarks Bar",
- "description": "Configures bookmarks that will appear in the Bookmarks Bar and can't be removed by the user.",
- "type": "array",
- "id": "ListOfBookmarks",
- "items": {
- "type": "object",
- "properties": {
- "title": {
- "title": "Bookmark name",
- "description": "The name that appears on the bookmark.",
- "type": "string"
- },
- "url": {
- "title": "Bookmark URL",
- "description": "The URL for the bookmark. If a URL is not set then this bookmark will be a folder.",
- "type": "string"
- },
- "children": {
- "title": "Contents of this bookmark folder",
- "description": "A list of bookmarks that will be inside this bookmark folder. If this is set then the URL for this bookmark will be ignored.",
- "$ref": "ListOfBookmarks"
- }
- }
- }
- },
- "Other Bookmarks": {
- "title": "Bookmarks in the Other Bookmarks folder",
- "description": "Configures bookmarks that will appear in the Other Bookmarks folder and can't be removed by the user.",
- "$ref": "ListOfBookmarks"
- }
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/mappy/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/mappy/manifest.json
deleted file mode 100644
index 2cacda9dc85..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/mappy/manifest.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "Mappy",
- "version": "1.0",
- "description": "Finds addresses in the web page you're on and pops up a map window.",
- "icons": { "128": "icon.png" },
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "content_scripts": [
- {
- "matches": ["http://*/*"],
- "js": ["mappy_content_script.js"]
- }
- ],
- "permissions": [
- "storage",
- "https://maps.google.com/*",
- "https://maps.googleapis.com/*"
- ],
- "page_action": {
- "default_name": "Display Map",
- "default_icon": "marker.png",
- "default_popup": "popup.html"
- },
- "manifest_version": 2,
- "content_security_policy": "default-src 'none'; style-src 'self'; script-src 'self'; connect-src https://maps.googleapis.com; img-src https://maps.googleapis.com"
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/maps_app/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/maps_app/manifest.json
deleted file mode 100644
index bb1f2e81008..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/maps_app/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "Google Maps",
- "version": "3",
- "icons": { "24": "24.png", "128": "128.png" },
- "app": {
- "urls": [
- "http://maps.google.com/"
- ],
- "launch": {
- "web_url": "http://maps.google.com/"
- }
- },
- "permissions": ["geolocation"],
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/news/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/news/_locales/en/messages.json
deleted file mode 100644
index 97e07c133ce..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/news/_locales/en/messages.json
+++ /dev/null
@@ -1,102 +0,0 @@
-{
- "extName": {
- "message": "News Reader (by Google)"
- },
- "extDesc": {
- "message": "Displays the latest stories from Google News in a popup."
- },
- "ext_default_title": {
- "message": "Google News"
- },
-
- "1": {
- "message": "Top Stories"
- },
- "n": {
- "message": "Nation"
- },
- "w": {
- "message": "World"
- },
- "b": {
- "message": "Business"
- },
- "t": {
- "message": "Science/Technology"
- },
- "e": {
- "message": "Entertainment"
- },
- "s": {
- "message": "Sports"
- },
- "m": {
- "message": "Health"
- },
- "po": {
- "message": "Most Popular"
- },
-
- "options": {
- "message": "Options"
- },
- "more_stories": {
- "message": "More stories"
- },
-
- "direction": {
- "message": "ltr"
- },
-
- "country": {
- "message": "Country:"
- },
- "topic": {
- "message": "Topics:"
- },
- "save": {
- "message": "Save"
- },
- "saveStatus": {
- "message": "Options saved"
- },
- "storyCount": {
- "message": "Number of stories:"
- },
- "newsOption": {
- "message": "Google News Options"
- },
- "customText": {
- "message": "Custom Topics:"
- },
- "maximumTopics": {
- "message": "(Maximum $count$)",
- "placeholders": {
- "count": {
- "content": "$1"
- }
- }
- },
- "submitButton": {
- "message": "Add"
- },
- "deleteTitle": {
- "message": "Delete"
- },
- "invalidChars": {
- "message": "Invalid character(s)"
- },
- "noTopic": {
- "message": "At least one Topic must be selected"
- },
-
- "fetchError": {
- "message": "Error: Failed to fetch news stories."
- },
- "wrongTopic": {
- "message": "Error: Not a valid feed."
- },
- "noStory": {
- "message": "No story right now"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/news/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/news/manifest.json
deleted file mode 100644
index a64df9cb5aa..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/news/manifest.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "__MSG_extName__",
- "version": "2.0",
- "description": "__MSG_extDesc__",
- "icons": { "128": "images/news_icon.png" },
- "default_locale":"en",
- "browser_action": {
- "default_title": "__MSG_ext_default_title__",
- "default_icon": "images/news_action.png",
- "default_popup": "views/feed.html"
- },
- "permissions": [
- "tabs",
- "http://news.google.com/*"
- ],
- "options_page": "views/options.html",
- "background": {
- "page": "views/background.html"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/news_a11y/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/news_a11y/manifest.json
deleted file mode 100644
index 496ad4f3c57..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/news_a11y/manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "News Reader",
- "version": "1.1",
- "description": "Displays the first 5 items from the 'Google News - top news' RSS feed in a popup.",
- "icons": { "128": "news_icon.png" },
- "browser_action": {
- "default_title": "Google News",
- "default_icon": "news_action.png",
- "default_popup": "feed.html"
- },
- "permissions": [
- "tabs",
- "http://news.google.com/*"
- ],
- "manifest_version": 2,
- "content_security_policy": "img-src 'self' http://* https://*; script-src 'self'; connect-src http://news.google.com; frame-src data:"
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/en/messages.json
deleted file mode 100644
index 9f5ea5db27e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/en/messages.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "name": {
- "message": "News Reader",
- "description": "Extension name in manifest."
- },
- "description": {
- "message": "Displays the first 5 items from the '$Google$ News - top news' RSS feed in a popup.",
- "description": "Extension description in manifest.",
- "placeholders": {
- "google": {
- "content": "Google",
- "example": "Google"
- }
- }
- },
- "default_title": {
- "message": "$Google$ News",
- "description": "Extension browser action tooltip text in manifest.",
- "placeholders": {
- "google": {
- "content": "Google",
- "example": "Google"
- }
- }
- },
- "unknown_title": {
- "message": "Unknown title",
- "description": "Unknown news title."
- },
- "error": {
- "message": "Error: $error$",
- "description": "Generic error template. Expects error parameter to be passed in.",
- "placeholders": {
- "error": {
- "content": "$1",
- "example": "Failed to fetch RSS feed."
- }
- }
- },
- "failed_to_fetch_rss": {
- "message": "Failed to fetch RSS feed.",
- "description": "User visible error message."
- },
- "not_a_valid_feed": {
- "message": "Not a valid feed.",
- "description": "User visible error message."
- },
- "more_stories": {
- "message": "To $Google$ News \u00BB",
- "description": "Link name to more Google News.",
- "placeholders": {
- "google": {
- "content": "Google",
- "example": "Google"
- }
- }
- },
- "newsUrl": {
- "message": "http://news.google.com",
- "description": "Url to Google News."
- }
-}
-
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/es/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/es/messages.json
deleted file mode 100644
index 2093149dd40..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/es/messages.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
- "name": {
- "message": "Lector de noticias",
- "description": "Nombre de la extensin en el manifiesto."
- },
- "description": {
- "message": "Muestra los primeros 5 eventos de '$Google$ noticias - destacados' RSS feed en una ventana.",
- "description": "Descripcin de la extensin en el manifiesto.",
- "placeholders": {
- "google": {
- "content": "Google",
- "example": "Google"
- }
- }
- },
- "default_title": {
- "message": "$Google$ noticias",
- "description": "Texto de la accion de men de la extension en el manifiesto.",
- "placeholders": {
- "google": {
- "content": "Google",
- "example": "Google"
- }
- }
- },
- "unknown_title": {
- "message": "Ttulo desconocido",
- "description": "Noticia con ttulo desconocido."
- },
- "error": {
- "message": "Error: $error$",
- "description": "Plantilla de error genrico. Hace falta pasar un parmetro de error.",
- "placeholders": {
- "error": {
- "content": "$1",
- "example": "Fallo al capturar el RSS feed."
- }
- }
- },
- "failed_to_fetch_rss": {
- "message": "Fallo al capturar el RSS feed.",
- "description": "Mensaje de error visible para el usuario."
- },
- "not_a_valid_feed": {
- "message": "Feed no vlido.",
- "description": "Mensaje de error visible para el usuario."
- },
- "more_stories": {
- "message": "Ir a $Google$ noticias \u00BB",
- "description": "Nombre del enlace a Google noticias.",
- "placeholders": {
- "google": {
- "content": "Google",
- "example": "Google"
- }
- }
- },
- "newsUrl": {
- "message": "http://news.google.es",
- "description": "Direccin de Google News."
- }
-}
-
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/sr/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/sr/messages.json
deleted file mode 100644
index 7d43d7a0976..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/_locales/sr/messages.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "name": {
- "message": "Читач вести",
- "description": "Назив екстензије у манифесту."
- },
- "description": {
- "message": "Приказује првих 5 вести са '$Google$ Вести - главне вести' у прозорчићу.",
- "description": "Опис екстензије у манифесту.",
- "placeholders": {
- "google": {
- "content": "Google",
- "example": "Google"
- }
- }
- },
- "default_title": {
- "message": "$Google$ Вести",
- "description": "Назив дугмета екстензије.",
- "placeholders": {
- "google": {
- "content": "Google",
- "example": "Google"
- }
- }
- },
- "unknown_title": {
- "message": "Непознат наслов",
- "description": "Непознат наслов вести."
- },
- "error": {
- "message": "Грешка - $error$",
- "description": "Општи облик грешке.",
- "placeholders": {
- "error": {
- "content": "$1",
- "example": "фид је недоступан."
- }
- }
- },
- "failed_to_fetch_rss": {
- "message": "фид је недоступан.",
- "description": "Порука грешке коју види корисник када је фид недоступан."
- },
- "not_a_valid_feed": {
- "message": "неисправан фид.",
- "description": "Порука грешке коју види корисник када је фид неисправан."
- },
- "more_stories": {
- "message": "Ка $Google$ Вестима \u00BB",
- "description": "Назив везе ка још вести.",
- "placeholders": {
- "google": {
- "content": "Google",
- "example": "Google"
- }
- }
- }
-}
-
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/manifest.json
deleted file mode 100644
index 32b4cc0e6ef..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/news_i18n/manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "__MSG_name__",
- "version": "1.1",
- "description": "__MSG_description__",
- "icons": { "128": "news_icon.png" },
- "browser_action": {
- "default_title": "__MSG_default_title__",
- "default_icon": "news_action.png",
- "default_popup": "feed.html"
- },
- "permissions": [
- "tabs",
- "http://news.google.com/*",
- "http://news.google.es/*"
- ],
- "default_locale": "en"
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/no_cookies/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/no_cookies/manifest.json
deleted file mode 100644
index 1a0681c9b0f..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/no_cookies/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "No Cookies",
- "description": "Removes 'Cookie' and 'Set-Cookie' headers.",
- "version": "1.0",
- "manifest_version": 2,
- "permissions": [
- "webRequest",
- "webRequestBlocking",
- "https://*/*",
- "http://*/*"
- ],
- "background": {
- "scripts": ["background.js"]
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/oauth_contacts/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/oauth_contacts/manifest.json
deleted file mode 100644
index 5771b423999..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/oauth_contacts/manifest.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "name": "Sample - OAuth Contacts",
- "version": "1.0.6",
- "icons": { "48": "img/icon-48.png",
- "128": "img/icon-128.png" },
- "description": "Uses OAuth to connect to Google's contacts service and display a list of your contacts.",
- "background": {
- "scripts": [
- "chrome_ex_oauthsimple.js",
- "chrome_ex_oauth.js",
- "background.js"
- ]
- },
- "browser_action": {
- "default_title": "",
- "default_icon": "img/icon-19-off.png"
- },
- "permissions": [
- "tabs",
- "http://www.google.com/m8/feeds/*",
- "https://www.google.com/accounts/OAuthGetRequestToken",
- "https://www.google.com/accounts/OAuthAuthorizeToken",
- "https://www.google.com/accounts/OAuthGetAccessToken"
- ],
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/optional_permissions/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/optional_permissions/manifest.json
deleted file mode 100644
index ac62ef2d528..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/optional_permissions/manifest.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "Optional Permissions New Tab",
- "version": "1.2.5.0",
- "description": "Demonstrates optional permissions in extensions",
- "permissions": ["storage"],
- "optional_permissions": [
- "topSites"
- ],
- "icons": {
- "16": "images/optional_permissions16.png",
- "32": "images/optional_permissions32.png",
- "48": "images/optional_permissions48.png",
- "128": "images/optional_permissions128.png"
- },
- "chrome_url_overrides": {
- "newtab": "newtab.html"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/plugin_settings/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/plugin_settings/_locales/en/messages.json
deleted file mode 100644
index f2bd7f5aec1..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/plugin_settings/_locales/en/messages.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "extName": {
- "message": "Per-plugin content settings"
- },
- "extDescription": {
- "message": "Customize your content setting for different plugins."
- },
- "patternColumnHeader": {
- "message": "Hostname Pattern"
- },
- "settingColumnHeader": {
- "message": "Behavior"
- },
- "allowRule": {
- "message": "Allow"
- },
- "blockRule": {
- "message": "Block"
- },
- "addNewPattern": {
- "message": "Add a new hostname pattern"
- }
-} \ No newline at end of file
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/plugin_settings/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/plugin_settings/manifest.json
deleted file mode 100644
index a6181e2c888..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/plugin_settings/manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "name" : "__MSG_extName__",
- "version" : "0.6",
- "description" : "__MSG_extDescription__",
- "options_page": "options.html",
- "permissions": [
- "contentSettings"
- ],
- "icons": {
- "128": "bunny128.png",
- "48": "bunny48.png"
- },
- "minimum_chrome_version": "16.0.912",
- "default_locale": "en",
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/proxy_configuration/_locales/en/messages.json b/chromium/chrome/common/extensions/docs/examples/extensions/proxy_configuration/_locales/en/messages.json
deleted file mode 100644
index 74bc6f35640..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/proxy_configuration/_locales/en/messages.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "extName": {
- "message": "Proxy Extension API Sample",
- "description": "The extension name."
- },
- "extDescription": {
- "message": "Set Chrome-specific proxies; a demonstration of Chrome's Proxy API",
- "description": "The extension description."
- },
- "headerDirectConnection": {
- "message": "Direct Connection",
- "description": "Header for 'Direct Connection' configuration `fieldset`."
- },
- "errorNoExtensionAccess": {
- "message": "Sorry. This browser's proxy settings cannot be controlled via extensions.",
- "description": "Error message displayed when `levelOfControl` is 'not_controllable'."
- },
- "errorOtherExtensionControls": {
- "message": "Sorry. This browser's proxy settings are being controlled by another extension. Please visit chrome://extensions for details.",
- "description": "Error message displayed when `levelOfControl` is 'controlled_by_other_extensions'."
- },
- "errorSettingRegularProxy": {
- "message": "Setting regular proxy settings failed. Sorry!",
- "description": "Error message, displayed when failing to set regular proxy settings."
- },
- "errorSettingIncognitoProxy": {
- "message": "Setting incognito proxy settings failed. Sorry!",
- "description": "Error message, displayed when failing to set incognito proxy settings."
- },
- "successfullySetProxy": {
- "message": "Your proxy settings have been saved successfully; this window will close automagically. Have a nice day!",
- "description": "Success message, displayed after proxy settings have been written."
- },
- "errorPopupTitle": {
- "message": "Error: $1",
- "description": "Error message used as popup title."
- },
- "errorProxyError": {
- "message": "ProxyError: $1.",
- "description": "Error message displayed in popup when an error occurs."
- },
- "errorProxyDetailedError": {
- "message": "ProxyError: $1. $2.",
- "description": "Error message displayed in popup when an error occurs."
- },
- "errorIdNotFound": {
- "message": "Element with ID `$1` doesn't exist in the document",
- "description": "Error message thrown when the given `id` doesn't exist"
- },
- "errorIdNotForm": {
- "message": "Element with ID `$1` isn't a form element.",
- "description": "Error message thrown when the given `id` isn't a form element."
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/proxy_configuration/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/proxy_configuration/manifest.json
deleted file mode 100644
index 41e4e869678..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/proxy_configuration/manifest.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "name": "__MSG_extName__",
- "version": "0.4",
- "description": "__MSG_extDescription__",
- "default_locale": "en",
- "browser_action": {
- "default_icon": "icon16.png",
- "default_popup": "popup.html"
- },
- "icons": {
- "16": "icon16.png",
- "32": "icon32.png",
- "48": "icon48.png",
- "128": "icon128.png"
- },
- "background": {
- "scripts": [
- "proxy_form_controller.js",
- "proxy_error_handler.js",
- "background.js"
- ]
- },
- "permissions": [
- "proxy"
- ],
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/speak_selection/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/speak_selection/manifest.json
deleted file mode 100644
index fed36081f99..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/speak_selection/manifest.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "name": "Speak Selection",
- "version": "1.1",
- "description": "Speaks the current selection out loud.",
- "permissions": [
- "<all_urls>",
- "tts",
- "tabs"
- ],
-
- "background": {
- "scripts": [
- "keycodes.js",
- "tabs.js",
- "background.js"
- ]
- },
-
- "browser_action": {
- "default_icon": "SpeakSel19.png",
- "default_title": "Speak Selection"
- },
-
- "options_page": "options.html",
-
- "minimum_chrome_version": "14",
-
- "content_scripts": [
- {
- "matches": [
- "<all_urls>"
- ],
- "all_frames": true,
- "js": [
- "keycodes.js",
- "content_script.js"
- ]
- }
- ],
-
- "icons": {
- "16": "SpeakSel16.png",
- "48": "SpeakSel48.png",
- "128": "SpeakSel128.png",
- "256": "SpeakSel256.png"
- },
-
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/talking_alarm_clock/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/talking_alarm_clock/manifest.json
deleted file mode 100644
index 79f5b50a6d2..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/talking_alarm_clock/manifest.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "name": "Talking Alarm Clock",
- "version": "1.3",
- "description": "A clock with two configurable alarms that will play a sound and speak a phrase of your choice.",
- "permissions": [ "background", "tts" ],
-
- "background": { "scripts": ["common.js", "background.js"] },
-
- "browser_action": {
- "default_icon": "clock-19.png",
- "default_title": "Talking Alarm Clock",
- "default_popup": "popup.html"
- },
-
- "icons": {
- "16": "clock-16.png",
- "48": "clock-48.png",
- "128": "clock-128.png",
- "256": "clock-256.png"
- },
-
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/ttsdebug/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/ttsdebug/manifest.json
deleted file mode 100644
index 0a856f92856..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/ttsdebug/manifest.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "app": {
- "launch": {
- "local_path": "ttsdebug.html"
- }
- },
- "description": "Tool for developers of Chrome TTS engine extensions to help them test their engines are implementing the API correctly.",
- "icons": {
- "16": "16.png",
- "128": "128.png",
- "256": "256.png"
- },
- "minimum_chrome_version": "14",
- "name": "TTS Debug",
- "permissions": [ "tts" ],
- "version": "1.0",
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/extensions/ttsdemo/manifest.json b/chromium/chrome/common/extensions/docs/examples/extensions/ttsdemo/manifest.json
deleted file mode 100644
index ade1281d469..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/extensions/ttsdemo/manifest.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "app": {
- "launch": {
- "local_path": "ttsdemo.html"
- }
- },
- "description": "Demo Chrome's synthesized text-to-speech capabilities.",
- "icons": {
- "16": "16.png",
- "128": "128.png",
- "256": "256.png"
- },
- "minimum_chrome_version": "14",
- "name": "TTS Demo",
- "permissions": [ "tts" ],
- "version": "2.1",
-
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/howto/sandbox/manifest.json b/chromium/chrome/common/extensions/docs/examples/howto/sandbox/manifest.json
deleted file mode 100644
index 0fd7c52b674..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/howto/sandbox/manifest.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "Sandboxed Frame",
- "description": "Demonstrate use of handlebars inside a sandboxed frame",
- "version": "1.0",
- "manifest_version": 2,
- "permissions": ["notifications"],
- "background": {
- "page": "eventpage.html",
- "persistent": false
- },
- "browser_action": {
- "default_icon" : "icon.png",
- "default_title": "Start Event Page"
- },
- "sandbox": {
- "pages": ["sandbox.html"]
- },
- "web_accessible_resources": ["icon.png"]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/howto/tab_shortcuts/manifest.json b/chromium/chrome/common/extensions/docs/examples/howto/tab_shortcuts/manifest.json
deleted file mode 100644
index 198ac7a54f7..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/howto/tab_shortcuts/manifest.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "name": "Tab Shortcuts",
- "version": "1.0",
- "description": "Allows pinning and duplication of tabs via keyboard shortcuts.",
- "manifest_version": 2,
- "background": {
- "scripts": ["tab_shortcuts.js"],
- "persistent": false
- },
- "commands": {
- "toggle-pin-tab": {
- "suggested_key": {
- "default": "Ctrl+Shift+X",
- "mac": "Command+Shift+X"
- },
- "description": "Toggles whether the current tab is pinned."
- },
- "duplicate-tab": {
- "suggested_key": {
- "default": "Ctrl+Shift+Z",
- "mac": "Command+Shift+Z"
- },
- "description": "Duplicates the current tab."
- }
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/tutorials/analytics/manifest.json b/chromium/chrome/common/extensions/docs/examples/tutorials/analytics/manifest.json
deleted file mode 100644
index 11f90a07c7e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/tutorials/analytics/manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "name": "Event Tracking with Google Analytics",
- "version": "2.0.0",
- "description": "A sample extension which uses Google Analytics to track usage.",
- "browser_action": {
- "default_title": "Open the popup",
- "default_icon": "analytics-extension-icon-19.png",
- "default_popup" : "popup.html"
- },
- "icons": {
- "48": "analytics-extension-icon-48.png",
- "128": "analytics-extension-icon-128.png"
- },
-
- "manifest_version": 2,
- "content_security_policy": "script-src 'self' https://ssl.google-analytics.com; object-src 'self'"
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/tutorials/broken_background_color/manifest.json b/chromium/chrome/common/extensions/docs/examples/tutorials/broken_background_color/manifest.json
deleted file mode 100644
index 8e84613c98d..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/tutorials/broken_background_color/manifest.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "name": "Broken Background Color",
- "version": "1.0",
- "description": "Fix an Extension!",
- "permissions": ["activeTab", "declarativeContent", "storage"],
- "options_page": "options.html",
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "page_action": {
- "default_popup": "popup.html",
- "default_icon": {
- "16": "images/get_started16.png",
- "32": "images/get_started32.png",
- "48": "images/get_started48.png",
- "128": "images/get_started128.png"
- }
- },
- "icons": {
- "16": "images/get_started16.png",
- "32": "images/get_started32.png",
- "48": "images/get_started48.png",
- "128": "images/get_started128.png"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/tutorials/get_started/manifest.json b/chromium/chrome/common/extensions/docs/examples/tutorials/get_started/manifest.json
deleted file mode 100644
index b9ff56c22d5..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/tutorials/get_started/manifest.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "Getting Started Example",
- "version": "1.0",
- "description": "Build an Extension!",
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/tutorials/get_started_complete/manifest.json b/chromium/chrome/common/extensions/docs/examples/tutorials/get_started_complete/manifest.json
deleted file mode 100644
index 71290e77441..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/tutorials/get_started_complete/manifest.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "name": "Getting Started Example",
- "version": "1.0",
- "description": "Build an Extension!",
- "permissions": ["activeTab", "declarativeContent", "storage"],
- "options_page": "options.html",
- "background": {
- "scripts": ["background.js"],
- "persistent": false
- },
- "page_action": {
- "default_popup": "popup.html",
- "default_icon": {
- "16": "images/get_started16.png",
- "32": "images/get_started32.png",
- "48": "images/get_started48.png",
- "128": "images/get_started128.png"
- }
- },
- "icons": {
- "16": "images/get_started16.png",
- "32": "images/get_started32.png",
- "48": "images/get_started48.png",
- "128": "images/get_started128.png"
- },
- "manifest_version": 2
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/tutorials/getstarted/manifest.json b/chromium/chrome/common/extensions/docs/examples/tutorials/getstarted/manifest.json
deleted file mode 100644
index 28a1fda3744..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/tutorials/getstarted/manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "manifest_version": 2,
-
- "name": "Getting started example",
- "description": "This extension allows the user to change the background color of the current page.",
- "version": "1.0",
-
- "browser_action": {
- "default_icon": "icon.png",
- "default_popup": "popup.html"
- },
- "permissions": [
- "activeTab",
- "storage"
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/tutorials/hello_extensions/manifest.json b/chromium/chrome/common/extensions/docs/examples/tutorials/hello_extensions/manifest.json
deleted file mode 100644
index d21bdaae0ee..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/tutorials/hello_extensions/manifest.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "Hello Extensions",
- "description" : "Base Level Extension",
- "version": "1.0",
- "browser_action": {
- "default_popup": "hello.html",
- "default_icon": "hello_extensions.png"
- },
- "manifest_version": 2,
- "commands": {
- "_execute_browser_action": {
- "suggested_key": {
- "default": "Ctrl+Shift+F",
- "mac": "MacCtrl+Shift+F"
- },
- "description": "Opens hello.html"
- }
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/examples/tutorials/oauth_starter/manifest.json b/chromium/chrome/common/extensions/docs/examples/tutorials/oauth_starter/manifest.json
deleted file mode 100644
index 1035894ad22..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/tutorials/oauth_starter/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "OAuth Tutorial FriendBlock",
- "version": "1.0",
- "description": "Uses OAuth to connect to Google's People API and display contacts photos.",
- "manifest_version": 2,
- "browser_action": {
- "default_title": "FriendBlock, friends face's in a block."
- },
- "background": {
- "scripts": [
- "background.js"
- ],
- "persistent": false
- }
- }
diff --git a/chromium/chrome/common/extensions/docs/examples/tutorials/oauth_tutorial_complete/manifest.json b/chromium/chrome/common/extensions/docs/examples/tutorials/oauth_tutorial_complete/manifest.json
deleted file mode 100644
index 5afe50bee4e..00000000000
--- a/chromium/chrome/common/extensions/docs/examples/tutorials/oauth_tutorial_complete/manifest.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "name": "OAuth Tutorial FriendBlock",
- "version": "1.0",
- "description": "Uses OAuth to connect to Google's People API and display contacts photos.",
- "manifest_version": 2,
- "browser_action": {
- "default_title": "FriendBlock, friends face's in a block."
- },
- "permissions": [
- "identity"
- ],
- "background": {
- "scripts": [
- "background.js"
- ],
- "persistent": false
- },
- "oauth2": {
- "client_id": "ClientIDFromGoogleAPIConsole",
- "scopes":["https://www.googleapis.com/auth/contacts.readonly"]
- },
- "key": "KeyFromDeveloperDashboardHere"
-}
diff --git a/chromium/chrome/common/extensions/docs/server2/known_broken_links.json b/chromium/chrome/common/extensions/docs/server2/known_broken_links.json
deleted file mode 100644
index 4b1d59fdaa9..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/known_broken_links.json
+++ /dev/null
@@ -1,2019 +0,0 @@
-[
- [
- 302,
- "extensions/app_identity.html",
- "extensions/publish_app.html",
- "redirects to /apps/publish_app.html"
- ],
- [
- 404,
- "apps/manifest/storage.html",
- "apps/manifest/chrome:/policy",
- "target page not found"
- ],
- [
- 200,
- "apps/api_index.html",
- "#manifest",
- "target anchor not found"
- ],
- [
- 404,
- "apps/tut_oauth.html",
- "apps/examples/extensions/oauth_contacts/chrome_ex_oauth.html",
- "target page not found"
- ],
- [
- 404,
- "apps/tut_oauth.html",
- "apps/examples/extensions/oauth_contacts/chrome_ex_oauth.js",
- "target page not found"
- ],
- [
- 404,
- "apps/tut_oauth.html",
- "apps/examples/extensions/oauth_contacts/chrome_ex_oauthsimple.js",
- "target page not found"
- ],
- [
- 404,
- "apps/tut_oauth.html",
- "apps/examples/extensions/oauth_contacts/onload.js",
- "target page not found"
- ],
- [
- 200,
- "extensions/debugger.html",
- "extensions/samples.html#debugger",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/privacy.html",
- "extensions/samples.html#privacy",
- "target anchor not found"
- ],
- [
- 200,
- "apps/events.html",
- "#filtered",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/contextMenus.html",
- "extensions/samples.html#contextMenus",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/webRequest.html",
- "extensions/samples.html#webrequest",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/browsingData.html",
- "extensions/samples.html#browsingData",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/override.html",
- "extensions/samples.html#chrome_url_overrides",
- "target anchor not found"
- ],
- [
- 302,
- "apps/types.html",
- "apps/proxy.html#overview-examples",
- "redirects to /extensions/proxy.html"
- ],
- [
- 302,
- "apps/types.html",
- "apps/proxy.html#property-settings",
- "redirects to /extensions/proxy.html"
- ],
- [
- 302,
- "apps/experimental_webInspector.html",
- "apps/experimental_devtools.html",
- "redirects to /extensions/experimental_devtools.html"
- ],
- [
- 302,
- "apps/experimental_devtools_network.html",
- "apps/devtools_network.html",
- "redirects to /extensions/devtools_network.html"
- ],
- [
- 404,
- "extensions/manifest/storage.html",
- "extensions/manifest/chrome:/policy",
- "target page not found"
- ],
- [
- 302,
- "apps/tut_debugging.html",
- "apps/getstarted.html",
- "redirects to /extensions/getstarted.html"
- ],
- [
- 302,
- "apps/tut_debugging.html",
- "apps/getstarted.html#unpacked",
- "redirects to /extensions/getstarted.html"
- ],
- [
- 302,
- "apps/tut_debugging.html",
- "apps/getstarted.html#next-steps",
- "redirects to /extensions/getstarted.html"
- ],
- [
- 302,
- "apps/storage.html",
- "apps/manifest/incognito.html",
- "redirects to /extensions/manifest/incognito.html"
- ],
- [
- 302,
- "apps/messaging.html",
- "apps/tabs.html#method-sendMessage",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/messaging.html",
- "apps/tabs.html#method-connect",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/messaging.html",
- "apps/tabs.html#method-connect",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "extensions/notifications.html",
- "extensions/app_external.html",
- "redirects to /apps/app_external.html"
- ],
- [
- 302,
- "extensions/notifications.html",
- "extensions/app_lifecycle.html#create_event_page",
- "redirects to /apps/app_lifecycle.html"
- ],
- [
- 302,
- "apps/app_codelab8_webresources.html",
- "apps/webview_tag.html",
- "redirects to /apps/tags/webview.html"
- ],
- [
- 302,
- "apps/app_codelab8_webresources.html",
- "apps/webview_tag.html",
- "redirects to /apps/tags/webview.html"
- ],
- [
- 200,
- "apps/contextMenus.html",
- "apps/samples.html#contextMenus",
- "target anchor not found"
- ],
- [
- 302,
- "apps/contextMenus.html",
- "apps/tabs.html#type-Tab",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/contextMenus.html",
- "apps/tabs.html#type-Tab",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/contextMenus.html",
- "apps/tabs.html#type-Tab",
- "redirects to /extensions/tabs.html"
- ],
- [
- 404,
- "extensions/manifest/externally_connectable.html",
- "extensions/manifest/runtime.html#method-connect",
- "target page not found"
- ],
- [
- 404,
- "extensions/manifest/externally_connectable.html",
- "extensions/manifest/runtime.html#method-sendMessage",
- "target page not found"
- ],
- [
- 404,
- "extensions/manifest/externally_connectable.html",
- "extensions/manifest/runtime.html#property-MessageSender-tlsChannelId",
- "target page not found"
- ],
- [
- 404,
- "extensions/manifest/externally_connectable.html",
- "extensions/manifest/runtime.html#property-MessageSender-tlsChannelId",
- "target page not found"
- ],
- [
- 404,
- "extensions/declare_permissions.html",
- "extensions/dns.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/declare_permissions.html",
- "extensions/idltest.html",
- "target page not found"
- ],
- [
- 302,
- "extensions/declare_permissions.html",
- "extensions/system_display.html",
- "redirects to /apps/system_display.html"
- ],
- [
- 200,
- "extensions/experimental.html",
- "extensions/samples.html#experimental",
- "target anchor not found"
- ],
- [
- 302,
- "extensions/samples.html",
- "extensions/app_runtime.html",
- "redirects to /apps/app_runtime.html"
- ],
- [
- 302,
- "extensions/samples.html",
- "extensions/app_runtime.html#event-onLaunched",
- "redirects to /apps/app_runtime.html"
- ],
- [
- 302,
- "extensions/samples.html",
- "extensions/app_window.html#method-create",
- "redirects to /apps/app_window.html"
- ],
- [
- 302,
- "extensions/samples.html",
- "extensions/app_runtime.html#event-onLaunched",
- "redirects to /apps/app_runtime.html"
- ],
- [
- 302,
- "extensions/samples.html",
- "extensions/app_runtime.html#event-onRestarted",
- "redirects to /apps/app_runtime.html"
- ],
- [
- 302,
- "extensions/samples.html",
- "extensions/app_window.html#method-create",
- "redirects to /apps/app_window.html"
- ],
- [
- 200,
- "extensions/contentSettings.html",
- "extensions/samples.html#contentSettings",
- "target anchor not found"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_inspectedWindow.html",
- "redirects to /extensions/devtools_inspectedWindow.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_network.html",
- "redirects to /extensions/devtools_network.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_panels.html",
- "redirects to /extensions/devtools_panels.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_panels.html",
- "redirects to /extensions/devtools_panels.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_inspectedWindow.html",
- "redirects to /extensions/devtools_inspectedWindow.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_network.html",
- "redirects to /extensions/devtools_network.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/extension.html",
- "redirects to /extensions/extension.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_panels.html",
- "redirects to /extensions/devtools_panels.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_inspectedWindow.html",
- "redirects to /extensions/devtools_inspectedWindow.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_panels.html#method-ExtensionSidebarPane-setPage",
- "redirects to /extensions/devtools_panels.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_panels.html#method-ExtensionSidebarPane-setObject",
- "redirects to /extensions/devtools_panels.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_panels.html#method-ExtensionSidebarPane-setExpression",
- "redirects to /extensions/devtools_panels.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/tabs.html#method-executeScript",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_inspectedWindow.html#property-tabId",
- "redirects to /extensions/devtools_inspectedWindow.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/tabs.html#method-executeScript",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_inspectedWindow.html#method-eval",
- "redirects to /extensions/devtools_inspectedWindow.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/tabs.html#method-executeScript",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_inspectedWindow.html#method-eval",
- "redirects to /extensions/devtools_inspectedWindow.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/devtools_inspectedWindow.html#method-eval",
- "redirects to /extensions/devtools_inspectedWindow.html"
- ],
- [
- 302,
- "apps/devtools.html",
- "apps/tabs.html#method-sendMessage",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/event_pages.html",
- "apps/declarativeWebRequest.html",
- "redirects to /extensions/declarativeWebRequest.html"
- ],
- [
- 302,
- "apps/event_pages.html",
- "apps/extension.html#method-getBackgroundPage",
- "redirects to /extensions/extension.html"
- ],
- [
- 200,
- "apps/event_pages.html",
- "apps/events.html#filtered",
- "target anchor not found"
- ],
- [
- 302,
- "apps/event_pages.html",
- "apps/tabs.html#event-onUpdated",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/event_pages.html",
- "apps/webNavigation.html#event-onCompleted",
- "redirects to /extensions/webNavigation.html"
- ],
- [
- 200,
- "extensions/declarativeWebRequest.html",
- "#type-Rule",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/topSites.html",
- "extensions/samples.html#topsites",
- "target anchor not found"
- ],
- [
- 302,
- "apps/content_scripts.html",
- "apps/extension.html",
- "redirects to /extensions/extension.html"
- ],
- [
- 302,
- "apps/content_scripts.html",
- "apps/tabs.html#method-executeScript",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/content_scripts.html",
- "apps/tabs.html#method-insertCSS",
- "redirects to /extensions/tabs.html"
- ],
- [
- 200,
- "apps/content_scripts.html",
- "apps/samples.html#script",
- "target anchor not found"
- ],
- [
- 200,
- "apps/content_scripts.html",
- "apps/samples.html#message-timer",
- "target anchor not found"
- ],
- [
- 200,
- "apps/content_scripts.html",
- "apps/samples.html#page-redder",
- "target anchor not found"
- ],
- [
- 200,
- "apps/content_scripts.html",
- "apps/samples.html#email-this-page-(by-google)",
- "target anchor not found"
- ],
- [
- 302,
- "apps/experimental_devtools_inspectedWindow.html",
- "apps/devtools_inspectedWindow.html",
- "redirects to /extensions/devtools_inspectedWindow.html"
- ],
- [
- 302,
- "apps/background_pages.html",
- "apps/manifest/incognito.html",
- "redirects to /extensions/manifest/incognito.html"
- ],
- [
- 302,
- "apps/background_pages.html",
- "apps/overview.html#arch",
- "redirects to /extensions/overview.html"
- ],
- [
- 200,
- "apps/background_pages.html",
- "apps/declare_permissions.html#background",
- "target anchor not found"
- ],
- [
- 302,
- "apps/background_pages.html",
- "apps/extension.html#method-getViews",
- "redirects to /extensions/extension.html"
- ],
- [
- 302,
- "apps/background_pages.html",
- "apps/extension.html#method-getBackgroundPage",
- "redirects to /extensions/extension.html"
- ],
- [
- 302,
- "apps/background_pages.html",
- "apps/tabs.html#method-create",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/packaging.html",
- "apps/overview.html",
- "redirects to /extensions/overview.html"
- ],
- [
- 302,
- "apps/declare_permissions.html",
- "apps/cookies.html",
- "redirects to /extensions/cookies.html"
- ],
- [
- 404,
- "apps/declare_permissions.html",
- "target page not found"
- ],
- [
- 302,
- "apps/declare_permissions.html",
- "apps/desktopCapture.html",
- "redirects to /extensions/desktopCapture.html"
- ],
- [
- 404,
- "apps/declare_permissions.html",
- "apps/diagnostics.html",
- "target page not found"
- ],
- [
- 404,
- "apps/declare_permissions.html",
- "apps/dns.html",
- "target page not found"
- ],
- [
- 302,
- "apps/declare_permissions.html",
- "apps/fileBrowserHandler.html",
- "redirects to /extensions/fileBrowserHandler.html"
- ],
- [
- 404,
- "apps/declare_permissions.html",
- "apps/fileSystemProvider.html",
- "target page not found"
- ],
- [
- 302,
- "apps/declare_permissions.html",
- "apps/signedInDevices.html",
- "redirects to /extensions/signedInDevices.html"
- ],
- [
- 404,
- "apps/declare_permissions.html",
- "apps/system_network.html",
- "target page not found"
- ],
- [
- 404,
- "apps/declare_permissions.html",
- "apps/webview.html",
- "target page not found"
- ],
- [
- 302,
- "apps/app_deprecated.html",
- "apps/webview_tag.html",
- "redirects to /apps/tags/webview.html"
- ],
- [
- 200,
- "extensions/content_scripts.html",
- "extensions/samples.html#script",
- "target anchor not found"
- ],
- [
- 302,
- "apps/samples.html",
- "apps/extension.html#property-lastError",
- "redirects to /extensions/extension.html"
- ],
- [
- 302,
- "apps/samples.html",
- "apps/extension.html#property-lastError-message",
- "redirects to /extensions/extension.html"
- ],
- [
- 302,
- "apps/samples.html",
- "apps/extension.html#property-lastError",
- "redirects to /extensions/extension.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/activityLogPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/app.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/bookmarkManagerPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/bookmarks.html",
- "redirects to /extensions/bookmarks.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/override.html",
- "redirects to /extensions/override.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/brailleDisplayPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/browserAction.html",
- "redirects to /extensions/browserAction.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/browsingData.html",
- "redirects to /extensions/browsingData.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/cast_channel.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/cast_streaming_rtpStream.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/cast_streaming_session.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/cast_streaming_udpTransport.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/chromeosInfoPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/cloudPrintPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/commandLinePrivate.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/commands.html",
- "redirects to /extensions/commands.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/contentSettings.html",
- "redirects to /extensions/contentSettings.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/cookies.html",
- "redirects to /extensions/cookies.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/debugger.html",
- "redirects to /extensions/debugger.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/declarativeContent.html",
- "redirects to /extensions/declarativeContent.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/declarativeWebRequest.html",
- "redirects to /extensions/declarativeWebRequest.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/webRequest.html",
- "redirects to /extensions/webRequest.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/desktopCapture.html",
- "redirects to /extensions/desktopCapture.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/developerPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/devtools_inspectedWindow.html",
- "redirects to /extensions/devtools_inspectedWindow.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/devtools_network.html",
- "redirects to /extensions/devtools_network.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/devtools_panels.html",
- "redirects to /extensions/devtools_panels.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/diagnostics.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/dial.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/dns.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/downloads.html",
- "redirects to /extensions/downloads.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/echoPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/enterprise_platformKeysPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/experimental_accessibility.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/experimental_devtools_console.html",
- "redirects to /extensions/experimental_devtools_console.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/experimental_discovery.html",
- "redirects to /extensions/experimental_discovery.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/experimental_history.html",
- "redirects to /extensions/experimental_history.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/extension.html",
- "redirects to /extensions/extension.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/feedbackPrivate.html",
- "redirects to /extensions/feedbackPrivate.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/fileBrowserHandler.html",
- "redirects to /extensions/fileBrowserHandler.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/fileBrowserHandlerInternal.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/fileManagerPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/fileSystemProvider.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/firstRunPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/fontSettings.html",
- "redirects to /extensions/fontSettings.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/history.html",
- "redirects to /extensions/history.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/override.html",
- "redirects to /extensions/override.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/identityPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/idltest.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/input_ime.html",
- "redirects to /extensions/input_ime.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/inputMethodPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/logPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/management.html",
- "redirects to /extensions/management.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/override.html",
- "redirects to /extensions/override.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/manifestTypes.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/mdns.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/mediaGalleriesPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/mediaPlayerPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/metricsPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/networkingPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/omnibox.html",
- "redirects to /extensions/omnibox.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/pageAction.html",
- "redirects to /extensions/pageAction.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/pageActions.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/pageCapture.html",
- "redirects to /extensions/pageCapture.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/preferencesPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/privacy.html",
- "redirects to /extensions/privacy.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/processes.html",
- "redirects to /extensions/processes.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/proxy.html",
- "redirects to /extensions/proxy.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/sessions.html",
- "redirects to /extensions/sessions.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/signedInDevices.html",
- "redirects to /extensions/signedInDevices.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/sockets_tcp.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/sockets_tcpServer.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/sockets_udp.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/streamsPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/system_network.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/systemIndicator.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/systemPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/tabCapture.html",
- "redirects to /extensions/tabCapture.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/tabs.html",
- "redirects to /extensions/tabs.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/terminalPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/test.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/topSites.html",
- "redirects to /extensions/topSites.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/ttsEngine.html",
- "redirects to /extensions/ttsEngine.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/virtualKeyboardPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/wallpaperPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/webNavigation.html",
- "redirects to /extensions/webNavigation.html"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/webRequest.html",
- "redirects to /extensions/webRequest.html"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/webRequestInternal.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/webstorePrivate.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/webview.html",
- "target page not found"
- ],
- [
- 404,
- "apps/private_apis.html",
- "apps/webviewTag.html",
- "target page not found"
- ],
- [
- 302,
- "apps/private_apis.html",
- "apps/windows.html",
- "redirects to /extensions/windows.html"
- ],
- [
- 200,
- "apps/private_apis.html",
- "#icon",
- "target anchor not found"
- ],
- [
- 200,
- "apps/private_apis.html",
- "#tooltip",
- "target anchor not found"
- ],
- [
- 200,
- "apps/private_apis.html",
- "#badge",
- "target anchor not found"
- ],
- [
- 200,
- "apps/private_apis.html",
- "#popups",
- "target anchor not found"
- ],
- [
- 200,
- "apps/private_apis.html",
- "#usage",
- "target anchor not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-ContentWindow",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-WebRequestEventInteface",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-ClearDataOptions",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-ClearDataTypeSet",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-ClearDataOptions",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-ClearDataTypeSet",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-InjectDetails",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-InjectDetails",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-InjectDetails",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-InjectDetails",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#method-setUserAgentOverride",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-DialogController",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-NewWindow",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-MediaPermissionRequest",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-GeolocationPermissionRequest",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-PointerLockPermissionRequest",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-DownloadPermissionRequest",
- "target page not found"
- ],
- [
- 404,
- "apps/tags/webview.html",
- "apps/tags/webviewTag.html#type-LoadPluginPermissionRequest",
- "target page not found"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/bookmarks.html",
- "redirects to /extensions/bookmarks.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/history.html",
- "redirects to /extensions/history.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/topSites.html",
- "redirects to /extensions/topSites.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/tabs.html",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/windows.html",
- "redirects to /extensions/windows.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/webNavigation.html",
- "redirects to /extensions/webNavigation.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/contentSettings.html",
- "redirects to /extensions/contentSettings.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/debugger.html",
- "redirects to /extensions/debugger.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/proxy.html",
- "redirects to /extensions/proxy.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/activeTab.html",
- "redirects to /extensions/activeTab.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/management.html",
- "redirects to /extensions/management.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/privacy.html",
- "redirects to /extensions/privacy.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/signedInDevices.html",
- "redirects to /extensions/signedInDevices.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/ttsEngine.html",
- "redirects to /extensions/ttsEngine.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/tabs.html#type-Tab",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/permission_warnings.html",
- "apps/management.html#method-getPermissionWarningsByManifest",
- "redirects to /extensions/management.html"
- ],
- [
- 404,
- "extensions/whats_new.html",
- "extensions/manifest/geolocation.html",
- "target page not found"
- ],
- [
- 200,
- "extensions/devtools_inspectedWindow.html",
- "extensions/samples.html#devtools",
- "target anchor not found"
- ],
- [
- 302,
- "apps/runtime.html",
- "apps/tabs.html#type-Tab",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/runtime.html",
- "apps/tabs.html#type-Tab",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/runtime.html",
- "apps/tabs.html#method-connect",
- "redirects to /extensions/tabs.html"
- ],
- [
- 302,
- "apps/runtime.html",
- "apps/tabs.html#method-sendMessage",
- "redirects to /extensions/tabs.html"
- ],
- [
- 200,
- "extensions/devtools_network.html",
- "extensions/samples.html#devtools.network",
- "target anchor not found"
- ],
- [
- 302,
- "apps/desktop_notifications.html",
- "apps/extension.html#method-getBackgroundPage",
- "redirects to /extensions/extension.html"
- ],
- [
- 302,
- "apps/desktop_notifications.html",
- "apps/extension.html#method-getViews",
- "redirects to /extensions/extension.html"
- ],
- [
- 404,
- "apps/manifest/externally_connectable.html",
- "apps/manifest/runtime.html#method-connect",
- "target page not found"
- ],
- [
- 404,
- "apps/manifest/externally_connectable.html",
- "apps/manifest/runtime.html#method-sendMessage",
- "target page not found"
- ],
- [
- 404,
- "apps/manifest/externally_connectable.html",
- "apps/manifest/runtime.html#property-MessageSender-tlsChannelId",
- "target page not found"
- ],
- [
- 404,
- "apps/manifest/externally_connectable.html",
- "apps/manifest/runtime.html#property-MessageSender-tlsChannelId",
- "target page not found"
- ],
- [
- 200,
- "extensions/omnibox.html",
- "extensions/samples.html#omnibox",
- "target anchor not found"
- ],
- [
- 302,
- "apps/experimental_devtools_panels.html",
- "apps/devtools_panels.html",
- "redirects to /extensions/devtools_panels.html"
- ],
- [
- 200,
- "extensions/api_index.html",
- "#icon",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/api_index.html",
- "#tooltip",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/api_index.html",
- "#badge",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/api_index.html",
- "#popups",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/api_index.html",
- "#manifest",
- "target anchor not found"
- ],
- [
- 302,
- "apps/faq.html",
- "apps/browserAction.html",
- "redirects to /extensions/browserAction.html"
- ],
- [
- 302,
- "apps/faq.html",
- "apps/pageAction.html",
- "redirects to /extensions/pageAction.html"
- ],
- [
- 302,
- "apps/faq.html",
- "apps/management.html",
- "redirects to /extensions/management.html"
- ],
- [
- 302,
- "extensions/runtime.html",
- "extensions/app_lifecycle.html",
- "redirects to /apps/app_lifecycle.html"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/activityLogPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/app.html",
- "target page not found"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/app_runtime.html",
- "redirects to /apps/app_runtime.html"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/app_window.html",
- "redirects to /apps/app_window.html"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/audio.html",
- "redirects to /apps/audio.html"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/bluetooth.html",
- "redirects to /apps/bluetooth.html"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/bookmarkManagerPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/brailleDisplayPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/cast_channel.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/cast_streaming_rtpStream.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/cast_streaming_session.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/cast_streaming_udpTransport.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/chromeosInfoPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/cloudPrintPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/commandLinePrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/developerPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/diagnostics.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/dial.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/dns.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/echoPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/enterprise_platformKeysPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/experimental_accessibility.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/fileBrowserHandlerInternal.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/fileManagerPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/fileSystem.html",
- "redirects to /apps/fileSystem.html"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/fileSystemProvider.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/firstRunPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/identityPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/idltest.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/inputMethodPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/logPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/manifestTypes.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/mdns.html",
- "target page not found"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/mediaGalleries.html",
- "redirects to /apps/mediaGalleries.html"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/mediaGalleriesPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/mediaPlayerPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/metricsPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/networkingPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/pageActions.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/preferencesPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "target page not found"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/serial.html",
- "redirects to /apps/serial.html"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/socket.html",
- "redirects to /apps/socket.html"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/sockets_tcp.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/sockets_tcpServer.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/sockets_udp.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/streamsPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/syncFileSystem.html",
- "redirects to /apps/syncFileSystem.html"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/app_storage.html",
- "redirects to /apps/app_storage.html"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/system_display.html",
- "redirects to /apps/system_display.html"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/system_network.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/systemIndicator.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/systemPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/terminalPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/test.html",
- "target page not found"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/usb.html",
- "redirects to /apps/usb.html"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/virtualKeyboardPrivate.html",
- "target page not found"
- ],
- [
- 302,
- "extensions/private_apis.html",
- "extensions/wallpaper.html",
- "redirects to /apps/wallpaper.html"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/wallpaperPrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/webRequestInternal.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/webstorePrivate.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/webview.html",
- "target page not found"
- ],
- [
- 404,
- "extensions/private_apis.html",
- "extensions/webviewTag.html",
- "target page not found"
- ],
- [
- 200,
- "extensions/private_apis.html",
- "#usage",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/tabs.html",
- "#type-ImageDetails",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/tabs.html",
- "#type-ImageDetails",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/declarativeContent.html",
- "#type-Rule",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/whats_new.html",
- "#badge",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/whats_new.html",
- "#icon",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/whats_new.html",
- "#manifest",
- "target anchor not found"
- ],
- [
- 200,
- "apps/whats_new.html",
- "#manifest",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/whats_new.html",
- "#popups",
- "target anchor not found"
- ],
- [
- 200,
- "extensions/whats_new.html",
- "#tooltip",
- "target anchor not found"
- ]
-]
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/branch_utility/first.json b/chromium/chrome/common/extensions/docs/server2/test_data/branch_utility/first.json
deleted file mode 100644
index 24f360a73d1..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/branch_utility/first.json
+++ /dev/null
@@ -1,310 +0,0 @@
-[
- {
- "os": "win",
- "versions": [
- {
- "base_trunk_revision": "r?",
- "base_webkit_revision": "r?",
- "branch_revision": "NA",
- "channel": "canary",
- "date": "00/00/00",
- "prev_date": "05/13/13",
- "prev_version": "32.0.1506.0",
- "true_branch": null,
- "v8_ver": null,
- "version": "0.0.0.0",
- "wk_ver": null
- },
- {
- "base_trunk_revision": 198577,
- "base_webkit_revision": 149738,
- "branch_revision": 199640,
- "channel": "dev",
- "date": "05/13/13",
- "prev_date": "05/09/13",
- "prev_version": "31.0.1612.1",
- "true_branch": "1612",
- "v8_ver": "3.18.5.2",
- "version": "31.0.1612.2",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 190564,
- "base_webkit_revision": 146842,
- "branch_revision": 198567,
- "channel": "beta",
- "date": "05/08/13",
- "prev_date": "05/01/13",
- "prev_version": "30.0.1599.0",
- "true_branch": "1599",
- "v8_ver": "3.17.6.13",
- "version": "30.0.1599.10",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 181864,
- "base_webkit_revision": 142426,
- "branch_revision": 193017,
- "channel": "stable",
- "date": "04/09/13",
- "prev_date": "03/26/13",
- "prev_version": "29.0.1547.18",
- "true_branch": "1547",
- "v8_ver": "3.16.14.11",
- "version": "29.0.1547.22",
- "wk_ver": "537.31"
- }
- ]
- },
- {
- "os": "ios",
- "versions": [
- {
- "base_trunk_revision": 190564,
- "base_webkit_revision": 146842,
- "branch_revision": 191487,
- "channel": "beta",
- "date": "05/10/13",
- "prev_date": "05/07/13",
- "prev_version": "30.0.1599.9",
- "true_branch": "1599",
- "v8_ver": "3.17.6.1",
- "version": "30.0.1599.10",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 181864,
- "base_webkit_revision": 142426,
- "branch_revision": "NA",
- "channel": "stable",
- "date": "04/29/13",
- "prev_date": "04/09/13",
- "prev_version": "29.0.1547.50",
- "true_branch": null,
- "v8_ver": null,
- "version": "29.0.1410.53",
- "wk_ver": null
- }
- ]
- },
- {
- "os": "cros",
- "versions": [
- {
- "base_trunk_revision": 198577,
- "base_webkit_revision": 149738,
- "branch_revision": 199640,
- "channel": "dev",
- "date": "05/14/13",
- "prev_date": "05/09/13",
- "prev_version": "31.0.1612.4",
- "true_branch": "1612",
- "v8_ver": "3.18.5.2",
- "version": "31.0.1612.11",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 190564,
- "base_webkit_revision": 146842,
- "branch_revision": 198939,
- "channel": "beta",
- "date": "05/10/13",
- "prev_date": "05/03/13",
- "prev_version": "30.0.1599.76",
- "true_branch": "1599",
- "v8_ver": "3.17.6.13",
- "version": "30.0.1599.83",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 181864,
- "base_webkit_revision": 142426,
- "branch_revision": 191765,
- "channel": "stable",
- "date": "04/11/13",
- "prev_date": "04/04/13",
- "prev_version": "28.0.1547.173",
- "true_branch": "1547",
- "v8_ver": "3.16.14.11",
- "version": "29.0.1547.57",
- "wk_ver": "537.31"
- }
- ]
- },
- {
- "os": "cf",
- "versions": [
- {
- "base_trunk_revision": 198577,
- "base_webkit_revision": 149738,
- "branch_revision": 199640,
- "channel": "dev",
- "date": "05/13/13",
- "prev_date": "05/09/13",
- "prev_version": "31.0.1500.5",
- "true_branch": "1612",
- "v8_ver": "3.18.5.2",
- "version": "31.0.1500.11",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 190564,
- "base_webkit_revision": 146842,
- "branch_revision": 198567,
- "channel": "beta",
- "date": "05/08/13",
- "prev_date": "05/01/13",
- "prev_version": "30.0.1453.73",
- "true_branch": "1599",
- "v8_ver": "3.17.6.13",
- "version": "30.0.1453.81",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 181864,
- "base_webkit_revision": 142426,
- "branch_revision": 193017,
- "channel": "stable",
- "date": "04/09/13",
- "prev_date": "03/26/13",
- "prev_version": "29.0.1410.43",
- "true_branch": "1547",
- "v8_ver": "3.16.14.11",
- "version": "29.0.1410.64",
- "wk_ver": "537.31"
- }
- ]
- },
- {
- "os": "mac",
- "versions": [
- {
- "base_trunk_revision": 199851,
- "base_webkit_revision": 150220,
- "branch_revision": "NA",
- "channel": "canary",
- "date": "05/14/13",
- "prev_date": "05/13/13",
- "prev_version": "32.0.1506.0",
- "true_branch": "trunk",
- "v8_ver": "3.19.0.2",
- "version": "32.0.1507.0",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 198577,
- "base_webkit_revision": 149738,
- "branch_revision": 199640,
- "channel": "dev",
- "date": "05/13/13",
- "prev_date": "05/09/13",
- "prev_version": "31.0.1500.6",
- "true_branch": "1500",
- "v8_ver": "3.18.5.2",
- "version": "31.0.1500.11",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 190564,
- "base_webkit_revision": 146842,
- "branch_revision": 198567,
- "channel": "beta",
- "date": "05/08/13",
- "prev_date": "05/01/13",
- "prev_version": "30.0.1453.73",
- "true_branch": "1453",
- "v8_ver": "3.17.6.13",
- "version": "30.0.1453.81",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 181864,
- "base_webkit_revision": 142426,
- "branch_revision": 193261,
- "channel": "stable",
- "date": "04/10/13",
- "prev_date": "04/09/13",
- "prev_version": "29.0.1410.63",
- "true_branch": "1410",
- "v8_ver": "3.16.14.11",
- "version": "29.0.1410.65",
- "wk_ver": "537.31"
- }
- ]
- },
- {
- "os": "linux",
- "versions": [
- {
- "base_trunk_revision": 198577,
- "base_webkit_revision": 149738,
- "branch_revision": 199640,
- "channel": "dev",
- "date": "05/14/13",
- "prev_date": "05/09/13",
- "prev_version": "31.0.1612.1",
- "true_branch": "1612",
- "v8_ver": "3.18.5.2",
- "version": "31.0.1612.2",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 190564,
- "base_webkit_revision": 146842,
- "branch_revision": 198567,
- "channel": "beta",
- "date": "05/09/13",
- "prev_date": "05/02/13",
- "prev_version": "30.0.1599.0",
- "true_branch": "1599",
- "v8_ver": "3.17.6.13",
- "version": "30.0.1599.10",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 181864,
- "base_webkit_revision": 142426,
- "branch_revision": 192696,
- "channel": "stable",
- "date": "04/09/13",
- "prev_date": "03/26/13",
- "prev_version": "29.0.1547.18",
- "true_branch": "1547",
- "v8_ver": "3.16.14.11",
- "version": "29.0.1547.22",
- "wk_ver": "537.31"
- }
- ]
- },
- {
- "os": "android",
- "versions": [
- {
- "base_trunk_revision": 190564,
- "base_webkit_revision": 146842,
- "branch_revision": 199333,
- "channel": "beta",
- "date": "05/11/13",
- "prev_date": "05/02/13",
- "prev_version": "30.0.1453.74",
- "true_branch": "1453",
- "v8_ver": "3.17.6.13",
- "version": "30.0.1453.85",
- "wk_ver": "537.36"
- },
- {
- "base_trunk_revision": 181864,
- "base_webkit_revision": 142426,
- "branch_revision": 191860,
- "channel": "stable",
- "date": "04/18/13",
- "prev_date": "03/12/13",
- "prev_version": "28.0.1364.169",
- "true_branch": "1410",
- "v8_ver": "3.16.14.11",
- "version": "29.0.1410.58",
- "wk_ver": "537.31"
- }
- ]
- }
-]
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/branch_utility/second.json b/chromium/chrome/common/extensions/docs/server2/test_data/branch_utility/second.json
deleted file mode 100644
index f14fd588a8f..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/branch_utility/second.json
+++ /dev/null
@@ -1 +0,0 @@
-[{"timestamp": "2014-06-03 14:20:11.466940", "version": "37.0.2024.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-28 17:34:14.640050", "version": "37.0.2017.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-23 00:42:16.974880", "version": "37.0.2008.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-20 18:31:15.985070", "version": "36.0.1985.18", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-15 23:55:15.924940", "version": "36.0.1985.5", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-13 17:00:10.004960", "version": "36.0.1985.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-05-06 22:39:01.402240", "version": "36.0.1976.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-30 21:51:18.067990", "version": "36.0.1964.4", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-29 17:35:11.397850", "version": "36.0.1964.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-24 22:42:37.461710", "version": "36.0.1951.5", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-15 23:55:39.012960", "version": "36.0.1941.0", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-10 21:26:42.836030", "version": "36.0.1933.0", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-08 17:40:09.919590", "version": "35.0.1916.27", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-04 14:24:42.078490", "version": "35.0.1916.17", "os": "win", "channel": "dev"}, {"timestamp": "2014-04-03 16:34:05.903530", "version": "35.0.1916.14", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-31 20:24:18.562490", "version": "35.0.1916.6", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-27 19:12:14.284860", "version": "35.0.1912.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-25 22:12:43.934170", "version": "35.0.1908.4", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-18 19:12:45.029430", "version": "35.0.1897.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-11 15:52:03.062480", "version": "35.0.1883.0", "os": "win", "channel": "dev"}, {"timestamp": "2014-03-04 17:08:05.147800", "version": "35.0.1870.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-27 20:15:24.982930", "version": "35.0.1862.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-25 18:56:50.835670", "version": "34.0.1847.11", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-20 01:00:09.105560", "version": "34.0.1847.3", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-14 01:02:31.857440", "version": "34.0.1838.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-12 08:09:51.218870", "version": "34.0.1833.5", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-06 16:16:44.348590", "version": "34.0.1825.4", "os": "win", "channel": "dev"}, {"timestamp": "2014-02-05 20:10:09.511680", "version": "34.0.1820.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-28 20:49:26.805000", "version": "34.0.1809.0", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-21 21:34:21.385560", "version": "34.0.1797.2", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-16 20:06:23.869950", "version": "34.0.1788.0", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-14 15:52:46.003690", "version": "33.0.1750.29", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-13 16:52:00.486800", "version": "33.0.1750.27", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-09 16:13:53.961450", "version": "33.0.1750.22", "os": "win", "channel": "dev"}, {"timestamp": "2014-01-08 05:33:56.762720", "version": "33.0.1750.18", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-19 19:49:09.574590", "version": "33.0.1750.5", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-18 01:33:20.112740", "version": "33.0.1750.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-12 20:48:25.292070", "version": "33.0.1736.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-11 18:37:56.569580", "version": "33.0.1734.5", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-06 21:42:30.823000", "version": "33.0.1729.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-12-03 16:28:07.934720", "version": "33.0.1726.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-11-21 18:52:48.991750", "version": "33.0.1712.4", "os": "win", "channel": "dev"}, {"timestamp": "2013-11-20 02:16:12.385330", "version": "33.0.1712.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-11-12 16:40:15.159270", "version": "33.0.1707.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-11-07 14:51:35.231580", "version": "32.0.1700.6", "os": "win", "channel": "dev"}, {"timestamp": "2013-11-05 23:25:13.273680", "version": "32.0.1700.4", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-31 19:34:38.528860", "version": "32.0.1687.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-29 20:22:29.668330", "version": "32.0.1685.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-22 19:47:38.530570", "version": "32.0.1678.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-17 18:06:15.765170", "version": "32.0.1671.4", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-15 20:08:18.091540", "version": "32.0.1671.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-09 14:25:52.405750", "version": "32.0.1664.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-04 00:12:16.636970", "version": "32.0.1659.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-10-02 00:52:42.386520", "version": "31.0.1650.8", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-26 14:40:17.476110", "version": "31.0.1650.4", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-25 03:12:18.996600", "version": "31.0.1650.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-19 22:59:22.657090", "version": "31.0.1636.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-19 01:37:49.821160", "version": "31.0.1632.7", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-12 22:32:48.501310", "version": "31.0.1626.5", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-10 22:35:15.246280", "version": "31.0.1626.1", "os": "win", "channel": "dev"}, {"timestamp": "2013-09-06 02:43:36.410970", "version": "31.0.1622.7", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-28 20:56:45.395210", "version": "31.0.1612.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-28 01:32:03.681630", "version": "31.0.1612.1", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-20 13:28:08.161490", "version": "30.0.1599.14", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-15 22:36:45.696890", "version": "30.0.1599.10", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-13 16:11:10.052430", "version": "30.0.1599.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-08-06 18:52:06.791740", "version": "30.0.1588.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-30 20:08:35.055580", "version": "30.0.1581.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-23 19:29:24.547040", "version": "30.0.1573.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-18 23:01:29.276420", "version": "30.0.1568.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-16 22:24:11.526890", "version": "30.0.1566.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-15 22:00:12.802300", "version": "29.0.1547.22", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-11 21:05:36.722350", "version": "29.0.1547.18", "os": "win", "channel": "dev"}, {"timestamp": "2013-07-08 22:38:42.088720", "version": "29.0.1547.15", "os": "win", "channel": "dev"}, {"timestamp": "2013-06-25 20:46:46.536100", "version": "29.0.1547.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-06-18 22:59:55.045240", "version": "29.0.1541.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-06-12 01:26:30.924470", "version": "29.0.1535.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-06-06 22:41:06.770150", "version": "29.0.1530.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-29 17:58:53.665720", "version": "29.0.1521.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-24 17:57:59.583870", "version": "29.0.1516.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-21 20:39:44.712530", "version": "28.0.1500.20", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-13 19:30:30.489720", "version": "28.0.1500.11", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-09 19:58:41.813520", "version": "28.0.1500.5", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-07 23:38:18.617460", "version": "28.0.1500.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-05-02 23:41:18.903620", "version": "28.0.1496.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-30 23:25:13.544170", "version": "28.0.1490.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-22 22:59:15.937080", "version": "28.0.1485.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-16 00:48:20.258500", "version": "28.0.1478.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-09 02:46:07.932850", "version": "28.0.1469.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-05 18:19:28.047880", "version": "28.0.1464.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-04-02 17:53:25.145500", "version": "27.0.1453.12", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-29 18:16:49.135440", "version": "27.0.1453.9", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-28 18:59:48.314880", "version": "27.0.1453.6", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-27 01:53:23.549490", "version": "27.0.1453.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-21 21:49:11.673003", "version": "27.0.1448.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-19 00:30:49.325001", "version": "27.0.1444.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-13 17:35:03.840143", "version": "27.0.1438.7", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-06 18:32:27.534513", "version": "27.0.1430.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-05 23:32:37.811235", "version": "27.0.1430.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-03-01 01:11:51.636345", "version": "27.0.1425.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-26 22:03:01.937236", "version": "27.0.1423.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-22 00:09:52.181335", "version": "26.0.1410.12", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-20 00:15:47.421613", "version": "26.0.1410.10", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-14 20:18:49.043086", "version": "26.0.1410.5", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-13 01:49:23.707966", "version": "26.0.1410.3", "os": "win", "channel": "dev"}, {"timestamp": "2013-02-05 00:43:13.792515", "version": "26.0.1403.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-01-30 21:11:13.672237", "version": "26.0.1397.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-01-17 22:44:44.632486", "version": "26.0.1386.0", "os": "win", "channel": "dev"}, {"timestamp": "2013-01-16 01:48:57.646407", "version": "26.0.1384.2", "os": "win", "channel": "dev"}, {"timestamp": "2013-01-10 23:07:12.859265", "version": "25.0.1364.29", "os": "win", "channel": "dev"}, {"timestamp": "2013-01-08 00:05:42.205853", "version": "25.0.1364.26", "os": "win", "channel": "dev"}, {"timestamp": "2012-12-20 22:09:26.410205", "version": "25.0.1364.5", "os": "win", "channel": "dev"}, {"timestamp": "2012-12-19 02:42:39.891241", "version": "25.0.1364.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-12-14 02:37:09.422238", "version": "25.0.1359.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-12-10 22:13:57.477126", "version": "25.0.1354.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-12-07 00:16:59.533106", "version": "25.0.1349.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-11-28 23:28:57.174249", "version": "25.0.1337.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-11-13 00:52:33.199907", "version": "25.0.1323.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-11-06 19:47:19.447099", "version": "24.0.1312.5", "os": "win", "channel": "dev"}, {"timestamp": "2012-11-01 19:24:01.894562", "version": "24.0.1312.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-10-31 00:02:11.721761", "version": "24.0.1312.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-10-24 19:15:16.032706", "version": "24.0.1305.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-10-16 21:19:13.934724", "version": "24.0.1297.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-10-09 21:43:57.388586", "version": "24.0.1290.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-10-03 00:26:19.358696", "version": "24.0.1284.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-27 18:02:10.613799", "version": "23.0.1271.10", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-25 21:21:48.349277", "version": "23.0.1271.6", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-20 19:44:35.978350", "version": "23.0.1271.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-18 22:20:03.359033", "version": "23.0.1270.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-11 00:20:53.369165", "version": "23.0.1262.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-09-04 22:21:13.241591", "version": "23.0.1255.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-31 18:17:38.950756", "version": "23.0.1251.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-28 00:25:54.509043", "version": "23.0.1246.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-23 23:54:55.732357", "version": "23.0.1243.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-21 23:18:47.854439", "version": "22.0.1229.12", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-16 23:21:39.455435", "version": "22.0.1229.8", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-14 23:47:34.092347", "version": "22.0.1229.6", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-09 20:31:55.344300", "version": "22.0.1229.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-08-08 00:27:15.391271", "version": "22.0.1229.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-07-30 23:47:10.355043", "version": "22.0.1221.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-07-25 18:00:05.742833", "version": "22.0.1215.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-07-25 17:44:05.066159", "version": "22.0.1207.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-07-23 23:56:27.699693", "version": "22.0.1215.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-07-10 00:02:30.417237", "version": "22.0.1201.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-29 02:43:02.275037", "version": "21.0.1180.15", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-26 02:18:28.893003", "version": "21.0.1180.11", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-22 00:00:03.686656", "version": "21.0.1180.4", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-19 23:29:49.503880", "version": "21.0.1180.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-11 23:44:12.497616", "version": "21.0.1171.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-06-05 00:47:31.436958", "version": "21.0.1163.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-30 00:52:58.227015", "version": "21.0.1155.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-22 00:44:35.275578", "version": "21.0.1145.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-17 23:34:11.088684", "version": "20.0.1132.11", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-16 00:34:12.839658", "version": "20.0.1132.8", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-11 20:57:40.039867", "version": "20.0.1132.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-09 01:08:05.596451", "version": "20.0.1130.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-04 01:43:59.271464", "version": "20.0.1123.4", "os": "win", "channel": "dev"}, {"timestamp": "2012-05-02 06:26:54.601413", "version": "20.0.1123.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-25 00:17:05.365861", "version": "20.0.1115.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-19 19:17:27.858190", "version": "20.0.1105.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-18 00:32:32.752429", "version": "20.0.1105.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-10 22:39:50.903181", "version": "20.0.1096.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-06 00:24:37.313690", "version": "19.0.1084.15", "os": "win", "channel": "dev"}, {"timestamp": "2012-04-03 22:45:44.162647", "version": "19.0.1084.9", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-29 23:53:38.806929", "version": "19.0.1084.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-28 20:19:37.578118", "version": "19.0.1081.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-23 22:11:16.748494", "version": "19.0.1077.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-15 15:39:24.417446", "version": "19.0.1068.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-13 23:14:16.841667", "version": "19.0.1068.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-03-07 02:29:03.087025", "version": "19.0.1061.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-29 00:35:00.361479", "version": "19.0.1055.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-24 00:15:03.802307", "version": "19.0.1049.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-15 01:26:52.693277", "version": "19.0.1041.0", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-10 22:28:43.002042", "version": "19.0.1036.7", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-08 02:11:36.342233", "version": "18.0.1025.7", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-03 02:05:01.992245", "version": "18.0.1025.3", "os": "win", "channel": "dev"}, {"timestamp": "2012-02-01 00:50:43.302643", "version": "18.0.1025.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-01-25 01:52:32.852157", "version": "18.0.1017.2", "os": "win", "channel": "dev"}, {"timestamp": "2012-01-18 02:18:21.471775", "version": "18.0.1010.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-01-11 04:43:37.274858", "version": "18.0.1003.1", "os": "win", "channel": "dev"}, {"timestamp": "2012-01-05 00:02:51.015231", "version": "17.0.963.26", "os": "win", "channel": "dev"}, {"timestamp": "2011-12-16 02:56:07.709380", "version": "17.0.963.12", "os": "win", "channel": "dev"}, {"timestamp": "2011-12-13 00:20:16.966016", "version": "17.0.963.6", "os": "win", "channel": "dev"}, {"timestamp": "2011-12-09 00:45:52.579935", "version": "17.0.963.2", "os": "win", "channel": "dev"}, {"timestamp": "2011-12-06 23:45:11.121224", "version": "17.0.963.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-11-18 00:13:13.547951", "version": "17.0.942.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-11-15 00:36:36.682142", "version": "17.0.938.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-11-08 00:01:54.107311", "version": "17.0.932.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-11-03 23:38:13.871933", "version": "17.0.928.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-11-01 23:05:53.469821", "version": "16.0.912.21", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-27 23:08:29.273571", "version": "16.0.912.15", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-26 00:33:00.645906", "version": "16.0.912.12", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-20 23:31:54.410987", "version": "16.0.912.4", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-18 23:21:28.765917", "version": "16.0.912.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-10 23:51:01.411375", "version": "16.0.904.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-10-04 00:00:02.368667", "version": "16.0.899.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-27 00:01:19.501162", "version": "16.0.891.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-23 00:00:04.600297", "version": "16.0.889.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-21 00:29:45.279457", "version": "15.0.874.21", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-15 23:35:15.396772", "version": "15.0.874.15", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-13 23:00:02.220450", "version": "15.0.874.12", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-09 01:15:01.462271", "version": "15.0.874.5", "os": "win", "channel": "dev"}, {"timestamp": "2011-09-07 23:28:26.943667", "version": "15.0.874.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-30 00:53:44.167535", "version": "15.0.865.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-24 23:45:01.557603", "version": "15.0.861.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-17 17:50:57.766559", "version": "15.0.854.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-16 23:32:55.862838", "version": "15.0.849.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-10 23:45:12.449065", "version": "14.0.835.35", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-08 23:39:27.586298", "version": "14.0.835.29", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-05 00:20:22.656768", "version": "14.0.835.18", "os": "win", "channel": "dev"}, {"timestamp": "2011-08-01 23:30:39.166312", "version": "14.0.835.15", "os": "win", "channel": "dev"}, {"timestamp": "2011-07-29 00:07:02.915730", "version": "14.0.835.8", "os": "win", "channel": "dev"}, {"timestamp": "2011-07-27 00:29:22.495411", "version": "14.0.835.2", "os": "win", "channel": "dev"}, {"timestamp": "2011-07-19 00:18:39.510135", "version": "14.0.825.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-07-12 00:19:19.815197", "version": "14.0.814.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-28 00:25:51.373550", "version": "14.0.803.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-20 23:31:21.882224", "version": "14.0.797.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-16 23:24:40.782210", "version": "14.0.794.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-16 00:50:32.462022", "version": "13.0.782.24", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-14 01:22:42.462647", "version": "13.0.782.20", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-10 00:54:02.498892", "version": "13.0.782.14", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-08 21:28:42.336949", "version": "13.0.782.13", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-08 00:42:42.523798", "version": "13.0.782.11", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-06 05:45:01.690681", "version": "13.0.782.10", "os": "win", "channel": "dev"}, {"timestamp": "2011-06-02 00:18:23.923209", "version": "13.0.782.1", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-24 00:23:25.417993", "version": "13.0.772.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-17 21:36:01.649909", "version": "13.0.767.1", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-12 21:30:02.816615", "version": "13.0.761.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-07 00:26:42.381502", "version": "12.0.742.30", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-06 00:50:01.184756", "version": "12.0.742.21", "os": "win", "channel": "dev"}, {"timestamp": "2011-05-03 01:32:45.837483", "version": "12.0.742.16", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-29 00:47:01.978221", "version": "12.0.742.12", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-26 00:48:15.791589", "version": "12.0.742.9", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-22 21:52:40.866321", "version": "12.0.742.5", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-21 01:07:21.274640", "version": "12.0.742.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-13 00:18:03.352933", "version": "12.0.733.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-04-06 01:25:31.730658", "version": "12.0.725.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-24 23:56:50.353141", "version": "12.0.712.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-21 23:12:14.929546", "version": "11.0.696.16", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-17 23:35:19.195017", "version": "11.0.696.14", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-16 00:37:36.670682", "version": "11.0.696.12", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-11 02:25:22.766989", "version": "11.0.696.3", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-09 02:42:49.254367", "version": "11.0.696.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-03 22:40:08.703552", "version": "11.0.686.3", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-01 20:35:16.946853", "version": "11.0.686.1", "os": "win", "channel": "dev"}, {"timestamp": "2011-03-01 02:36:12.261887", "version": "11.0.686.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-02-17 23:15:13.205432", "version": "11.0.672.2", "os": "win", "channel": "dev"}, {"timestamp": "2011-02-16 23:02:09.686153", "version": "10.0.648.82", "os": "win", "channel": "dev"}, {"timestamp": "2011-02-09 01:08:19.428149", "version": "10.0.648.45", "os": "win", "channel": "dev"}, {"timestamp": "2011-02-04 01:31:33.914043", "version": "10.0.648.18", "os": "win", "channel": "dev"}, {"timestamp": "2011-02-01 04:02:58.551081", "version": "10.0.648.11", "os": "win", "channel": "dev"}, {"timestamp": "2011-01-27 01:58:03.833503", "version": "10.0.648.6", "os": "win", "channel": "dev"}, {"timestamp": "2011-01-20 20:34:10.485114", "version": "10.0.642.2", "os": "win", "channel": "dev"}, {"timestamp": "2011-01-11 20:29:22.440018", "version": "10.0.634.0", "os": "win", "channel": "dev"}, {"timestamp": "2011-01-06 06:16:24.266016", "version": "10.0.628.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-20 19:43:27.003393", "version": "10.0.612.3", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-16 23:09:02.613656", "version": "10.0.612.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-14 01:51:30.028630", "version": "9.0.597.19", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-10 17:40:35.218863", "version": "9.0.597.16", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-10 02:13:57.432350", "version": "9.0.597.15", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-07 02:02:57.524983", "version": "9.0.597.10", "os": "win", "channel": "dev"}, {"timestamp": "2010-12-01 22:58:13.664530", "version": "9.0.597.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-11-19 01:08:11.505390", "version": "9.0.587.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-11-10 00:46:46.659929", "version": "9.0.576.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-11-05 01:20:03.009405", "version": "9.0.570.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-11-03 01:02:56.557176", "version": "9.0.570.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-30 01:11:40.679688", "version": "8.0.552.23", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-27 01:07:18.524939", "version": "8.0.552.18", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-21 23:21:07.362399", "version": "8.0.552.11", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-19 03:29:35.380392", "version": "8.0.552.5", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-13 00:03:39.843245", "version": "8.0.552.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-10-06 22:51:53.761849", "version": "7.0.544.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-30 20:34:16.449689", "version": "7.0.536.2", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-28 22:49:52.102607", "version": "7.0.517.24", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-24 23:15:18.317542", "version": "7.0.517.17", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-17 01:02:24.580776", "version": "7.0.517.8", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-13 21:15:08.408742", "version": "7.0.517.5", "os": "win", "channel": "dev"}, {"timestamp": "2010-09-09 01:03:59.649612", "version": "7.0.517.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-08-26 00:05:03.192544", "version": "7.0.503.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-08-17 22:28:45.281781", "version": "6.0.495.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-08-13 14:23:58.981512", "version": "6.0.490.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-08-06 22:53:12.693314", "version": "6.0.472.25", "os": "win", "channel": "dev"}, {"timestamp": "2010-08-05 00:22:02.989672", "version": "6.0.472.22", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-30 23:14:34.906503", "version": "6.0.472.14", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-28 23:49:30.339032", "version": "6.0.472.11", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-22 00:09:53.631080", "version": "6.0.472.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-15 22:58:14.785376", "version": "6.0.466.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-09 14:18:49.147870", "version": "6.0.458.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-07-02 23:12:13.572119", "version": "6.0.453.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-06-25 01:37:06.165522", "version": "6.0.447.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-06-18 19:49:04.312351", "version": "6.0.437.3", "os": "win", "channel": "dev"}, {"timestamp": "2010-06-17 23:02:50.189680", "version": "6.0.427.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-06-17 18:31:39.466049", "version": "6.0.437.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-06-03 18:37:41.545861", "version": "6.0.422.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-05-20 21:03:10.341977", "version": "6.0.408.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-05-14 03:19:25.209091", "version": "6.0.401.1", "os": "win", "channel": "dev"}, {"timestamp": "2010-05-07 01:36:38.203980", "version": "5.0.396.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-05-04 01:31:54.330134", "version": "5.0.375.29", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-30 22:08:37.591885", "version": "5.0.375.28", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-27 20:56:13.817069", "version": "5.0.375.23", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-23 00:30:19.613747", "version": "5.0.375.17", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-17 01:18:06.570807", "version": "5.0.375.9", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-14 23:39:10.591308", "version": "5.0.375.7", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-13 01:11:37.789960", "version": "5.0.375.3", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-09 01:12:39.670401", "version": "5.0.371.0", "os": "win", "channel": "dev"}, {"timestamp": "2010-04-02 18:16:57.406165", "version": "5.0.366.2", "os": "win", "channel": "dev"}] \ No newline at end of file
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/file_system/stat_result.json b/chromium/chrome/common/extensions/docs/server2/test_data/file_system/stat_result.json
deleted file mode 100644
index 0c5d79d9b41..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/file_system/stat_result.json
+++ /dev/null
@@ -1,86 +0,0 @@
-{
- "extension_api.h": "146163",
- "_permission_features.json": "150186",
- "file_system.idl": "150515",
- "input_ime.json": "149101",
- "context_menus.json": "140112",
- "app.json": "133722",
- "browser_action.json": "148043",
- "test.json": "145505",
- "chromeos_info_private.json": "150737",
- "font_settings.json": "147621",
- "management.json": "151113",
- "bookmark_manager.json": "140864",
- "experimental_commands.json": "149147",
- "web_navigation.json": "148204",
- "echo_private.json": "136747",
- "i18n.json": "149045",
- "storage.json": "149837",
- "experimental_media_galleries.idl": "150164",
- "web_request_internal.json": "138481",
- "app_window.idl": "147710",
- "web_request.json": "138481",
- "windows.json": "140947",
- "terminal_private.json": "136747",
- "experimental_rlz.json": "136747",
- "system_private.json": "136747",
- "content_settings.json": "136747",
- "file_browser_handler.json": "149101",
- "devtools.json": "124878",
- "experimental_dns.idl": "136747",
- "experimental_speech_input.json": "136747",
- "api.gyp": "151113",
- "experimental_identity.idl": "147523",
- "runtime.json": "148956",
- "alarms.idl": "143049",
- "declarative_web_request.json": "150421",
- "devtools/": "149291",
- "experimental_idltest.idl": "138707",
- "script_badge.json": "146930",
- "extension_api_unittest.cc": "149819",
- "events.json": "143168",
- "tts.json": "134209",
- "metrics_private.json": "136747",
- "experimental_usb.idl": "144221",
- "webstore.json": "127930",
- "managed_mode_private.json": "142720",
- "downloads.idl": "146201",
- "serial.idl": "150186",
- "page_capture.json": "147890",
- "_manifest_features.json": "150827",
- "browsing_data.json": "142133",
- "top_sites.json": "136747",
- "page_actions.json": "136747",
- "page_action.json": "137065",
- "history.json": "129086",
- "bookmarks.json": "149307",
- "permissions.json": "124878",
- "experimental_app.json": "148848",
- "media_player_private.json": "136747",
- "experimental_input_virtual_keyboard.json": "138223",
- "privacy.json": "136588",
- "tabs.json": "149631",
- "tts_engine.json": "136747",
- "experimental_bluetooth.idl": "150898",
- "idle.json": "124878",
- "input_method_private.json": "136747",
- "experimental_accessibility.json": "136747",
- "push_messaging.idl": "149536",
- "webstore_private.json": "150455",
- "extension.json": "146855",
- "extension_api.cc": "149819",
- "file_manager_private.json": "150806",
- "cloud_print_private.json": "149303",
- "omnibox.json": "124878",
- "processes.json": "137690",
- "proxy.json": "136588",
- "file_browser_handler_internal.json": "142683",
- "types.json": "146093",
- "experimental_record.json": "145342",
- "debugger.json": "147894",
- "socket.idl": "150190",
- "OWNERS": "150079",
- "cookies.json": "124878",
- "infobars.json": "136747",
- "wallpaper_private.json": "148400"
-}
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/github_file_system/expected_list.json b/chromium/chrome/common/extensions/docs/server2/test_data/github_file_system/expected_list.json
deleted file mode 100644
index eee9d7f4f26..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/github_file_system/expected_list.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
- "": [
- ".gitignore",
- "README.md",
- "analytics/",
- "appsquare/",
- "browser-tag/",
- "calculator/",
- "camera-capture/",
- "clock/",
- "context-menu/",
- "diff/",
- "dojo/",
- "filesystem-access/",
- "frameless-window/",
- "gdocs/",
- "hello-world/",
- "identity/",
- "io2012-presentation/",
- "ioio/",
- "mdns-browser/",
- "mini-code-edit/",
- "nodejs-net.coffee",
- "sandbox/",
- "sandboxed-content/",
- "serial-control-signals/",
- "serial/",
- "servo/",
- "singleton/",
- "storage/",
- "telnet/",
- "text-editor/",
- "udp/",
- "usb/",
- "weather/",
- "webgl/",
- "webintents/",
- "windows/",
- "zephyr_hxm/"
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/expected/extensions_sidenav.json b/chromium/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/expected/extensions_sidenav.json
deleted file mode 100644
index e5c4cc2e831..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/rietveld_patcher/expected/extensions_sidenav.json
+++ /dev/null
@@ -1,6 +0,0 @@
-[
- {
- "title": "Test Foo",
- "fileName": "test_foo.html"
- }
-]
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/samples_data_source/expected.json b/chromium/chrome/common/extensions/docs/server2/test_data/samples_data_source/expected.json
deleted file mode 100644
index 904e5d809b4..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/samples_data_source/expected.json
+++ /dev/null
@@ -1,10 +0,0 @@
-[
- {
- "api_calls": [
- { "name": "bobaloo.foop" },
- { "name": "jimmy.bobaloo.loopoo" },
- { "name": "jimmy.jimmy" },
- { "name": "hallo.bobaloo" }
- ]
- }
-]
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/samples_data_source/samples.json b/chromium/chrome/common/extensions/docs/server2/test_data/samples_data_source/samples.json
deleted file mode 100644
index 4c0152718c1..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/samples_data_source/samples.json
+++ /dev/null
@@ -1,24 +0,0 @@
-[
- {
- "api_calls": [
- { "name": "bobaloo.foop" },
- { "name": "jimmy.bobaloo.loopoo" },
- { "name": "jimmy.jimmy" },
- { "name": "hallo.bobaloo" }
- ]
- },
- {
- "api_calls": [
- { "name": "timmy.bobaloo.affa" },
- { "name": "jimmy.baloo.loopoo" },
- { "name": "jimmy.jimmy" }
- ]
- },
- {
- "api_calls": [
- { "name": "torta.lamb.paco" },
- { "name": "jimmy.baloo.loopoo" },
- { "name": "jimmy.jimmy" }
- ]
- }
-]
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/input.json b/chromium/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/input.json
deleted file mode 100644
index e089d8b493e..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/template_data_source/partials/input.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "name": {
- "first": "Bob",
- "last": "Jones"
- },
- "part": "elbow"
-}
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_def_test.json b/chromium/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_def_test.json
deleted file mode 100644
index 01fbab60cc8..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/test_json/add_rules_def_test.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "namespace": "events",
- "description": "A namespace to contain addRules.",
- "types": [
- {
- "name": "Event",
- "type": "object",
- "description": "The object to contain addRules.",
- "functions": [
- {
- "name": "addRules",
- "type": "function",
- "description": "Registers rules to handle events.",
- "parameters": [ { "name": "notable_name_to_check_for" } ]
- }
- ]
- }
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/test_json/expected_tester.json b/chromium/chrome/common/extensions/docs/server2/test_data/test_json/expected_tester.json
deleted file mode 100644
index 4c91dfd8da8..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/test_json/expected_tester.json
+++ /dev/null
@@ -1,218 +0,0 @@
-{
- "functions": [
- {
- "name": "get",
- "parameters": [
- {
- "parentName": "get",
- "functions": [],
- "choices": [
- {
- "properties": [],
- "name": "string",
- "simple_type": "string",
- "functions": [],
- "events": [],
- "id": "type-a-string",
- "description": null
- },
- {
- "properties": [],
- "last": true,
- "name": "array",
- "functions": [],
- "events": [],
- "array": {
- "properties": [],
- "name": "arrayType",
- "simple_type": "string",
- "functions": [],
- "events": [],
- "id": "type-array-arrayType",
- "description": null
- },
- "id": "type-a-array",
- "description": null
- }
- ],
- "name": "a",
- "parameters": [],
- "id": "property-get-a",
- "returns": null,
- "optional": null,
- "properties": [],
- "description": "a param"
- },
- {
- "parentName": "get",
- "last": true,
- "name": "callback",
- "simple_type": "function",
- "optional": false,
- "id": "property-get-callback",
- "description": null
- }
- ],
- "callback": {
- "parameters": [
- {
- "description": null,
- "array": {
- "properties": [],
- "name": "resultsType",
- "functions": [],
- "events": [],
- "link": {
- "text": "TypeA",
- "href": "tester.html#type-TypeA",
- "name": "TypeA"
- },
- "id": "type-results-resultsType",
- "description": null
- },
- "optional": null,
- "id": "property-callback-results",
- "parentName": "callback",
- "functions": [],
- "last": true,
- "name": "results",
- "parameters": [],
- "properties": [],
- "returns": null
- }
- ],
- "optional": false,
- "name": "callback",
- "simple_type": {
- "simple_type": "function"
- }
- },
- "returns": null,
- "id": "method-get",
- "description": "Gets stuff."
- }
- ],
- "properties": [],
- "name": "tester",
- "description": "a test api",
- "introList": [
- {
- "content": [
- {
- "text": "a test api"
- }
- ],
- "title": "Description"
- },
- {
- "content": [
- {
- "message": true,
- "trunk": true,
- "version": null
- }
- ],
- "title": "Availability"
- },
- {
- "content": [
- {
- "text": "\"thing1\", \"thing2\"",
- "perm": "tester"
- },
- {
- "text": "is an API for testing things."
- }
- ],
- "title": "Permissions"
- },
- {
- "content": [
- {
- "text": "Welcome!",
- "link": "https://tester.test.com/welcome.html"
- }
- ],
- "title": "Learn More"
- }
- ],
- "types": [
- {
- "properties": [
- {
- "parentName": "TypeA",
- "functions": [],
- "name": "b",
- "parameters": [],
- "id": "property-TypeA-b",
- "array": {
- "properties": [],
- "name": "bType",
- "functions": [],
- "events": [],
- "link": {
- "text": "TypeA",
- "href": "tester.html#type-TypeA",
- "name": "TypeA"
- },
- "id": "type-b-bType",
- "description": null
- },
- "returns": null,
- "optional": true,
- "properties": [],
- "description": "List of TypeA."
- }
- ],
- "name": "TypeA",
- "simple_type": "object",
- "functions": [],
- "events": [],
- "id": "type-TypeA",
- "description": "A cool thing."
- }
- ],
- "events": [
- {
- "callback": null,
- "name": "EventA",
- "parameters": [
- {
- "parentName": "EventA",
- "functions": [],
- "simple_type": "string",
- "name": "id",
- "parameters": [],
- "id": "property-EventA-id",
- "returns": null,
- "optional": null,
- "properties": [],
- "description": null
- },
- {
- "description": null,
- "link": {
- "text": "TypeA",
- "href": "tester.html#type-TypeA",
- "name": "TypeA"
- },
- "optional": null,
- "id": "property-EventA-bookmark",
- "parentName": "EventA",
- "functions": [],
- "last": true,
- "name": "bookmark",
- "parameters": [],
- "properties": [],
- "returns": null
- }
- ],
- "supportsRules": false,
- "filters": [],
- "conditions": [],
- "id": "event-EventA",
- "actions": [],
- "description": "A cool event."
- }
- ]
-}
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/test_json/ref_test_data_source.json b/chromium/chrome/common/extensions/docs/server2/test_data/test_json/ref_test_data_source.json
deleted file mode 100644
index 11216091a63..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/test_json/ref_test_data_source.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "ref_test": {
- "types": [
- { "name": "type1" },
- { "name": "type2" },
- { "name": "type3" }
- ],
- "events": [
- { "name": "event1" }
- ],
- "properties": [
- { "name": "prop1" }
- ],
- "functions": [
- { "name": "func1" }
- ]
- },
- "other": {
- "types": [
- { "name": "type2" }
- ]
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/server2/test_data/test_json/test_file_data_source.json b/chromium/chrome/common/extensions/docs/server2/test_data/test_json/test_file_data_source.json
deleted file mode 100644
index 13bd52a48b0..00000000000
--- a/chromium/chrome/common/extensions/docs/server2/test_data/test_json/test_file_data_source.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "tester": {
- "types": [
- { "name": "TypeA" }
- ],
- "functions": [
- { "name": "get" }
- ],
- "events": [
- { "name": "EventA" }
- ]
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/templates/json/api_availabilities.json b/chromium/chrome/common/extensions/docs/templates/json/api_availabilities.json
deleted file mode 100644
index a55ddba950f..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/json/api_availabilities.json
+++ /dev/null
@@ -1,51 +0,0 @@
-// Availability for these APIs either can't be accurately found or would take a
-// significant amount of specific logic to determine (devtools).
-// The versions listed here were drawn either from hardcoded HTML intro tables
-// or from the whats_new page.
-{
- "devtools.inspectedWindow": {
- "channel": "stable",
- "version": 18
- },
- "devtools.network": {
- "channel": "stable",
- "version": 18
- },
- "devtools.panels": {
- "channel": "stable",
- "version": 18
- },
- "input.ime": {
- "channel": "stable",
- "version": 21
- },
- "mediaGalleries": {
- "channel": "stable",
- "version": 23
- },
- "notifications": {
- "channel": "stable",
- "version": 28
- },
- "storage": {
- "channel": "stable",
- "version": 20
- },
- "pageCapture": {
- "channel": "stable",
- "version": 18
- },
- "webstore": {
- // Only 'webstorePrivate' is present before version 19.
- "channel": "stable",
- "version": 15
- },
- "webviewTag": {
- "channel": "stable",
- "version": 25
- },
- "webviewTag.WebRequestEventInterface": {
- "channel": "stable",
- "version": 33
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/templates/json/apps_sidenav.json b/chromium/chrome/common/extensions/docs/templates/json/apps_sidenav.json
deleted file mode 100644
index cf6d4bdea32..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/json/apps_sidenav.json
+++ /dev/null
@@ -1,278 +0,0 @@
-[
- {
- "title": "Discover",
- "items": [
- {
- "title": "What Are Chrome Apps?",
- "href": "/apps/about_apps"
- }
- ]
- },
- {
- "title": "Develop",
- "items": [
- {
- "title": "Create Your First App",
- "href": "/apps/first_app"
- },
- {
- "title": "Tutorials",
- "toggleable": true,
- "items": [
- {
- "title": "Learn with a Codelab",
- "toggleable": true,
- "items": [
- {
- "title": "About this Codelab",
- "href": "/apps/app_codelab"
- },
- {
- "title": "1 - Set Up Development Environment",
- "href": "/apps/app_codelab1_setup"
- },
- {
- "title": "2 - Create Basic App",
- "href": "/apps/app_codelab2_basic"
- },
- {
- "title": "3 - Create MVC",
- "href": "/apps/app_codelab3_mvc"
- },
- {
- "title": "4 - Save and Fetch Data",
- "href": "/apps/app_codelab5_data"
- },
- {
- "title": "5 - Manage App Lifecycle",
- "href": "/apps/app_codelab6_lifecycle"
- },
- {
- "title": "6 - Access User's Data",
- "href": "/apps/app_codelab7_useridentification"
- },
- {
- "title": "7 - Access Web Resources",
- "href": "/apps/app_codelab8_webresources"
- },
- {
- "title": "8 - Publish App",
- "href": "/apps/app_codelab_10_publishing"
- }
- ]
- },
- {
- "title": "MVC Architecture & Frameworks",
- "toggleable": true,
- "items": [
- {
- "title": "About MVC Architecture",
- "href": "/apps/app_frameworks"
- },
- {
- "title": "Build Apps with AngularJS",
- "href": "/apps/angular_framework"
- },
- {
- "title": "Build Apps with Sencha Ext JS",
- "href": "/apps/sencha_framework"
- },
- {
- "title": "Game Engines",
- "href": "/apps/game_engines"
- }
- ]
- }
- ]
- },
- {
- "title": "Chrome App Concepts",
- "toggleable": true,
- "items": [
- {
- "title": "The Fundamentals",
- "toggleable": true,
- "items": [
- {
- "title": "App Architecture",
- "href": "/apps/app_architecture"
- },
- {
- "title": "App Lifecycle",
- "href": "/apps/app_lifecycle"
- },
- {
- "title": "Offline First",
- "href": "/apps/offline_apps"
- },
- {
- "title": "External Content",
- "href": "/apps/app_external"
- }
- ]
- },
- {
- "title": "Security",
- "toggleable": true,
- "items": [
- {
- "title": "Content Security Policy",
- "href": "/apps/contentSecurityPolicy"
- }
- ]
- },
- {
- "title": "Cloud-Enable Your App",
- "toggleable": true,
- "items": [
- {
- "title": "Cloud Messaging",
- "toggleable": true,
- "items": [
- {
- "title": "About Cloud Messaging",
- "href": "/apps/cloudMessaging"
- },
- {
- "title": "Client Reference",
- "href": "/apps/gcm"
- }
- ]
- },
- {
- "title": "Cloud Storage",
- "toggleable": true,
- "items": [
- {
- "title": "chrome.storage",
- "href": "/apps/storage"
- }
- ]
- },
- {
- "title": "User Authentication",
- "href": "/apps/app_identity"
- }
- ]
- },
- {
- "title": "Store and Retrieve Data",
- "toggleable": true,
- "items": [
- {
- "title": "Storage APIs",
- "href": "/apps/app_storage"
- }
- ]
- },
- {
- "title": "Use Low-Level System Services",
- "toggleable": true,
- "items": [
- {
- "title": "USB",
- "href": "/apps/app_usb"
- },
- {
- "title": "Serial",
- "href": "/apps/app_serial"
- },
- {
- "title": "Network Communications",
- "href": "/apps/app_network"
- },
- {
- "title": "Bluetooth",
- "href": "/apps/app_bluetooth"
- }
- ]
- },
- {
- "title": "Interact with the Host Platform",
- "toggleable": true,
- "items": [
- {
- "title": "Rich Notifications",
- "href": "/apps/desktop_notifications"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "title": "Distribute",
- "items": [
- {
- "title": "Publish Your App",
- "href": "/apps/publish_app"
- },
- {
- "title": "Monetize Your App",
- "toggleable": true,
- "items": [
- {
- "title": "Google Wallet for Digital Goods",
- "href": "/apps/google_wallet"
- }
- ]
- },
- {
- "title": "Analytics",
- "href": "/apps/analytics"
- }
- ]
- },
- {
- "title": "Reference",
- "items": [
- {
- "title": "Chrome Platform APIs",
- "href": "/apps/api_index"
- },
- {
- "title": "Webview Tag",
- "href": "/apps/tags/webview"
- },
- {
- "title": "Web APIs",
- "href": "/apps/api_other"
- },
- {
- "title": "Manifest File Format",
- "href": "/apps/manifest"
- },
- {
- "title": "Disabled Web Features",
- "href": "/apps/app_deprecated"
- }
- ]
- },
- {
- "title": "Samples",
- "items": [
- {
- "title": "Sample Apps",
- "href": "/apps/samples"
- }
- ]
- },
- {
- "title": "Help",
- "items": [
- {
- "title": "FAQ",
- "href": "/apps/faq"
- },
- {
- "title": "Google Groups",
- "href": "https://groups.google.com/a/chromium.org/forum/#!forum/chromium-apps"
- },
- {
- "title": "Stack Overflow",
- "href": "http://stackoverflow.com/questions/tagged/google-chrome-app"
- }
- ]
- }
-]
diff --git a/chromium/chrome/common/extensions/docs/templates/json/chrome_sidenav.json b/chromium/chrome/common/extensions/docs/templates/json/chrome_sidenav.json
deleted file mode 100644
index 8c607a44a13..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/json/chrome_sidenav.json
+++ /dev/null
@@ -1,834 +0,0 @@
-[
- {
- "title": "Chrome",
- "href": "/extensions",
- "items": [
- {
- "title": "Extend the Browser",
- "href": "/extensions",
- "items": [
- {
- "title": "What are Extensions?",
- "href": "/extensions"
- },
- {
- "title": "Get Started Tutorial",
- "href": "/extensions/getstarted"
- },
- {
- "title": "Overview",
- "href": "/extensions/overview",
- "items": [
- {
- "title": "Manifest Format",
- "href": "/extensions/manifest"
- },
- {
- "title": "Manage Events",
- "href": "/extensions/background_pages"
- },
- {
- "title": "Design User Interface",
- "href": "/extensions/user_interface"
- },
- {
- "title": "Content Scripts",
- "href": "/extensions/content_scripts"
- },
- {
- "title": "Declare Permissions and Warn Users",
- "href": "/extensions/permission_warnings"
- },
- {
- "title": "Give Users Options",
- "href": "/extensions/options"
- }
- ]
- },
- {
- "title": "Developer Guide",
- "href": "/extensions/devguide",
- "items": [
- {
- "title": "Reach Peak Performance",
- "href": "/extensions/performance"
- },
- {
- "title": "Protect User Privacy",
- "href": "/extensions/user_privacy"
- },
- {
- "title": "Stay Secure",
- "href": "/extensions/security"
- },
- {
- "title": "Debugging",
- "href": "/extensions/tut_debugging"
- },
- {
- "title": "OAuth",
- "href": "/extensions/tut_oauth"
- },
- {
- "title": "Accessibility",
- "href": "/extensions/a11y"
- },
- {
- "title": "Content Security Policy",
- "href": "/extensions/contentSecurityPolicy"
- },
- {
- "title": "Cross-Origin XHR",
- "href": "/extensions/xhr"
- },
- {
- "title": "Internationalization",
- "href": "/extensions/i18n"
- },
- {
- "title": "Message Passing",
- "href": "/extensions/messaging"
- },
- {
- "title": "Native Messaging",
- "href": "/extensions/nativeMessaging"
- },
- {
- "title": "Match Patterns",
- "href": "/extensions/match_patterns"
- },
- {
- "title": "Extension Quality Guidelines FAQ",
- "href": "/extensions/single_purpose"
- }
- ]
- },
- {
- "title": "Samples",
- "href": "/extensions/samples"
- },
- {
- "title": "Help",
- "href": "/extensions/faq",
- "items": [
- {
- "title": "FAQ",
- "href": "/extensions/faq"
- },
- {
- "title": "What's New?",
- "href": "/extensions/whats_new"
- },
- {
- "title": "Google Groups",
- "href": "https://groups.google.com/a/chromium.org/forum/#!forum/chromium-extensions"
- },
- {
- "title": "Stack Overflow",
- "href": "http://stackoverflow.com/tags/google-chrome-extension/info"
- }
- ]
- }
- ]
- },
- {
- "title": "Web Store Publishing and Distribution",
- "href": "/webstore",
- "items": [
- {
- "title": "Distribution Overview",
- "href": "/webstore",
- "items": [
- {
- "title": "Distributing Products Built for Chrome",
- "href": "/webstore"
- },
- {
- "title": "What Is the Chrome Web Store?",
- "href": "/webstore/about_webstore"
- },
- {
- "title": "What Can You Publish?",
- "href": "/webstore/overview"
- },
- {
- "title": "Tutorial: Getting Started",
- "href": "/webstore/get_started_simple"
- },
- {
- "title": "Samples",
- "href": "/webstore/samples"
- }
- ]
- },
- {
- "title": "Publish Extensions",
- "href": "/extensions/hosting",
- "items": [
- {
- "title": "Hosting and Updating",
- "href": "/extensions/hosting"
- },
- {
- "title": "Hosting Policy Changes",
- "href": "/extensions/hosting_changes"
- },
- {
- "title": "Google Analytics",
- "href": "/extensions/tut_analytics"
- },
- {
- "title": "Publishing Themes",
- "href": "/extensions/themes"
- },
- {
- "title": "Other Deployment Options",
- "href": "/extensions/external_extensions"
- }
- ]
- },
- {
- "title": "Monetizing",
- "href": "/webstore/money",
- "items": [
- {
- "title": "Monetizing Your App",
- "href": "/webstore/money"
- },
- {
- "title": "Using Google Accounts",
- "href": "/webstore/identify_user"
- },
- {
- "title": "One-Time Payments",
- "href": "/webstore/one_time_payments"
- },
- {
- "title": "Pricing",
- "href": "/webstore/pricing"
- }
- ]
- },
- {
- "title": "Branding",
- "href": "/webstore/branding",
- "items": [
- {
- "title": "Branding Guidelines",
- "href": "/webstore/branding"
- },
- {
- "title": "Supplying Images",
- "href": "/webstore/images"
- }
- ]
- },
- {
- "title": "Help",
- "href": "/webstore/best_practices",
- "items": [
- {
- "title": "Best Practices",
- "href": "/webstore/best_practices"
- },
- {
- "title": "FAQ",
- "href": "/webstore/faq"
- },
- {
- "title": "Stack Overflow",
- "href": "http://stackoverflow.com/questions/tagged/google-chrome-app"
- },
- {
- "title": "Articles",
- "href": "/webstore/articles"
- }
- ]
- }
- ]
- },
- {
- "title": "Mobile Chrome",
- "href": "/multidevice",
- "items": [
- {
- "title": "Chrome for a Multi-Device World",
- "href": "/multidevice",
- "items": [
- {
- "title": "User Agents",
- "href": "/multidevice/user-agent"
- },
- {
- "title": "Chrome Custom Tabs",
- "href": "/multidevice/android/customtabs"
- },
- {
- "title": "Mobile Emulation",
- "href": "/devtools/docs/mobile-emulation"
- },
- {
- "title": "Remote Debugging",
- "href": "/devtools/docs/remote-debugging"
- }
- ]
- },
- {
- "title": "Chrome for Android",
- "href": "/multidevice/android/overview",
- "items": [
- {
- "title": "Overview",
- "href": "/multidevice/android/overview"
- },
- {
- "title": "Android Intents with Chrome",
- "href": "/multidevice/android/intents"
- },
- {
- "title": "Chrome Custom Tabs",
- "href": "/multidevice/android/customtabs"
- }
- ]
- },
- {
- "title": "Chrome WebView",
- "href": "/multidevice/webview/overview",
- "items": [
- {
- "title": "WebView for Android",
- "href": "/multidevice/webview/overview"
- },
- {
- "title": "Getting Started",
- "href": "/multidevice/webview/gettingstarted"
- },
- {
- "title": "Pixel-Perfect UI",
- "href": "/multidevice/webview/pixelperfect"
- },
- {
- "title": "WebView Workflow",
- "href": "/multidevice/webview/workflow"
- },
- {
- "title": "Tips & Tricks",
- "href": "/multidevice/webview/tipsandtricks"
- }
- ]
- },
- {
- "title": "Chrome for iOS",
- "href": "/multidevice/ios/links",
- "items": [
- {
- "title": "Opening Links in Chrome",
- "href": "/multidevice/ios/links"
- },
- {
- "title": "User Agent",
- "href": "/multidevice/user-agent#chrome_for_ios_user_agent"
- }
- ]
- },
- {
- "title": "FAQ",
- "href": "/multidevice/faq"
- }
- ]
- }
- ]
- },
- {
- "title": "Chrome OS",
- "items": [
- {
- "title": "Apps",
- "href": "/apps/about_apps",
- "items": [
- {
- "title": "Learn Basics",
- "href": "/apps/about_apps",
- "items": [
- {
- "title": "What Are Chrome Apps?",
- "href": "/apps/about_apps"
- },
- {
- "title": "Extension Quality Guidelines FAQ",
- "href": "/extensions/single_purpose"
- },
- {
- "title": "Create Your First App",
- "href": "/apps/first_app"
- },
- {
- "title": "App Architecture",
- "href": "/apps/app_architecture"
- },
- {
- "title": "App Lifecycle",
- "href": "/apps/app_lifecycle"
- },
- {
- "title": "Content Security Policy",
- "href": "/apps/contentSecurityPolicy"
- }
- ]
- },
- {
- "title": "Learn with Codelab",
- "href": "/apps/app_codelab_intro",
- "items": [
- {
- "title": "Intro - Build Chrome App",
- "href": "/apps/app_codelab_intro"
- },
- {
- "title": "1 - Create and run a Chrome App",
- "href": "/apps/app_codelab_basics"
- },
- {
- "title": "2 - Import an existing web app",
- "href": "/apps/app_codelab_import_todomvc"
- },
- {
- "title": "3 - Add alarms and notifications",
- "href": "/apps/app_codelab_alarms"
- },
- {
- "title": "4 - Open external links with a webview",
- "href": "/apps/app_codelab_webview"
- },
- {
- "title": "5 - Add images from the web",
- "href": "/apps/app_codelab_images"
- },
- {
- "title": "6 - Export todos to the filesystem",
- "href": "/apps/app_codelab_filesystem"
- },
- {
- "title": "7 - Publish your app",
- "href": "/apps/app_codelab_publish"
- }
- ]
- },
- {
- "title": "Run Chrome Apps on Mobile",
- "href": "/apps/chrome_apps_on_mobile"
- },
- {
- "title": "Samples",
- "href": "/apps/samples"
- },
- {
- "title": "Develop in the Cloud",
- "href": "/apps/offline_apps",
- "items": [
- {
- "title": "Offline First",
- "href": "/apps/offline_apps"
- },
- {
- "title": "Handling External Content",
- "href": "/apps/app_external"
- },
- {
- "title": "Storing Data",
- "href": "/apps/app_storage"
- },
- {
- "title": "Managing Offline Storage",
- "href": "/apps/offline_storage"
- },
- {
- "title": "Native Messaging",
- "href": "/apps/nativeMessaging"
- },
- {
- "title": "Rich Notifications",
- "href": "/apps/richNotifications"
- },
- {
- "title": "User Authentication",
- "href": "/apps/app_identity"
- }
- ]
- },
- {
- "title": "User Low-Level System Services",
- "href": "/apps/app_usb",
- "items": [
- {
- "title": "USB",
- "href": "/apps/app_usb"
- },
- {
- "title": "Serial",
- "href": "/apps/app_serial"
- },
- {
- "title": "Network Communications",
- "href": "/apps/app_network"
- },
- {
- "title": "Bluetooth",
- "href": "/apps/app_bluetooth"
- }
- ]
- },
- {
- "title": "MVC Architecture & Frameworks",
- "href": "/apps/app_frameworks",
- "items": [
- {
- "title": "About MVC Architecture",
- "href": "/apps/app_frameworks"
- },
- {
- "title": "Build Apps with AngularJS",
- "href": "/apps/angular_framework"
- },
- {
- "title": "Build Apps with SenchaJS",
- "href": "/apps/sencha_framework"
- },
- {
- "title": "Game Engines",
- "href": "/apps/game_engines"
- }
- ]
- },
- {
- "title": "Distribute Apps",
- "href": "/apps/publish_app",
- "items": [
- {
- "title": "Publish Your App",
- "href": "/apps/publish_app"
- },
- {
- "title": "Monetize Your App",
- "href": "/webstore/payments-iap"
- },
- {
- "title": "One-Time Payments",
- "href": "/webstore/one_time_payments"
- },
- {
- "title": "Analytics",
- "href": "/apps/analytics"
- }
- ]
- },
- {
- "title": "Chrome Platform APIs",
- "href": "/apps/manifest",
- "items": [
- {
- "title": "Manifest File Format",
- "href": "/apps/manifest"
- },
- {
- "title": "Webview Tag",
- "href": "/apps/tags/webview"
- },
- {
- "title": "Appview Tag",
- "href": "/apps/tags/appview"
- },
- {
- "title": "Web APIs",
- "href": "/apps/api_other"
- },
- {
- "title": "Disabled Web Features",
- "href": "/apps/app_deprecated"
- }
- ]
- },
- {
- "title": "Help",
- "href": "/apps/faq",
- "items": [
- {
- "title": "FAQ",
- "href": "/apps/faq"
- },
- {
- "title": "Stack Overflow",
- "href": "http://stackoverflow.com/questions/tagged/google-chrome-app"
- }
- ]
- }
- ]
- },
- {
- "title": "Native Client",
- "href": "/native-client",
- "items": [
- {
- "title": "Learn Basics",
- "href": "/native-client",
- "items": [
- {
- "title": "Technical Overview",
- "href": "/native-client/overview"
- },
- {
- "title": "NaCl and PNaCl",
- "href": "/native-client/nacl-and-pnacl"
- }
- ]
- },
- {
- "title": "WebAssembly Migration Guide",
- "href": "/native-client/migration"
- },
- {
- "title": "Download the SDK",
- "href": "/native-client/sdk/download",
- "items": [
- {
- "title": "Download the Native Client SDK",
- "href": "/native-client/sdk/download"
- },
- {
- "title": "Examples",
- "href": "/native-client/sdk/examples"
- },
- {
- "title": "Release Notes",
- "href": "/native-client/sdk/release-notes"
- }
- ]
- },
- {
- "title": "Tutorial",
- "href": "/native-client/devguide/tutorial/tutorial-part1",
- "items": [
- {
- "title": "Part 1: Simple PNaCl Web App",
- "href": "/native-client/devguide/tutorial/tutorial-part1"
- },
- {
- "title": "Part 2: SDK Build System and Chrome Apps",
- "href": "/native-client/devguide/tutorial/tutorial-part2"
- },
- {
- "title": "Chrome Dev Summit 2014 - Codelabs",
- "href": "/native-client/cds2014"
- }
- ]
- },
- {
- "title": "Development Cycle",
- "href": "/native-client/devguide/devcycle/building",
- "items": [
- {
- "title": "Building",
- "href": "/native-client/devguide/devcycle/building"
- },
- {
- "title": "Running",
- "href": "/native-client/devguide/devcycle/running"
- },
- {
- "title": "Debugging",
- "href": "/native-client/devguide/devcycle/debugging"
- },
- {
- "title": "Debugging with Visual Studio",
- "href": "/native-client/devguide/devcycle/vs-addin"
- },
- {
- "title": "Dynamic Linking and Loading with GlibC",
- "href": "/native-client/devguide/devcycle/dynamic-loading"
- }
- ]
- },
- {
- "title": "Coding Your Application",
- "href": "/native-client/devguide/coding/application-structure",
- "items": [
- {
- "title": "Application Structure",
- "href": "/native-client/devguide/coding/application-structure"
- },
- {
- "title": "Native Client Modules",
- "href": "/native-client/devguide/coding/native-client-modules"
- },
- {
- "title": "3D Graphics",
- "href": "/native-client/devguide/coding/3D-graphics"
- },
- {
- "title": "Audio",
- "href": "/native-client/devguide/coding/audio"
- },
- {
- "title": "File I/O",
- "href": "/native-client/devguide/coding/file-io"
- },
- {
- "title": "The nacl_io Library",
- "href": "/native-client/devguide/coding/nacl_io"
- },
- {
- "title": "Messaging System",
- "href": "/native-client/devguide/coding/message-system"
- },
- {
- "title": "Progress Events",
- "href": "/native-client/devguide/coding/progress-events"
- },
- {
- "title": "URL Loading",
- "href": "/native-client/devguide/coding/url-loading"
- },
- {
- "title": "View Change, Focus, & Input Events",
- "href": "/native-client/devguide/coding/view-focus-input-events"
- }
- ]
- },
- {
- "title": "Distribute Your Apps",
- "href": "/native-client/devguide/distributing"
- },
- {
- "title": "Pepper API Reference",
- "href": "/native-client/c-api",
- "items": [
- {
- "title": "Pepper C API (Stable)",
- "href": "/native-client/c-api"
- },
- {
- "title": "Pepper C++ API (Stable)",
- "href": "/native-client/cpp-api"
- },
- {
- "title": "Pepper C API (Beta)",
- "href": "/native-client/c-api-beta"
- },
- {
- "title": "Pepper C++ API (Beta)",
- "href": "/native-client/cpp-api-beta"
- },
- {
- "title": "Pepper C API (Dev)",
- "href": "/native-client/c-api-dev"
- },
- {
- "title": "Pepper C++ API (Dev)",
- "href": "/native-client/cpp-api-dev"
- }
- ]
- },
- {
- "title": "Additional Reference & Versions",
- "href": "/native-client/glossary",
- "items": [
- {
- "title": "Glossary",
- "href": "/native-client/glossary"
- },
- {
- "title": "Contributor Ideas",
- "href": "/native-client/reference/ideas"
- },
- {
- "title": "Native Client Manifest (nmf) Format",
- "href": "/native-client/reference/nacl-manifest-format"
- },
- {
- "title": "Contents of PNaCl Bitcode Files",
- "href": "/native-client/reference/pnacl-bitcode-manual"
- },
- {
- "title": "PNaCl Bitcode Reference Manual",
- "href": "/native-client/reference/pnacl-bitcode-abi"
- },
- {
- "title": "PNaCl Undefined Behavior",
- "href": "/native-client/reference/pnacl-undefined-behavior"
- },
- {
- "title": "PNaCl C/C++ Language Support",
- "href": "/native-client/reference/pnacl-c-cpp-language-support"
- },
- {
- "title": "Sandbox Internals",
- "href": "/native-client/reference/sandbox_internals/index",
- "items": [
- {
- "title": "ARM 32-bit Sandbox",
- "href": "/native-client/reference/sandbox_internals/arm-32-bit-sandbox"
- },
- {
- "title": "x86-64 Sandbox",
- "href": "/native-client/reference/sandbox_internals/x86-64-sandbox"
- }
- ]
- },
- {
- "title": "Design Documents",
- "href": "/native-client/reference/design-docs"
- }
- ]
- },
- {
- "title": "Help",
- "href": "/native-client/faq",
- "items": [
- {
- "title": "FAQ",
- "href": "/native-client/faq"
- },
- {
- "title": "Forums & Issues Tracker",
- "href": "/native-client/help"
- },
- {
- "title": "Publications & Presentations",
- "href": "/native-client/publications-and-presentations"
- },
- {
- "title": "Security Contest Archive",
- "href": "/native-client/community/security-contest/index"
- }
- ]
- }
- ]
- }
- ]
- },
- {
- "title": "Chrome APIs",
- "items": [
- {
- "title": "Extensions APIs",
- "href": "/extensions/api_index",
- "items": [
- {
- "title": "Extension APIs",
- "href": "/extensions/api_index"
- }
- ]
- },
- {
- "title": "Apps APIs",
- "href": "/apps/api_index",
- "items": [
- {
- "title": "Apps APIs",
- "href": "/apps/api_index"
- }
- ]
- }
- ]
- }
-]
diff --git a/chromium/chrome/common/extensions/docs/templates/json/content_providers.json b/chromium/chrome/common/extensions/docs/templates/json/content_providers.json
deleted file mode 100644
index 2b700ce79c8..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/json/content_providers.json
+++ /dev/null
@@ -1,105 +0,0 @@
-// === Overview ===
-//
-// This file configures where to find and how to serve content in the docserver.
-// It's the most fundamentally important file in all of the docserver.
-//
-// === Format ===
-//
-// Each entry declares a rule with:
-// * An arbitrary identifier key e.g. "cr-extensions-examples".
-// * What URL the rule should be invoked with, given by "serveFrom", e.g.
-// "extensions/examples".
-// * An object describing where the content originates, either "chromium",
-// "github", or "gcs".
-// * "chromium" must provide a "dir" value specifying which chromium directory
-// to look in, e.g. "extensions/samples".
-// * "github" must provide "owner" and "repo" values specifying the owner of
-// the GitHub repository, and the repository name, e.g. "GoogleChrome" and
-// "chrome-app-samples" respectively.
-//
-// In the chromium example, when the user navigates to
-//
-// developer.chrome.com/extensions/examples/some/sample/path
-//
-// then
-// 1. The "cr-extensions-examples" rule is invoked (since it's served from
-// "extensions/examples").
-// 2. The docserver will look up the path "docs/examples/some/sample/path"
-// in chromium - the URL after the "serveFrom" path (some/sample/path)
-// prefixed by the chromium directory (docs/examples).
-// 3. Then render and serve it.
-//
-// === Special properties ===
-//
-// There are some other properties that can be specified:
-// * "supportsZip" indicates whether directories are allowed to be served as
-// zip files. For safety this isn't supported for arbitrary URLs, only those
-// within a rule that has "supportsZip": true.
-// * "supportsTemplates" indicates whether HTML files should be treated and
-// renderered as templates, versus just plain text. Complex documentation
-// which interacts with docserver features (like API listing) need to set
-// this to true. Otherwise, it's safer and more efficient to omit it.
-
-{
- "cr-chrome-docs-home": {
- "chromium": {
- "dir": "chrome/docs"
- },
- "defaultExtensions": [".html", ".md"],
- "serveFrom": "home",
- "supportsTemplates": true
- },
- "cr-extensions-examples": {
- "chromium": {
- "dir": "chrome/common/extensions/docs/examples"
- },
- "serveFrom": "extensions/examples",
- "supportsZip": true
- },
- "cr-public": {
- "chromium": {
- "dir": "chrome/common/extensions/docs/templates/public"
- },
- "defaultExtensions": [".html", ".md"],
- "serveFrom": "",
- "supportsTemplates": true
- },
- "cr-static": {
- "chromium": {
- "dir": "chrome/common/extensions/docs/static"
- },
- "serveFrom": "static"
- },
- "cr-native-client": {
- "chromium": {
- "dir": "native_client_sdk/doc_generated"
- },
- "defaultExtensions": [".html", ".md"],
- "serveFrom": "native-client",
- "supportsTemplates": true
- },
- "devtools-docs": {
- "defaultExtensions": [".html", ".md"],
- "gcs": {
- "bucket": "gs://chromedocs-devtools"
- },
- "serveFrom": "devtools",
- "supportsTemplates": true
- },
- "multidevice-docs": {
- "defaultExtensions": [".html", ".md"],
- "gcs": {
- "bucket": "gs://chromedocs-multidevice"
- },
- "serveFrom": "multidevice",
- "supportsTemplates": true
- },
- "webstore-docs": {
- "defaultExtensions": [".html", ".md"],
- "gcs": {
- "bucket": "gs://chromedocs-webstore"
- },
- "serveFrom": "webstore",
- "supportsTemplates": true
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/templates/json/extensions_sidenav.json b/chromium/chrome/common/extensions/docs/templates/json/extensions_sidenav.json
deleted file mode 100644
index 75ad47c1053..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/json/extensions_sidenav.json
+++ /dev/null
@@ -1,222 +0,0 @@
-[
- {
- "title": "Getting Started",
- "href": "/extensions/getstarted"
- },
- {
- "title": "Overview",
- "href": "/extensions/overview"
- },
- {
- "title": "What's New?",
- "href": "/extensions/whats_new"
- },
- {
- "title": "Developer's Guide",
- "href": "/extensions/devguide",
- "items": [
- {
- "title": "Browser UI",
- "toggleable": true,
- "items": [
- {
- "title": "Browser Actions",
- "href": "/extensions/browserAction"
- },
- {
- "title": "Context Menus",
- "href": "/extensions/contextMenus"
- },
- {
- "title": "Desktop Notifications",
- "href": "/extensions/desktop_notifications"
- },
- {
- "title": "Omnibox",
- "href": "/extensions/omnibox"
- },
- {
- "title": "Options Pages",
- "href": "/extensions/options"
- },
- {
- "title": "Override Pages",
- "href": "/extensions/override"
- },
- {
- "title": "Page Actions",
- "href": "/extensions/pageAction"
- }
- ]
- },
- {
- "title": "Browser Interaction",
- "toggleable": true,
- "items": [
- {
- "title": "Bookmarks",
- "href": "/extensions/bookmarks"
- },
- {
- "title": "Cookies",
- "href": "/extensions/cookies"
- },
- {
- "title": "Extending DevTools",
- "href": "/extensions/devtools"
- },
- {
- "title": "Events",
- "href": "/extensions/events"
- },
- {
- "title": "History",
- "href": "/extensions/history"
- },
- {
- "title": "Management",
- "href": "/extensions/management"
- },
- {
- "title": "Tabs",
- "href": "/extensions/tabs"
- },
- {
- "title": "Windows",
- "href": "/extensions/windows"
- }
- ]
- },
- {
- "title": "Implementation",
- "toggleable": true,
- "items": [
- {
- "title": "Accessibility",
- "href": "/extensions/a11y"
- },
- {
- "title": "Event Pages",
- "href": "/extensions/event_pages"
- },
- {
- "title": "Content Security Policy",
- "href": "/extensions/contentSecurityPolicy"
- },
- {
- "title": "Content Scripts",
- "href": "/extensions/content_scripts"
- },
- {
- "title": "Cross-Origin XHR",
- "href": "/extensions/xhr"
- },
- {
- "title": "Internationalization",
- "href": "/extensions/i18n"
- },
- {
- "title": "Message Passing",
- "href": "/extensions/messaging"
- },
- {
- "title": "Optional Permissions",
- "href": "/extensions/permissions"
- },
- {
- "title": "NPAPI Plugins",
- "href": "/extensions/npapi"
- }
- ]
- },
- {
- "title": "Finishing",
- "toggleable": true,
- "items": [
- {
- "title": "Hosting",
- "href": "/extensions/hosting"
- },
- {
- "title": "Other Deployment Options",
- "href": "/extensions/external_extensions"
- }
- ]
- }
- ]
- },
- {
- "title": "Tutorials",
- "href": "/extensions/tutorials",
- "items": [
- {
- "title": "Manifest V2",
- "href": "/extensions/tut_migration_to_manifest_v2"
- },
- {
- "title": "Debugging",
- "href": "/extensions/tut_debugging"
- },
- {
- "title": "Google Analytics",
- "href": "/extensions/tut_analytics"
- },
- {
- "title": "OAuth",
- "href": "/extensions/tut_oauth"
- }
- ]
- },
- {
- "title": "Reference",
- "items": [
- {
- "title": "Formats",
- "toggleable": true,
- "items": [
- {
- "title": "Manifest Files",
- "href": "/extensions/manifest"
- },
- {
- "title": "Match Patterns",
- "href": "/extensions/match_patterns"
- }
- ]
- },
- {
- "title": "Permission Warnings",
- "href": "/extensions/permission_warnings"
- },
- {
- "title": "chrome.* APIs",
- "href": "/extensions/api_index"
- },
- {
- "title": "Other APIs",
- "href": "/extensions/api_other"
- }
- ]
- },
- {
- "title": "More",
- "items": [
- {
- "title": "FAQ",
- "href": "/extensions/faq"
- },
- {
- "title": "Chrome Web Store",
- "href": "http://code.google.com/chrome/webstore/docs/index.html"
- },
- {
- "title": "Hosted Apps",
- "href": "http://code.google.com/chrome/apps/docs/developers_guide.html"
- },
- {
- "title": "Themes",
- "href": "/extensions/themes"
- }
- ]
- }
-]
diff --git a/chromium/chrome/common/extensions/docs/templates/json/intro_tables.json b/chromium/chrome/common/extensions/docs/templates/json/intro_tables.json
deleted file mode 100644
index aae113b3440..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/json/intro_tables.json
+++ /dev/null
@@ -1,333 +0,0 @@
-{
- "alarms": {
- "Learn More": [
- {
- "link": "event_pages",
- "text": "Event Pages"
- }
- ]
- },
- "app_runtime": {
- "Learn More": [
- {
- "link": "app_lifecycle",
- "text": "Manage App Lifecycle"
- },
- {
- "link": "https://developers.google.com/live/shows/10291095/",
- "text": "Chrome Office Hours: Introduction to Chrome Apps"
- }
- ]
- },
- "app_window": {
- "Learn More": [
- {
- "link": "about_apps#look",
- "text": "How they look"
- },
- {
- "link": "app_lifecycle",
- "text": "Manage App Lifecycle"
- },
- {
- "link": "https://developers.google.com/live/shows/9118010/",
- "text": "Chrome Apps Office Hours: Building Awesome Multi-window Apps"
- }
- ]
- },
- "bluetooth": {
- "Learn More": [
- {
- "link": "app_bluetooth",
- "text": "Bluetooth"
- }
- ]
- },
- "bluetoothLowEnergy": {
- "Learn More": [
- {
- "link": "app_bluetooth.html",
- "text": "Bluetooth"
- }
- ]
- },
- "bluetoothSocket": {
- "Learn More": [
- {
- "link": "app_bluetooth.html",
- "text": "Bluetooth"
- }
- ]
- },
- "cookies": {
- "Permissions": [
- {
- "class": "code",
- "text": "\"cookies\""
- },
- {
- "link": "declare_permissions#host-permissions",
- "text": "host permissions"
- }
- ]
- },
- "declarativeContent": {
- "Learn More": [
- {
- "link": "events",
- "text": "Declarative Events"
- },
- {
- "link": "activeTab",
- "text": "activeTab"
- }
- ]
- },
- "declarativeNetRequest": {
- "Permissions": [
- {
- "class": "code",
- "text": "\"declarativeNetRequest\""
- },
- {
- "link": "declare_permissions#host-permissions",
- "text": "host permissions"
- }
- ]
- },
- "declarativeWebRequest": {
- "Permissions": [
- {
- "class": "code",
- "text": "\"declarativeWebRequest\""
- },
- {
- "link": "declare_permissions#host-permissions",
- "text": "host permissions"
- }
- ]
- },
- "downloads": {
- "Permissions": [
- {
- "class": "code",
- "text": "\"downloads\""
- }
- ]
- },
- "fileSystem": {
- "Permissions": [
- {
- "class": "code",
- "text": "\"fileSystem\""
- },
- {
- "class": "code",
- "text": "{\"fileSystem\": [\"write\"]}"
- },
- {
- "class": "code",
- "text": "{\"fileSystem\": [\"write\", \"retainEntries\", \"directory\"]}"
- }
- ],
- "Learn More": [
- {
- "link": "app_storage",
- "text": "Manage Data"
- },
- {
- "link": "angular_framework",
- "text": "Build Apps with AngularJS"
- },
- {
- "link": "https://developers.google.com/live/shows/7320022-1001/",
- "text": "Chrome Apps Office Hours: TextDrive and AngularJS"
- }
- ]
- },
- "gcm": {
- "Learn More": [
- {
- "link": "https://developers.google.com/cloud-messaging/chrome/client",
- "text": "Implementing GCM Client on Chrome"
- }
- ]
- },
- "identity": {
- "Learn More": [
- {
- "link": "app_identity",
- "text": "Identify User"
- }
- ]
- },
- "mediaGalleries": {
- "Permissions": [
- {
- "class": "code",
- "text": "{\"mediaGalleries\": [\"accessType1\", \"accessType2\", ...]}"
- },
- {
- "class": "code",
- "text": "{\"mediaGalleries\": [\"accessType1\", \"accessType2\", ..., \"allAutoDetected\"]}"
- },
- {
- "partial": "intro_tables/see_manifest.html"
- }
- ],
- "Learn More": [
- {
- "link": "https://developers.google.com/live/shows/10479832/",
- "text": "Chrome Office Hours: The Media Galleries API"
- }
- ]
- },
- "notifications": {
- "Learn More": [
- {
- "link": "richNotifications",
- "text": "Rich Notifications"
- },
- {
- "link": "inform_users",
- "text": "Keep Users Informed"
- },
- {
- "link": "https://developers.google.com/live/shows/83992232-1001/",
- "text": "Chrome Apps Office Hours: Rich Notifications"
- }
- ]
- },
- "permissions": {
- "Learn More": [
- {
- "link": "declare_permissions",
- "text": "Declaring permissions"
- }
- ]
- },
- "runtime": {
- "Learn More": [
- {
- "link": "app_lifecycle",
- "text": "Manage App Lifecycle",
- "extension_types": ["platform_app"]
- },
- {
- "link": "event_pages",
- "text": "Event Pages"
- }
- ]
- },
- "serial": {
- "Learn More": [
- {
- "link": "app_usb",
- "text": "Accessing Hardware Devices"
- }
- ]
- },
- "socket": {
- "Permissions": [
- {
- "class": "code",
- "text": "{\"socket\": [\"rule1\", \"rule2\"]}"
- },
- {
- "partial": "intro_tables/socket_permissions.html"
- }
- ],
- "Learn More": [
- {
- "link": "app_network",
- "text": "Network Communications"
- },
- {
- "link": "sencha_framework",
- "text": "Build Apps with Sencha ExtJS"
- },
- {
- "link": "https://developers.google.com/live/shows/7320022-5001/",
- "text": "Chrome Apps Office Hours: Networking APIs"
- },
- {
- "link": "https://developers.google.com/live/shows/7320022-2001/",
- "text": "Chrome Apps Office Hours: Controlling an AR ParrotDrone"
- }
- ]
- },
- "storage": {
- "Learn More": [
- {
- "link": "https://youtu.be/tmzxMO9lrF0",
- "text": "Chrome Apps Office Hours: Chrome Storage APIs"
- },
- {
- "link": "https://youtu.be/4cIFRn0rp5s",
- "text": "Chrome Apps Office Hours: Storage API Deep Dive"
- }
- ]
- },
- "syncFileSystem": {
- "Learn More": [
- {
- "link": "app_storage",
- "text": "Manage Data"
- },
- {
- "link": "https://developers.google.com/live/shows/83992232-2001/",
- "text": "Chrome Office Hours: Synched File System"
- }
- ]
- },
- "tabs": {
- "Permissions": [
- {
- "partial": "intro_tables/tabs_permissions.html"
- }
- ]
- },
- "tts": {
- "Learn More": [
- {
- "link": "https://developers.google.com/live/shows/7320022-7001/",
- "text": "Chrome Office Hours: Text to Speech API"
- }
- ]
- },
- "usb": {
- "Learn More": [
- {
- "link": "app_usb",
- "text": "Accessing Hardware Devices"
- }
- ]
- },
- "webRequest": {
- "Permissions": [
- {
- "class": "code",
- "text": "\"webRequest\""
- },
- {
- "link": "declare_permissions#host-permissions",
- "text": "host permissions"
- }
- ]
- },
- "webstore": {
- "Learn More": [
- {
- "link": "https://developers.google.com/chrome/web-store/docs/inline_installation",
- "text": "Using Inline Installation"
- }
- ]
- },
- "windows": {
- "Permissions": [
- {
- "partial": "intro_tables/windows_permissions.html"
- }
- ]
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/templates/json/manifest.json b/chromium/chrome/common/extensions/docs/templates/json/manifest.json
deleted file mode 100644
index afbec4ec01d..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/json/manifest.json
+++ /dev/null
@@ -1,252 +0,0 @@
-{
- "action_handlers": {
- "documentation": "manifest/action_handlers",
- "example": ["new_note"]
- },
- "app": {
- "documentation": "manifest/app",
- "example": {},
- "level": "required"
- },
- "app.background": {
- "example": {"scripts": ["background.js"]},
- "level": "required"
- },
- "background": {
- "documentation": "background_pages"
- },
- "background.persistent": {
- "documentation": "event_pages",
- "example": false,
- "level": "recommended"
- },
- "bluetooth": {
- "documentation": "manifest/bluetooth",
- "example": {
- "uuids": [ "1105", "1006" ]
- }
- },
- "browser_action": {
- "documentation": "browserAction",
- "example": {},
- "level": "only_one"
- },
- "chrome_settings_overrides": {
- "documentation": "settings_override",
- "example": {}
- },
- "chrome_ui_overrides": {
- "documentation": "ui_override",
- "example": {
- "bookmarks_ui": {
- "remove_button": true,
- "remove_bookmark_shortcut": true
- }
- }
- },
- "chrome_url_overrides": {
- "documentation": "override",
- "example": {}
- },
- "commands": {
- "documentation": "commands",
- "example": {}
- },
- "content_scripts": {
- "documentation": "content_scripts",
- "example": [{}]
- },
- "content_security_policy": {
- "documentation": "contentSecurityPolicy",
- "example": "policyString"
- },
- "default_locale": {
- "documentation": "manifest/default_locale",
- "example": "en",
- "level": "recommended"
- },
- "description": {
- "documentation": "manifest/description",
- "example": "A plain text description",
- "level": "recommended"
- },
- "devtools_page": {
- "documentation": "devtools",
- "example": "devtools.html"
- },
- "event_rules": {
- "documentation": "manifest/event_rules",
- "example": [{}]
- },
- "export": {
- "documentation": "shared_modules",
- "example": {}
- },
- "externally_connectable": {
- "documentation": "manifest/externally_connectable",
- "example": {
- "matches": ["*://*.example.com/*"]
- }
- },
- "file_browser_handlers": {
- "documentation": "fileBrowserHandler",
- "example": []
- },
- "file_handlers": {
- "documentation": "manifest/file_handlers",
- "example": {}
- },
- "file_system_provider_capabilities": {
- "documentation": "manifest/file_system_provider",
- "example": {
- "configurable": true,
- "multiple_mounts": true,
- "source": "network"
- }
- },
- "homepage_url": {
- "documentation": "manifest/homepage_url",
- "example": "http://path/to/homepage"
- },
- "icons": {
- "documentation": "manifest/icons",
- "example": {},
- "level": "recommended"
- },
- "import": {
- "documentation": "shared_modules",
- "example": [{"id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}]
- },
- "incognito": {
- "documentation": "manifest/incognito",
- "example": "spanning, split, or not_allowed"
- },
- "key": {
- "documentation": "manifest/key",
- "example": "publicKey"
- },
- "kiosk_enabled": {
- "documentation": "manifest/kiosk_enabled#kiosk_enabled",
- "example": true
- },
- "kiosk_only": {
- "documentation": "manifest/kiosk_enabled#kiosk_only",
- "example": true
- },
- "manifest_version": {
- "documentation": "manifest/manifest_version",
- "example": 2,
- "level": "required"
- },
- "minimum_chrome_version": {
- "documentation": "manifest/minimum_chrome_version",
- "example": "versionString"
- },
- "nacl_modules": {
- "documentation": "manifest/nacl_modules",
- "example": []
- },
- "name": {
- "documentation": "manifest/name#name",
- "example": "My {{platform}}",
- "level": "required"
- },
- "offline_enabled": {
- "documentation": "manifest/offline_enabled",
- "example": true
- },
- "omnibox": {
- "documentation": "omnibox",
- "example": {
- "keyword": "aString"
- }
- },
- "optional_permissions": {
- "documentation": "permissions",
- "example": ["tabs"]
- },
- "options_page": {
- "documentation": "options",
- "example": "options.html"
- },
- "options_ui": {
- "documentation": "optionsV2",
- "example": {
- "page": "options.html",
- "chrome_style": true
- }
- },
- "page_action": {
- "documentation": "pageAction",
- "example": {},
- "level": "only_one"
- },
- "permissions": {
- "documentation": "declare_permissions",
- "example": ["tabs"]
- },
- "requirements": {
- "documentation": "manifest/requirements",
- "example": {}
- },
- "sandbox": {
- "documentation": "manifest/sandbox",
- "example": []
- },
- "short_name": {
- "documentation": "manifest/name#short_name",
- "example": "Short Name"
- },
- "sockets": {
- "documentation": "manifest/sockets",
- "example": {
- "tcp": { "connect": "*" }, "udp": { "send": "*" }
- }
- },
- "storage": {
- "documentation": "manifest/storage",
- "example": {
- "managed_schema": "schema.json"
- }
- },
- "theme": {
- "documentation": "themes",
- "example": {},
- "level": "only_one"
- },
- "tts_engine": {
- "documentation": "ttsEngine",
- "example": {}
- },
- "update_url": {
- "documentation": "autoupdate",
- "example": "http://path/to/updateInfo.xml"
- },
- "url_handlers": {
- "documentation": "manifest/url_handlers",
- "example": {}
- },
- "usb_printers": {
- "documentation": "manifest/usb_printers",
- "example": {
- "filters": []
- }
- },
- "version": {
- "documentation": "manifest/version",
- "example": "versionString",
- "level": "required"
- },
- "version_name": {
- "documentation": "manifest/version",
- "example": "aString"
- },
- "web_accessible_resources": {
- "documentation": "manifest/web_accessible_resources",
- "example": []
- },
- "webview": {
- "documentation": "tags/webview#local_resources",
- "example": {}
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/templates/json/permissions.json b/chromium/chrome/common/extensions/docs/templates/json/permissions.json
deleted file mode 100644
index 5d3a415c9bd..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/json/permissions.json
+++ /dev/null
@@ -1,69 +0,0 @@
-{
- "host-permissions": {
- "channel": "stable",
- "anchor": "host-permissions",
- "name": "[scheme]:[host]/*",
- "partial": "permissions/host_permissions.html",
- "extension_types": ["legacy_packaged_app", "extension", "platform_app"]
- },
- "activeTab": {
- "partial": "permissions/active_tab.html"
- },
- "alwaysOnTopWindows": {
- "partial": "permissions/always_on_top_windows.html"
- },
- "audioCapture": {
- "partial": "permissions/audio_capture.html"
- },
- "background": {
- "partial": "permissions/background.html"
- },
- "chrome://favicon/": {
- "anchor": "favicon",
- "extension_types": ["extension"],
- "name": "chrome://favicon/",
- "partial": "permissions/favicon.html"
- },
- "clipboardRead": {
- "partial": "permissions/clipboard_read.html"
- },
- "clipboardWrite": {
- "partial": "permissions/clipboard_write.html"
- },
- "experimental": {
- "partial": "permissions/experimental.html"
- },
- "fullscreen": {
- "partial": "permissions/fullscreen.html"
- },
- "geolocation": {
- "partial": "permissions/geolocation.html"
- },
- "nativeMessaging": {
- "partial": "permissions/nativeMessaging.html"
- },
- "notifications": {
- "partial": "permissions/notifications.html"
- },
- "pointerLock": {
- "partial": "permissions/pointer_lock.html"
- },
- "syncFileSystem": {
- "partial": "permissions/sync_file_system.html"
- },
- "tabs": {
- "partial": "permissions/tabs.html"
- },
- "unlimitedStorage": {
- "partial": "permissions/unlimited_storage.html"
- },
- "videoCapture": {
- "partial": "permissions/video_capture.html"
- },
- "webRequestBlocking": {
- "partial": "permissions/web_request_blocking.html"
- },
- "webview": {
- "partial": "permissions/webview.html"
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/templates/json/strings.json b/chromium/chrome/common/extensions/docs/templates/json/strings.json
deleted file mode 100644
index 8b1d36418ef..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/json/strings.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- // General strings.
- "app": "app",
- "appsTitle": "Apps",
- "devtools": "devtools",
- "devtoolsTitle": "DevTools",
- "extension": "extension",
- "extensionsTitle": "Extensions",
- "events": "events",
- "methods": "methods",
- "multidevice": "multi-device",
- "multideviceTitle": "Multi-device",
- "nacl": "native client",
- "naclTitle": "Native Client",
- "properties": "properties",
- "sampleApps": "Sample Apps",
- "sampleExtensions": "Sample Extensions",
- "webstore": "webstore",
- "webstoreTitle": "Chrome Web Store",
-
- // Canonical references to DevTools articles.
- "canonicalDevToolsConsole": "https://developers.google.com/web/tools/javascript/console/console-reference",
- "canonicalDevToolsOverview": "https://developers.google.com/web/tools/setup/workspace/setup-devtools",
- "canonicalDevToolsInspectBasics": "https://developers.google.com/web/tools/iterate/inspect-styles/basics",
- "canonicalDevToolsNavigateConsole": "https://developers.google.com/web/tools/javascript/console/console-ui",
- "canonicalDevToolsTips": "https://developers.google.com/web/updates/tip/",
- "canonicalDevToolsEditStyles": "https://developers.google.com/web/tools/iterate/inspect-styles/basics",
- "canonicalDevToolsPreprocessors": "https://developers.google.com/web/tools/setup/workspace/setup-preprocessors",
- "canonicalDevToolsLocalStorage": "https://developers.google.com/web/tools/iterate/manage-data/local-storage",
- "canonicalDevToolsJavaScript": "https://developers.google.com/web/tools/javascript/",
- "canonicalDevToolsDeviceMode": "https://developers.google.com/web/tools/setup/device-testing/devtools-emulator",
- "canonicalDevToolsRemoteDebugging": "https://developers.google.com/web/tools/setup/remote-debugging/remote-debugging",
- "canonicalDevToolsWorkspaces": "https://developers.google.com/web/tools/setup/workspace/setup-workflow",
- "canonicalDevToolsNetwork": "https://developers.google.com/web/tools/profile-performance/network-performance/resource-loading",
- "canonicalDevToolsTimeline": "https://developers.google.com/web/tools/profile-performance/evaluate-performance/timeline-tool",
- "canonicalDevToolsForcedSynchronousLayoutDemo": "https://developers.google.com/web/tools/profile-performance/rendering-tools/forced-synchronous-layouts",
- "canonicalDevToolsCPUProfiling": "https://developers.google.com/web/tools/profile-performance/rendering-tools/js-execution",
- "canonicalDevToolsMemoryProfiling": "https://developers.google.com/web/tools/profile-performance/memory-problems/memory-diagnosis",
- "canonicalDevToolsMemory101": "https://developers.google.com/web/tools/profile-performance/memory-problems/memory-101",
- "canonicalDevToolsCommandLine": "https://developers.google.com/web/tools/javascript/command-line/command-line-reference",
- "canonicalDevToolsShortcuts": "https://developers.google.com/web/tools/iterate/inspect-styles/shortcuts"
-}
diff --git a/chromium/chrome/common/extensions/docs/templates/json/whats_new.json b/chromium/chrome/common/extensions/docs/templates/json/whats_new.json
deleted file mode 100644
index 9f6b366a2a5..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/json/whats_new.json
+++ /dev/null
@@ -1,367 +0,0 @@
-{
- "backgroundpages.to-be-non-persistent": {
- "type": "additionsToExistingApis",
- "description": "Background pages can optionally be non-persistent, using a feature we call <code>event pages</code>. Event pages run only while they're being used, and will unload when idle to save resources.",
- "version": 22
- },
- "chromeSetting.set-regular-only-scope": {
- "type": "additionsToExistingApis",
- "description": "The types.ChromeSetting.set method now has a <code>regular_only</code> scope.",
- "version": 21
- },
- "browsingData.RemovalOptions.set-originTypes-property": {
- "type": "additionsToExistingApis",
- "description": "The browsingData.RemovalOptions now has an <code>originTypes</code> property.",
- "version": 21
- },
- "management.uninstall.set-showConfirmDialog": {
- "type": "additionsToExistingApis",
- "description": "The management.uninstall method now has a <code>showConfirmDialog</code> parameter.",
- "version": 21
- },
- "contextMenus.create.set-unique-IDs": {
- "type": "additionsToExistingApis",
- "description": "The contextMenus.create method now allows you to specify unique IDs for each item. This is intended to be used with the new <code>contextMenus.onClicked</code> event, to distinguish the clicked item.",
- "version": 21
- },
- "browserAction.setIcon-and-pageAction.setIcon": {
- "type": "additionsToExistingApis",
- "description": "The browserAction.setIcon and pageAction.setIcon methods now accept optional callbacks.",
- "version": 21
- },
- "privacy.websites.has-protectedContentEnabled-property": {
- "type": "additionsToExistingApis",
- "description": "The privacy.websites namespace now has a <code>protectedContentEnabled</code> property.",
- "version": 21
- },
- "tabs.move.index.accept--1": {
- "type": "additionsToExistingApis",
- "description": "The <code>index</code> parameter to the tabs.move method now accepts -1 to indicate that the tab should be placed at the end.",
- "version": 21
- },
- "tabs.highlight.windowId.be-optional": {
- "type": "additionsToExistingApis",
- "description": "The <code>windowId</code> parameter to the tabs.highlight method is now optional.",
- "version": 21
- },
- "manifest-v1-deprecated": {
- "type": "manifestChanges",
- "description": "Manifest version 1 was deprecated in Chrome 18 and will be phased out according to the Manifest version 1 support",
- "version": 20
- },
- "chrome.contextMenus.create-and-update-has-enabled-parameter": {
- "type": "additionsToExistingApis",
- "description": "The chrome.contextMenus contextMenus.create and contextMenus.update methods now have an <code>enabled</code> parameter.",
- "version": 20
- },
- " privacy.services.has-spellingServiceEnabled-setting": {
- "type": "additionsToExistingApis",
- "description": "The privacy API's privacy.services object now has a <code>spellingServiceEnabled</code> setting.",
- "version": 20
- },
- "chrome.tabs.executeScript-and-insertCSS-has-runAt-parameter": {
- "type": "additionsToExistingApis",
- "description": "The chrome.tabs tabs.executeScript and tabs.insertCSS now accept a runAt parameter.",
- "version": 20
- },
- "sendRequest.deprecated-for-runtime-and-sendMessage": {
- "type": "additionsToExistingApis",
- "description": "The <code>sendRequest()</code> method has been deprecated in favor of the <code>sendMessage()</code> method for both the runtime.sendMessage and tabs.sendMessage.",
- "version": 20
- },
- "window.window.support-fullscreen-state": {
- "type": "additionsToExistingApis",
- "description": "The window API's windows.Window object now has an <code>alwaysOnTop</code> property and supports the fullscreen state.",
- "version": 19
- },
- "chrome.tabs.query.has-currentWindow-and-lastFocusedWindow-parameter": {
- "type": "additionsToExistingApis",
- "description": "The <code>chrome.tabs</code> tabs.query method now has the <code>currentWindow</code> and <code>lastFocusedWindow</code> parameters.",
- "version": 19
- },
- "browser.action.api.has-new-getter-fucntions": {
- "type": "additionsToExistingApis",
- "description": "The browser action API has the following new getter functions: browserAction.getTitle, browserAction.getBadgeText, browserAction.getBadgeBackgroundColor, and browserAction.getPopup.",
- "version": 19
- },
- "page.action.has-new-getter-functions": {
- "type": "additionsToExistingApis",
- "description": "The page action API has the following new getter functions: pageAction.getTitle and pageAction.getPopup.",
- "version": 19
- },
- "chrome.tabs.create-update-methods-has-openerTabId-parameter": {
- "type": "additionsToExistingApis",
- "description": "The chrome.tabs tabs.create and tabs.update methods now have an <code>openerTabId</code> parameter",
- "version": 18
- },
- "new-manifest-version-field-specifies-the-version": {
- "type": "manifestChanges",
- "description": "The new manifest version field specifies the version of the manifest that your package requires. As of Chrome 18, you should use manifest version 2.",
- "version": 18
- },
- "new-CSP-field-define-extensions-policies": {
- "type": "manifestChanges",
- "description": "The new Content Security Policy (CSP) field is used to define an extension's policies towards the types of content that can be loaded and executed by the extension.",
- "version": 18
- },
- "background-pages-includes-scripts-property": {
- "type": "manifestChanges",
- "description": "Most background pages only include a list of script files. For these background pages, you can use the new background.scripts property and Chrome will generate a background page for you.",
- "version": 18
- },
- "new-web-accessible-resources-field": {
- "type": "manifestChanges",
- "description": "The new web_accessible_resources field specifies the paths of packaged resources that are expected to be usable in the context of a web page.",
- "version": 18
- },
- "permission-be-optional-for-some-apis": {
- "type": "manifestChanges",
- "description": "Permissions can be optional for the content setting API, the web navigation API, and the new web request API.",
- "version": 17
- },
- "management.ExtensionInfo.object.has-disabledReason-property": {
- "type": "additionsToExistingApis",
- "description": "The management API's management.ExtensionInfo object now has a <code>disabledReason</code> property.",
- "version": 17
- },
- "omnibox.api.works-in-split-incognito-mode": {
- "type": "additionsToExistingApis",
- "description": "The omnibox API now works in split incognito mode.",
- "version": 17
- },
- "new-requirements-field-declare-extension-requirements": {
- "type": "manifestChanges",
- "description": "The new requirements field allows you to declare extension requirements up front. For example, you can use this field to specify that your app requires 3D graphics support in order to use features such as CSS 3D Tranforms or WebGL.",
- "version": 16
- },
- "tabs.query.gets-all-tabs": {
- "type": "additionsToExistingApis",
- "description": "The new tabs.query method gets all tabs that have the specified properties or all tabs if no properties are specified.",
- "version": 16
- },
- "tabs.reload.preserve-local-cache": {
- "type": "additionsToExistingApis",
- "description": "The new tabs.reload method reloads a tab and includes the option to preserve the local cache of the reloaded tab.",
- "version": 16
- },
- "management.ExtensionInfo.has-updateURL-property": {
- "type": "additionsToExistingApis",
- "description": "The management API's management.ExtensionInfo object now has an <code>updateURL</code> property.",
- "version": 16
- },
- "external_extensions.json.limit-supported-locals": {
- "type": "additionsToExistingApis",
- "description": "You can now limit the supported locales for an external extension by adding the <code>supported_locales</code> attribute to the <code>external_extensions.json</code>.",
- "version": 16
- },
- "getAllInWindow-getSelected.deprecated": {
- "type": "additionsToExistingApis",
- "description": "The methods <code>getAllInWindow()</code> and <code>getSelected()</code> have been deprecated. To get details about all tabs in the specified window, use tabs.query with the argument {'windowId': windowId}. To get the tab that is selected in the specified window, use <code>chrome.tabs.query()</code> with the argument <code>{'active': true}</code>.",
- "version": 16
- },
- "tabs.upate-doesnot-need-tabId": {
- "type": "additionsToExistingApis",
- "description": "You are no longer required to specify the <code>tabId</code> for the tabs.update method. When not provided, the tabId defaults to the selected tab of the current window.",
- "version": 16
- },
- "external-files-be-owned-by-users-in-wheel-group": {
- "type": "additionsToExistingApis",
- "description": "External extension files on Mac OS can now be owned by users within a wheel group (or an admin group).",
- "version": 16
- },
- "experimental-permission-no-longer-required-for-panel-type": {
- "type": "additionsToExistingApis",
- "description": "Experimental permission for deprecated windows.create panel type.",
- "version": 16
- },
- "offline_enabled.field-specify-without-connection": {
- "type": "manifestChanges",
- "description": "The new offline_enabled field lets you specify that your app works well even without an internet connection.",
- "version": 15
- },
- "management.getPermissionWarningsById.retrieve-permission-warning": {
- "type": "additionsToExistingApis",
- "description": "You can retrieve permission warnings using the new management API methods management.getPermissionWarningsById and management.getPermissionWarningsByManifest.",
- "version": 15
- },
- "management.ExtensionInfo.has-offlineEnabled": {
- "type": "additionsToExistingApis",
- "description": "The management API’s management.ExtensionInfo object has a new field, offlineEnabled.",
- "version": 15
- },
- "internationalize.using-placeholders": {
- "type": "additionsToExistingApis",
- "description": "You can now internationalize content script CSS files by using __MSG_messagename__ placeholders.",
- "version": 15
- },
- "tabs.update.callback-passed-null": {
- "type": "additionsToExistingApis",
- "description": "The callback for the tabs.update method is passed null instead of the tab details if the extension does not have the tabs permission.",
- "version": 15
- },
- "content_security_policy-prevent-xss-attack": {
- "type": "manifestChanges",
- "description": "The new content_security_policy field can help prevent cross-site scripting vulnerabilities in your extension.",
- "version": 14
- },
- "nacl_modules.register-native-client-modules": {
- "type": "manifestChanges",
- "description": "The new nacl_modules field lets you register Native Client modules as content handlers for MIME types.",
- "version": 14
- },
- "context.menu.items-appear-in-documents": {
- "type": "additionsToExistingApis",
- "description": "Context menu items can now appear even in documents that have file:// or chrome:// URLs. Previously, they were restricted to documents with http:// or https:// URLs.",
- "version": 14
- },
- "drawAttention-field-specify-that-window": {
- "type": "additionsToExistingApis",
- "description": "An optional drawAttention field in windows.update's updateInfo object lets you specify that the window should entice the user to change focus to it.",
- "version": 14
- },
- "bookmarks.getSubTree-retrieve-bookmarks-hierarchy": {
- "type": "additionsToExistingApis",
- "description": "The new bookmarks.getSubTree function lets you retrieve just part of the Bookmarks hierarchy",
- "version": 14
- },
- "tabs.permission.no-longer-required-for-tabs-remove": {
- "type": "additionsToExistingApis",
- "description": "The tabs permission is no longer required for tabs.remove and tabs.onRemoved.",
- "version": 14
- },
- "exclude_matches-targets-content-script-precisely": {
- "type": "manifestChanges",
- "description": "A new <code>exclude_matches</code> item in the content_scripts field lets you target your content script more precisely. For details, see Match patterns and globs.",
- "version": 13
- },
- "new-clipboardRead-specify-capabilities-for-document.execCommand": {
- "type": "manifestChanges",
- "description": "New clipboardRead and clipboardWrite permissions specify capabilities for <code>document.execCommand()</code>.",
- "version": 13
- },
- "content-scripts-make-cross-origin-requests": {
- "type": "additionsToExistingApis",
- "description": "Content scripts can now make cross-origin XMLHttpRequests to the same sites that their parent extension can, eliminating the need to relay these requests through a background page.",
- "version": 13
- },
- "use-runat-in-greasemonkey-script": {
- "type": "additionsToExistingApis",
- "description": "You can now use <code>@run-at</code> in an imported Greasemonkey script to control when the script is injected. It works the same way as <code>run_at</code> in content scripts.",
- "version": 13
- },
- "two-new-chrome-extension-methods": {
- "type": "additionsToExistingApis",
- "description": "Two new <code>chrome.extension</code> methods—extension.isAllowedFileSchemeAccess and extension.isAllowedIncognitoAccess—let you determine whether your extension has increased access, which the user specifies using the extensions management page (chrome://extensions).",
- "version": 12
- },
- "window.create.takes-focused-value": {
- "type": "additionsToExistingApis",
- "description": "The windows.create method can now take a <code>focused</code> value. Previously, all new windows had the keyboard focus; now you can create windows without interrupting the user's typing.",
- "version": 12
- },
- "manifest-specifies-experimental-permission": {
- "type": "additionsToExistingApis",
- "description": "If the manifest specifies experimental permission, your extension can specify panel as the value of the <code>type</code> field in the windows.create method or the windows.Window type.",
- "version": 12
- },
- "cookies.onChanged.event-has-a-cause-parameter": {
- "type": "additionsToExistingApis",
- "description": "The cookies.onChanged event of <code>chrome.cookies</code> now has a <code>cause</code> parameter.",
- "version": 12
- },
- "chrome.contextMenus.create.specifies-frame-value": {
- "type": "additionsToExistingApis",
- "description": "The <code>chrome.contextMenus</code> contextMenus.create and contextMenus.update methods now let you specify a context value of frame",
- "version": 12
- },
- "host-permission-for-tabs-operation": {
- "type": "additionsToExistingApis",
- "description": "For security reasons, you can no longer call tabs.captureVisibleTab on just any tab. Instead, you now must have host permission for the URL displayed by that tab. To get the previous behavior, specify <code><all_urls></code> for the host permission.",
- "version": 11
- },
- "management.ExtensionInfo.has-homepageUrl-property": {
- "type": "additionsToExistingApis",
- "description": "The management API's management.ExtensionInfo object now has a <code>homepageUrl</code> property.",
- "version": 11
- },
- "management.has-homepageUrl-property": {
- "type": "additionsToExistingApis",
- "description": "The management API now lets you get the icons of disabled apps and extensions. Also, you can now modify the regular icon's URL to get its disabled equivalent. See management.IconInfo for details.",
- "version": 11
- },
- "cookies.set-take-callbacks": {
- "type": "additionsToExistingApis",
- "description": "The cookies API cookies.set and cookies.remove methods can now take callbacks.",
- "version": 11
- },
- "new.background-permission-extends-life-of-chrome": {
- "type": "manifestChanges",
- "description": "The new background permission extends the life of Chrome, allowing your extension or app to run even when Chrome has no windows open.",
- "version": 10
- },
- "windows.create.has-tabId-field": {
- "type": "additionsToExistingApis",
- "description": "The windows.create method now has a <code>tabId</code> field. You can use it to move a tab or panel into a new window.",
- "version": 10
- },
- "homepage-url-field-specify-extension-homepage": {
- "type": "manifestChanges",
- "description": "The homepage_url field lets you specify the extension or app's homepage.",
- "version": 9
- },
- "tabs.Tab.has-pinned-property": {
- "type": "additionsToExistingApis",
- "description": "The tabs.Tab object now has a <code>pinned</code> property that's reflected in various <code>chrome.tabs</code> methods. For example, you can tabs.create a pinned tab.",
- "version": 9
- },
- "windows.create.takes-urls": {
- "type": "additionsToExistingApis",
- "description": "The windows.create method can now take a list of URLs, letting you create multiple tabs in the new window.",
- "version": 9
- },
- "management.get.specified-apps": {
- "type": "additionsToExistingApis",
- "description": "The new management.get method lets you get information about the specified extension or app.",
- "version": 9
- },
- "introduce-split-incognito-mode": {
- "type": "manifestChanges",
- "description": "Introduced split incognito mode as the default for installable web apps (also available to extensions).",
- "version": 7
- },
- "tabs.create-and-update-no-longer-require-tabs-permission": {
- "type": "manifestChanges",
- "description": "The tabs API <code>create()</code> and <code>update()</code> methods no longer require the tabs permission, removing one common cause of scary dialogs.",
- "version": 7
- },
- "geolocation-permission-access-users-location": {
- "type": "manifestChanges",
- "description": "The geolocation permission gives an extension access to the user's physical location.",
- "version": 6
- },
- "match-patterns-select-all-schemes": {
- "type": "manifestChanges",
- "description": "Match patterns can now select all schemes or all URLs.",
- "version": 6
- },
- "access-file-urls-triggers-access-warning": {
- "type": "manifestChanges",
- "description": "Access to file:/// URLs no longer triggers the access to your machine security warning, but now requires user opt-in from the extensions management page.",
- "version": 6
- },
- "extension.getViews.return-popup-views": {
- "type": "additionsToExistingApis",
- "description": "The extension.getViews method can now return popup views.",
- "version": 6
- },
- "windows.WINDOW_ID_NONE.identifies": {
- "type": "additionsToExistingApis",
- "description": "A new windows.WINDOW_ID_NONE constant identifies when focus shifts away from the browser.",
- "version": 6
- },
- "tabs.getCurrent-returns-tab": {
- "type": "additionsToExistingApis",
- "description": "The new tabs.getCurrent method returns the tab associated with the currently executing script.",
- "version": 6
- }
-}
diff --git a/chromium/chrome/common/extensions/docs/templates/public/apps/redirects.json b/chromium/chrome/common/extensions/docs/templates/public/apps/redirects.json
deleted file mode 100644
index 6347547fcba..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/public/apps/redirects.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "": "about_apps",
- "app_csp": "contentSecurityPolicy",
- "cloudMessaging": "https://developers.google.com/cloud-messaging/chrome/client",
- "cloudMessagingV1": "https://developers.google.com/cloud-messaging/chrome/client",
- "crx": "/extensions/linux_hosting",
- "pushMessaging": "https://developers.google.com/cloud-messaging/chrome/client",
- "gcm_tos": "https://developers.google.com/terms/",
- "gcm_server": "https://developers.google.com/cloud-messaging/server",
- "getstarted_arc": "https://developer.android.com/chrome-os/intro.html",
- "google_wallet": "../webstore/payments-iap",
- "experimental_systemInfo_storage": "system_storage",
- "in_app_payments": "google_wallet",
- "index": "about_apps",
- "inform_users": "https://developers.google.com/cloud-messaging/chrome/client",
- "packaging": "/extensions/packaging",
- "systemInfo_cpu": "system_cpu",
- "systemInfo_display": "system_display",
- "systemInfo_memory": "system_memory",
- "webview": "tags/webview",
- "webview_tag": "tags/webview",
- "app_codelab": "app_codelab_intro",
- "app_codelab1_setup": "app_codelab_intro",
- "app_codelab2_basic": "app_codelab_intro",
- "app_codelab3_mvc": "app_codelab_intro",
- "app_codelab5_data": "app_codelab_intro",
- "app_codelab6_lifecycle": "app_codelab_intro",
- "app_codelab7_useridentification": "app_codelab_intro",
- "app_codelab8_webresources": "app_codelab_intro",
- "app_codelab_10_publishing": "app_codelab_intro",
- "arc_in_app_payments": "https://developer.android.com/chrome-os/intro.html",
- "arc_playservices": "https://developer.android.com/chrome-os/intro.html"
-}
diff --git a/chromium/chrome/common/extensions/docs/templates/public/extensions/redirects.json b/chromium/chrome/common/extensions/docs/templates/public/extensions/redirects.json
deleted file mode 100644
index f855b38d02a..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/public/extensions/redirects.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "experimental.debugger": "debugger",
- "experimental_debugger": "debugger",
- "experimental.infobars": "infobars",
- "experimental_infobars": "infobars",
- "experimental.systemInfo_storage": "system_storage",
- "experimental_systemInfo_storage": "system_storage",
- "systemInfo_cpu": "system_cpu",
- "systemInfo_memory": "system_memory",
- "index": ".",
- "optionsV2": "/extensions/options",
- "cloudMessaging": "https://developers.google.com/cloud-messaging/chrome/client",
- "cloudMessagingV1": "https://developers.google.com/cloud-messaging/chrome/client",
- "pushMessaging": "https://developers.google.com/cloud-messaging/chrome/client",
- "gcm_tos": "https://developers.google.com/terms/",
- "gcm_server": "https://developers.google.com/cloud-messaging/server",
- "autoupdate": "hosting",
- "packaging": "hosting",
- "crx": "hosting"
-}
diff --git a/chromium/chrome/common/extensions/docs/templates/public/redirects.json b/chromium/chrome/common/extensions/docs/templates/public/redirects.json
deleted file mode 100644
index 6c724a291fe..00000000000
--- a/chromium/chrome/common/extensions/docs/templates/public/redirects.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "": "/home",
- "apps": "/apps/about_apps"
-}
diff --git a/chromium/chrome/common/extensions/extension_constants.cc b/chromium/chrome/common/extensions/extension_constants.cc
new file mode 100644
index 00000000000..53d88ca26df
--- /dev/null
+++ b/chromium/chrome/common/extensions/extension_constants.cc
@@ -0,0 +1,132 @@
+// 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 "base/macros.h"
+#include "build/build_config.h"
+#include "chrome/common/extensions/extension_constants.h"
+
+namespace extension_urls {
+
+const char kWebstoreSourceField[] = "utm_source";
+
+const char kLaunchSourceAppList[] = "chrome-app-launcher";
+const char kLaunchSourceAppListSearch[] = "chrome-app-launcher-search";
+const char kLaunchSourceAppListInfoDialog[] = "chrome-app-launcher-info-dialog";
+
+} // namespace extension_urls
+
+namespace extension_misc {
+
+const char kCalculatorAppId[] = "joodangkbfjnajiiifokapkpmhfnpleo";
+const char kCalendarAppId[] = "ejjicmeblgpmajnghnpcppodonldlgfn";
+const char kChromeRemoteDesktopAppId[] = "gbchcmhmhahfdphkhkmpfmihenigjmpp";
+const char kCloudPrintAppId[] = "mfehgcgbbipciphmccgaenjidiccnmng";
+const char kDataSaverExtensionId[] = "pfmgfdlgomnbgkofeojodiodmgpgmkac";
+const char kDocsOfflineExtensionId[] = "ghbmnnjooekpmoecnnnilnnbdlolhkhi";
+const char kDriveHostedAppId[] = "apdfllckaahabafndbhieahigkjlhalf";
+const char kEnterpriseWebStoreAppId[] = "afchcafgojfnemjkcbhfekplkmjaldaa";
+const char kGmailAppId[] = "pjkljhegncpnkpknbcohdijeoejaedia";
+const char kGoogleDocAppId[] = "aohghmighlieiainnegkcijnfilokake";
+const char kGoogleMapsAppId[] = "lneaknkopdijkpnocmklfnjbeapigfbh";
+const char kGooglePhotosAppId[] = "hcglmfcclpfgljeaiahehebeoaiicbko";
+const char kGooglePlayBooksAppId[] = "mmimngoggfoobjdlefbcabngfnmieonb";
+const char kGooglePlayMoviesAppId[] = "gdijeikdkaembjbdobgfkoidjkpbmlkd";
+const char kGooglePlayMusicAppId[] = "icppfcnhkcmnfdhfhphakoifcfokfdhg";
+const char kGooglePlusAppId[] = "dlppkpafhbajpcmmoheippocdidnckmm";
+const char kGoogleSheetsAppId[] = "felcaaldnbdncclmgdcncolpebgiejap";
+const char kGoogleSlidesAppId[] = "aapocclcgogkmnckokdopfmhonfmgoek";
+const char kHTermAppId[] = "pnhechapfaindjhompbnflcldabbghjo";
+const char kHTermDevAppId[] = "okddffdblfhhnmhodogpojmfkjmhinfp";
+const char kIdentityApiUiAppId[] = "ahjaciijnoiaklcomgnblndopackapon";
+const char kCroshBuiltinAppId[] = "nkoccljplnhpfnfiajclkommnmllphnl";
+const char kTextEditorAppId[] = "mmfbcljfglbokpmkimbfghdkjmjhdgbg";
+const char kInAppPaymentsSupportAppId[] = "nmmhkkegccagdldgiimedpiccmgmieda";
+const char kMediaRouterStableExtensionId[] = "pkedcjkdefgpdelpbcmbmeomcjbeemfm";
+const char kCloudReportingExtensionId[] = "oempjldejiginopiohodkdoklcjklbaa";
+
+const char* const kBuiltInFirstPartyExtensionIds[] = {
+ kCalculatorAppId,
+ kCalendarAppId,
+ kChromeRemoteDesktopAppId,
+ kCloudPrintAppId,
+ kDataSaverExtensionId,
+ kDocsOfflineExtensionId,
+ kDriveHostedAppId,
+ kEnterpriseWebStoreAppId,
+ kGmailAppId,
+ kGoogleDocAppId,
+ kGoogleMapsAppId,
+ kGooglePhotosAppId,
+ kGooglePlayBooksAppId,
+ kGooglePlayMoviesAppId,
+ kGooglePlayMusicAppId,
+ kGooglePlusAppId,
+ kGoogleSheetsAppId,
+ kGoogleSlidesAppId,
+ kHTermAppId,
+ kHTermDevAppId,
+ kIdentityApiUiAppId,
+ kCroshBuiltinAppId,
+ kTextEditorAppId,
+ kInAppPaymentsSupportAppId,
+ kMediaRouterStableExtensionId,
+ kCloudReportingExtensionId,
+#if defined(OS_CHROMEOS)
+ kAssessmentAssistantExtensionId,
+ kAutoclickExtensionId,
+ kSelectToSpeakExtensionId,
+ kSwitchAccessExtensionId,
+ kFirstRunDialogId,
+ kEspeakSpeechSynthesisExtensionId,
+ kGoogleSpeechSynthesisExtensionId,
+ kWallpaperManagerId,
+ kZipArchiverExtensionId,
+ kChromeCameraAppId,
+ kChromeCameraAppDevId,
+#endif // defined(OS_CHROMEOS)
+ nullptr, // Null-terminated array.
+};
+
+#if defined(OS_CHROMEOS)
+const char kAssessmentAssistantExtensionId[] =
+ "gndmhdcefbhlchkhipcnnbkcmicncehk";
+const char kAutoclickExtensionId[] = "egfdjlfmgnehecnclamagfafdccgfndp";
+const char kAutoclickExtensionPath[] = "chromeos/autoclick";
+const char kChromeVoxExtensionPath[] = "chromeos/chromevox";
+const char kSelectToSpeakExtensionId[] = "klbcgckkldhdhonijdbnhhaiedfkllef";
+const char kSelectToSpeakExtensionPath[] = "chromeos/select_to_speak";
+const char kSwitchAccessExtensionId[] = "pmehocpgjmkenlokgjfkaichfjdhpeol";
+const char kSwitchAccessExtensionPath[] = "chromeos/switch_access";
+const char kGuestManifestFilename[] = "manifest_guest.json";
+const char kConnectivityDiagnosticsPath[] =
+ "/usr/share/chromeos-assets/connectivity_diagnostics";
+const char kConnectivityDiagnosticsLauncherPath[] =
+ "/usr/share/chromeos-assets/connectivity_diagnostics_launcher";
+const char kFirstRunDialogId[] = "jdgcneonijmofocbhmijhacgchbihela";
+const char kEspeakSpeechSynthesisExtensionPath[] =
+ "/usr/share/chromeos-assets/speech_synthesis/espeak-ng";
+const char kEspeakSpeechSynthesisExtensionId[] =
+ "dakbfdmgjiabojdgbiljlhgjbokobjpg";
+const char kGoogleSpeechSynthesisExtensionPath[] =
+ "/usr/share/chromeos-assets/speech_synthesis/patts";
+const char kGoogleSpeechSynthesisExtensionId[] =
+ "gjjabgpgjpampikjhjpfhneeoapjbjaf";
+const char kWallpaperManagerId[] = "obklkkbkpaoaejdabbfldmcfplpdgolj";
+const char kZipArchiverExtensionId[] = "dmboannefpncccogfdikhmhpmdnddgoe";
+const char kZipArchiverExtensionPath[] = "chromeos/zip_archiver";
+const char kChromeCameraAppId[] = "hfhhnacclhffhdffklopdkcgdhifgngh";
+const char kChromeCameraAppDevId[] = "flgnmkgjffmkephdokeeliiopbjaafpm";
+const char kChromeCameraAppPath[] = "chromeos/camera";
+
+#endif // defined(CHROME_OS)
+
+const char kAppStateNotInstalled[] = "not_installed";
+const char kAppStateInstalled[] = "installed";
+const char kAppStateDisabled[] = "disabled";
+const char kAppStateRunning[] = "running";
+const char kAppStateCannotRun[] = "cannot_run";
+const char kAppStateReadyToRun[] = "ready_to_run";
+
+const char kMediaFileSystemPathPart[] = "_";
+} // namespace extension_misc
diff --git a/chromium/chrome/common/extensions/extension_constants.h b/chromium/chrome/common/extensions/extension_constants.h
new file mode 100644
index 00000000000..75717b341f9
--- /dev/null
+++ b/chromium/chrome/common/extensions/extension_constants.h
@@ -0,0 +1,272 @@
+// 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 CHROME_COMMON_EXTENSIONS_EXTENSION_CONSTANTS_H_
+#define CHROME_COMMON_EXTENSIONS_EXTENSION_CONSTANTS_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "build/build_config.h"
+#include "url/gurl.h"
+
+namespace extension_urls {
+
+// Field to use with webstore URL for tracking launch source.
+extern const char kWebstoreSourceField[];
+
+// Values to use with webstore URL launch source field.
+extern const char kLaunchSourceAppList[];
+extern const char kLaunchSourceAppListSearch[];
+extern const char kLaunchSourceAppListInfoDialog[];
+
+} // namespace extension_urls
+
+namespace extension_misc {
+
+// The extension id of the Calculator application.
+extern const char kCalculatorAppId[];
+
+// The extension id of the Calendar application.
+extern const char kCalendarAppId[];
+
+// The extension id of the Chrome Remote Desktop application.
+extern const char kChromeRemoteDesktopAppId[];
+
+// The extension id of the Cloud Print component application.
+extern const char kCloudPrintAppId[];
+
+// The extension id of the Data Saver extension.
+extern const char kDataSaverExtensionId[];
+
+// The extension id of the Google Docs Offline extension.
+extern const char kDocsOfflineExtensionId[];
+
+// The extension id of the Drive hosted app.
+extern const char kDriveHostedAppId[];
+
+// The extension id of the Enterprise Web Store component application.
+extern const char kEnterpriseWebStoreAppId[];
+
+// The extension id of GMail application.
+extern const char kGmailAppId[];
+
+// The extension id of the Google Doc application.
+extern const char kGoogleDocAppId[];
+
+// The extension id of the Google Maps application.
+extern const char kGoogleMapsAppId[];
+
+// The extension id of the Google Photos application.
+extern const char kGooglePhotosAppId[];
+
+// The extension id of the Google Play Books application.
+extern const char kGooglePlayBooksAppId[];
+
+// The extension id of the Google Play Movies application.
+extern const char kGooglePlayMoviesAppId[];
+
+// The extension id of the Google Play Music application.
+extern const char kGooglePlayMusicAppId[];
+
+// The extension id of the Google+ application.
+extern const char kGooglePlusAppId[];
+
+// The extension id of the Google Sheets application.
+extern const char kGoogleSheetsAppId[];
+
+// The extension id of the Google Slides application.
+extern const char kGoogleSlidesAppId[];
+
+// The extension id of the HTerm app for ChromeOS.
+extern const char kHTermAppId[];
+
+// The extension id of the HTerm dev app for ChromeOS.
+extern const char kHTermDevAppId[];
+
+// The extension id of the Identity API UI application.
+extern const char kIdentityApiUiAppId[];
+
+// The extension id of the Crosh component app for ChromeOS.
+extern const char kCroshBuiltinAppId[];
+
+// The extension id of the Text Editor application.
+extern const char kTextEditorAppId[];
+
+// The extension id of the in-app payments support application.
+extern const char kInAppPaymentsSupportAppId[];
+
+// The extension id of the stable media router extension.
+extern const char kMediaRouterStableExtensionId[];
+
+// The extension id of the Chrome Reporting extension.
+extern const char kCloudReportingExtensionId[];
+
+// A list of all the first party extension IDs, last entry is null.
+extern const char* const kBuiltInFirstPartyExtensionIds[];
+
+// The buckets used for app launches.
+enum AppLaunchBucket {
+ // Launch from NTP apps section while maximized.
+ APP_LAUNCH_NTP_APPS_MAXIMIZED,
+
+ // Launch from NTP apps section while collapsed.
+ APP_LAUNCH_NTP_APPS_COLLAPSED,
+
+ // Launch from NTP apps section while in menu mode.
+ APP_LAUNCH_NTP_APPS_MENU,
+
+ // Launch from NTP most visited section in any mode.
+ APP_LAUNCH_NTP_MOST_VISITED,
+
+ // Launch from NTP recently closed section in any mode.
+ APP_LAUNCH_NTP_RECENTLY_CLOSED,
+
+ // App link clicked from bookmark bar.
+ APP_LAUNCH_BOOKMARK_BAR,
+
+ // Nvigated to an app from within a web page (like by clicking a link).
+ APP_LAUNCH_CONTENT_NAVIGATION,
+
+ // Launch from session restore.
+ APP_LAUNCH_SESSION_RESTORE,
+
+ // Autolaunched at startup, like for pinned tabs.
+ APP_LAUNCH_AUTOLAUNCH,
+
+ // Launched from omnibox app links.
+ APP_LAUNCH_OMNIBOX_APP,
+
+ // App URL typed directly into the omnibox (w/ instant turned off).
+ APP_LAUNCH_OMNIBOX_LOCATION,
+
+ // Navigate to an app URL via instant.
+ APP_LAUNCH_OMNIBOX_INSTANT,
+
+ // Launch via chrome.management.launchApp.
+ APP_LAUNCH_EXTENSION_API,
+
+ // Launch an app via a shortcut. This includes using the --app or --app-id
+ // command line arguments, or via an app shim process on Mac.
+ APP_LAUNCH_CMD_LINE_APP,
+
+ // App launch by passing the URL on the cmd line (not using app switches).
+ APP_LAUNCH_CMD_LINE_URL,
+
+ // User clicked web store launcher on NTP.
+ APP_LAUNCH_NTP_WEBSTORE,
+
+ // App launched after the user re-enabled it on the NTP.
+ APP_LAUNCH_NTP_APP_RE_ENABLE,
+
+ // URL launched using the --app cmd line option, but the URL does not
+ // correspond to an installed app. These launches are left over from a
+ // feature that let you make desktop shortcuts from the file menu.
+ APP_LAUNCH_CMD_LINE_APP_LEGACY,
+
+ // User clicked web store link on the NTP footer.
+ APP_LAUNCH_NTP_WEBSTORE_FOOTER,
+
+ // User clicked [+] icon in apps page.
+ APP_LAUNCH_NTP_WEBSTORE_PLUS_ICON,
+
+ // User clicked icon in app launcher main view.
+ APP_LAUNCH_APP_LIST_MAIN,
+
+ // User clicked app launcher search result.
+ APP_LAUNCH_APP_LIST_SEARCH,
+
+ // User clicked the chrome app icon from the app launcher's main view.
+ APP_LAUNCH_APP_LIST_MAIN_CHROME,
+
+ // User clicked the webstore icon from the app launcher's main view.
+ APP_LAUNCH_APP_LIST_MAIN_WEBSTORE,
+
+ // User clicked the chrome app icon from the app launcher's search view.
+ APP_LAUNCH_APP_LIST_SEARCH_CHROME,
+
+ // User clicked the webstore icon from the app launcher's search view.
+ APP_LAUNCH_APP_LIST_SEARCH_WEBSTORE,
+ APP_LAUNCH_BUCKET_BOUNDARY,
+ APP_LAUNCH_BUCKET_INVALID
+};
+
+#if defined(OS_CHROMEOS)
+// The extension id of the Assessment Assistant extension.
+extern const char kAssessmentAssistantExtensionId[];
+// The extension id of the Automatic Clicks extension.
+extern const char kAutoclickExtensionId[];
+// Path to preinstalled Automatic Clicks extension (relative to
+// |chrome::DIR_RESOURCES|).
+extern const char kAutoclickExtensionPath[];
+// Path to preinstalled ChromeVox screen reader extension (relative to
+// |chrome::DIR_RESOURCES|).
+extern const char kChromeVoxExtensionPath[];
+// The extension id of the Select-to-speak extension.
+extern const char kSelectToSpeakExtensionId[];
+// Path to preinstalled Select-to-speak extension (relative to
+// |chrome::DIR_RESOURCES|).
+extern const char kSelectToSpeakExtensionPath[];
+// The extension id of the Switch access extension.
+extern const char kSwitchAccessExtensionId[];
+// Path to preinstalled Switch access extension (relative to
+// |chrome::DIR_RESOURCES|).
+extern const char kSwitchAccessExtensionPath[];
+// Name of the manifest file in an extension when a special manifest is used
+// for guest mode.
+extern const char kGuestManifestFilename[];
+// Path to preinstalled Connectivity Diagnostics extension.
+extern const char kConnectivityDiagnosticsPath[];
+extern const char kConnectivityDiagnosticsLauncherPath[];
+// The extension id of the first run dialog application.
+extern const char kFirstRunDialogId[];
+// Path to preinstalled Google speech synthesis extension.
+extern const char kGoogleSpeechSynthesisExtensionPath[];
+// The extension id of the Google speech synthesis extension.
+extern const char kGoogleSpeechSynthesisExtensionId[];
+// Path to preinstalled eSpeak-NG speech synthesis extension.
+extern const char kEspeakSpeechSynthesisExtensionPath[];
+// The extension id of the eSpeak-NG speech synthesis extension.
+extern const char kEspeakSpeechSynthesisExtensionId[];
+// The extension id of the wallpaper manager application.
+extern const char kWallpaperManagerId[];
+// The extension id of the zip archiver extension.
+extern const char kZipArchiverExtensionId[];
+// Path to preinstalled zip archiver extension.
+extern const char kZipArchiverExtensionPath[];
+// The app ID of Chrome camera app.
+extern const char kChromeCameraAppId[];
+// The dev app ID of Chrome camera app.
+extern const char kChromeCameraAppDevId[];
+// Path to preinstalled Chrome camera app.
+extern const char kChromeCameraAppPath[];
+#endif
+
+// What causes an extension to be installed? Used in histograms, so don't
+// change existing values.
+enum CrxInstallCause {
+ INSTALL_CAUSE_UNSET = 0,
+ INSTALL_CAUSE_USER_DOWNLOAD,
+ INSTALL_CAUSE_UPDATE,
+ INSTALL_CAUSE_EXTERNAL_FILE,
+ INSTALL_CAUSE_AUTOMATION,
+ NUM_INSTALL_CAUSES
+};
+
+// The states that an app can be in, as reported by chrome.app.installState
+// and chrome.app.runningState.
+extern const char kAppStateNotInstalled[];
+extern const char kAppStateInstalled[];
+extern const char kAppStateDisabled[];
+extern const char kAppStateRunning[];
+extern const char kAppStateCannotRun[];
+extern const char kAppStateReadyToRun[];
+
+// The path part of the file system url used for media file systems.
+extern const char kMediaFileSystemPathPart[];
+} // namespace extension_misc
+
+#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_CONSTANTS_H_
diff --git a/chromium/chrome/common/extensions/extension_metrics.cc b/chromium/chrome/common/extensions/extension_metrics.cc
new file mode 100644
index 00000000000..8e6f776ca9c
--- /dev/null
+++ b/chromium/chrome/common/extensions/extension_metrics.cc
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/extension_metrics.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+
+namespace extensions {
+
+void RecordAppLaunchType(extension_misc::AppLaunchBucket bucket,
+ extensions::Manifest::Type app_type) {
+ DCHECK_LT(bucket, extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
+ if (app_type == extensions::Manifest::TYPE_PLATFORM_APP) {
+ UMA_HISTOGRAM_ENUMERATION("Apps.AppLaunch", bucket,
+ extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Extensions.AppLaunch", bucket,
+ extension_misc::APP_LAUNCH_BUCKET_BOUNDARY);
+ }
+}
+
+void RecordAppListSearchLaunch(const extensions::Extension* extension) {
+ extension_misc::AppLaunchBucket bucket =
+ extension_misc::APP_LAUNCH_APP_LIST_SEARCH;
+ if (extension->id() == extensions::kWebStoreAppId)
+ bucket = extension_misc::APP_LAUNCH_APP_LIST_SEARCH_WEBSTORE;
+ else if (extension->id() == extension_misc::kChromeAppId)
+ bucket = extension_misc::APP_LAUNCH_APP_LIST_SEARCH_CHROME;
+ RecordAppLaunchType(bucket, extension->GetType());
+}
+
+void RecordAppListMainLaunch(const extensions::Extension* extension) {
+ extension_misc::AppLaunchBucket bucket =
+ extension_misc::APP_LAUNCH_APP_LIST_MAIN;
+ if (extension->id() == extensions::kWebStoreAppId)
+ bucket = extension_misc::APP_LAUNCH_APP_LIST_MAIN_WEBSTORE;
+ else if (extension->id() == extension_misc::kChromeAppId)
+ bucket = extension_misc::APP_LAUNCH_APP_LIST_MAIN_CHROME;
+ RecordAppLaunchType(bucket, extension->GetType());
+}
+
+void RecordWebStoreLaunch() {
+ RecordAppLaunchType(extension_misc::APP_LAUNCH_NTP_WEBSTORE,
+ extensions::Manifest::TYPE_HOSTED_APP);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/extension_metrics.h b/chromium/chrome/common/extensions/extension_metrics.h
new file mode 100644
index 00000000000..ec31705df61
--- /dev/null
+++ b/chromium/chrome/common/extensions/extension_metrics.h
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_EXTENSION_METRICS_H_
+#define CHROME_COMMON_EXTENSIONS_EXTENSION_METRICS_H_
+
+#include "chrome/common/extensions/extension_constants.h"
+#include "extensions/common/manifest.h"
+
+namespace extensions {
+
+class Extension;
+
+// Records the given type of app launch for UMA.
+void RecordAppLaunchType(extension_misc::AppLaunchBucket bucket,
+ extensions::Manifest::Type app_type);
+
+// Records an app launch from the search view of the app list.
+void RecordAppListSearchLaunch(const extensions::Extension* extension);
+
+// Records an app launch from the main view of the app list.
+void RecordAppListMainLaunch(const extensions::Extension* extension);
+
+// Records a web store launch in the appropriate histograms.
+void RecordWebStoreLaunch();
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_METRICS_H_
diff --git a/chromium/chrome/common/extensions/extension_test_util.cc b/chromium/chrome/common/extensions/extension_test_util.cc
new file mode 100644
index 00000000000..ee6ef94256b
--- /dev/null
+++ b/chromium/chrome/common/extensions/extension_test_util.cc
@@ -0,0 +1,115 @@
+// 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 "chrome/common/extensions/extension_test_util.h"
+
+#include <memory>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "components/version_info/channel.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extensions_client.h"
+#include "extensions/common/features/feature_channel.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using extensions::Extension;
+using extensions::Manifest;
+
+namespace extension_test_util {
+
+scoped_refptr<Extension> LoadManifestUnchecked(const std::string& dir,
+ const std::string& test_file,
+ Manifest::Location location,
+ int extra_flags,
+ const std::string& id,
+ std::string* error) {
+ base::FilePath path;
+ base::PathService::Get(chrome::DIR_TEST_DATA, &path);
+ path = path.AppendASCII("extensions")
+ .AppendASCII(dir)
+ .AppendASCII(test_file);
+
+ JSONFileValueDeserializer deserializer(path);
+ std::unique_ptr<base::Value> result = deserializer.Deserialize(NULL, error);
+ if (!result)
+ return NULL;
+ const base::DictionaryValue* dict;
+ CHECK(result->GetAsDictionary(&dict));
+
+ scoped_refptr<Extension> extension = Extension::Create(
+ path.DirName(), location, *dict, extra_flags, id, error);
+ return extension;
+}
+
+scoped_refptr<Extension> LoadManifestUnchecked(const std::string& dir,
+ const std::string& test_file,
+ Manifest::Location location,
+ int extra_flags,
+ std::string* error) {
+ return LoadManifestUnchecked(
+ dir, test_file, location, extra_flags, std::string(), error);
+}
+
+scoped_refptr<Extension> LoadManifest(const std::string& dir,
+ const std::string& test_file,
+ Manifest::Location location,
+ int extra_flags) {
+ std::string error;
+ scoped_refptr<Extension> extension =
+ LoadManifestUnchecked(dir, test_file, location, extra_flags, &error);
+
+ EXPECT_TRUE(extension.get()) << test_file << ":" << error;
+ return extension;
+}
+
+scoped_refptr<Extension> LoadManifest(const std::string& dir,
+ const std::string& test_file,
+ int extra_flags) {
+ return LoadManifest(dir, test_file, Manifest::INVALID_LOCATION, extra_flags);
+}
+
+scoped_refptr<Extension> LoadManifestStrict(const std::string& dir,
+ const std::string& test_file) {
+ return LoadManifest(dir, test_file, Extension::NO_FLAGS);
+}
+
+scoped_refptr<Extension> LoadManifest(const std::string& dir,
+ const std::string& test_file) {
+ return LoadManifest(dir, test_file, Extension::NO_FLAGS);
+}
+
+void SetGalleryUpdateURL(const GURL& new_url) {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ command_line->AppendSwitchASCII(switches::kAppsGalleryUpdateURL,
+ new_url.spec());
+ extensions::ExtensionsClient::Get()->InitializeWebStoreUrls(command_line);
+}
+
+std::unique_ptr<extensions::ScopedCurrentChannel>
+GetOverrideChannelForActionType(extensions::ActionInfo::Type action_type) {
+ std::unique_ptr<extensions::ScopedCurrentChannel> channel;
+ // The "action" key is currently restricted to trunk. Use a fake channel iff
+ // we're testing that key, so that we still get multi-channel coverage for
+ // browser and page actions.
+ switch (action_type) {
+ case extensions::ActionInfo::TYPE_ACTION:
+ channel = std::make_unique<extensions::ScopedCurrentChannel>(
+ version_info::Channel::UNKNOWN);
+ break;
+ case extensions::ActionInfo::TYPE_PAGE:
+ case extensions::ActionInfo::TYPE_BROWSER:
+ break;
+ }
+ return channel;
+}
+
+} // namespace extension_test_util
diff --git a/chromium/chrome/common/extensions/extension_test_util.h b/chromium/chrome/common/extensions/extension_test_util.h
new file mode 100644
index 00000000000..0c20ba4223c
--- /dev/null
+++ b/chromium/chrome/common/extensions/extension_test_util.h
@@ -0,0 +1,70 @@
+// 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 CHROME_COMMON_EXTENSIONS_EXTENSION_TEST_UTIL_H_
+#define CHROME_COMMON_EXTENSIONS_EXTENSION_TEST_UTIL_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/ref_counted.h"
+#include "chrome/common/extensions/api/extension_action/action_info.h"
+#include "extensions/common/manifest.h"
+
+class GURL;
+
+namespace extensions {
+class Extension;
+class ScopedCurrentChannel;
+}
+
+namespace extension_test_util {
+
+// Helpers for loading manifests, |dir| is relative to chrome::DIR_TEST_DATA
+// followed by "extensions".
+scoped_refptr<extensions::Extension> LoadManifestUnchecked(
+ const std::string& dir,
+ const std::string& test_file,
+ extensions::Manifest::Location location,
+ int extra_flags,
+ const std::string& id,
+ std::string* error);
+
+scoped_refptr<extensions::Extension> LoadManifestUnchecked(
+ const std::string& dir,
+ const std::string& test_file,
+ extensions::Manifest::Location location,
+ int extra_flags,
+ std::string* error);
+
+scoped_refptr<extensions::Extension> LoadManifest(
+ const std::string& dir,
+ const std::string& test_file,
+ extensions::Manifest::Location location,
+ int extra_flags);
+
+scoped_refptr<extensions::Extension> LoadManifest(const std::string& dir,
+ const std::string& test_file,
+ int extra_flags);
+
+scoped_refptr<extensions::Extension> LoadManifestStrict(
+ const std::string& dir,
+ const std::string& test_file);
+
+scoped_refptr<extensions::Extension> LoadManifest(const std::string& dir,
+ const std::string& test_file);
+
+void SetGalleryUpdateURL(const GURL& new_url);
+
+// Returns a ScopedCurrentChannel object to use in tests if one is necessary for
+// the given |action_type| specified in the manifest. This will only return
+// non-null if the "action" manifest key is used.
+// TODO(https://crbug.com/893373): Remove this one the "action" key is launched
+// to stable.
+std::unique_ptr<extensions::ScopedCurrentChannel>
+GetOverrideChannelForActionType(extensions::ActionInfo::Type action_type);
+
+} // namespace extension_test_util
+
+#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_TEST_UTIL_H_
diff --git a/chromium/chrome/common/extensions/extension_unittest.cc b/chromium/chrome/common/extensions/extension_unittest.cc
new file mode 100644
index 00000000000..09fe2826445
--- /dev/null
+++ b/chromium/chrome/common/extensions/extension_unittest.cc
@@ -0,0 +1,447 @@
+// 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 <stddef.h>
+
+#include "base/files/file_util.h"
+#include "base/format_macros.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/command.h"
+#include "chrome/common/extensions/extension_test_util.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/crx_file/id_util.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/extension_resource.h"
+#include "extensions/common/file_util.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_handlers/content_scripts_handler.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/common/value_builder.h"
+#include "extensions/test/test_extension_dir.h"
+#include "net/base/mime_sniffer.h"
+#include "net/dns/mock_host_resolver.h"
+#include "skia/ext/image_operations.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/codec/png_codec.h"
+#include "url/gurl.h"
+
+using extension_test_util::LoadManifest;
+using extension_test_util::LoadManifestStrict;
+using base::FilePath;
+
+namespace extensions {
+
+// We persist location values in the preferences, so this is a sanity test that
+// someone doesn't accidentally change them.
+TEST(ExtensionTest, LocationValuesTest) {
+ ASSERT_EQ(0, Manifest::INVALID_LOCATION);
+ ASSERT_EQ(1, Manifest::INTERNAL);
+ ASSERT_EQ(2, Manifest::EXTERNAL_PREF);
+ ASSERT_EQ(3, Manifest::EXTERNAL_REGISTRY);
+ ASSERT_EQ(4, Manifest::UNPACKED);
+ ASSERT_EQ(5, Manifest::COMPONENT);
+ ASSERT_EQ(6, Manifest::EXTERNAL_PREF_DOWNLOAD);
+ ASSERT_EQ(7, Manifest::EXTERNAL_POLICY_DOWNLOAD);
+ ASSERT_EQ(8, Manifest::COMMAND_LINE);
+ ASSERT_EQ(9, Manifest::EXTERNAL_POLICY);
+}
+
+TEST(ExtensionTest, LocationPriorityTest) {
+ for (int i = 0; i < Manifest::NUM_LOCATIONS; i++) {
+ Manifest::Location loc = static_cast<Manifest::Location>(i);
+
+ // INVALID is not a valid location.
+ if (loc == Manifest::INVALID_LOCATION)
+ continue;
+
+ // Comparing a location that has no rank will hit a CHECK. Do a
+ // compare with every valid location, to be sure each one is covered.
+
+ // Check that no install source can override a componenet extension.
+ ASSERT_EQ(Manifest::COMPONENT,
+ Manifest::GetHigherPriorityLocation(Manifest::COMPONENT, loc));
+ ASSERT_EQ(Manifest::COMPONENT,
+ Manifest::GetHigherPriorityLocation(loc, Manifest::COMPONENT));
+
+ // Check that any source can override a user install. This might change
+ // in the future, in which case this test should be updated.
+ ASSERT_EQ(loc,
+ Manifest::GetHigherPriorityLocation(Manifest::INTERNAL, loc));
+ ASSERT_EQ(loc,
+ Manifest::GetHigherPriorityLocation(loc, Manifest::INTERNAL));
+ }
+
+ // Check a few interesting cases that we know can happen:
+ ASSERT_EQ(Manifest::EXTERNAL_POLICY_DOWNLOAD,
+ Manifest::GetHigherPriorityLocation(
+ Manifest::EXTERNAL_POLICY_DOWNLOAD,
+ Manifest::EXTERNAL_PREF));
+
+ ASSERT_EQ(Manifest::EXTERNAL_PREF,
+ Manifest::GetHigherPriorityLocation(
+ Manifest::INTERNAL,
+ Manifest::EXTERNAL_PREF));
+}
+
+TEST(ExtensionTest, EnsureNewLinesInExtensionNameAreCollapsed) {
+ DictionaryBuilder manifest;
+ std::string unsanitized_name = "Test\n\n\n\n\n\n\n\n\n\n\n\nNew lines\u0085";
+ manifest.Set("name", unsanitized_name)
+ .Set("manifest_version", 2)
+ .Set("description", "some description");
+ scoped_refptr<const Extension> extension =
+ ExtensionBuilder()
+ .SetManifest(manifest.Build())
+ .MergeManifest(DictionaryBuilder().Set("version", "0.1").Build())
+ .Build();
+ ASSERT_TRUE(extension.get());
+ EXPECT_EQ("TestNew lines", extension->name());
+ // Ensure that non-localized name is not sanitized.
+ EXPECT_EQ(unsanitized_name, extension->non_localized_name());
+}
+
+TEST(ExtensionTest, EnsureWhitespacesInExtensionNameAreCollapsed) {
+ DictionaryBuilder manifest;
+ std::string unsanitized_name = "Test Whitespace";
+ manifest.Set("name", unsanitized_name)
+ .Set("manifest_version", 2)
+ .Set("description", "some description");
+ scoped_refptr<const Extension> extension =
+ ExtensionBuilder()
+ .SetManifest(manifest.Build())
+ .MergeManifest(DictionaryBuilder().Set("version", "0.1").Build())
+ .Build();
+ ASSERT_TRUE(extension.get());
+ EXPECT_EQ("Test Whitespace", extension->name());
+ // Ensure that non-localized name is not sanitized.
+ EXPECT_EQ(unsanitized_name, extension->non_localized_name());
+}
+
+// TODO(crbug.com/794252): Disallow empty extension names from being locally
+// loaded.
+TEST(ExtensionTest, EmptyName) {
+ DictionaryBuilder manifest1;
+ manifest1.Set("name", "")
+ .Set("manifest_version", 2)
+ .Set("description", "some description");
+ scoped_refptr<const Extension> extension =
+ ExtensionBuilder()
+ .SetManifest(manifest1.Build())
+ .MergeManifest(DictionaryBuilder().Set("version", "0.1").Build())
+ .Build();
+ ASSERT_TRUE(extension.get());
+ EXPECT_EQ("", extension->name());
+
+ DictionaryBuilder manifest2;
+ manifest2.Set("name", " ")
+ .Set("manifest_version", 2)
+ .Set("description", "some description");
+ extension =
+ ExtensionBuilder()
+ .SetManifest(manifest2.Build())
+ .MergeManifest(DictionaryBuilder().Set("version", "0.1").Build())
+ .Build();
+ ASSERT_TRUE(extension.get());
+ EXPECT_EQ("", extension->name());
+}
+
+TEST(ExtensionTest, RTLNameInLTRLocale) {
+ // Test the case when a directional override is the first character.
+ auto run_rtl_test = [](const wchar_t* name, const wchar_t* expected) {
+ SCOPED_TRACE(
+ base::StringPrintf("Name: %ls, Expected: %ls", name, expected));
+ DictionaryBuilder manifest;
+ manifest.Set("name", base::WideToUTF8(name))
+ .Set("manifest_version", 2)
+ .Set("description", "some description")
+ .Set("version",
+ "0.1"); // <NOTE> Moved this here to avoid the MergeManifest call.
+ scoped_refptr<const Extension> extension =
+ ExtensionBuilder().SetManifest(manifest.Build()).Build();
+ ASSERT_TRUE(extension);
+ const int kResourceId = IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE;
+ const base::string16 expected_utf16 = base::WideToUTF16(expected);
+ EXPECT_EQ(l10n_util::GetStringFUTF16(kResourceId, expected_utf16),
+ l10n_util::GetStringFUTF16(kResourceId,
+ base::UTF8ToUTF16(extension->name())));
+ EXPECT_EQ(base::WideToUTF8(expected), extension->name());
+ };
+
+ run_rtl_test(L"\x202emoc.elgoog", L"\x202emoc.elgoog\x202c");
+ run_rtl_test(L"\x202egoogle\x202e.com/\x202eguest",
+ L"\x202egoogle\x202e.com/\x202eguest\x202c\x202c\x202c");
+ run_rtl_test(L"google\x202e.com", L"google\x202e.com\x202c");
+
+ run_rtl_test(L"كبير Google التطبيق",
+#if !defined(OS_WIN)
+ L"\x200e\x202bكبير Google التطبيق\x202c\x200e");
+#else
+ // On Windows for an LTR locale, no changes to the string are
+ // made.
+ L"كبير Google التطبيق");
+#endif // !OS_WIN
+}
+
+TEST(ExtensionTest, GetResourceURLAndPath) {
+ scoped_refptr<Extension> extension = LoadManifestStrict("empty_manifest",
+ "empty.json");
+ EXPECT_TRUE(extension.get());
+
+ EXPECT_EQ(extension->url().spec() + "bar/baz.js",
+ Extension::GetResourceURL(extension->url(), "bar/baz.js").spec());
+ EXPECT_EQ(extension->url().spec() + "baz.js",
+ Extension::GetResourceURL(extension->url(),
+ "bar/../baz.js").spec());
+ EXPECT_EQ(extension->url().spec() + "baz.js",
+ Extension::GetResourceURL(extension->url(), "../baz.js").spec());
+
+ // Test that absolute-looking paths ("/"-prefixed) are pasted correctly.
+ EXPECT_EQ(extension->url().spec() + "test.html",
+ extension->GetResourceURL("/test.html").spec());
+}
+
+TEST(ExtensionTest, GetResource) {
+ const FilePath valid_path_test_cases[] = {
+ FilePath(FILE_PATH_LITERAL("manifest.json")),
+ FilePath(FILE_PATH_LITERAL("a/b/c/manifest.json")),
+ FilePath(FILE_PATH_LITERAL("com/manifest.json")),
+ FilePath(FILE_PATH_LITERAL("lpt/manifest.json")),
+ };
+ const FilePath invalid_path_test_cases[] = {
+ // Directory name
+ FilePath(FILE_PATH_LITERAL("src/")),
+ // Contains a drive letter specification.
+ FilePath(FILE_PATH_LITERAL("C:\\manifest.json")),
+ // Use backslash '\\' as separator.
+ FilePath(FILE_PATH_LITERAL("a\\b\\c\\manifest.json")),
+ // Reserved Characters with extension
+ FilePath(FILE_PATH_LITERAL("mani>fest.json")),
+ FilePath(FILE_PATH_LITERAL("mani<fest.json")),
+ FilePath(FILE_PATH_LITERAL("mani*fest.json")),
+ FilePath(FILE_PATH_LITERAL("mani:fest.json")),
+ FilePath(FILE_PATH_LITERAL("mani?fest.json")),
+ FilePath(FILE_PATH_LITERAL("mani|fest.json")),
+ // Reserved Characters without extension
+ FilePath(FILE_PATH_LITERAL("mani>fest")),
+ FilePath(FILE_PATH_LITERAL("mani<fest")),
+ FilePath(FILE_PATH_LITERAL("mani*fest")),
+ FilePath(FILE_PATH_LITERAL("mani:fest")),
+ FilePath(FILE_PATH_LITERAL("mani?fest")),
+ FilePath(FILE_PATH_LITERAL("mani|fest")),
+ // Reserved Names with extension.
+ FilePath(FILE_PATH_LITERAL("com1.json")),
+ FilePath(FILE_PATH_LITERAL("com9.json")),
+ FilePath(FILE_PATH_LITERAL("LPT1.json")),
+ FilePath(FILE_PATH_LITERAL("LPT9.json")),
+ FilePath(FILE_PATH_LITERAL("CON.json")),
+ FilePath(FILE_PATH_LITERAL("PRN.json")),
+ FilePath(FILE_PATH_LITERAL("AUX.json")),
+ FilePath(FILE_PATH_LITERAL("NUL.json")),
+ // Reserved Names without extension.
+ FilePath(FILE_PATH_LITERAL("com1")),
+ FilePath(FILE_PATH_LITERAL("com9")),
+ FilePath(FILE_PATH_LITERAL("LPT1")),
+ FilePath(FILE_PATH_LITERAL("LPT9")),
+ FilePath(FILE_PATH_LITERAL("CON")),
+ FilePath(FILE_PATH_LITERAL("PRN")),
+ FilePath(FILE_PATH_LITERAL("AUX")),
+ FilePath(FILE_PATH_LITERAL("NUL")),
+ // Reserved Names as directory.
+ FilePath(FILE_PATH_LITERAL("com1/manifest.json")),
+ FilePath(FILE_PATH_LITERAL("com9/manifest.json")),
+ FilePath(FILE_PATH_LITERAL("LPT1/manifest.json")),
+ FilePath(FILE_PATH_LITERAL("LPT9/manifest.json")),
+ FilePath(FILE_PATH_LITERAL("CON/manifest.json")),
+ FilePath(FILE_PATH_LITERAL("PRN/manifest.json")),
+ FilePath(FILE_PATH_LITERAL("AUX/manifest.json")),
+ FilePath(FILE_PATH_LITERAL("NUL/manifest.json")),
+ };
+
+ scoped_refptr<Extension> extension = LoadManifestStrict("empty_manifest",
+ "empty.json");
+ EXPECT_TRUE(extension.get());
+ for (size_t i = 0; i < base::size(valid_path_test_cases); ++i)
+ EXPECT_TRUE(!extension->GetResource(valid_path_test_cases[i]).empty());
+ for (size_t i = 0; i < base::size(invalid_path_test_cases); ++i)
+ EXPECT_TRUE(extension->GetResource(invalid_path_test_cases[i]).empty());
+}
+
+TEST(ExtensionTest, GetAbsolutePathNoError) {
+ scoped_refptr<Extension> extension = LoadManifestStrict("absolute_path",
+ "absolute.json");
+ EXPECT_TRUE(extension.get());
+ std::string err;
+ std::vector<InstallWarning> warnings;
+ EXPECT_TRUE(file_util::ValidateExtension(extension.get(), &err, &warnings));
+ EXPECT_EQ(0U, warnings.size());
+
+ EXPECT_EQ(extension->path().AppendASCII("test.html").value(),
+ extension->GetResource("test.html").GetFilePath().value());
+ EXPECT_EQ(extension->path().AppendASCII("test.js").value(),
+ extension->GetResource("test.js").GetFilePath().value());
+}
+
+
+TEST(ExtensionTest, IdIsValid) {
+ EXPECT_TRUE(crx_file::id_util::IdIsValid("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
+ EXPECT_TRUE(crx_file::id_util::IdIsValid("pppppppppppppppppppppppppppppppp"));
+ EXPECT_TRUE(crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmnop"));
+ EXPECT_TRUE(crx_file::id_util::IdIsValid("ABCDEFGHIJKLMNOPABCDEFGHIJKLMNOP"));
+ EXPECT_FALSE(crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmno"));
+ EXPECT_FALSE(
+ crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmnopa"));
+ EXPECT_FALSE(
+ crx_file::id_util::IdIsValid("0123456789abcdef0123456789abcdef"));
+ EXPECT_FALSE(
+ crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmnoq"));
+ EXPECT_FALSE(
+ crx_file::id_util::IdIsValid("abcdefghijklmnopabcdefghijklmno0"));
+}
+
+// This test ensures that the mimetype sniffing code stays in sync with the
+// actual crx files that we test other parts of the system with.
+TEST(ExtensionTest, MimeTypeSniffing) {
+ auto get_mime_type_from_crx = [](const base::FilePath& file_path) {
+ SCOPED_TRACE(file_path.AsUTF8Unsafe());
+
+ std::string data;
+ EXPECT_TRUE(base::ReadFileToString(file_path, &data));
+
+ std::string result;
+ EXPECT_TRUE(net::SniffMimeType(
+ data.c_str(), data.size(), GURL("http://www.example.com/foo.crx"),
+ std::string(), net::ForceSniffFileUrlsForHtml::kDisabled, &result));
+
+ return result;
+ };
+
+ base::FilePath dir_path;
+ ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &dir_path));
+ dir_path = dir_path.AppendASCII("extensions");
+
+ // First, test an extension packed a long time ago (but in this galaxy).
+ // Specifically, this package is using the crx2 format, whereas modern chrome
+ // uses crx3.
+ EXPECT_EQ(
+ Extension::kMimeType,
+ get_mime_type_from_crx(dir_path.AppendASCII("legacy_crx_package.crx")));
+
+ // Then, an extension whose crx has a bad magic number (it should be Cr24).
+ EXPECT_EQ("application/octet-stream",
+ get_mime_type_from_crx(dir_path.AppendASCII("bad_magic.crx")));
+
+ // Finally, an extension that we pack right. This. Instant.
+ // This verifies that the modern extensions Chrome packs are always
+ // recognized as the extension mime type.
+ // Regression test for https://crbug.com/831284.
+ TestExtensionDir test_dir;
+ test_dir.WriteManifest(R"(
+ {
+ "name": "New extension",
+ "version": "0.2",
+ "manifest_version": 2
+ })");
+ EXPECT_EQ(Extension::kMimeType, get_mime_type_from_crx(test_dir.Pack()));
+}
+
+TEST(ExtensionTest, WantsFileAccess) {
+ scoped_refptr<Extension> extension;
+ GURL file_url("file:///etc/passwd");
+
+ // Ignore the policy delegate for this test.
+ PermissionsData::SetPolicyDelegate(NULL);
+
+ // <all_urls> permission
+ extension = LoadManifest("permissions", "permissions_all_urls.json");
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_FALSE(
+ extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
+ extension = LoadManifest(
+ "permissions", "permissions_all_urls.json", Extension::ALLOW_FILE_ACCESS);
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_TRUE(
+ extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
+
+ // file:///* permission
+ extension = LoadManifest("permissions", "permissions_file_scheme.json");
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_FALSE(
+ extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
+ extension = LoadManifest("permissions",
+ "permissions_file_scheme.json",
+ Extension::ALLOW_FILE_ACCESS);
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_TRUE(
+ extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
+
+ // http://* permission
+ extension = LoadManifest("permissions", "permissions_http_scheme.json");
+ EXPECT_FALSE(extension->wants_file_access());
+ EXPECT_FALSE(
+ extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
+ extension = LoadManifest("permissions",
+ "permissions_http_scheme.json",
+ Extension::ALLOW_FILE_ACCESS);
+ EXPECT_FALSE(extension->wants_file_access());
+ EXPECT_FALSE(
+ extension->permissions_data()->CanAccessPage(file_url, -1, nullptr));
+
+ // <all_urls> content script match
+ extension = LoadManifest("permissions", "content_script_all_urls.json");
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage(
+ file_url, -1, nullptr));
+ extension = LoadManifest("permissions", "content_script_all_urls.json",
+ Extension::ALLOW_FILE_ACCESS);
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_TRUE(extension->permissions_data()->CanRunContentScriptOnPage(
+ file_url, -1, nullptr));
+
+ // file:///* content script match
+ extension = LoadManifest("permissions", "content_script_file_scheme.json");
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage(
+ file_url, -1, nullptr));
+ extension = LoadManifest("permissions", "content_script_file_scheme.json",
+ Extension::ALLOW_FILE_ACCESS);
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_TRUE(extension->permissions_data()->CanRunContentScriptOnPage(
+ file_url, -1, nullptr));
+
+ // http://* content script match
+ extension = LoadManifest("permissions", "content_script_http_scheme.json");
+ EXPECT_FALSE(extension->wants_file_access());
+ EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage(
+ file_url, -1, nullptr));
+ extension = LoadManifest("permissions", "content_script_http_scheme.json",
+ Extension::ALLOW_FILE_ACCESS);
+ EXPECT_FALSE(extension->wants_file_access());
+ EXPECT_FALSE(extension->permissions_data()->CanRunContentScriptOnPage(
+ file_url, -1, nullptr));
+}
+
+TEST(ExtensionTest, ExtraFlags) {
+ scoped_refptr<Extension> extension;
+ extension = LoadManifest("app", "manifest.json", Extension::FROM_WEBSTORE);
+ EXPECT_TRUE(extension->from_webstore());
+
+ extension = LoadManifest("app", "manifest.json", Extension::FROM_BOOKMARK);
+ EXPECT_TRUE(extension->from_bookmark());
+
+ extension = LoadManifest("app", "manifest.json", Extension::NO_FLAGS);
+ EXPECT_FALSE(extension->from_bookmark());
+ EXPECT_FALSE(extension->from_webstore());
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/feature_switch_unittest.cc b/chromium/chrome/common/extensions/feature_switch_unittest.cc
new file mode 100644
index 00000000000..98fc911d2bd
--- /dev/null
+++ b/chromium/chrome/common/extensions/feature_switch_unittest.cc
@@ -0,0 +1,132 @@
+// 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 "extensions/common/feature_switch.h"
+
+#include "base/command_line.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using extensions::FeatureSwitch;
+
+namespace {
+
+const char kSwitchName[] = "test-switch";
+
+template<FeatureSwitch::DefaultValue T>
+class FeatureSwitchTest : public testing::Test {
+ public:
+ FeatureSwitchTest()
+ : command_line_(base::CommandLine::NO_PROGRAM),
+ feature_(&command_line_, kSwitchName, T) {}
+ protected:
+ base::CommandLine command_line_;
+ FeatureSwitch feature_;
+};
+
+typedef FeatureSwitchTest<FeatureSwitch::DEFAULT_DISABLED>
+ FeatureSwitchDisabledTest;
+typedef FeatureSwitchTest<FeatureSwitch::DEFAULT_ENABLED>
+ FeatureSwitchEnabledTest;
+
+} // namespace
+
+TEST_F(FeatureSwitchDisabledTest, NoSwitchValue) {
+ EXPECT_FALSE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchDisabledTest, FalseSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "0");
+ EXPECT_FALSE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchDisabledTest, GibberishSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "monkey");
+ EXPECT_FALSE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchDisabledTest, Override) {
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, false);
+ EXPECT_FALSE(feature_.IsEnabled());
+ }
+ EXPECT_FALSE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, true);
+ EXPECT_TRUE(feature_.IsEnabled());
+ }
+ EXPECT_FALSE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchDisabledTest, TrueSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "1");
+ EXPECT_TRUE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, false);
+ EXPECT_FALSE(feature_.IsEnabled());
+ }
+ EXPECT_TRUE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, true);
+ EXPECT_TRUE(feature_.IsEnabled());
+ }
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchDisabledTest, TrimSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, " \t 1\n ");
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, NoSwitchValue) {
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, TrueSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "1");
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, GibberishSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "monkey");
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, Override) {
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, true);
+ EXPECT_TRUE(feature_.IsEnabled());
+ }
+ EXPECT_TRUE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, false);
+ EXPECT_FALSE(feature_.IsEnabled());
+ }
+ EXPECT_TRUE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, FalseSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "0");
+ EXPECT_FALSE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, true);
+ EXPECT_TRUE(feature_.IsEnabled());
+ }
+ EXPECT_FALSE(feature_.IsEnabled());
+
+ {
+ FeatureSwitch::ScopedOverride override(&feature_, false);
+ EXPECT_FALSE(feature_.IsEnabled());
+ }
+ EXPECT_FALSE(feature_.IsEnabled());
+}
+
+TEST_F(FeatureSwitchEnabledTest, TrimSwitchValue) {
+ command_line_.AppendSwitchASCII(kSwitchName, "\t\t 0 \n");
+ EXPECT_FALSE(feature_.IsEnabled());
+}
diff --git a/chromium/chrome/common/extensions/image_writer/OWNERS b/chromium/chrome/common/extensions/image_writer/OWNERS
new file mode 100644
index 00000000000..22549adc7c9
--- /dev/null
+++ b/chromium/chrome/common/extensions/image_writer/OWNERS
@@ -0,0 +1 @@
+haven@chromium.org
diff --git a/chromium/chrome/common/extensions/image_writer/image_writer_util_mac.cc b/chromium/chrome/common/extensions/image_writer/image_writer_util_mac.cc
new file mode 100644
index 00000000000..62432ee27aa
--- /dev/null
+++ b/chromium/chrome/common/extensions/image_writer/image_writer_util_mac.cc
@@ -0,0 +1,112 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/image_writer/image_writer_util_mac.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/storage/IOMedia.h>
+
+#include "base/mac/foundation_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_ioobject.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace extensions {
+
+namespace {
+
+bool IsUsbDevice(io_object_t disk_obj) {
+ io_object_t current_obj = disk_obj;
+ io_object_t parent_obj = 0;
+ // Keep scoped object outside the loop so the object lives to the next
+ // GetParentEntry.
+ base::mac::ScopedIOObject<io_object_t> parent_obj_ref(parent_obj);
+
+ while ((IORegistryEntryGetParentEntry(
+ current_obj, kIOServicePlane, &parent_obj)) == KERN_SUCCESS) {
+ current_obj = parent_obj;
+ parent_obj_ref.reset(parent_obj);
+
+ base::ScopedCFTypeRef<CFStringRef> class_name(
+ IOObjectCopyClass(current_obj));
+ if (!class_name) {
+ LOG(ERROR) << "Could not get object class of IO Registry Entry.";
+ continue;
+ }
+
+ if (CFStringCompare(class_name.get(), CFSTR("IOUSBMassStorageClass"), 0) ==
+ kCFCompareEqualTo) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace
+
+bool IsSuitableRemovableStorageDevice(io_object_t disk_obj,
+ std::string* out_bsd_name,
+ uint64_t* out_size_in_bytes,
+ bool* out_removable) {
+ base::ScopedCFTypeRef<CFMutableDictionaryRef> dict;
+ kern_return_t result = IORegistryEntryCreateCFProperties(
+ disk_obj, dict.InitializeInto(), kCFAllocatorDefault, 0);
+ if (result != KERN_SUCCESS) {
+ MACH_LOG(ERROR, result) << "Unable to get properties of disk object.";
+ return false;
+ }
+
+ // Do not allow Core Storage volumes, even though they are marked as "whole
+ // media", as they are entirely contained on a different volume.
+ CFBooleanRef cf_corestorage = base::mac::GetValueFromDictionary<CFBooleanRef>(
+ dict, CFSTR("CoreStorage"));
+ if (cf_corestorage && CFBooleanGetValue(cf_corestorage))
+ return false;
+
+ // Do not allow APFS containers, even though they are marked as "whole
+ // media", as they are entirely contained on a different volume.
+ CFStringRef cf_content =
+ base::mac::GetValueFromDictionary<CFStringRef>(dict, CFSTR("Content"));
+ if (cf_content &&
+ CFStringCompare(cf_content, CFSTR("EF57347C-0000-11AA-AA11-00306543ECAC"),
+ 0) == kCFCompareEqualTo) {
+ return false;
+ }
+
+ CFBooleanRef cf_removable = base::mac::GetValueFromDictionary<CFBooleanRef>(
+ dict, CFSTR(kIOMediaRemovableKey));
+ bool removable = CFBooleanGetValue(cf_removable);
+ bool is_usb = IsUsbDevice(disk_obj);
+
+ if (!removable && !is_usb)
+ return false;
+
+ if (out_size_in_bytes) {
+ CFNumberRef cf_media_size = base::mac::GetValueFromDictionary<CFNumberRef>(
+ dict, CFSTR(kIOMediaSizeKey));
+ if (cf_media_size)
+ CFNumberGetValue(cf_media_size, kCFNumberLongLongType, out_size_in_bytes);
+ else
+ *out_size_in_bytes = 0;
+ }
+
+ if (out_bsd_name) {
+ CFStringRef cf_bsd_name = base::mac::GetValueFromDictionary<CFStringRef>(
+ dict, CFSTR(kIOBSDNameKey));
+ if (out_bsd_name)
+ *out_bsd_name = base::SysCFStringRefToUTF8(cf_bsd_name);
+ else
+ *out_bsd_name = std::string();
+ }
+
+ if (out_removable)
+ *out_removable = removable;
+
+ return true;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/image_writer/image_writer_util_mac.h b/chromium/chrome/common/extensions/image_writer/image_writer_util_mac.h
new file mode 100644
index 00000000000..ca11e589422
--- /dev/null
+++ b/chromium/chrome/common/extensions/image_writer/image_writer_util_mac.h
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_IMAGE_WRITER_IMAGE_WRITER_UTIL_MAC_H_
+#define CHROME_COMMON_EXTENSIONS_IMAGE_WRITER_IMAGE_WRITER_UTIL_MAC_H_
+
+#include <IOKit/IOKitLib.h>
+
+#include <string>
+
+namespace extensions {
+
+// Determines whether the specified disk is suitable for writing an image onto.
+// If this function returns true, it also returns other info values; pass
+// null if those values are not wanted.
+bool IsSuitableRemovableStorageDevice(io_object_t disk_obj,
+ std::string* out_bsd_name,
+ uint64_t* out_size_in_bytes,
+ bool* out_removable);
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_IMAGE_WRITER_IMAGE_WRITER_UTIL_MAC_H_
diff --git a/chromium/chrome/common/extensions/manifest_handlers/app_icon_color_info.cc b/chromium/chrome/common/extensions/manifest_handlers/app_icon_color_info.cc
new file mode 100644
index 00000000000..12b55c1193f
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/app_icon_color_info.cc
@@ -0,0 +1,86 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/manifest_handlers/app_icon_color_info.h"
+
+#include <memory>
+
+#include "base/no_destructor.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "extensions/common/image_util.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+namespace {
+
+const AppIconColorInfo& GetAppIconColorInfo(const Extension* extension) {
+ static const base::NoDestructor<AppIconColorInfo> fallback;
+
+ AppIconColorInfo* info = static_cast<AppIconColorInfo*>(
+ extension->GetManifestData(keys::kAppIconColor));
+ return info ? *info : *fallback;
+}
+
+} // namespace
+
+AppIconColorInfo::AppIconColorInfo() : icon_color_(SK_ColorTRANSPARENT) {
+}
+
+AppIconColorInfo::~AppIconColorInfo() {
+}
+
+// static
+SkColor AppIconColorInfo::GetIconColor(const Extension* extension) {
+ return GetAppIconColorInfo(extension).icon_color_;
+}
+
+// static
+const std::string& AppIconColorInfo::GetIconColorString(
+ const Extension* extension) {
+ return GetAppIconColorInfo(extension).icon_color_string_;
+}
+
+AppIconColorHandler::AppIconColorHandler() {
+}
+
+AppIconColorHandler::~AppIconColorHandler() {
+}
+
+bool AppIconColorHandler::Parse(Extension* extension, base::string16* error) {
+ std::unique_ptr<AppIconColorInfo> app_icon_color_info(new AppIconColorInfo);
+
+ const base::Value* temp = NULL;
+ if (extension->manifest()->Get(keys::kAppIconColor, &temp)) {
+ if (!temp->GetAsString(&app_icon_color_info->icon_color_string_)) {
+ *error =
+ base::UTF8ToUTF16(extensions::manifest_errors::kInvalidAppIconColor);
+ return false;
+ }
+
+ if (!image_util::ParseHexColorString(
+ app_icon_color_info->icon_color_string_,
+ &app_icon_color_info->icon_color_)) {
+ *error =
+ base::UTF8ToUTF16(extensions::manifest_errors::kInvalidAppIconColor);
+ return false;
+ }
+ }
+
+ extension->SetManifestData(keys::kAppIconColor,
+ std::move(app_icon_color_info));
+ return true;
+}
+
+base::span<const char* const> AppIconColorHandler::Keys() const {
+ static constexpr const char* kKeys[] = {keys::kAppIconColor};
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/app_icon_color_info.h b/chromium/chrome/common/extensions/manifest_handlers/app_icon_color_info.h
new file mode 100644
index 00000000000..41348e98bda
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/app_icon_color_info.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_ICON_COLOR_INFO_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_ICON_COLOR_INFO_H_
+
+#include "base/macros.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handler.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace extensions {
+
+// A structure to hold the parsed app icon color data.
+struct AppIconColorInfo : public Extension::ManifestData {
+ AppIconColorInfo();
+ ~AppIconColorInfo() override;
+
+ static SkColor GetIconColor(const Extension* extension);
+ static const std::string& GetIconColorString(const Extension* extension);
+
+ // The color to use if icons need to be generated for the app.
+ SkColor icon_color_;
+
+ // The string representation of the icon color.
+ std::string icon_color_string_;
+};
+
+// Parses the "app.icon_color" manifest key.
+class AppIconColorHandler : public ManifestHandler {
+ public:
+ AppIconColorHandler();
+ ~AppIconColorHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+
+ private:
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(AppIconColorHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_ICON_COLOR_INFO_H_
diff --git a/chromium/chrome/common/extensions/manifest_handlers/app_launch_info.cc b/chromium/chrome/common/extensions/manifest_handlers/app_launch_info.cc
new file mode 100644
index 00000000000..7e12fb7cf64
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/app_launch_info.cc
@@ -0,0 +1,330 @@
+// 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 "chrome/common/extensions/manifest_handlers/app_launch_info.h"
+
+#include <memory>
+
+#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/url_constants.h"
+#include "components/cloud_devices/common/cloud_devices_urls.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace values = manifest_values;
+namespace errors = manifest_errors;
+
+namespace {
+
+bool ReadLaunchDimension(const extensions::Manifest* manifest,
+ const char* key,
+ int* target,
+ bool is_valid_container,
+ base::string16* error) {
+ const base::Value* temp = NULL;
+ if (manifest->Get(key, &temp)) {
+ if (!is_valid_container) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidLaunchValueContainer,
+ key);
+ return false;
+ }
+ if (!temp->GetAsInteger(target) || *target < 0) {
+ *target = 0;
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidLaunchValue,
+ key);
+ return false;
+ }
+ }
+ return true;
+}
+
+static base::LazyInstance<AppLaunchInfo>::DestructorAtExit
+ g_empty_app_launch_info = LAZY_INSTANCE_INITIALIZER;
+
+const AppLaunchInfo& GetAppLaunchInfo(const Extension* extension) {
+ AppLaunchInfo* info = static_cast<AppLaunchInfo*>(
+ extension->GetManifestData(keys::kLaunch));
+ return info ? *info : g_empty_app_launch_info.Get();
+}
+
+} // namespace
+
+AppLaunchInfo::AppLaunchInfo()
+ : launch_container_(LaunchContainer::kLaunchContainerTab),
+ launch_width_(0),
+ launch_height_(0) {}
+
+AppLaunchInfo::~AppLaunchInfo() {
+}
+
+// static
+const std::string& AppLaunchInfo::GetLaunchLocalPath(
+ const Extension* extension) {
+ return GetAppLaunchInfo(extension).launch_local_path_;
+}
+
+// static
+const GURL& AppLaunchInfo::GetLaunchWebURL(
+ const Extension* extension) {
+ return GetAppLaunchInfo(extension).launch_web_url_;
+}
+
+// static
+extensions::LaunchContainer AppLaunchInfo::GetLaunchContainer(
+ const Extension* extension) {
+ return GetAppLaunchInfo(extension).launch_container_;
+}
+
+// static
+int AppLaunchInfo::GetLaunchWidth(const Extension* extension) {
+ return GetAppLaunchInfo(extension).launch_width_;
+}
+
+// static
+int AppLaunchInfo::GetLaunchHeight(const Extension* extension) {
+ return GetAppLaunchInfo(extension).launch_height_;
+}
+
+// static
+GURL AppLaunchInfo::GetFullLaunchURL(const Extension* extension) {
+ const AppLaunchInfo& info = GetAppLaunchInfo(extension);
+ if (info.launch_local_path_.empty())
+ return info.launch_web_url_;
+ else
+ return extension->url().Resolve(info.launch_local_path_);
+}
+
+bool AppLaunchInfo::Parse(Extension* extension, base::string16* error) {
+ if (!LoadLaunchURL(extension, error) ||
+ !LoadLaunchContainer(extension, error))
+ return false;
+ return true;
+}
+
+bool AppLaunchInfo::LoadLaunchURL(Extension* extension, base::string16* error) {
+ const base::Value* temp = NULL;
+
+ // Launch URL can be either local (to chrome-extension:// root) or an absolute
+ // web URL.
+ if (extension->manifest()->Get(keys::kLaunchLocalPath, &temp)) {
+ if (extension->manifest()->Get(keys::kLaunchWebURL, NULL)) {
+ *error = base::ASCIIToUTF16(errors::kLaunchPathAndURLAreExclusive);
+ return false;
+ }
+
+ if (extension->manifest()->Get(keys::kWebURLs, NULL)) {
+ *error = base::ASCIIToUTF16(errors::kLaunchPathAndExtentAreExclusive);
+ return false;
+ }
+
+ std::string launch_path;
+ if (!temp->GetAsString(&launch_path)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchLocalPath);
+ return false;
+ }
+
+ // Ensure the launch path is a valid relative URL.
+ GURL resolved = extension->url().Resolve(launch_path);
+ if (!resolved.is_valid() || resolved.GetOrigin() != extension->url()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchLocalPath);
+ return false;
+ }
+
+ launch_local_path_ = launch_path;
+ } else if (extension->manifest()->Get(keys::kLaunchWebURL, &temp)) {
+ std::string launch_url;
+ if (!temp->GetAsString(&launch_url)) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWebURL);
+ return false;
+ }
+
+ // Ensure the launch web URL is a valid absolute URL and web extent scheme.
+ GURL url(launch_url);
+ URLPattern pattern(Extension::kValidWebExtentSchemes);
+ if (extension->from_bookmark()) {
+ // System Web Apps are bookmark apps that point to chrome:// URLs.
+ int valid_schemes = Extension::kValidBookmarkAppSchemes;
+ if (extension->location() == Manifest::EXTERNAL_COMPONENT)
+ valid_schemes |= URLPattern::SCHEME_CHROMEUI;
+ pattern.SetValidSchemes(valid_schemes);
+ }
+ if ((!url.is_valid() || !pattern.SetScheme(url.scheme()))) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWebURL);
+ return false;
+ }
+
+ launch_web_url_ = url;
+ } else if (extension->is_legacy_packaged_app()) {
+ *error = base::ASCIIToUTF16(errors::kLaunchURLRequired);
+ return false;
+ }
+
+ // For the Chrome component app, override launch url to new tab.
+ if (extension->id() == extension_misc::kChromeAppId) {
+ launch_web_url_ = GURL(chrome::kChromeUINewTabURL);
+ return true;
+ }
+
+ // If there is no extent, we default the extent based on the launch URL.
+ // Skip this step if the extension is from a bookmark app, as they are
+ // permissionless.
+ if (extension->web_extent().is_empty() && !launch_web_url_.is_empty() &&
+ !extension->from_bookmark()) {
+ URLPattern pattern(Extension::kValidWebExtentSchemes);
+ if (!pattern.SetScheme("*")) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWebURL);
+ return false;
+ }
+ pattern.SetHost(launch_web_url_.host());
+ pattern.SetPath("/*");
+ extension->AddWebExtentPattern(pattern);
+ }
+
+ // In order for the --apps-gallery-url switch to work with the gallery
+ // process isolation, we must insert any provided value into the component
+ // app's launch url and web extent.
+ if (extension->id() == extensions::kWebStoreAppId) {
+ std::string gallery_url_str =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kAppsGalleryURL);
+
+ // Empty string means option was not used.
+ if (!gallery_url_str.empty()) {
+ GURL gallery_url(gallery_url_str);
+ OverrideLaunchURL(extension, gallery_url);
+ }
+ } else if (extension->id() == extension_misc::kCloudPrintAppId) {
+ // In order for the --type=service switch to work, we must update the launch
+ // URL and web extent.
+ GURL url =
+ cloud_devices::GetCloudPrintRelativeURL("enable_chrome_connector");
+ if (!url.is_empty()) {
+ OverrideLaunchURL(extension, url);
+ }
+ }
+
+ return true;
+}
+
+bool AppLaunchInfo::LoadLaunchContainer(Extension* extension,
+ base::string16* error) {
+ const base::Value* tmp_launcher_container = NULL;
+ if (!extension->manifest()->Get(keys::kLaunchContainer,
+ &tmp_launcher_container))
+ return true;
+
+ std::string launch_container_string;
+ if (!tmp_launcher_container->GetAsString(&launch_container_string)) {
+ *error = base::ASCIIToUTF16(errors::kInvalidLaunchContainer);
+ return false;
+ }
+
+ if (launch_container_string == values::kLaunchContainerPanelDeprecated) {
+ launch_container_ = LaunchContainer::kLaunchContainerPanelDeprecated;
+ } else if (launch_container_string == values::kLaunchContainerTab) {
+ launch_container_ = LaunchContainer::kLaunchContainerTab;
+ } else {
+ *error = base::ASCIIToUTF16(errors::kInvalidLaunchContainer);
+ return false;
+ }
+
+ // TODO(manucornet): Remove this special behavior now that panels are
+ // deprecated.
+ bool can_specify_initial_size =
+ launch_container_ == LaunchContainer::kLaunchContainerPanelDeprecated;
+
+ // Validate the container width if present.
+ if (!ReadLaunchDimension(extension->manifest(),
+ keys::kLaunchWidth,
+ &launch_width_,
+ can_specify_initial_size,
+ error)) {
+ return false;
+ }
+
+ // Validate container height if present.
+ if (!ReadLaunchDimension(extension->manifest(),
+ keys::kLaunchHeight,
+ &launch_height_,
+ can_specify_initial_size,
+ error)) {
+ return false;
+ }
+
+ return true;
+}
+
+void AppLaunchInfo::OverrideLaunchURL(Extension* extension,
+ GURL override_url) {
+ if (!override_url.is_valid()) {
+ DLOG(WARNING) << "Invalid override url given for " << extension->name();
+ return;
+ }
+ if (override_url.has_port()) {
+ DLOG(WARNING) << "Override URL passed for " << extension->name()
+ << " should not contain a port. Removing it.";
+
+ GURL::Replacements remove_port;
+ remove_port.ClearPort();
+ override_url = override_url.ReplaceComponents(remove_port);
+ }
+
+ launch_web_url_ = override_url;
+
+ URLPattern pattern(Extension::kValidWebExtentSchemes);
+ URLPattern::ParseResult result = pattern.Parse(override_url.spec());
+ DCHECK_EQ(result, URLPattern::ParseResult::kSuccess);
+ pattern.SetPath(pattern.path() + '*');
+ extension->AddWebExtentPattern(pattern);
+}
+
+AppLaunchManifestHandler::AppLaunchManifestHandler() {
+}
+
+AppLaunchManifestHandler::~AppLaunchManifestHandler() {
+}
+
+bool AppLaunchManifestHandler::Parse(Extension* extension,
+ base::string16* error) {
+ std::unique_ptr<AppLaunchInfo> info(new AppLaunchInfo);
+ if (!info->Parse(extension, error))
+ return false;
+ extension->SetManifestData(keys::kLaunch, std::move(info));
+ return true;
+}
+
+bool AppLaunchManifestHandler::AlwaysParseForType(Manifest::Type type) const {
+ return type == Manifest::TYPE_LEGACY_PACKAGED_APP;
+}
+
+base::span<const char* const> AppLaunchManifestHandler::Keys() const {
+ static constexpr const char* kKeys[] = {
+ keys::kLaunchLocalPath, keys::kLaunchWebURL, keys::kLaunchContainer,
+ keys::kLaunchHeight, keys::kLaunchWidth};
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/app_launch_info.h b/chromium/chrome/common/extensions/manifest_handlers/app_launch_info.h
new file mode 100644
index 00000000000..6bfd10e7b94
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/app_launch_info.h
@@ -0,0 +1,85 @@
+// 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 CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_LAUNCH_INFO_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_LAUNCH_INFO_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_handler.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+// Container that holds the parsed app launch data.
+class AppLaunchInfo : public Extension::ManifestData {
+ public:
+ AppLaunchInfo();
+ ~AppLaunchInfo() override;
+
+ // Get the local path inside the extension to use with the launcher.
+ static const std::string& GetLaunchLocalPath(const Extension* extension);
+
+ // Get the absolute web url to use with the launcher.
+ static const GURL& GetLaunchWebURL(const Extension* extension);
+
+ // The window type that an app's manifest specifies to launch into.
+ // This is not always the window type an app will open into, because
+ // users can override the way each app launches. See
+ // ExtensionPrefs::GetLaunchContainer(), which looks at a per-app pref
+ // to decide what container an app will launch in.
+ static LaunchContainer GetLaunchContainer(
+ const Extension* extension);
+
+ // The default size of the container when launching. Only respected for
+ // containers like panels and windows.
+ static int GetLaunchWidth(const Extension* extension);
+ static int GetLaunchHeight(const Extension* extension);
+
+ // Get the fully resolved absolute launch URL.
+ static GURL GetFullLaunchURL(const Extension* extension);
+
+ bool Parse(Extension* extension, base::string16* error);
+
+ private:
+ bool LoadLaunchURL(Extension* extension, base::string16* error);
+ bool LoadLaunchContainer(Extension* extension, base::string16* error);
+ void OverrideLaunchURL(Extension* extension, GURL override_url);
+
+ std::string launch_local_path_;
+
+ GURL launch_web_url_;
+
+ LaunchContainer launch_container_;
+
+ int launch_width_;
+ int launch_height_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppLaunchInfo);
+};
+
+// Parses all app launch related keys in the manifest.
+class AppLaunchManifestHandler : public ManifestHandler {
+ public:
+ AppLaunchManifestHandler();
+ ~AppLaunchManifestHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+ bool AlwaysParseForType(Manifest::Type type) const override;
+
+ private:
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(AppLaunchManifestHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_LAUNCH_INFO_H_
diff --git a/chromium/chrome/common/extensions/manifest_handlers/app_theme_color_info.cc b/chromium/chrome/common/extensions/manifest_handlers/app_theme_color_info.cc
new file mode 100644
index 00000000000..aaf0eca56e9
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/app_theme_color_info.cc
@@ -0,0 +1,68 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/manifest_handlers/app_theme_color_info.h"
+
+#include <memory>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "extensions/common/image_util.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+AppThemeColorInfo::AppThemeColorInfo() {}
+
+AppThemeColorInfo::~AppThemeColorInfo() {}
+
+// static
+base::Optional<SkColor> AppThemeColorInfo::GetThemeColor(
+ const Extension* extension) {
+ AppThemeColorInfo* info = static_cast<AppThemeColorInfo*>(
+ extension->GetManifestData(keys::kAppThemeColor));
+ return info ? info->theme_color : base::Optional<SkColor>();
+}
+
+AppThemeColorHandler::AppThemeColorHandler() {}
+
+AppThemeColorHandler::~AppThemeColorHandler() {}
+
+bool AppThemeColorHandler::Parse(Extension* extension, base::string16* error) {
+ std::string theme_color_string;
+ SkColor theme_color = SK_ColorTRANSPARENT;
+ if (!extension->manifest()->GetString(keys::kAppThemeColor,
+ &theme_color_string) ||
+ !image_util::ParseRgbColorString(theme_color_string, &theme_color)) {
+ *error = base::UTF8ToUTF16(errors::kInvalidAppThemeColor);
+ return false;
+ }
+
+ // Currently, only allow the theme_color key for bookmark apps. We'll add
+ // an install warning in Validate().
+ if (!extension->from_bookmark()) {
+ extension->AddInstallWarning(
+ InstallWarning(errors::kInvalidThemeColorAppType));
+ return true;
+ }
+
+ auto app_theme_color_info = std::make_unique<AppThemeColorInfo>();
+ app_theme_color_info->theme_color = static_cast<SkColor>(theme_color);
+ extension->SetManifestData(keys::kAppThemeColor,
+ std::move(app_theme_color_info));
+
+ return true;
+}
+
+base::span<const char* const> AppThemeColorHandler::Keys() const {
+ static constexpr const char* kKeys[] = {keys::kAppThemeColor};
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/app_theme_color_info.h b/chromium/chrome/common/extensions/manifest_handlers/app_theme_color_info.h
new file mode 100644
index 00000000000..b8984825068
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/app_theme_color_info.h
@@ -0,0 +1,43 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_THEME_COLOR_INFO_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_THEME_COLOR_INFO_H_
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handler.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace extensions {
+
+// A structure to hold the parsed app theme color data.
+struct AppThemeColorInfo : public Extension::ManifestData {
+ AppThemeColorInfo();
+ ~AppThemeColorInfo() override;
+
+ static base::Optional<SkColor> GetThemeColor(const Extension* extension);
+
+ // The color to use for the browser frame.
+ base::Optional<SkColor> theme_color;
+};
+
+// Parses the "app.theme_color" manifest key.
+class AppThemeColorHandler : public ManifestHandler {
+ public:
+ AppThemeColorHandler();
+ ~AppThemeColorHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+
+ private:
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(AppThemeColorHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_APP_THEME_COLOR_INFO_H_
diff --git a/chromium/chrome/common/extensions/manifest_handlers/app_theme_color_manifest_unittest.cc b/chromium/chrome/common/extensions/manifest_handlers/app_theme_color_manifest_unittest.cc
new file mode 100644
index 00000000000..92e47056e14
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/app_theme_color_manifest_unittest.cc
@@ -0,0 +1,37 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stl_util.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+class ThemeColorMatchesManifestTest : public ChromeManifestTest {};
+
+TEST_F(ThemeColorMatchesManifestTest, ThemeColor) {
+ Testcase testcases[] = {
+ Testcase("theme_color.json", std::string(),
+ extensions::Manifest::INTERNAL, Extension::FROM_BOOKMARK),
+ };
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_SUCCESS);
+
+ Testcase failure_testcases[] = {
+ Testcase("theme_color_wrong_type.json",
+ extensions::manifest_errors::kInvalidAppThemeColor),
+ };
+ RunTestcases(failure_testcases, base::size(failure_testcases),
+ EXPECT_TYPE_ERROR);
+
+ Testcase warning_testcases[] = {
+ Testcase("theme_color.json",
+ extensions::manifest_errors::kInvalidThemeColorAppType),
+ };
+ RunTestcases(warning_testcases, base::size(warning_testcases),
+ EXPECT_TYPE_WARNING);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/automation_unittest.cc b/chromium/chrome/common/extensions/manifest_handlers/automation_unittest.cc
new file mode 100644
index 00000000000..9b45a321ff5
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/automation_unittest.cc
@@ -0,0 +1,292 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/version_info/version_info.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/features/feature_channel.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/automation.h"
+#include "extensions/common/permissions/permission_message_test_util.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+class AutomationManifestTest : public ChromeManifestTest {
+ public:
+ AutomationManifestTest() : channel_(version_info::Channel::UNKNOWN) {}
+
+ protected:
+ AutomationInfo* GetAutomationInfo(scoped_refptr<Extension> extension) {
+ return static_cast<AutomationInfo*>(
+ extension->GetManifestData(manifest_keys::kAutomation));
+ }
+
+ private:
+ ScopedCurrentChannel channel_;
+};
+
+TEST_F(AutomationManifestTest, AsBooleanFalse) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("automation_boolean_false.json");
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyNoPermissionMessages(extension->permissions_data()));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_FALSE(info);
+}
+
+TEST_F(AutomationManifestTest, AsBooleanTrue) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("automation_boolean_true.json");
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyOnePermissionMessage(
+ extension->permissions_data(),
+ "Read and change your data on www.google.com"));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_FALSE(info->desktop);
+ EXPECT_FALSE(info->interact);
+ EXPECT_TRUE(info->matches.is_empty());
+}
+
+TEST_F(AutomationManifestTest, InteractTrue) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("automation_interact_true.json");
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyOnePermissionMessage(
+ extension->permissions_data(),
+ "Read and change your data on www.google.com"));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_FALSE(info->desktop);
+ EXPECT_TRUE(info->interact);
+ EXPECT_TRUE(info->matches.is_empty());
+}
+
+TEST_F(AutomationManifestTest, Matches) {
+ scoped_refptr<Extension> extension = LoadAndExpectWarning(
+ "automation_matches.json",
+ ErrorUtils::FormatErrorMessage(
+ automation_errors::kErrorInvalidMatch, "www.badpattern.com",
+ URLPattern::GetParseResultString(
+ URLPattern::ParseResult::kMissingSchemeSeparator)));
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyOnePermissionMessage(
+ extension->permissions_data(),
+ "Read your data on www.google.com and www.twitter.com"));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_FALSE(info->desktop);
+ EXPECT_FALSE(info->interact);
+ EXPECT_FALSE(info->matches.is_empty());
+
+ EXPECT_TRUE(info->matches.MatchesURL(GURL("http://www.google.com/")));
+ EXPECT_TRUE(info->matches.MatchesURL(GURL("http://www.google.com")));
+ EXPECT_TRUE(info->matches.MatchesURL(GURL("http://www.twitter.com/")));
+ EXPECT_TRUE(info->matches.MatchesURL(GURL("http://www.twitter.com")));
+
+ EXPECT_FALSE(info->matches.MatchesURL(GURL("http://www.bing.com/")));
+ EXPECT_FALSE(info->matches.MatchesURL(GURL("http://www.bing.com")));
+}
+
+TEST_F(AutomationManifestTest, MatchesAndPermissions) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("automation_matches_and_permissions.json");
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(
+ VerifyTwoPermissionMessages(extension->permissions_data(),
+ "Read and change your data on www.google.com",
+ "Read your data on www.twitter.com", false));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_FALSE(info->desktop);
+ EXPECT_FALSE(info->interact);
+ EXPECT_FALSE(info->matches.is_empty());
+
+ EXPECT_TRUE(info->matches.MatchesURL(GURL("http://www.twitter.com/")));
+ EXPECT_TRUE(info->matches.MatchesURL(GURL("http://www.twitter.com")));
+}
+
+TEST_F(AutomationManifestTest, EmptyMatches) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectWarning("automation_empty_matches.json",
+ automation_errors::kErrorNoMatchesProvided);
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyNoPermissionMessages(extension->permissions_data()));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_FALSE(info->desktop);
+ EXPECT_FALSE(info->interact);
+ EXPECT_TRUE(info->matches.is_empty());
+}
+
+TEST_F(AutomationManifestTest, NoValidMatches) {
+ std::string error;
+ scoped_refptr<Extension> extension =
+ LoadExtension(ManifestData("automation_no_valid_matches.json"), &error);
+ ASSERT_TRUE(extension.get());
+ EXPECT_EQ("", error);
+ EXPECT_EQ(2u, extension->install_warnings().size());
+ EXPECT_EQ(ErrorUtils::FormatErrorMessage(
+ automation_errors::kErrorInvalidMatch, "www.badpattern.com",
+ URLPattern::GetParseResultString(
+ URLPattern::ParseResult::kMissingSchemeSeparator)),
+ extension->install_warnings()[0].message);
+ EXPECT_EQ(automation_errors::kErrorNoMatchesProvided,
+ extension->install_warnings()[1].message);
+
+ EXPECT_TRUE(VerifyNoPermissionMessages(extension->permissions_data()));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_FALSE(info->desktop);
+ EXPECT_FALSE(info->interact);
+ EXPECT_TRUE(info->matches.is_empty());
+}
+
+TEST_F(AutomationManifestTest, DesktopFalse) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("automation_desktop_false.json");
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyOnePermissionMessage(
+ extension->permissions_data(),
+ "Read and change your data on www.google.com"));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_FALSE(info->desktop);
+ EXPECT_FALSE(info->interact);
+ EXPECT_TRUE(info->matches.is_empty());
+}
+
+TEST_F(AutomationManifestTest, DesktopTrue) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("automation_desktop_true.json");
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyOnePermissionMessage(
+ extension->permissions_data(),
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_TRUE(info->desktop);
+ EXPECT_TRUE(info->interact);
+ EXPECT_TRUE(info->matches.is_empty());
+}
+
+TEST_F(AutomationManifestTest, Desktop_InteractTrue) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("automation_desktop_interact_true.json");
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyOnePermissionMessage(
+ extension->permissions_data(),
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_TRUE(info->desktop);
+ EXPECT_TRUE(info->interact);
+ EXPECT_TRUE(info->matches.is_empty());
+}
+
+TEST_F(AutomationManifestTest, Desktop_InteractFalse) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectWarning("automation_desktop_interact_false.json",
+ automation_errors::kErrorDesktopTrueInteractFalse);
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyOnePermissionMessage(
+ extension->permissions_data(),
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_TRUE(info->desktop);
+ EXPECT_TRUE(info->interact);
+ EXPECT_TRUE(info->matches.is_empty());
+}
+
+TEST_F(AutomationManifestTest, Desktop_MatchesSpecified) {
+ scoped_refptr<Extension> extension = LoadAndExpectWarning(
+ "automation_desktop_matches_specified.json",
+ automation_errors::kErrorDesktopTrueMatchesSpecified);
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyOnePermissionMessage(
+ extension->permissions_data(),
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_TRUE(info->desktop);
+ EXPECT_TRUE(info->interact);
+ EXPECT_TRUE(info->matches.is_empty());
+}
+
+TEST_F(AutomationManifestTest, AllHostsInteractFalse) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("automation_all_hosts_interact_false.json");
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyOnePermissionMessage(
+ extension->permissions_data(),
+ l10n_util::GetStringUTF16(
+ IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS_READ_ONLY)));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_FALSE(info->desktop);
+ EXPECT_FALSE(info->interact);
+ EXPECT_FALSE(info->matches.is_empty());
+ EXPECT_TRUE(info->matches.MatchesAllURLs());
+}
+
+TEST_F(AutomationManifestTest, AllHostsInteractTrue) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("automation_all_hosts_interact_true.json");
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyOnePermissionMessage(
+ extension->permissions_data(),
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)));
+
+ const AutomationInfo* info = AutomationInfo::Get(extension.get());
+ ASSERT_TRUE(info);
+
+ EXPECT_FALSE(info->desktop);
+ EXPECT_TRUE(info->interact);
+ EXPECT_FALSE(info->matches.is_empty());
+ EXPECT_TRUE(info->matches.MatchesAllURLs());
+}
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/content_scripts_manifest_unittest.cc b/chromium/chrome/common/extensions/manifest_handlers/content_scripts_manifest_unittest.cc
new file mode 100644
index 00000000000..0cf96ce9e76
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/content_scripts_manifest_unittest.cc
@@ -0,0 +1,105 @@
+// 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/command_line.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "chrome/common/webui_url_constants.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/file_util.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/content_scripts_handler.h"
+#include "extensions/common/switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace errors = manifest_errors;
+
+class ContentScriptsManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(ContentScriptsManifestTest, MatchPattern) {
+ Testcase testcases[] = {
+ // chrome:// urls are not allowed.
+ Testcase("content_script_chrome_url_invalid.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidMatch, base::NumberToString(0),
+ base::NumberToString(0),
+ URLPattern::GetParseResultString(
+ URLPattern::ParseResult::kInvalidScheme))),
+
+ // Match paterns must be strings.
+ Testcase("content_script_match_pattern_not_string.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidMatch, base::NumberToString(0),
+ base::NumberToString(0), errors::kExpectString))};
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
+
+ LoadAndExpectSuccess("ports_in_content_scripts.json");
+}
+
+TEST_F(ContentScriptsManifestTest, OnChromeUrlsWithFlag) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kExtensionsOnChromeURLs);
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("content_script_chrome_url_invalid.json");
+ const GURL newtab_url(chrome::kChromeUINewTabURL);
+ EXPECT_TRUE(
+ ContentScriptsInfo::ExtensionHasScriptAtURL(extension.get(), newtab_url));
+}
+
+TEST_F(ContentScriptsManifestTest, ScriptableHosts) {
+ // TODO(yoz): Test GetScriptableHosts.
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("content_script_yahoo.json");
+ URLPatternSet scriptable_hosts =
+ ContentScriptsInfo::GetScriptableHosts(extension.get());
+
+ URLPatternSet expected;
+ expected.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://yahoo.com/*"));
+
+ EXPECT_EQ(expected, scriptable_hosts);
+}
+
+TEST_F(ContentScriptsManifestTest, ContentScriptIds) {
+ scoped_refptr<Extension> extension1 =
+ LoadAndExpectSuccess("content_script_yahoo.json");
+ scoped_refptr<Extension> extension2 =
+ LoadAndExpectSuccess("content_script_yahoo.json");
+ const UserScriptList& user_scripts1 =
+ ContentScriptsInfo::GetContentScripts(extension1.get());
+ ASSERT_EQ(1u, user_scripts1.size());
+ int id = user_scripts1[0]->id();
+ const UserScriptList& user_scripts2 =
+ ContentScriptsInfo::GetContentScripts(extension2.get());
+ ASSERT_EQ(1u, user_scripts2.size());
+ // The id of the content script should be one higher than the previous.
+ EXPECT_EQ(id + 1, user_scripts2[0]->id());
+}
+
+TEST_F(ContentScriptsManifestTest, FailLoadingNonUTF8Scripts) {
+ base::FilePath install_dir;
+ ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &install_dir));
+ install_dir = install_dir.AppendASCII("extensions")
+ .AppendASCII("bad")
+ .AppendASCII("bad_encoding");
+
+ std::string error;
+ scoped_refptr<Extension> extension(file_util::LoadExtension(
+ install_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error));
+ ASSERT_TRUE(extension.get() == NULL);
+ ASSERT_STREQ(
+ "Could not load file 'bad_encoding.js' for content script. "
+ "It isn't UTF-8 encoded.",
+ error.c_str());
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/exclude_matches_manifest_unittest.cc b/chromium/chrome/common/extensions/manifest_handlers/exclude_matches_manifest_unittest.cc
new file mode 100644
index 00000000000..f3dbc6d1cc0
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/exclude_matches_manifest_unittest.cc
@@ -0,0 +1,32 @@
+// 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/stl_util.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/extension.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+class ExcludeMatchesManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(ExcludeMatchesManifestTest, ExcludeMatchPatterns) {
+ Testcase testcases[] = {
+ Testcase("exclude_matches.json"),
+ Testcase("exclude_matches_empty.json")
+ };
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_SUCCESS);
+
+ Testcase testcases2[] = {
+ Testcase("exclude_matches_not_list.json",
+ "Invalid value for 'content_scripts[0].exclude_matches'."),
+ Testcase("exclude_matches_invalid_host.json",
+ "Invalid value for 'content_scripts[0].exclude_matches[0]': "
+ "Invalid host wildcard.")
+ };
+ RunTestcases(testcases2, base::size(testcases2), EXPECT_TYPE_ERROR);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/extension_action_handler.cc b/chromium/chrome/common/extensions/manifest_handlers/extension_action_handler.cc
new file mode 100644
index 00000000000..07307416cda
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/extension_action_handler.cc
@@ -0,0 +1,135 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/manifest_handlers/extension_action_handler.h"
+
+#include <memory>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/common/extensions/api/extension_action/action_info.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/grit/generated_resources.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/file_util.h"
+#include "extensions/common/image_util.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+ExtensionActionHandler::ExtensionActionHandler() {
+}
+
+ExtensionActionHandler::~ExtensionActionHandler() {
+}
+
+bool ExtensionActionHandler::Parse(Extension* extension,
+ base::string16* error) {
+ const char* key = nullptr;
+ const char* error_key = nullptr;
+ ActionInfo::Type type = ActionInfo::TYPE_ACTION;
+ if (extension->manifest()->HasKey(manifest_keys::kAction)) {
+ key = manifest_keys::kAction;
+ error_key = manifest_errors::kInvalidAction;
+ // type ACTION is correct.
+ }
+
+ if (extension->manifest()->HasKey(manifest_keys::kPageAction)) {
+ if (key != nullptr) {
+ // An extension can only have one action.
+ *error = base::ASCIIToUTF16(manifest_errors::kOneUISurfaceOnly);
+ return false;
+ }
+ key = manifest_keys::kPageAction;
+ error_key = manifest_errors::kInvalidPageAction;
+ type = ActionInfo::TYPE_PAGE;
+ }
+
+ if (extension->manifest()->HasKey(manifest_keys::kBrowserAction)) {
+ if (key != nullptr) {
+ // An extension can only have one action.
+ *error = base::ASCIIToUTF16(manifest_errors::kOneUISurfaceOnly);
+ return false;
+ }
+ key = manifest_keys::kBrowserAction;
+ error_key = manifest_errors::kInvalidBrowserAction;
+ type = ActionInfo::TYPE_BROWSER;
+ }
+
+ if (key) {
+ const base::DictionaryValue* dict = nullptr;
+ if (!extension->manifest()->GetDictionary(key, &dict)) {
+ *error = base::ASCIIToUTF16(error_key);
+ return false;
+ }
+
+ std::unique_ptr<ActionInfo> action_info =
+ ActionInfo::Load(extension, type, dict, error);
+ if (!action_info)
+ return false; // Failed to parse extension action definition.
+
+ switch (type) {
+ case ActionInfo::TYPE_ACTION:
+ ActionInfo::SetExtensionActionInfo(extension, std::move(action_info));
+ break;
+ case ActionInfo::TYPE_PAGE:
+ ActionInfo::SetPageActionInfo(extension, std::move(action_info));
+ break;
+ case ActionInfo::TYPE_BROWSER:
+ ActionInfo::SetBrowserActionInfo(extension, std::move(action_info));
+ break;
+ }
+ } else { // No key, used for synthesizing an action for extensions with none.
+ if (Manifest::IsComponentLocation(extension->location()))
+ return true; // Don't synthesize actions for component extensions.
+ if (extension->was_installed_by_default())
+ return true; // Don't synthesize actions for default extensions.
+
+ // Set an empty page action. We use a page action (instead of a browser
+ // action) because the action should not be seen as enabled on every page.
+ auto action_info = std::make_unique<ActionInfo>(ActionInfo::TYPE_PAGE);
+ action_info->synthesized = true;
+ ActionInfo::SetPageActionInfo(extension, std::move(action_info));
+ }
+
+ return true;
+}
+
+bool ExtensionActionHandler::Validate(
+ const Extension* extension,
+ std::string* error,
+ std::vector<InstallWarning>* warnings) const {
+ int error_message = 0;
+ const ActionInfo* action = ActionInfo::GetPageActionInfo(extension);
+ if (action) {
+ error_message = IDS_EXTENSION_LOAD_ICON_FOR_PAGE_ACTION_FAILED;
+ } else {
+ action = ActionInfo::GetBrowserActionInfo(extension);
+ error_message = IDS_EXTENSION_LOAD_ICON_FOR_BROWSER_ACTION_FAILED;
+ }
+
+ // Analyze the icons for visibility using the default toolbar color, since
+ // the majority of Chrome users don't modify their theme.
+ if (action && !action->default_icon.empty() &&
+ !file_util::ValidateExtensionIconSet(
+ action->default_icon, extension, error_message,
+ image_util::kDefaultToolbarColor, error)) {
+ return false;
+ }
+ return true;
+}
+
+bool ExtensionActionHandler::AlwaysParseForType(Manifest::Type type) const {
+ return type == Manifest::TYPE_EXTENSION || type == Manifest::TYPE_USER_SCRIPT;
+}
+
+base::span<const char* const> ExtensionActionHandler::Keys() const {
+ static constexpr const char* kKeys[] = {
+ manifest_keys::kPageAction,
+ manifest_keys::kBrowserAction,
+ };
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/extension_action_handler.h b/chromium/chrome/common/extensions/manifest_handlers/extension_action_handler.h
new file mode 100644
index 00000000000..295c4247f90
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/extension_action_handler.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_EXTENSION_ACTION_HANDLER_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_EXTENSION_ACTION_HANDLER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "extensions/common/manifest_handler.h"
+
+namespace extensions {
+
+// Parses the "page_action" and "browser_action" manifest keys.
+class ExtensionActionHandler : public ManifestHandler {
+ public:
+ ExtensionActionHandler();
+ ~ExtensionActionHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+ bool Validate(const Extension* extension,
+ std::string* error,
+ std::vector<InstallWarning>* warnings) const override;
+
+ private:
+ bool AlwaysParseForType(Manifest::Type type) const override;
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionActionHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_EXTENSION_ACTION_HANDLER_H_
diff --git a/chromium/chrome/common/extensions/manifest_handlers/extension_action_handler_unittest.cc b/chromium/chrome/common/extensions/manifest_handlers/extension_action_handler_unittest.cc
new file mode 100644
index 00000000000..ac0b3f7187a
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/extension_action_handler_unittest.cc
@@ -0,0 +1,307 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/manifest_handlers/extension_action_handler.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/strcat.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/values_test_util.h"
+#include "base/values.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/api/extension_action/action_info.h"
+#include "components/version_info/channel.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_icon_set.h"
+#include "extensions/common/features/feature_channel.h"
+#include "extensions/common/file_util.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace {
+
+// TODO(devlin): We don't need this separate enum now that SystemIndicator is
+// no longer part of ActionInfo.
+enum class TestActionType {
+ kBrowserAction,
+ kPageAction,
+ kAction,
+};
+
+base::FilePath GetTestDataDir() {
+ base::FilePath path;
+ base::PathService::Get(chrome::DIR_TEST_DATA, &path);
+ return path.AppendASCII("extensions").AppendASCII("manifest_handlers");
+}
+
+} // namespace
+
+// Tests that an unpacked extension with an invisible browser action
+// default icon fails as expected.
+TEST(ExtensionActionHandlerTest, LoadInvisibleBrowserActionIconUnpacked) {
+ base::FilePath extension_dir =
+ GetTestDataDir().AppendASCII("browser_action_invisible_icon");
+ // Set the flag that enables the error.
+ file_util::SetReportErrorForInvisibleIconForTesting(true);
+ std::string error;
+ scoped_refptr<Extension> extension(file_util::LoadExtension(
+ extension_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error));
+ file_util::SetReportErrorForInvisibleIconForTesting(false);
+ EXPECT_FALSE(extension);
+ EXPECT_EQ("The icon is not sufficiently visible 'invisible_icon.png'.",
+ error);
+}
+
+// Tests that an unpacked extension with an invisible page action
+// default icon fails as expected.
+TEST(ExtensionActionHandlerTest, LoadInvisiblePageActionIconUnpacked) {
+ base::FilePath extension_dir =
+ GetTestDataDir().AppendASCII("page_action_invisible_icon");
+ // Set the flag that enables the error.
+ file_util::SetReportErrorForInvisibleIconForTesting(true);
+ std::string error;
+ scoped_refptr<Extension> extension(file_util::LoadExtension(
+ extension_dir, Manifest::UNPACKED, Extension::NO_FLAGS, &error));
+ file_util::SetReportErrorForInvisibleIconForTesting(false);
+ EXPECT_FALSE(extension);
+ EXPECT_EQ("The icon is not sufficiently visible 'invisible_icon.png'.",
+ error);
+}
+
+// A parameterized test suite to test each different extension action key
+// ("page_action", "browser_action", "action").
+class ExtensionActionManifestTest
+ : public ManifestTest,
+ public testing::WithParamInterface<TestActionType> {
+ public:
+ ExtensionActionManifestTest() {}
+ ~ExtensionActionManifestTest() override {}
+
+ // Constructs and returns a ManifestData object with the provided
+ // |action_spec|.
+ ManifestData GetManifestData(const char* action_spec) {
+ constexpr char kManifestStub[] =
+ R"({
+ "name": "Test",
+ "manifest_version": 2,
+ "version": "0.1",
+ "%s": %s
+ })";
+
+ const char* action_key = nullptr;
+ switch (GetParam()) {
+ case TestActionType::kBrowserAction:
+ action_key = manifest_keys::kBrowserAction;
+ break;
+ case TestActionType::kPageAction:
+ action_key = manifest_keys::kPageAction;
+ break;
+ case TestActionType::kAction:
+ action_key = manifest_keys::kAction;
+ break;
+ }
+
+ base::Value manifest_value = base::test::ParseJson(
+ base::StringPrintf(kManifestStub, action_key, action_spec));
+ EXPECT_TRUE(manifest_value.is_dict());
+ EXPECT_FALSE(manifest_value.is_none());
+ return ManifestData(std::move(manifest_value), "test");
+ }
+
+ // Returns the ActionInfo for the given |extension| corresponding with the
+ // action key of the test param.
+ const ActionInfo* GetActionInfo(const Extension& extension) {
+ const ActionInfo* action_info = nullptr;
+ switch (GetParam()) {
+ case TestActionType::kBrowserAction:
+ action_info = ActionInfo::GetBrowserActionInfo(&extension);
+ break;
+ case TestActionType::kPageAction:
+ action_info = ActionInfo::GetPageActionInfo(&extension);
+ break;
+ case TestActionType::kAction:
+ action_info = ActionInfo::GetExtensionActionInfo(&extension);
+ break;
+ }
+
+ return action_info;
+ }
+
+ private:
+ // The "action" key is restricted to trunk.
+ ScopedCurrentChannel scoped_channel_{version_info::Channel::UNKNOWN};
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionActionManifestTest);
+};
+
+// Tests that parsing an action succeeds and properly populates the given
+// fields.
+TEST_P(ExtensionActionManifestTest, Basic) {
+ constexpr char kValidAllFields[] =
+ R"({
+ "default_popup": "popup.html",
+ "default_title": "Title",
+ "default_icon": "icon.png"
+ })";
+ scoped_refptr<const Extension> extension =
+ LoadAndExpectSuccess(GetManifestData(kValidAllFields));
+ ASSERT_TRUE(extension);
+ const ActionInfo* action_info = GetActionInfo(*extension);
+ ASSERT_TRUE(action_info);
+
+ EXPECT_EQ(extension->GetResourceURL("popup.html"),
+ action_info->default_popup_url);
+ EXPECT_EQ("Title", action_info->default_title);
+ // Make a copy of the map since [] is more readable than find() for comparing
+ // values.
+ ExtensionIconSet::IconMap icons = action_info->default_icon.map();
+ EXPECT_EQ(1u, icons.size());
+ EXPECT_EQ(icons[extension_misc::EXTENSION_ICON_GIGANTOR], "icon.png");
+}
+
+// Tests that specifying an empty action (e.g., "action": {}) works correctly,
+// with empty defaults.
+TEST_P(ExtensionActionManifestTest, TestEmptyAction) {
+ constexpr char kValidNoFields[] = "{}";
+ scoped_refptr<const Extension> extension =
+ LoadAndExpectSuccess(GetManifestData(kValidNoFields));
+ ASSERT_TRUE(extension);
+ const ActionInfo* action_info = GetActionInfo(*extension);
+ ASSERT_TRUE(action_info);
+
+ EXPECT_EQ(GURL(), action_info->default_popup_url);
+ EXPECT_EQ(std::string(), action_info->default_title);
+ const ExtensionIconSet::IconMap& icons = action_info->default_icon.map();
+ EXPECT_TRUE(icons.empty());
+}
+
+// Tests specifying an icon dictionary (with different pixel sizes) in the
+// action.
+TEST_P(ExtensionActionManifestTest, ValidIconDictionary) {
+ constexpr char kValidIconDictionary[] =
+ R"({
+ "default_icon": {
+ "24": "icon24.png",
+ "48": "icon48.png",
+ "79": "icon79.png"
+ }
+ })";
+
+ scoped_refptr<const Extension> extension =
+ LoadAndExpectSuccess(GetManifestData(kValidIconDictionary));
+ ASSERT_TRUE(extension);
+ const ActionInfo* action_info = GetActionInfo(*extension);
+ ASSERT_TRUE(action_info);
+
+ EXPECT_EQ(GURL(), action_info->default_popup_url);
+ EXPECT_EQ(std::string(), action_info->default_title);
+ // Make a copy of the map since [] is more readable than find() for comparing
+ // values.
+ ExtensionIconSet::IconMap icons = action_info->default_icon.map();
+ EXPECT_EQ(3u, icons.size());
+ EXPECT_EQ("icon24.png", icons[24]);
+ EXPECT_EQ("icon48.png", icons[48]);
+ EXPECT_EQ("icon79.png", icons[79]);
+}
+
+// Tests some invalid cases.
+TEST_P(ExtensionActionManifestTest, Invalid) {
+ constexpr char kInvalidTopLevel1[] = "[]";
+ constexpr char kInvalidTopLevel2[] = "\"foo\"";
+ constexpr char kInvalidTopLevel3[] = "17";
+
+ const char* expected_error = nullptr;
+ switch (GetParam()) {
+ case TestActionType::kBrowserAction:
+ expected_error = manifest_errors::kInvalidBrowserAction;
+ break;
+ case TestActionType::kPageAction:
+ expected_error = manifest_errors::kInvalidPageAction;
+ break;
+ case TestActionType::kAction:
+ expected_error = manifest_errors::kInvalidAction;
+ break;
+ }
+
+ for (const char* spec :
+ {kInvalidTopLevel1, kInvalidTopLevel2, kInvalidTopLevel3}) {
+ LoadAndExpectError(GetManifestData(spec), expected_error);
+ }
+
+ constexpr char kInvalidPopup[] = R"({ "default_popup": {} })";
+ LoadAndExpectError(GetManifestData(kInvalidPopup),
+ manifest_errors::kInvalidActionDefaultPopup);
+ constexpr char kInvalidTitle[] = R"({ "default_title": {} })";
+ LoadAndExpectError(GetManifestData(kInvalidTitle),
+ manifest_errors::kInvalidActionDefaultTitle);
+ constexpr char kInvalidIcon[] = R"({ "default_icon": [] })";
+ LoadAndExpectError(GetManifestData(kInvalidIcon),
+ manifest_errors::kInvalidActionDefaultIcon);
+}
+
+// Test the handling of the default_state key.
+TEST_P(ExtensionActionManifestTest, DefaultState) {
+ constexpr char kDefaultStateDisabled[] = R"({"default_state": "disabled"})";
+ constexpr char kDefaultStateEnabled[] = R"({"default_state": "enabled"})";
+ constexpr char kDefaultStateInvalid[] = R"({"default_state": "foo"})";
+
+ // default_state is only valid for "action" types.
+ const bool default_state_allowed = GetParam() == TestActionType::kAction;
+ const char* key_disallowed_error =
+ manifest_errors::kDefaultStateShouldNotBeSet;
+
+ struct {
+ // The manifest definition of the action key.
+ const char* spec;
+ // The expected error, if parsing was unsuccessful.
+ const char* expected_error;
+ // The expected state, if parsing was successful.
+ base::Optional<ActionInfo::DefaultState> expected_state;
+ } test_cases[] = {
+ {kDefaultStateDisabled,
+ default_state_allowed ? nullptr : key_disallowed_error,
+ default_state_allowed ? base::make_optional(ActionInfo::STATE_DISABLED)
+ : base::nullopt},
+ {kDefaultStateEnabled,
+ default_state_allowed ? nullptr : key_disallowed_error,
+ default_state_allowed ? base::make_optional(ActionInfo::STATE_ENABLED)
+ : base::nullopt},
+ {kDefaultStateInvalid,
+ default_state_allowed ? manifest_errors::kInvalidActionDefaultState
+ : key_disallowed_error,
+ base::nullopt},
+ };
+
+ for (const auto& test_case : test_cases) {
+ SCOPED_TRACE(test_case.spec);
+
+ if (test_case.expected_error == nullptr) {
+ ASSERT_TRUE(test_case.expected_state);
+ scoped_refptr<const Extension> extension =
+ LoadAndExpectSuccess(GetManifestData(test_case.spec));
+ ASSERT_TRUE(extension);
+ const ActionInfo* action_info = GetActionInfo(*extension);
+ ASSERT_TRUE(action_info);
+ EXPECT_EQ(*test_case.expected_state, action_info->default_state);
+ } else {
+ ASSERT_FALSE(test_case.expected_state);
+ LoadAndExpectError(GetManifestData(test_case.spec),
+ test_case.expected_error);
+ }
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(,
+ ExtensionActionManifestTest,
+ testing::Values(TestActionType::kBrowserAction,
+ TestActionType::kPageAction,
+ TestActionType::kAction));
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/linked_app_icons.cc b/chromium/chrome/common/extensions/manifest_handlers/linked_app_icons.cc
new file mode 100644
index 00000000000..79a6f4e5148
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/linked_app_icons.cc
@@ -0,0 +1,110 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/manifest_handlers/linked_app_icons.h"
+
+#include <memory>
+
+#include "base/lazy_instance.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+namespace {
+
+static base::LazyInstance<LinkedAppIcons>::DestructorAtExit
+ g_empty_linked_app_icons = LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+LinkedAppIcons::IconInfo::IconInfo() {
+}
+
+LinkedAppIcons::IconInfo::~IconInfo() {
+}
+
+LinkedAppIcons::LinkedAppIcons() {
+}
+
+LinkedAppIcons::LinkedAppIcons(const LinkedAppIcons& other) = default;
+
+LinkedAppIcons::~LinkedAppIcons() {
+}
+
+// static
+const LinkedAppIcons& LinkedAppIcons::GetLinkedAppIcons(
+ const Extension* extension) {
+ LinkedAppIcons* info = static_cast<LinkedAppIcons*>(
+ extension->GetManifestData(keys::kLinkedAppIcons));
+ return info ? *info : g_empty_linked_app_icons.Get();
+}
+
+LinkedAppIconsHandler::LinkedAppIconsHandler() {
+}
+
+LinkedAppIconsHandler::~LinkedAppIconsHandler() {
+}
+
+bool LinkedAppIconsHandler::Parse(Extension* extension, base::string16* error) {
+ std::unique_ptr<LinkedAppIcons> linked_app_icons(new LinkedAppIcons);
+
+ const base::Value* icons_value = nullptr;
+ const base::ListValue* icons_list = nullptr;
+ if (extension->manifest()->Get(keys::kLinkedAppIcons, &icons_value)) {
+ if (!icons_value->GetAsList(&icons_list)) {
+ *error = base::UTF8ToUTF16(
+ extensions::manifest_errors::kInvalidLinkedAppIcons);
+ return false;
+ }
+
+ for (const auto& icon_value : *icons_list) {
+ const base::DictionaryValue* icon_dict = nullptr;
+ if (!icon_value.GetAsDictionary(&icon_dict)) {
+ *error = base::UTF8ToUTF16(
+ extensions::manifest_errors::kInvalidLinkedAppIcon);
+ return false;
+ }
+
+ std::string url_string;
+ if (!icon_dict->GetString(keys::kLinkedAppIconURL, &url_string)) {
+ *error = base::UTF8ToUTF16(
+ extensions::manifest_errors::kInvalidLinkedAppIconURL);
+ return false;
+ }
+
+ LinkedAppIcons::IconInfo info;
+ info.url = GURL(url_string);
+ if (!info.url.is_valid()) {
+ *error = base::UTF8ToUTF16(
+ extensions::manifest_errors::kInvalidLinkedAppIconURL);
+ return false;
+ }
+
+ if (!icon_dict->GetInteger(keys::kLinkedAppIconSize, &info.size)) {
+ *error = base::UTF8ToUTF16(
+ extensions::manifest_errors::kInvalidLinkedAppIconSize);
+ return false;
+ }
+
+ linked_app_icons->icons.push_back(info);
+ }
+ }
+
+ extension->SetManifestData(keys::kLinkedAppIcons,
+ std::move(linked_app_icons));
+ return true;
+}
+
+base::span<const char* const> LinkedAppIconsHandler::Keys() const {
+ static constexpr const char* kKeys[] = {keys::kLinkedAppIcons};
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/linked_app_icons.h b/chromium/chrome/common/extensions/manifest_handlers/linked_app_icons.h
new file mode 100644
index 00000000000..32845384e44
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/linked_app_icons.h
@@ -0,0 +1,51 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_LINKED_APP_ICONS_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_LINKED_APP_ICONS_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handler.h"
+
+namespace extensions {
+
+// A structure to hold the parsed linked app icon data.
+struct LinkedAppIcons : public Extension::ManifestData {
+ struct IconInfo {
+ IconInfo();
+ ~IconInfo();
+
+ GURL url;
+ int size;
+ };
+
+ LinkedAppIcons();
+ LinkedAppIcons(const LinkedAppIcons& other);
+ ~LinkedAppIcons() override;
+
+ static const LinkedAppIcons& GetLinkedAppIcons(const Extension* extension);
+
+ std::vector<IconInfo> icons;
+};
+
+// Parses the "app.linked_icons" manifest key.
+class LinkedAppIconsHandler : public ManifestHandler {
+ public:
+ LinkedAppIconsHandler();
+ ~LinkedAppIconsHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+
+ private:
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(LinkedAppIconsHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_LINKED_APP_ICONS_H_
diff --git a/chromium/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.cc b/chromium/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.cc
new file mode 100644
index 00000000000..51c27ebe3ad
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.cc
@@ -0,0 +1,63 @@
+// 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 "chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/version.h"
+#include "chrome/grit/chromium_strings.h"
+#include "components/version_info/version_info.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_constants.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+MinimumChromeVersionChecker::MinimumChromeVersionChecker() {
+}
+
+MinimumChromeVersionChecker::~MinimumChromeVersionChecker() {
+}
+
+bool MinimumChromeVersionChecker::Parse(Extension* extension,
+ base::string16* error) {
+ std::string minimum_version_string;
+ if (!extension->manifest()->GetString(keys::kMinimumChromeVersion,
+ &minimum_version_string)) {
+ *error = base::ASCIIToUTF16(errors::kInvalidMinimumChromeVersion);
+ return false;
+ }
+
+ base::Version minimum_version(minimum_version_string);
+ if (!minimum_version.IsValid()) {
+ *error = base::ASCIIToUTF16(errors::kInvalidMinimumChromeVersion);
+ return false;
+ }
+
+ const base::Version& current_version = version_info::GetVersion();
+ if (!current_version.IsValid()) {
+ NOTREACHED();
+ return false;
+ }
+
+ if (current_version.CompareTo(minimum_version) < 0) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ errors::kChromeVersionTooLow,
+ l10n_util::GetStringUTF8(IDS_PRODUCT_NAME),
+ minimum_version_string);
+ return false;
+ }
+ return true;
+}
+
+base::span<const char* const> MinimumChromeVersionChecker::Keys() const {
+ static constexpr const char* kKeys[] = {keys::kMinimumChromeVersion};
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.h b/chromium/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.h
new file mode 100644
index 00000000000..4ca64305326
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.h
@@ -0,0 +1,31 @@
+// 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 CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_MINIMUM_CHROME_VERSION_CHECKER_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_MINIMUM_CHROME_VERSION_CHECKER_H_
+
+#include "base/macros.h"
+#include "extensions/common/manifest_handler.h"
+
+namespace extensions {
+
+// Checks that the "minimum_chrome_version" requirement is met.
+class MinimumChromeVersionChecker : public ManifestHandler {
+ public:
+ MinimumChromeVersionChecker();
+ ~MinimumChromeVersionChecker() override;
+
+ // Validate minimum Chrome version. We don't need to store this, since the
+ // extension is not valid if it is incorrect.
+ bool Parse(Extension* extension, base::string16* error) override;
+
+ private:
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(MinimumChromeVersionChecker);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_MINIMUM_CHROME_VERSION_CHECKER_H_
diff --git a/chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler.cc b/chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler.cc
new file mode 100644
index 00000000000..397c3f73ce6
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler.cc
@@ -0,0 +1,72 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/manifest_handlers/natively_connectable_handler.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+
+namespace extensions {
+
+namespace {
+
+const NativelyConnectableHosts* GetHosts(const Extension& extension) {
+ return static_cast<const NativelyConnectableHosts*>(
+ extension.GetManifestData(manifest_keys::kNativelyConnectable));
+}
+
+} // namespace
+
+NativelyConnectableHosts::NativelyConnectableHosts() = default;
+NativelyConnectableHosts::~NativelyConnectableHosts() = default;
+
+// static
+const std::set<std::string>*
+NativelyConnectableHosts::GetConnectableNativeMessageHosts(
+ const Extension& extension) {
+ const auto* hosts = GetHosts(extension);
+ if (!hosts) {
+ return nullptr;
+ }
+ return &hosts->hosts;
+}
+
+NativelyConnectableHandler::NativelyConnectableHandler() = default;
+NativelyConnectableHandler::~NativelyConnectableHandler() = default;
+
+bool NativelyConnectableHandler::Parse(Extension* extension,
+ base::string16* error) {
+ const base::Value* natively_connectable_hosts = nullptr;
+ if (!extension->manifest()->GetList(manifest_keys::kNativelyConnectable,
+ &natively_connectable_hosts)) {
+ *error = base::ASCIIToUTF16(manifest_errors::kInvalidNativelyConnectable);
+ return false;
+ }
+
+ auto hosts = std::make_unique<NativelyConnectableHosts>();
+ for (const auto& host : natively_connectable_hosts->GetList()) {
+ if (!host.is_string() || host.GetString().empty()) {
+ *error =
+ base::ASCIIToUTF16(manifest_errors::kInvalidNativelyConnectableValue);
+ return false;
+ }
+ hosts->hosts.insert(host.GetString());
+ }
+
+ extension->SetManifestData(manifest_keys::kNativelyConnectable,
+ std::move(hosts));
+ return true;
+}
+
+base::span<const char* const> NativelyConnectableHandler::Keys() const {
+ static constexpr const char* kKeys[] = {manifest_keys::kNativelyConnectable};
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler.h b/chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler.h
new file mode 100644
index 00000000000..8a32c3a4091
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler.h
@@ -0,0 +1,48 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_NATIVELY_CONNECTABLE_HANDLER_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_NATIVELY_CONNECTABLE_HANDLER_H_
+
+#include <set>
+#include <string>
+
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handler.h"
+
+namespace extensions {
+
+// A structure to hold the parsed list of native messaging hosts that can
+// connect to this extension.
+struct NativelyConnectableHosts : public Extension::ManifestData {
+ NativelyConnectableHosts();
+ ~NativelyConnectableHosts() override;
+
+ static const std::set<std::string>* GetConnectableNativeMessageHosts(
+ const Extension& extension);
+
+ // A set of native messaging hosts allowed to initiate connection to this
+ // extension.
+ std::set<std::string> hosts;
+};
+
+// Parses the "natively_connectable" manifest key.
+class NativelyConnectableHandler : public ManifestHandler {
+ public:
+ NativelyConnectableHandler();
+ ~NativelyConnectableHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+
+ private:
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(NativelyConnectableHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_NATIVELY_CONNECTABLE_HANDLER_H_
diff --git a/chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler_unittest.cc b/chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler_unittest.cc
new file mode 100644
index 00000000000..67e59904ce5
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/natively_connectable_handler_unittest.cc
@@ -0,0 +1,57 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/manifest_handlers/natively_connectable_handler.h"
+
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permission_message_test_util.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+using NativelyConnectableManifestTest = ChromeManifestTest;
+
+TEST_F(NativelyConnectableManifestTest, Basic) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("natively_connectable.json");
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyNoPermissionMessages(extension->permissions_data()));
+
+ auto* hosts =
+ NativelyConnectableHosts::GetConnectableNativeMessageHosts(*extension);
+ ASSERT_TRUE(hosts);
+ EXPECT_EQ(*hosts, (std::set<std::string>{
+ "com.google.chrome.test.echo",
+ "com.google.chrome.test.host_binary_missing",
+ }));
+}
+
+TEST_F(NativelyConnectableManifestTest, Unset) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("natively_connectable_unset.json");
+ ASSERT_TRUE(extension.get());
+
+ EXPECT_TRUE(VerifyNoPermissionMessages(extension->permissions_data()));
+
+ EXPECT_FALSE(
+ NativelyConnectableHosts::GetConnectableNativeMessageHosts(*extension));
+}
+
+TEST_F(NativelyConnectableManifestTest, IncorrectType) {
+ LoadAndExpectError("natively_connectable_incorrect_type.json",
+ manifest_errors::kInvalidNativelyConnectable);
+}
+
+TEST_F(NativelyConnectableManifestTest, IncorrectValuesType) {
+ LoadAndExpectError("natively_connectable_incorrect_values_type.json",
+ manifest_errors::kInvalidNativelyConnectableValue);
+}
+
+TEST_F(NativelyConnectableManifestTest, EmptyHost) {
+ LoadAndExpectError("natively_connectable_empty_host.json",
+ manifest_errors::kInvalidNativelyConnectableValue);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc b/chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
new file mode 100644
index 00000000000..6c83bbae4d8
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler.cc
@@ -0,0 +1,183 @@
+// 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 "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "components/url_formatter/url_formatter.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension_set.h"
+#include "extensions/common/feature_switch.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/permissions_parser.h"
+#include "extensions/common/permissions/api_permission_set.h"
+#include "extensions/common/permissions/manifest_permission.h"
+#include "extensions/common/permissions/permissions_info.h"
+#include "extensions/common/permissions/settings_override_permission.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_utils.h"
+#include "url/gurl.h"
+
+using extensions::api::manifest_types::ChromeSettingsOverrides;
+
+namespace extensions {
+namespace {
+
+std::unique_ptr<GURL> CreateManifestURL(const std::string& url) {
+ std::unique_ptr<GURL> manifest_url(new GURL(url));
+ if (!manifest_url->is_valid() ||
+ !manifest_url->SchemeIsHTTPOrHTTPS())
+ return std::unique_ptr<GURL>();
+ return manifest_url;
+}
+
+std::unique_ptr<GURL> ParseHomepage(const ChromeSettingsOverrides& overrides,
+ base::string16* error) {
+ if (!overrides.homepage)
+ return std::unique_ptr<GURL>();
+ std::unique_ptr<GURL> manifest_url = CreateManifestURL(*overrides.homepage);
+ if (!manifest_url) {
+ *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
+ manifest_errors::kInvalidHomepageOverrideURL, *overrides.homepage);
+ }
+ return manifest_url;
+}
+
+std::vector<GURL> ParseStartupPage(const ChromeSettingsOverrides& overrides,
+ base::string16* error) {
+ std::vector<GURL> urls;
+ if (!overrides.startup_pages)
+ return urls;
+
+ for (std::vector<std::string>::const_iterator i =
+ overrides.startup_pages->begin(); i != overrides.startup_pages->end();
+ ++i) {
+ std::unique_ptr<GURL> manifest_url = CreateManifestURL(*i);
+ if (!manifest_url) {
+ *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
+ manifest_errors::kInvalidStartupOverrideURL, *i);
+ } else {
+ urls.push_back(GURL());
+ urls.back().Swap(manifest_url.get());
+ }
+ }
+ return urls;
+}
+
+std::unique_ptr<ChromeSettingsOverrides::Search_provider> ParseSearchEngine(
+ ChromeSettingsOverrides* overrides,
+ base::string16* error) {
+ if (!overrides->search_provider)
+ return std::unique_ptr<ChromeSettingsOverrides::Search_provider>();
+ if (!CreateManifestURL(overrides->search_provider->search_url)) {
+ *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
+ manifest_errors::kInvalidSearchEngineURL,
+ overrides->search_provider->search_url);
+ return std::unique_ptr<ChromeSettingsOverrides::Search_provider>();
+ }
+ if (overrides->search_provider->prepopulated_id)
+ return std::move(overrides->search_provider);
+ if (!overrides->search_provider->name ||
+ !overrides->search_provider->keyword ||
+ !overrides->search_provider->encoding ||
+ !overrides->search_provider->favicon_url) {
+ *error =
+ base::ASCIIToUTF16(manifest_errors::kInvalidSearchEngineMissingKeys);
+ return std::unique_ptr<ChromeSettingsOverrides::Search_provider>();
+ }
+ if (!CreateManifestURL(*overrides->search_provider->favicon_url)) {
+ *error = extensions::ErrorUtils::FormatErrorMessageUTF16(
+ manifest_errors::kInvalidSearchEngineURL,
+ *overrides->search_provider->favicon_url);
+ return std::unique_ptr<ChromeSettingsOverrides::Search_provider>();
+ }
+ return std::move(overrides->search_provider);
+}
+
+std::string FormatUrlForDisplay(const GURL& url) {
+ base::StringPiece host = url.host_piece();
+ // A www. prefix is not informative and thus not worth the limited real estate
+ // in the permissions UI.
+ // TODO(catmullings): Ideally, we wouldn't be using custom code to format URLs
+ // here, since we have a number of methods that do that more universally.
+ return base::UTF16ToUTF8(url_formatter::StripWWW(base::UTF8ToUTF16(host)));
+}
+
+} // namespace
+
+SettingsOverrides::SettingsOverrides() {}
+
+SettingsOverrides::~SettingsOverrides() {}
+
+// static
+const SettingsOverrides* SettingsOverrides::Get(
+ const Extension* extension) {
+ return static_cast<SettingsOverrides*>(
+ extension->GetManifestData(manifest_keys::kSettingsOverride));
+}
+
+SettingsOverridesHandler::SettingsOverridesHandler() {}
+
+SettingsOverridesHandler::~SettingsOverridesHandler() {}
+
+bool SettingsOverridesHandler::Parse(Extension* extension,
+ base::string16* error) {
+ const base::Value* dict = NULL;
+ CHECK(extension->manifest()->Get(manifest_keys::kSettingsOverride, &dict));
+ std::unique_ptr<ChromeSettingsOverrides> settings(
+ ChromeSettingsOverrides::FromValue(*dict, error));
+ if (!settings)
+ return false;
+
+ std::unique_ptr<SettingsOverrides> info(new SettingsOverrides);
+ info->homepage = ParseHomepage(*settings, error);
+ info->search_engine = ParseSearchEngine(settings.get(), error);
+ info->startup_pages = ParseStartupPage(*settings, error);
+ if (!info->homepage && !info->search_engine && info->startup_pages.empty()) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ manifest_errors::kInvalidEmptyDictionary,
+ manifest_keys::kSettingsOverride);
+ return false;
+ }
+
+ if (info->search_engine) {
+ PermissionsParser::AddAPIPermission(
+ extension, new SettingsOverrideAPIPermission(
+ PermissionsInfo::GetInstance()->GetByID(
+ APIPermission::kSearchProvider),
+ FormatUrlForDisplay(*CreateManifestURL(
+ info->search_engine->search_url))));
+ }
+ if (!info->startup_pages.empty()) {
+ PermissionsParser::AddAPIPermission(
+ extension,
+ new SettingsOverrideAPIPermission(
+ PermissionsInfo::GetInstance()->GetByID(
+ APIPermission::kStartupPages),
+ // We only support one startup page even though the type of the
+ // manifest property is a list, only the first one is used.
+ FormatUrlForDisplay(info->startup_pages[0])));
+ }
+ if (info->homepage) {
+ PermissionsParser::AddAPIPermission(
+ extension,
+ new SettingsOverrideAPIPermission(
+ PermissionsInfo::GetInstance()->GetByID(APIPermission::kHomepage),
+ FormatUrlForDisplay(*(info->homepage))));
+ }
+ extension->SetManifestData(manifest_keys::kSettingsOverride, std::move(info));
+ return true;
+}
+
+base::span<const char* const> SettingsOverridesHandler::Keys() const {
+ static constexpr const char* kKeys[] = {manifest_keys::kSettingsOverride};
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler.h b/chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler.h
new file mode 100644
index 00000000000..265fb1ecf9f
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_SETTINGS_OVERRIDES_HANDLER_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_SETTINGS_OVERRIDES_HANDLER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "chrome/common/extensions/api/manifest_types.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handler.h"
+
+namespace extensions {
+
+enum SettingsApiOverrideType {
+ BUBBLE_TYPE_HOME_PAGE = 0,
+ BUBBLE_TYPE_SEARCH_ENGINE,
+ BUBBLE_TYPE_STARTUP_PAGES,
+};
+
+// SettingsOverride is associated with "chrome_settings_overrides" manifest key.
+// An extension can add a search engine as default or non-default, overwrite the
+// homepage and append a startup page to the list.
+struct SettingsOverrides : public Extension::ManifestData {
+ SettingsOverrides();
+ ~SettingsOverrides() override;
+
+ static const SettingsOverrides* Get(const Extension* extension);
+
+ std::unique_ptr<api::manifest_types::ChromeSettingsOverrides::Search_provider>
+ search_engine;
+ std::unique_ptr<GURL> homepage;
+ std::vector<GURL> startup_pages;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SettingsOverrides);
+};
+
+class SettingsOverridesHandler : public ManifestHandler {
+ public:
+ SettingsOverridesHandler();
+ ~SettingsOverridesHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+
+ private:
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(SettingsOverridesHandler);
+};
+
+} // namespace extensions
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_SETTINGS_OVERRIDES_HANDLER_H_
diff --git a/chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc b/chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc
new file mode 100644
index 00000000000..1575768051a
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/settings_overrides_handler_unittest.cc
@@ -0,0 +1,202 @@
+// 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 "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
+
+#include <memory>
+
+#include "base/json/json_string_value_serializer.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "components/version_info/version_info.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/features/feature_channel.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_url_handlers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kManifest[] =
+ "{"
+ " \"version\" : \"1.0.0.0\","
+ " \"manifest_version\" : 2,"
+ " \"name\" : \"Test\","
+ " \"chrome_settings_overrides\" : {"
+ " \"homepage\" : \"http://www.homepage.com\","
+ " \"search_provider\" : {"
+ " \"name\" : \"first\","
+ " \"keyword\" : \"firstkey\","
+ " \"search_url\" : \"http://www.foo.com/s?q={searchTerms}\","
+ " \"favicon_url\" : \"http://www.foo.com/favicon.ico\","
+ " \"suggest_url\" : \"http://www.foo.com/s?q={searchTerms}\","
+ " \"encoding\" : \"UTF-8\","
+ " \"is_default\" : true"
+ " },"
+ " \"startup_pages\" : [\"http://www.startup.com\"]"
+ " }"
+ "}";
+
+const char kPrepopulatedManifest[] =
+ "{"
+ " \"version\" : \"1.0.0.0\","
+ " \"manifest_version\" : 2,"
+ " \"name\" : \"Test\","
+ " \"chrome_settings_overrides\" : {"
+ " \"search_provider\" : {"
+ " \"search_url\" : \"http://www.foo.com/s?q={searchTerms}\","
+ " \"prepopulated_id\" : 3,"
+ " \"is_default\" : true"
+ " }"
+ " }"
+ "}";
+
+const char kBrokenManifest[] =
+ "{"
+ " \"version\" : \"1.0.0.0\","
+ " \"manifest_version\" : 2,"
+ " \"name\" : \"Test\","
+ " \"chrome_settings_overrides\" : {"
+ " \"homepage\" : \"{invalid}\","
+ " \"search_provider\" : {"
+ " \"name\" : \"first\","
+ " \"keyword\" : \"firstkey\","
+ " \"search_url\" : \"{invalid}/s?q={searchTerms}\","
+ " \"favicon_url\" : \"{invalid}/favicon.ico\","
+ " \"encoding\" : \"UTF-8\","
+ " \"is_default\" : true"
+ " },"
+ " \"startup_pages\" : [\"{invalid}\"]"
+ " }"
+ "}";
+
+using extensions::api::manifest_types::ChromeSettingsOverrides;
+using extensions::Extension;
+using extensions::Manifest;
+using extensions::SettingsOverrides;
+namespace manifest_keys = extensions::manifest_keys;
+
+TEST(OverrideSettingsTest, ParseManifest) {
+#if defined(OS_MACOSX)
+ // On Mac, this API is limited to trunk.
+ extensions::ScopedCurrentChannel scoped_channel(
+ version_info::Channel::UNKNOWN);
+#endif // OS_MACOSX
+
+ std::string manifest(kManifest);
+ JSONStringValueDeserializer json(manifest);
+ std::string error;
+ std::unique_ptr<base::Value> root(json.Deserialize(NULL, &error));
+ ASSERT_TRUE(root);
+ ASSERT_TRUE(root->is_dict());
+ scoped_refptr<Extension> extension = Extension::Create(
+ base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+ Manifest::INVALID_LOCATION,
+ *static_cast<base::DictionaryValue*>(root.get()),
+ Extension::NO_FLAGS,
+ &error);
+ ASSERT_TRUE(extension.get());
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ ASSERT_TRUE(extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
+
+ SettingsOverrides* settings_override = static_cast<SettingsOverrides*>(
+ extension->GetManifestData(manifest_keys::kSettingsOverride));
+ ASSERT_TRUE(settings_override);
+ ASSERT_TRUE(settings_override->search_engine);
+ EXPECT_TRUE(settings_override->search_engine->is_default);
+ const ChromeSettingsOverrides::Search_provider* search_engine =
+ settings_override->search_engine.get();
+ EXPECT_EQ("first", *search_engine->name);
+ EXPECT_EQ("firstkey", *search_engine->keyword);
+ EXPECT_EQ("http://www.foo.com/s?q={searchTerms}", search_engine->search_url);
+ EXPECT_EQ("http://www.foo.com/favicon.ico", *search_engine->favicon_url);
+ EXPECT_EQ("http://www.foo.com/s?q={searchTerms}",
+ *search_engine->suggest_url);
+ EXPECT_EQ("UTF-8", *search_engine->encoding);
+
+ EXPECT_EQ(std::vector<GURL>(1, GURL("http://www.startup.com")),
+ settings_override->startup_pages);
+
+ ASSERT_TRUE(settings_override->homepage);
+ EXPECT_EQ(GURL("http://www.homepage.com"), *settings_override->homepage);
+#else
+ EXPECT_FALSE(
+ extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
+#endif
+}
+
+TEST(OverrideSettingsTest, ParsePrepopulatedId) {
+#if defined(OS_MACOSX)
+ // On Mac, this API is limited to trunk.
+ extensions::ScopedCurrentChannel scoped_channel(
+ version_info::Channel::UNKNOWN);
+#endif // OS_MACOSX
+
+ std::string manifest(kPrepopulatedManifest);
+ JSONStringValueDeserializer json(manifest);
+ std::string error;
+ std::unique_ptr<base::Value> root(json.Deserialize(NULL, &error));
+ ASSERT_TRUE(root);
+ ASSERT_TRUE(root->is_dict());
+ scoped_refptr<Extension> extension =
+ Extension::Create(base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+ Manifest::INVALID_LOCATION,
+ *static_cast<base::DictionaryValue*>(root.get()),
+ Extension::NO_FLAGS,
+ &error);
+ ASSERT_TRUE(extension.get());
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ ASSERT_TRUE(extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
+
+ SettingsOverrides* settings_override = static_cast<SettingsOverrides*>(
+ extension->GetManifestData(manifest_keys::kSettingsOverride));
+ ASSERT_TRUE(settings_override);
+ ASSERT_TRUE(settings_override->search_engine);
+ EXPECT_TRUE(settings_override->search_engine->is_default);
+ const ChromeSettingsOverrides::Search_provider* search_engine =
+ settings_override->search_engine.get();
+ ASSERT_TRUE(search_engine->prepopulated_id);
+ EXPECT_EQ("http://www.foo.com/s?q={searchTerms}", search_engine->search_url);
+ EXPECT_EQ(3, *search_engine->prepopulated_id);
+#else
+ EXPECT_FALSE(
+ extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
+#endif
+}
+
+TEST(OverrideSettingsTest, ParseBrokenManifest) {
+#if defined(OS_MACOSX)
+ // On Mac, this API is limited to trunk.
+ extensions::ScopedCurrentChannel scoped_channel(
+ version_info::Channel::UNKNOWN);
+#endif // OS_MACOSX
+
+ std::string manifest(kBrokenManifest);
+ JSONStringValueDeserializer json(manifest);
+ std::string error;
+ std::unique_ptr<base::Value> root(json.Deserialize(NULL, &error));
+ ASSERT_TRUE(root);
+ ASSERT_TRUE(root->is_dict());
+ scoped_refptr<Extension> extension = Extension::Create(
+ base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+ Manifest::INVALID_LOCATION,
+ *static_cast<base::DictionaryValue*>(root.get()),
+ Extension::NO_FLAGS,
+ &error);
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ EXPECT_FALSE(extension.get());
+ EXPECT_EQ(
+ extensions::ErrorUtils::FormatErrorMessage(
+ extensions::manifest_errors::kInvalidEmptyDictionary,
+ extensions::manifest_keys::kSettingsOverride),
+ error);
+#else
+ EXPECT_TRUE(extension.get());
+ EXPECT_FALSE(
+ extension->manifest()->HasPath(manifest_keys::kSettingsOverride));
+#endif
+}
+
+} // namespace
diff --git a/chromium/chrome/common/extensions/manifest_handlers/theme_handler.cc b/chromium/chrome/common/extensions/manifest_handlers/theme_handler.cc
new file mode 100644
index 00000000000..327b035e9d3
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/theme_handler.cc
@@ -0,0 +1,224 @@
+// 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 "chrome/common/extensions/manifest_handlers/theme_handler.h"
+
+#include <memory>
+
+#include "base/files/file_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/grit/generated_resources.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+namespace {
+
+bool LoadImages(const base::DictionaryValue* theme_value,
+ base::string16* error,
+ ThemeInfo* theme_info) {
+ const base::DictionaryValue* images_value = NULL;
+ if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) {
+ // Validate that the images are all strings.
+ for (base::DictionaryValue::Iterator iter(*images_value); !iter.IsAtEnd();
+ iter.Advance()) {
+ // The value may be a dictionary of scales and files paths.
+ // Or the value may be a file path, in which case a scale
+ // of 100% is assumed.
+ if (iter.value().is_dict()) {
+ const base::DictionaryValue* inner_value = NULL;
+ if (iter.value().GetAsDictionary(&inner_value)) {
+ for (base::DictionaryValue::Iterator inner_iter(*inner_value);
+ !inner_iter.IsAtEnd(); inner_iter.Advance()) {
+ if (!inner_iter.value().is_string()) {
+ *error = base::ASCIIToUTF16(errors::kInvalidThemeImages);
+ return false;
+ }
+ }
+ } else {
+ *error = base::ASCIIToUTF16(errors::kInvalidThemeImages);
+ return false;
+ }
+ } else if (!iter.value().is_string()) {
+ *error = base::ASCIIToUTF16(errors::kInvalidThemeImages);
+ return false;
+ }
+ }
+ theme_info->theme_images_.reset(images_value->DeepCopy());
+ }
+ return true;
+}
+
+bool LoadColors(const base::DictionaryValue* theme_value,
+ base::string16* error,
+ ThemeInfo* theme_info) {
+ const base::DictionaryValue* colors_value = NULL;
+ if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) {
+ // Validate that the colors are RGB or RGBA lists.
+ for (base::DictionaryValue::Iterator iter(*colors_value); !iter.IsAtEnd();
+ iter.Advance()) {
+ const base::ListValue* color_list = NULL;
+ double alpha = 0.0;
+ int color = 0;
+ // The color must be a list...
+ if (!iter.value().GetAsList(&color_list) ||
+ // ... and either 3 items (RGB) or 4 (RGBA).
+ ((color_list->GetSize() != 3) &&
+ ((color_list->GetSize() != 4) ||
+ // For RGBA, the fourth item must be a real or int alpha value.
+ // Note that GetDouble() can get an integer value.
+ !color_list->GetDouble(3, &alpha))) ||
+ // For both RGB and RGBA, the first three items must be ints (R,G,B).
+ !color_list->GetInteger(0, &color) ||
+ !color_list->GetInteger(1, &color) ||
+ !color_list->GetInteger(2, &color)) {
+ *error = base::ASCIIToUTF16(errors::kInvalidThemeColors);
+ return false;
+ }
+ }
+ theme_info->theme_colors_.reset(colors_value->DeepCopy());
+ }
+ return true;
+}
+
+bool LoadTints(const base::DictionaryValue* theme_value,
+ base::string16* error,
+ ThemeInfo* theme_info) {
+ const base::DictionaryValue* tints_value = NULL;
+ if (!theme_value->GetDictionary(keys::kThemeTints, &tints_value))
+ return true;
+
+ // Validate that the tints are all reals.
+ for (base::DictionaryValue::Iterator iter(*tints_value); !iter.IsAtEnd();
+ iter.Advance()) {
+ const base::ListValue* tint_list = NULL;
+ double v = 0.0;
+ if (!iter.value().GetAsList(&tint_list) ||
+ tint_list->GetSize() != 3 ||
+ !tint_list->GetDouble(0, &v) ||
+ !tint_list->GetDouble(1, &v) ||
+ !tint_list->GetDouble(2, &v)) {
+ *error = base::ASCIIToUTF16(errors::kInvalidThemeTints);
+ return false;
+ }
+ }
+ theme_info->theme_tints_.reset(tints_value->DeepCopy());
+ return true;
+}
+
+bool LoadDisplayProperties(const base::DictionaryValue* theme_value,
+ base::string16* error,
+ ThemeInfo* theme_info) {
+ const base::DictionaryValue* display_properties_value = NULL;
+ if (theme_value->GetDictionary(keys::kThemeDisplayProperties,
+ &display_properties_value)) {
+ theme_info->theme_display_properties_.reset(
+ display_properties_value->DeepCopy());
+ }
+ return true;
+}
+
+const ThemeInfo* GetInfo(const Extension* extension) {
+ return static_cast<ThemeInfo*>(extension->GetManifestData(keys::kTheme));
+}
+
+} // namespace
+
+ThemeInfo::ThemeInfo() {
+}
+
+ThemeInfo::~ThemeInfo() {
+}
+
+// static
+const base::DictionaryValue* ThemeInfo::GetImages(const Extension* extension) {
+ const ThemeInfo* theme_info = GetInfo(extension);
+ return theme_info ? theme_info->theme_images_.get() : NULL;
+}
+
+// static
+const base::DictionaryValue* ThemeInfo::GetColors(const Extension* extension) {
+ const ThemeInfo* theme_info = GetInfo(extension);
+ return theme_info ? theme_info->theme_colors_.get() : NULL;
+}
+
+// static
+const base::DictionaryValue* ThemeInfo::GetTints(const Extension* extension) {
+ const ThemeInfo* theme_info = GetInfo(extension);
+ return theme_info ? theme_info->theme_tints_.get() : NULL;
+}
+
+// static
+const base::DictionaryValue* ThemeInfo::GetDisplayProperties(
+ const Extension* extension) {
+ const ThemeInfo* theme_info = GetInfo(extension);
+ return theme_info ? theme_info->theme_display_properties_.get() : NULL;
+}
+
+ThemeHandler::ThemeHandler() {
+}
+
+ThemeHandler::~ThemeHandler() {
+}
+
+bool ThemeHandler::Parse(Extension* extension, base::string16* error) {
+ const base::DictionaryValue* theme_value = NULL;
+ if (!extension->manifest()->GetDictionary(keys::kTheme, &theme_value)) {
+ *error = base::ASCIIToUTF16(errors::kInvalidTheme);
+ return false;
+ }
+
+ std::unique_ptr<ThemeInfo> theme_info(new ThemeInfo);
+ if (!LoadImages(theme_value, error, theme_info.get()))
+ return false;
+ if (!LoadColors(theme_value, error, theme_info.get()))
+ return false;
+ if (!LoadTints(theme_value, error, theme_info.get()))
+ return false;
+ if (!LoadDisplayProperties(theme_value, error, theme_info.get()))
+ return false;
+
+ extension->SetManifestData(keys::kTheme, std::move(theme_info));
+ return true;
+}
+
+bool ThemeHandler::Validate(const Extension* extension,
+ std::string* error,
+ std::vector<InstallWarning>* warnings) const {
+ // Validate that theme images exist.
+ if (extension->is_theme()) {
+ const base::DictionaryValue* images_value =
+ extensions::ThemeInfo::GetImages(extension);
+ if (images_value) {
+ for (base::DictionaryValue::Iterator iter(*images_value); !iter.IsAtEnd();
+ iter.Advance()) {
+ std::string val;
+ if (iter.value().GetAsString(&val)) {
+ base::FilePath image_path = extension->path().Append(
+ base::FilePath::FromUTF8Unsafe(val));
+ if (!base::PathExists(image_path)) {
+ *error =
+ l10n_util::GetStringFUTF8(IDS_EXTENSION_INVALID_IMAGE_PATH,
+ image_path.LossyDisplayName());
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+base::span<const char* const> ThemeHandler::Keys() const {
+ static constexpr const char* kKeys[] = {keys::kTheme};
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/theme_handler.h b/chromium/chrome/common/extensions/manifest_handlers/theme_handler.h
new file mode 100644
index 00000000000..7f1b3f35c68
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/theme_handler.h
@@ -0,0 +1,64 @@
+// 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 CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_THEME_HANDLER_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_THEME_HANDLER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handler.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+namespace extensions {
+
+// A structure to hold the parsed theme data.
+struct ThemeInfo : public Extension::ManifestData {
+ // Define out of line constructor/destructor to please Clang.
+ ThemeInfo();
+ ~ThemeInfo() override;
+
+ static const base::DictionaryValue* GetImages(const Extension* extension);
+ static const base::DictionaryValue* GetColors(const Extension* extension);
+ static const base::DictionaryValue* GetTints(const Extension* extension);
+ static const base::DictionaryValue* GetDisplayProperties(
+ const Extension* extension);
+
+ // A map of resource id's to relative file paths.
+ std::unique_ptr<base::DictionaryValue> theme_images_;
+
+ // A map of color names to colors.
+ std::unique_ptr<base::DictionaryValue> theme_colors_;
+
+ // A map of color names to colors.
+ std::unique_ptr<base::DictionaryValue> theme_tints_;
+
+ // A map of display properties.
+ std::unique_ptr<base::DictionaryValue> theme_display_properties_;
+};
+
+// Parses the "theme" manifest key.
+class ThemeHandler : public ManifestHandler {
+ public:
+ ThemeHandler();
+ ~ThemeHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+ bool Validate(const Extension* extension,
+ std::string* error,
+ std::vector<InstallWarning>* warnings) const override;
+
+ private:
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(ThemeHandler);
+};
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_THEME_HANDLER_H_
diff --git a/chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler.cc b/chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler.cc
new file mode 100644
index 00000000000..51c6303f21e
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler.cc
@@ -0,0 +1,181 @@
+// 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 "chrome/common/extensions/manifest_handlers/ui_overrides_handler.h"
+
+#include <memory>
+
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/grit/generated_resources.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/feature_switch.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/manifest_permission.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/common/permissions/permissions_info.h"
+#include "ipc/ipc_message.h"
+
+using extensions::api::manifest_types::ChromeUIOverrides;
+
+namespace extensions {
+
+// The manifest permission implementation supports a permission for overriding
+// the bookmark UI.
+class UIOverridesHandler::ManifestPermissionImpl : public ManifestPermission {
+ public:
+ explicit ManifestPermissionImpl(bool override_bookmarks_ui_permission)
+ : override_bookmarks_ui_permission_(override_bookmarks_ui_permission) {}
+
+ // extensions::ManifestPermission overrides.
+ std::string name() const override { return manifest_keys::kUIOverride; }
+
+ std::string id() const override { return name(); }
+
+ PermissionIDSet GetPermissions() const override {
+ PermissionIDSet permissions;
+ if (override_bookmarks_ui_permission_) {
+ // TODO(sashab): Add rule to ChromePermissionMessageProvider:
+ // kOverrideBookmarksUI ->
+ // IDS_EXTENSION_PROMPT_WARNING_OVERRIDE_BOOKMARKS_UI
+ permissions.insert(APIPermission::kOverrideBookmarksUI);
+ }
+ return permissions;
+ }
+
+ bool FromValue(const base::Value* value) override {
+ return value && value->GetAsBoolean(&override_bookmarks_ui_permission_);
+ }
+
+ std::unique_ptr<base::Value> ToValue() const override {
+ return std::unique_ptr<base::Value>(
+ new base::Value(override_bookmarks_ui_permission_));
+ }
+
+ std::unique_ptr<ManifestPermission> Diff(
+ const ManifestPermission* rhs) const override {
+ const ManifestPermissionImpl* other =
+ static_cast<const ManifestPermissionImpl*>(rhs);
+
+ return std::make_unique<ManifestPermissionImpl>(
+ override_bookmarks_ui_permission_ &&
+ !other->override_bookmarks_ui_permission_);
+ }
+
+ std::unique_ptr<ManifestPermission> Union(
+ const ManifestPermission* rhs) const override {
+ const ManifestPermissionImpl* other =
+ static_cast<const ManifestPermissionImpl*>(rhs);
+
+ return std::make_unique<ManifestPermissionImpl>(
+ override_bookmarks_ui_permission_ ||
+ other->override_bookmarks_ui_permission_);
+ }
+
+ std::unique_ptr<ManifestPermission> Intersect(
+ const ManifestPermission* rhs) const override {
+ const ManifestPermissionImpl* other =
+ static_cast<const ManifestPermissionImpl*>(rhs);
+
+ return std::make_unique<ManifestPermissionImpl>(
+ override_bookmarks_ui_permission_ &&
+ other->override_bookmarks_ui_permission_);
+ }
+
+ private:
+ bool override_bookmarks_ui_permission_;
+};
+
+UIOverrides::UIOverrides() {}
+
+UIOverrides::~UIOverrides() {}
+
+const UIOverrides* UIOverrides::Get(const Extension* extension) {
+ return static_cast<UIOverrides*>(
+ extension->GetManifestData(manifest_keys::kUIOverride));
+}
+
+bool UIOverrides::RemovesBookmarkButton(const Extension* extension) {
+ const UIOverrides* ui_overrides = Get(extension);
+ return ui_overrides && ui_overrides->bookmarks_ui &&
+ ui_overrides->bookmarks_ui->remove_button &&
+ *ui_overrides->bookmarks_ui->remove_button;
+}
+
+bool UIOverrides::RemovesBookmarkShortcut(const Extension* extension) {
+ const UIOverrides* ui_overrides = Get(extension);
+ return ui_overrides && ui_overrides->bookmarks_ui &&
+ ui_overrides->bookmarks_ui->remove_bookmark_shortcut &&
+ *ui_overrides->bookmarks_ui->remove_bookmark_shortcut;
+}
+
+bool UIOverrides::RemovesBookmarkAllTabsShortcut(const Extension* extension) {
+ const UIOverrides* ui_overrides = Get(extension);
+ return ui_overrides && ui_overrides->bookmarks_ui &&
+ ui_overrides->bookmarks_ui->remove_bookmark_open_pages_shortcut &&
+ *ui_overrides->bookmarks_ui->remove_bookmark_open_pages_shortcut;
+}
+
+UIOverridesHandler::UIOverridesHandler() {}
+
+UIOverridesHandler::~UIOverridesHandler() {}
+
+bool UIOverridesHandler::Parse(Extension* extension, base::string16* error) {
+ const base::Value* dict = NULL;
+ CHECK(extension->manifest()->Get(manifest_keys::kUIOverride, &dict));
+ std::unique_ptr<ChromeUIOverrides> overrides(
+ ChromeUIOverrides::FromValue(*dict, error));
+ if (!overrides)
+ return false;
+
+ std::unique_ptr<UIOverrides> info(new UIOverrides);
+ info->bookmarks_ui.swap(overrides->bookmarks_ui);
+ if (!info->bookmarks_ui) {
+ *error = ErrorUtils::FormatErrorMessageUTF16(
+ manifest_errors::kInvalidEmptyDictionary,
+ manifest_keys::kUIOverride);
+ return false;
+ }
+ info->manifest_permission.reset(new ManifestPermissionImpl(
+ info->bookmarks_ui.get() != NULL));
+ extension->SetManifestData(manifest_keys::kUIOverride, std::move(info));
+ return true;
+}
+
+bool UIOverridesHandler::Validate(const Extension* extension,
+ std::string* error,
+ std::vector<InstallWarning>* warnings) const {
+ const UIOverrides* ui_overrides = UIOverrides::Get(extension);
+
+ if (ui_overrides && ui_overrides->bookmarks_ui) {
+ if (!FeatureSwitch::enable_override_bookmarks_ui()->IsEnabled()) {
+ warnings->push_back(InstallWarning(
+ ErrorUtils::FormatErrorMessage(
+ manifest_errors::kUnrecognizedManifestProperty,
+ manifest_keys::kBookmarkUI,
+ manifest_keys::kUIOverride)));
+ }
+ }
+
+ return true;
+}
+
+ManifestPermission* UIOverridesHandler::CreatePermission() {
+ return new ManifestPermissionImpl(false);
+}
+
+ManifestPermission* UIOverridesHandler::CreateInitialRequiredPermission(
+ const Extension* extension) {
+ const UIOverrides* data = UIOverrides::Get(extension);
+ if (data)
+ return data->manifest_permission->Clone().release();
+ return NULL;
+}
+base::span<const char* const> UIOverridesHandler::Keys() const {
+ static constexpr const char* kKeys[] = {manifest_keys::kUIOverride};
+ return kKeys;
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler.h b/chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler.h
new file mode 100644
index 00000000000..c9cbe44cbb3
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler.h
@@ -0,0 +1,64 @@
+// 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 CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_UI_OVERRIDES_HANDLER_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_UI_OVERRIDES_HANDLER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "chrome/common/extensions/api/manifest_types.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handler.h"
+
+namespace extensions {
+
+class ManifestPermission;
+
+// UIOverrides is associated with "chrome_ui_overrides" manifest key, and
+// represents manifest settings to override aspects of the Chrome user
+// interface.
+struct UIOverrides : public Extension::ManifestData {
+ UIOverrides();
+ ~UIOverrides() override;
+
+ static const UIOverrides* Get(const Extension* extension);
+
+ static bool RemovesBookmarkButton(const Extension* extension);
+ static bool RemovesBookmarkShortcut(const Extension* extension);
+ static bool RemovesBookmarkAllTabsShortcut(const Extension* extension);
+
+ std::unique_ptr<api::manifest_types::ChromeUIOverrides::Bookmarks_ui>
+ bookmarks_ui;
+
+ std::unique_ptr<ManifestPermission> manifest_permission;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(UIOverrides);
+};
+
+class UIOverridesHandler : public ManifestHandler {
+ public:
+ UIOverridesHandler();
+ ~UIOverridesHandler() override;
+
+ bool Parse(Extension* extension, base::string16* error) override;
+ bool Validate(const Extension* extension,
+ std::string* error,
+ std::vector<InstallWarning>* warnings) const override;
+
+ ManifestPermission* CreatePermission() override;
+ ManifestPermission* CreateInitialRequiredPermission(
+ const Extension* extension) override;
+
+ private:
+ class ManifestPermissionImpl;
+
+ base::span<const char* const> Keys() const override;
+
+ DISALLOW_COPY_AND_ASSIGN(UIOverridesHandler);
+};
+
+} // namespace extensions
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_UI_OVERRIDES_HANDLER_H_
diff --git a/chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler_unittest.cc b/chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler_unittest.cc
new file mode 100644
index 00000000000..4ed61a42315
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_handlers/ui_overrides_handler_unittest.cc
@@ -0,0 +1,107 @@
+// 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 "chrome/common/extensions/manifest_handlers/ui_overrides_handler.h"
+
+#include <memory>
+
+#include "base/command_line.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/version_info/version_info.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/features/feature_channel.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_url_handlers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kManifest[] =
+ "{"
+ " \"version\" : \"1.0.0.0\","
+ " \"manifest_version\" : 2,"
+ " \"name\" : \"Test\","
+ " \"chrome_ui_overrides\" : {"
+ " \"bookmarks_ui\" : {"
+ " \"remove_button\" : true,"
+ " \"remove_bookmark_shortcut\" : true"
+ " }"
+ " }"
+ "}";
+
+const char kBrokenManifest[] =
+ "{"
+ " \"version\" : \"1.0.0.0\","
+ " \"manifest_version\" : 2,"
+ " \"name\" : \"Test\","
+ " \"chrome_ui_overrides\" : {"
+ " }"
+ "}";
+
+using extensions::api::manifest_types::ChromeUIOverrides;
+using extensions::Extension;
+using extensions::Manifest;
+using extensions::UIOverrides;
+namespace manifest_keys = extensions::manifest_keys;
+
+class UIOverrideTest : public testing::Test {
+};
+
+
+TEST_F(UIOverrideTest, ParseManifest) {
+ extensions::ScopedCurrentChannel channel(version_info::Channel::DEV);
+ // This functionality requires a feature flag.
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ "--enable-override-bookmarks-ui", "1");
+ std::string manifest(kManifest);
+ JSONStringValueDeserializer json(manifest);
+ std::string error;
+ std::unique_ptr<base::Value> root(json.Deserialize(NULL, &error));
+ ASSERT_TRUE(root);
+ ASSERT_TRUE(root->is_dict());
+ scoped_refptr<Extension> extension = Extension::Create(
+ base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+ Manifest::INVALID_LOCATION,
+ *static_cast<base::DictionaryValue*>(root.get()),
+ Extension::NO_FLAGS,
+ &error);
+ ASSERT_TRUE(extension.get()) << error;
+ ASSERT_TRUE(extension->manifest()->HasPath(manifest_keys::kUIOverride));
+
+ UIOverrides* ui_override = static_cast<UIOverrides*>(
+ extension->GetManifestData(manifest_keys::kUIOverride));
+ ASSERT_TRUE(ui_override);
+ ASSERT_TRUE(ui_override->bookmarks_ui);
+ EXPECT_TRUE(ui_override->bookmarks_ui->remove_button);
+ EXPECT_TRUE(ui_override->bookmarks_ui->remove_bookmark_shortcut);
+}
+
+TEST_F(UIOverrideTest, ParseBrokenManifest) {
+ extensions::ScopedCurrentChannel channel(version_info::Channel::DEV);
+ // This functionality requires a feature flag.
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ "--enable-override-bookmarks-ui", "1");
+ std::string manifest(kBrokenManifest);
+ JSONStringValueDeserializer json(manifest);
+ std::string error;
+ std::unique_ptr<base::Value> root(json.Deserialize(NULL, &error));
+ ASSERT_TRUE(root);
+ ASSERT_TRUE(root->is_dict());
+ scoped_refptr<Extension> extension = Extension::Create(
+ base::FilePath(FILE_PATH_LITERAL("//nonexistent")),
+ Manifest::INVALID_LOCATION,
+ *static_cast<base::DictionaryValue*>(root.get()),
+ Extension::NO_FLAGS,
+ &error);
+ EXPECT_FALSE(extension.get());
+ EXPECT_EQ(
+ extensions::ErrorUtils::FormatErrorMessage(
+ extensions::manifest_errors::kInvalidEmptyDictionary,
+ extensions::manifest_keys::kUIOverride),
+ error);
+}
+
+} // namespace
diff --git a/chromium/chrome/common/extensions/manifest_tests/chrome_manifest_test.cc b/chromium/chrome/common/extensions/manifest_tests/chrome_manifest_test.cc
new file mode 100644
index 00000000000..656b54a7e8e
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/chrome_manifest_test.cc
@@ -0,0 +1,23 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_paths.h"
+#include "components/version_info/version_info.h"
+
+ChromeManifestTest::ChromeManifestTest()
+ // CHANNEL_UNKNOWN == trunk.
+ : current_channel_(version_info::Channel::UNKNOWN) {}
+
+ChromeManifestTest::~ChromeManifestTest() {
+}
+
+base::FilePath ChromeManifestTest::GetTestDataDir() {
+ base::FilePath path;
+ base::PathService::Get(chrome::DIR_TEST_DATA, &path);
+ return path.AppendASCII("extensions").AppendASCII("manifest_tests");
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/chrome_manifest_test.h b/chromium/chrome/common/extensions/manifest_tests/chrome_manifest_test.h
new file mode 100644
index 00000000000..bfcd99b40fd
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/chrome_manifest_test.h
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_MANIFEST_TESTS_CHROME_MANIFEST_TEST_H_
+#define CHROME_COMMON_EXTENSIONS_MANIFEST_TESTS_CHROME_MANIFEST_TEST_H_
+
+#include "base/macros.h"
+#include "extensions/common/features/feature_channel.h"
+#include "extensions/common/manifest_test.h"
+
+// Base class for unit tests that load manifest data from Chrome TEST_DATA_DIR.
+// TODO(jamescook): Move this class and all subclasses into the extensions
+// namespace.
+class ChromeManifestTest : public extensions::ManifestTest {
+ public:
+ ChromeManifestTest();
+ ~ChromeManifestTest() override;
+
+ // ManifestTest overrides:
+ base::FilePath GetTestDataDir() override;
+
+ private:
+ // Force the manifest tests to run as though they are on trunk, since several
+ // tests rely on manifest features being available that aren't on
+ // stable/beta.
+ //
+ // These objects nest, so if a test wants to explicitly test the behaviour
+ // on stable or beta, declare it inside that test.
+ extensions::ScopedCurrentChannel current_channel_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeManifestTest);
+};
+
+#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_TESTS_CHROME_MANIFEST_TEST_H_
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_about_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_about_unittest.cc
new file mode 100644
index 00000000000..88b89ddf3d0
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_about_unittest.cc
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/stl_util.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_url_handlers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace errors = extensions::manifest_errors;
+
+class AboutPageManifestTest : public ChromeManifestTest {};
+
+TEST_F(AboutPageManifestTest, AboutPageInSharedModules) {
+ scoped_refptr<extensions::Extension> extension;
+ extension = LoadAndExpectSuccess("shared_module_about.json");
+ EXPECT_EQ(GURL("chrome-extension://" + extension->id() + "/about.html"),
+ extensions::ManifestURL::GetAboutPage(extension.get()));
+
+ Testcase testcases[] = {
+ // Forbid data types other than strings.
+ Testcase("shared_module_about_invalid_type.json",
+ errors::kInvalidAboutPage),
+
+ // Forbid absolute URLs.
+ Testcase("shared_module_about_absolute.json",
+ errors::kInvalidAboutPageExpectRelativePath)};
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_background_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_background_unittest.cc
new file mode 100644
index 00000000000..5009ec2535f
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_background_unittest.cc
@@ -0,0 +1,261 @@
+// 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/command_line.h"
+#include "base/test/values_test_util.h"
+#include "base/values.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "components/version_info/version_info.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/features/feature_channel.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/background_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace errors = manifest_errors;
+namespace keys = manifest_keys;
+
+class ExtensionManifestBackgroundTest : public ChromeManifestTest {
+};
+
+// TODO(devlin): Can this file move to //extensions?
+
+TEST_F(ExtensionManifestBackgroundTest, BackgroundPermission) {
+ LoadAndExpectError("background_permission.json",
+ errors::kBackgroundPermissionNeeded);
+}
+
+TEST_F(ExtensionManifestBackgroundTest, BackgroundScripts) {
+ std::string error;
+ base::Value manifest = LoadManifest("background_scripts.json", &error);
+ ASSERT_TRUE(manifest.is_dict());
+
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess(ManifestData(&manifest, "")));
+ ASSERT_TRUE(extension.get());
+ const std::vector<std::string>& background_scripts =
+ BackgroundInfo::GetBackgroundScripts(extension.get());
+ ASSERT_EQ(2u, background_scripts.size());
+ EXPECT_EQ("foo.js", background_scripts[0u]);
+ EXPECT_EQ("bar/baz.js", background_scripts[1u]);
+
+ EXPECT_TRUE(BackgroundInfo::HasBackgroundPage(extension.get()));
+ EXPECT_EQ(
+ std::string("/") + kGeneratedBackgroundPageFilename,
+ BackgroundInfo::GetBackgroundURL(extension.get()).path());
+
+ manifest.SetPath({"background", "page"}, base::Value("monkey.html"));
+ LoadAndExpectError(ManifestData(&manifest, ""),
+ errors::kInvalidBackgroundCombination);
+}
+
+TEST_F(ExtensionManifestBackgroundTest, BackgroundPage) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("background_page.json"));
+ ASSERT_TRUE(extension.get());
+ EXPECT_EQ("/foo.html",
+ BackgroundInfo::GetBackgroundURL(extension.get()).path());
+ EXPECT_TRUE(BackgroundInfo::AllowJSAccess(extension.get()));
+}
+
+TEST_F(ExtensionManifestBackgroundTest, BackgroundAllowNoJsAccess) {
+ scoped_refptr<Extension> extension;
+ extension = LoadAndExpectSuccess("background_allow_no_js_access.json");
+ ASSERT_TRUE(extension.get());
+ EXPECT_FALSE(BackgroundInfo::AllowJSAccess(extension.get()));
+
+ extension = LoadAndExpectSuccess("background_allow_no_js_access2.json");
+ ASSERT_TRUE(extension.get());
+ EXPECT_FALSE(BackgroundInfo::AllowJSAccess(extension.get()));
+}
+
+TEST_F(ExtensionManifestBackgroundTest, BackgroundPageWebRequest) {
+ ScopedCurrentChannel current_channel(version_info::Channel::DEV);
+
+ std::string error;
+ base::Value manifest = LoadManifest("background_page.json", &error);
+ ASSERT_FALSE(manifest.is_none());
+ manifest.SetPath({"background", "persistent"}, base::Value(false));
+ manifest.SetKey(keys::kManifestVersion, base::Value(2));
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess(ManifestData(&manifest, "")));
+ ASSERT_TRUE(extension.get());
+ EXPECT_TRUE(BackgroundInfo::HasLazyBackgroundPage(extension.get()));
+
+ base::Value permissions(base::Value::Type::LIST);
+ permissions.Append(base::Value("webRequest"));
+ manifest.SetKey(keys::kPermissions, std::move(permissions));
+ LoadAndExpectError(ManifestData(&manifest, ""),
+ errors::kWebRequestConflictsWithLazyBackground);
+}
+
+TEST_F(ExtensionManifestBackgroundTest, BackgroundPageTransientBackground) {
+ ScopedCurrentChannel current_channel(version_info::Channel::DEV);
+
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess(ManifestData(base::test::ParseJson(R"(
+ {
+ "name": "test",
+ "manifest_version": 2,
+ "version": "1",
+ "background": {
+ "page": "foo.html"
+ }
+ })"),
+ "")));
+ ASSERT_TRUE(extension.get());
+ EXPECT_TRUE(BackgroundInfo::HasPersistentBackgroundPage(extension.get()));
+
+ LoadAndExpectError(
+ ManifestData(base::test::ParseJson(R"(
+ {
+ "name": "test",
+ "manifest_version": 2,
+ "version": "1",
+ "permissions": [
+ "transientBackground"
+ ],
+ "background": {
+ "page": "foo.html"
+ }
+ })"),
+ ""),
+ errors::kTransientBackgroundConflictsWithPersistentBackground);
+}
+
+TEST_F(ExtensionManifestBackgroundTest, BackgroundPagePersistentPlatformApp) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("background_page_persistent_app.json");
+ ASSERT_TRUE(extension->is_platform_app());
+ ASSERT_TRUE(BackgroundInfo::HasBackgroundPage(extension.get()));
+ EXPECT_FALSE(BackgroundInfo::HasPersistentBackgroundPage(extension.get()));
+
+ std::string error;
+ std::vector<InstallWarning> warnings;
+ ManifestHandler::ValidateExtension(extension.get(), &error, &warnings);
+ // Persistent background pages are not supported for packaged apps.
+ // The persistent flag is ignored and a warining is printed.
+ EXPECT_EQ(1U, warnings.size());
+ EXPECT_EQ(errors::kInvalidBackgroundPersistentInPlatformApp,
+ warnings[0].message);
+}
+
+TEST_F(ExtensionManifestBackgroundTest, BackgroundPagePersistentInvalidKey) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("background_page_invalid_persistent_key_app.json");
+ ASSERT_TRUE(extension->is_platform_app());
+ ASSERT_TRUE(BackgroundInfo::HasBackgroundPage(extension.get()));
+ EXPECT_FALSE(BackgroundInfo::HasPersistentBackgroundPage(extension.get()));
+
+ std::string error;
+ std::vector<InstallWarning> warnings;
+ ManifestHandler::ValidateExtension(extension.get(), &error, &warnings);
+ // The key 'background.persistent' is not supported for packaged apps.
+ EXPECT_EQ(1U, warnings.size());
+ EXPECT_EQ(errors::kBackgroundPersistentInvalidForPlatformApps,
+ warnings[0].message);
+}
+
+// Tests channel restriction on "background.service_worker" key.
+TEST_F(ExtensionManifestBackgroundTest, ServiceWorkerBasedBackgroundKey) {
+ // TODO(lazyboy): Add exhaustive tests here, e.g.
+ // - specifying a non-existent file.
+ // - specifying multiple files.
+ // - specifying invalid type (non-string) values.
+ {
+ ScopedCurrentChannel dev(version_info::Channel::DEV);
+ scoped_refptr<Extension> extension =
+ LoadAndExpectWarning("service_worker_based_background.json",
+ "'background.service_worker' requires canary "
+ "channel or newer, but this is the dev channel.");
+ }
+ {
+ ScopedCurrentChannel canary(version_info::Channel::CANARY);
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("service_worker_based_background.json");
+ }
+ {
+ ScopedCurrentChannel trunk(version_info::Channel::UNKNOWN);
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("service_worker_based_background.json");
+ }
+}
+
+TEST_F(ExtensionManifestBackgroundTest, ManifestV3Restrictions) {
+ auto get_expected_error = [](base::StringPiece key) {
+ return ErrorUtils::FormatErrorMessage(
+ errors::kBackgroundSpecificationInvalidForManifestV3, key);
+ };
+
+ {
+ constexpr char kManifestBackgroundPage[] =
+ R"({
+ "name": "MV3 Test",
+ "manifest_version": 3,
+ "version": "0.1",
+ "background": {
+ "page": "background.html"
+ }
+ })";
+ base::Value manifest_value = base::test::ParseJson(kManifestBackgroundPage);
+ LoadAndExpectError(
+ ManifestData(std::move(manifest_value), "background page"),
+ get_expected_error(keys::kBackgroundPage));
+ }
+ {
+ constexpr char kManifestBackgroundScripts[] =
+ R"({
+ "name": "MV3 Test",
+ "manifest_version": 3,
+ "version": "0.1",
+ "background": {
+ "scripts": ["background.js"]
+ }
+ })";
+ base::Value manifest_value =
+ base::test::ParseJson(kManifestBackgroundScripts);
+ LoadAndExpectError(
+ ManifestData(std::move(manifest_value), "background scripts"),
+ get_expected_error(keys::kBackgroundScripts));
+ }
+ {
+ constexpr char kManifestBackgroundPersistent[] =
+ R"({
+ "name": "MV3 Test",
+ "manifest_version": 3,
+ "version": "0.1",
+ "background": {
+ "service_worker": "worker.js",
+ "persistent": true
+ }
+ })";
+ base::Value manifest_value =
+ base::test::ParseJson(kManifestBackgroundPersistent);
+ LoadAndExpectError(
+ ManifestData(std::move(manifest_value), "persistent background"),
+ get_expected_error(keys::kBackgroundPersistent));
+ }
+ {
+ // An extension with no background key present should still be allowed.
+ constexpr char kManifestBackgroundPersistent[] =
+ R"({
+ "name": "MV3 Test",
+ "manifest_version": 3,
+ "version": "0.1"
+ })";
+ base::Value manifest_value =
+ base::test::ParseJson(kManifestBackgroundPersistent);
+ LoadAndExpectSuccess(
+ ManifestData(std::move(manifest_value), "no background"));
+ }
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_chromepermission_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_chromepermission_unittest.cc
new file mode 100644
index 00000000000..60568eb3a38
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_chromepermission_unittest.cc
@@ -0,0 +1,58 @@
+// 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 "base/command_line.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "chrome/common/url_constants.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/common/switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace errors = manifest_errors;
+
+typedef ChromeManifestTest ChromePermissionManifestTest;
+
+TEST_F(ChromePermissionManifestTest, ChromeURLPermissionInvalid) {
+ LoadAndExpectWarning("permission_chrome_url_invalid.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidPermissionScheme,
+ chrome::kChromeUINewTabURL));
+}
+
+TEST_F(ChromePermissionManifestTest, ChromeURLPermissionAllowedWithFlag) {
+ // Ignore the policy delegate for this test.
+ PermissionsData::SetPolicyDelegate(NULL);
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kExtensionsOnChromeURLs);
+ std::string error;
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("permission_chrome_url_invalid.json");
+ EXPECT_EQ("", error);
+ const GURL newtab_url(chrome::kChromeUINewTabURL);
+ EXPECT_TRUE(
+ extension->permissions_data()->CanAccessPage(newtab_url, 0, &error))
+ << error;
+}
+
+TEST_F(ChromePermissionManifestTest,
+ ChromeResourcesPermissionValidOnlyForComponents) {
+ LoadAndExpectWarning("permission_chrome_resources_url.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidPermissionScheme,
+ "chrome://resources/"));
+ std::string error;
+ LoadExtension(ManifestData("permission_chrome_resources_url.json"),
+ &error,
+ extensions::Manifest::COMPONENT,
+ Extension::NO_FLAGS);
+ EXPECT_EQ("", error);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_contentsecuritypolicy_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_contentsecuritypolicy_unittest.cc
new file mode 100644
index 00000000000..680a8ca11be
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_contentsecuritypolicy_unittest.cc
@@ -0,0 +1,35 @@
+// 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 "base/stl_util.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace errors = extensions::manifest_errors;
+namespace keys = extensions::manifest_keys;
+using extensions::ErrorUtils;
+
+class ContentSecurityPolicyManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(ContentSecurityPolicyManifestTest, InsecureContentSecurityPolicy) {
+ Testcase testcases[] = {
+ Testcase("insecure_contentsecuritypolicy_1.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidCSPInsecureValueIgnored,
+ keys::kContentSecurityPolicy, "http://example.com",
+ "script-src")),
+ Testcase(
+ "insecure_contentsecuritypolicy_2.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidCSPInsecureValueIgnored,
+ keys::kContentSecurityPolicy, "'unsafe-inline'", "script-src")),
+ Testcase("insecure_contentsecuritypolicy_3.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidCSPMissingSecureSrc,
+ keys::kContentSecurityPolicy, "object-src"))};
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_WARNING);
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_default_extent_path_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_default_extent_path_unittest.cc
new file mode 100644
index 00000000000..9d2a9bb58cf
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_default_extent_path_unittest.cc
@@ -0,0 +1,17 @@
+// 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 "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/extension.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST_F(ChromeManifestTest, DefaultPathForExtent) {
+ scoped_refptr<extensions::Extension> extension(
+ LoadAndExpectSuccess("default_path_for_extent.json"));
+
+ ASSERT_EQ(1u, extension->web_extent().patterns().size());
+ EXPECT_EQ("/*", extension->web_extent().patterns().begin()->path());
+ EXPECT_TRUE(extension->web_extent().MatchesURL(
+ GURL("http://www.google.com/monkey")));
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_devtools_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_devtools_unittest.cc
new file mode 100644
index 00000000000..427c04d370e
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_devtools_unittest.cc
@@ -0,0 +1,25 @@
+// 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 "chrome/common/extensions/chrome_manifest_url_handlers.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class DevToolsPageManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(DevToolsPageManifestTest, DevToolsExtensions) {
+ LoadAndExpectError("devtools_extension_url_invalid_type.json",
+ extensions::manifest_errors::kInvalidDevToolsPage);
+
+ scoped_refptr<extensions::Extension> extension;
+ extension = LoadAndExpectSuccess("devtools_extension.json");
+ EXPECT_EQ(extension->url().spec() + "devtools.html",
+ extensions::chrome_manifest_urls::GetDevToolsPage(extension.get())
+ .spec());
+ EXPECT_TRUE(extension->permissions_data()->HasEffectiveAccessToAllHosts());
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_dummy_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_dummy_unittest.cc
new file mode 100644
index 00000000000..afc1392fcf7
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_dummy_unittest.cc
@@ -0,0 +1,27 @@
+// 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 "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+
+namespace extensions {
+
+TEST_F(ChromeManifestTest, PlatformsKey) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("platforms_key.json");
+ EXPECT_EQ(0u, extension->install_warnings().size());
+}
+
+TEST_F(ChromeManifestTest, UnrecognizedKeyWarning) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectWarning("unrecognized_key.json",
+ "Unrecognized manifest key 'unrecognized_key_1'.");
+}
+
+// Tests that using the deprecated "plugins" key causes an install warning.
+TEST_F(ChromeManifestTest, DeprecatedPluginsKey) {
+ LoadAndExpectWarning("deprecated_plugins_key.json",
+ "Unrecognized manifest key 'plugins'.");
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_experimental_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_experimental_unittest.cc
new file mode 100644
index 00000000000..39ff3286e3b
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_experimental_unittest.cc
@@ -0,0 +1,27 @@
+// 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 "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+
+#include "base/command_line.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace errors = extensions::manifest_errors;
+
+TEST_F(ChromeManifestTest, ExperimentalPermission) {
+ LoadAndExpectWarning(
+ "experimental.json",
+ "'experimental' requires the 'experimental-extension-apis' "
+ "command line switch to be enabled.");
+ LoadAndExpectSuccess("experimental.json", extensions::Manifest::COMPONENT);
+ LoadAndExpectSuccess("experimental.json", extensions::Manifest::INTERNAL,
+ extensions::Extension::FROM_WEBSTORE);
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ extensions::switches::kEnableExperimentalExtensionApis);
+ LoadAndExpectSuccess("experimental.json");
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_homepage_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_homepage_unittest.cc
new file mode 100644
index 00000000000..7bc29b6b11d
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_homepage_unittest.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 "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_url_handlers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace errors = extensions::manifest_errors;
+
+class HomepageURLManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(HomepageURLManifestTest, ParseHomepageURLs) {
+ scoped_refptr<extensions::Extension> extension(
+ LoadAndExpectSuccess("homepage_valid.json"));
+
+ Testcase testcases[] = {
+ Testcase("homepage_empty.json",
+ errors::kInvalidHomepageURL),
+ Testcase("homepage_invalid.json",
+ errors::kInvalidHomepageURL),
+ Testcase("homepage_bad_schema.json",
+ errors::kInvalidHomepageURL)
+ };
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
+}
+
+TEST_F(HomepageURLManifestTest, GetHomepageURL) {
+ scoped_refptr<extensions::Extension> extension(
+ LoadAndExpectSuccess("homepage_valid.json"));
+ EXPECT_EQ(GURL("http://foo.com#bar"),
+ extensions::ManifestURL::GetHomepageURL(extension.get()));
+
+ // The Google Gallery URL ends with the id, which depends on the path, which
+ // can be different in testing, so we just check the part before id.
+ extension = LoadAndExpectSuccess("homepage_google_hosted.json");
+ EXPECT_TRUE(base::StartsWith(
+ extensions::ManifestURL::GetHomepageURL(extension.get()).spec(),
+ "https://chrome.google.com/webstore/detail/",
+ base::CompareCase::INSENSITIVE_ASCII));
+
+ extension = LoadAndExpectSuccess("homepage_externally_hosted.json");
+ EXPECT_EQ(GURL(), extensions::ManifestURL::GetHomepageURL(extension.get()));
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_icons_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_icons_unittest.cc
new file mode 100644
index 00000000000..fe4c5688148
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_icons_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.
+
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_icon_set.h"
+#include "extensions/common/manifest_handlers/icons_handler.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+class IconsManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(IconsManifestTest, NormalizeIconPaths) {
+ scoped_refptr<extensions::Extension> extension(
+ LoadAndExpectSuccess("normalize_icon_paths.json"));
+ const ExtensionIconSet& icons = IconsInfo::GetIcons(extension.get());
+
+ EXPECT_EQ("16.png", icons.Get(extension_misc::EXTENSION_ICON_BITTY,
+ ExtensionIconSet::MATCH_EXACTLY));
+ EXPECT_EQ("48.png", icons.Get(extension_misc::EXTENSION_ICON_MEDIUM,
+ ExtensionIconSet::MATCH_EXACTLY));
+}
+
+TEST_F(IconsManifestTest, IconSizes) {
+ scoped_refptr<extensions::Extension> extension(
+ LoadAndExpectSuccess("init_icon_size.json"));
+ const ExtensionIconSet& icons = IconsInfo::GetIcons(extension.get());
+
+ EXPECT_EQ("16.png", icons.Get(extension_misc::EXTENSION_ICON_BITTY,
+ ExtensionIconSet::MATCH_EXACTLY));
+ EXPECT_EQ("24.png", icons.Get(extension_misc::EXTENSION_ICON_SMALLISH,
+ ExtensionIconSet::MATCH_EXACTLY));
+ EXPECT_EQ("32.png", icons.Get(extension_misc::EXTENSION_ICON_SMALL,
+ ExtensionIconSet::MATCH_EXACTLY));
+ EXPECT_EQ("48.png", icons.Get(extension_misc::EXTENSION_ICON_MEDIUM,
+ ExtensionIconSet::MATCH_EXACTLY));
+ EXPECT_EQ("128.png", icons.Get(extension_misc::EXTENSION_ICON_LARGE,
+ ExtensionIconSet::MATCH_EXACTLY));
+ EXPECT_EQ("256.png", icons.Get(extension_misc::EXTENSION_ICON_EXTRA_LARGE,
+ ExtensionIconSet::MATCH_EXACTLY));
+ EXPECT_EQ("512.png", icons.Get(extension_misc::EXTENSION_ICON_GIGANTOR,
+ ExtensionIconSet::MATCH_EXACTLY));
+
+ // Any old size will be accepted.
+ EXPECT_EQ("300.png", IconsInfo::GetIcons(extension.get())
+ .Get(300, ExtensionIconSet::MATCH_EXACTLY));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
new file mode 100644
index 00000000000..fa1de5ddd84
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_initvalue_unittest.cc
@@ -0,0 +1,177 @@
+// 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 "base/command_line.h"
+#include "base/i18n/rtl.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "components/crx_file/id_util.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/features/simple_feature.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/options_page_info.h"
+#include "extensions/common/switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+namespace {
+
+// The ID of test manifests requiring allowlisting.
+const char kAllowlistID[] = "lmadimbbgapmngbiclpjjngmdickadpl";
+
+} // namespace
+
+namespace errors = manifest_errors;
+namespace keys = manifest_keys;
+
+class InitValueManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(InitValueManifestTest, InitFromValueInvalid) {
+ SimpleFeature::ScopedThreadUnsafeAllowlistForTest allowlist(kAllowlistID);
+ Testcase testcases[] = {
+ Testcase("init_invalid_version_missing.json", errors::kInvalidVersion),
+ Testcase("init_invalid_version_invalid.json", errors::kInvalidVersion),
+ Testcase("init_invalid_version_name_invalid.json",
+ errors::kInvalidVersionName),
+ Testcase("init_invalid_name_missing.json", errors::kInvalidName),
+ Testcase("init_invalid_name_invalid.json", errors::kInvalidName),
+ Testcase("init_invalid_description_invalid.json",
+ errors::kInvalidDescription),
+ Testcase("init_invalid_icons_invalid.json", errors::kInvalidIcons),
+ Testcase("init_invalid_icons_path_invalid.json",
+ errors::kInvalidIconPath),
+ Testcase("init_invalid_script_invalid.json",
+ errors::kInvalidContentScriptsList),
+ Testcase("init_invalid_script_item_invalid.json",
+ errors::kInvalidContentScript),
+ Testcase("init_invalid_script_matches_missing.json",
+ errors::kInvalidMatches),
+ Testcase("init_invalid_script_matches_invalid.json",
+ errors::kInvalidMatches),
+ Testcase("init_invalid_script_matches_empty.json",
+ errors::kInvalidMatchCount),
+ Testcase("init_invalid_script_match_item_invalid.json",
+ errors::kInvalidMatch),
+ Testcase("init_invalid_script_match_item_invalid_2.json",
+ errors::kInvalidMatch),
+ Testcase("init_invalid_script_files_missing.json", errors::kMissingFile),
+ Testcase("init_invalid_files_js_invalid.json", errors::kInvalidJsList),
+ Testcase("init_invalid_files_empty.json", errors::kMissingFile),
+ Testcase("init_invalid_files_js_empty_css_missing.json",
+ errors::kMissingFile),
+ Testcase("init_invalid_files_js_item_invalid.json", errors::kInvalidJs),
+ Testcase("init_invalid_files_css_invalid.json", errors::kInvalidCssList),
+ Testcase("init_invalid_files_css_item_invalid.json", errors::kInvalidCss),
+ Testcase("init_invalid_permissions_invalid.json",
+ errors::kInvalidPermissions),
+ Testcase("init_invalid_host_permissions_invalid.json",
+ errors::kInvalidHostPermissions),
+ Testcase("init_invalid_permissions_item_invalid.json",
+ errors::kInvalidPermission),
+ Testcase("init_invalid_options_url_invalid.json",
+ errors::kInvalidOptionsPage),
+ Testcase("init_invalid_locale_invalid.json",
+ errors::kInvalidDefaultLocale),
+ Testcase("init_invalid_locale_empty.json", errors::kInvalidDefaultLocale),
+ Testcase("init_invalid_min_chrome_invalid.json",
+ errors::kInvalidMinimumChromeVersion),
+ Testcase("init_invalid_chrome_version_too_low.json",
+ errors::kChromeVersionTooLow),
+ Testcase("init_invalid_short_name_empty.json", errors::kInvalidShortName),
+ Testcase("init_invalid_short_name_type.json", errors::kInvalidShortName),
+ };
+
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
+}
+
+TEST_F(InitValueManifestTest, InitFromValueValid) {
+ scoped_refptr<Extension> extension(LoadAndExpectSuccess(
+ "init_valid_minimal.json"));
+
+ base::FilePath path;
+ base::PathService::Get(chrome::DIR_TEST_DATA, &path);
+ path = path.AppendASCII("extensions");
+
+ EXPECT_TRUE(crx_file::id_util::IdIsValid(extension->id()));
+ EXPECT_EQ("1.0.0.0", extension->VersionString());
+ EXPECT_EQ("my extension", extension->name());
+ EXPECT_EQ(extension->name(), extension->short_name());
+ EXPECT_EQ(extension->id(), extension->url().host());
+ EXPECT_EQ(extension->path(), path);
+ EXPECT_EQ(path, extension->path());
+
+ // Test permissions scheme.
+ // We allow unknown API permissions, so this will be valid until we better
+ // distinguish between API and host permissions.
+ LoadAndExpectSuccess("init_valid_permissions.json");
+
+ // Test with an options page.
+ extension = LoadAndExpectSuccess("init_valid_options.json");
+ EXPECT_EQ(extensions::kExtensionScheme,
+ OptionsPageInfo::GetOptionsPage(extension.get()).scheme());
+ EXPECT_EQ("/options.html",
+ OptionsPageInfo::GetOptionsPage(extension.get()).path());
+
+ // Test optional short_name field.
+ extension = LoadAndExpectSuccess("init_valid_short_name.json");
+ EXPECT_EQ("a very descriptive extension name", extension->name());
+ EXPECT_EQ("concise name", extension->short_name());
+
+ // Test optional version_name field.
+ extension = LoadAndExpectSuccess("init_valid_version_name.json");
+ EXPECT_EQ("1.0.0.0", extension->VersionString());
+ EXPECT_EQ("1.0 alpha", extension->GetVersionForDisplay());
+
+ Testcase testcases[] = {
+ // Test with a minimum_chrome_version.
+ Testcase("init_valid_minimum_chrome.json"),
+
+ // Test a hosted app with a minimum_chrome_version.
+ Testcase("init_valid_app_minimum_chrome.json"),
+
+ // Test a hosted app with a requirements section.
+ Testcase("init_valid_app_requirements.json"),
+
+ // Verify empty permission settings are considered valid.
+ Testcase("init_valid_permissions_empty.json"),
+
+ // We allow unknown API permissions, so this will be valid until we better
+ // distinguish between API and host permissions.
+ Testcase("init_valid_permissions_unknown.json")
+ };
+
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_SUCCESS);
+}
+
+TEST_F(InitValueManifestTest, InitFromValueValidNameInRTL) {
+ std::string locale = l10n_util::GetApplicationLocale("");
+ base::i18n::SetICUDefaultLocale("he");
+
+ // No strong RTL characters in name.
+ scoped_refptr<Extension> extension(LoadAndExpectSuccess(
+ "init_valid_name_no_rtl.json"));
+
+ base::string16 localized_name(base::ASCIIToUTF16("Dictionary (by Google)"));
+ base::i18n::AdjustStringForLocaleDirection(&localized_name);
+ EXPECT_EQ(localized_name, base::UTF8ToUTF16(extension->name()));
+
+ // Strong RTL characters in name.
+ extension = LoadAndExpectSuccess("init_valid_name_strong_rtl.json");
+
+ localized_name = base::WideToUTF16(L"Dictionary (\x05D1\x05D2" L" Google)");
+ base::i18n::AdjustStringForLocaleDirection(&localized_name);
+ EXPECT_EQ(localized_name, base::UTF8ToUTF16(extension->name()));
+
+ // Reset locale.
+ base::i18n::SetICUDefaultLocale(locale);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_isolatedapp_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_isolatedapp_unittest.cc
new file mode 100644
index 00000000000..984de2d3556
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_isolatedapp_unittest.cc
@@ -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.
+
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+
+#include "base/command_line.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/app_isolation_info.h"
+#include "extensions/common/switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace errors = manifest_errors;
+
+class IsolatedAppsManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(IsolatedAppsManifestTest, IsolatedApps) {
+ LoadAndExpectWarning(
+ "isolated_app_valid.json",
+ "'experimental' requires the 'experimental-extension-apis' "
+ "command line switch to be enabled.");
+
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ extensions::switches::kEnableExperimentalExtensionApis);
+ scoped_refptr<Extension> extension2(
+ LoadAndExpectSuccess("isolated_app_valid.json"));
+ EXPECT_TRUE(AppIsolationInfo::HasIsolatedStorage(extension2.get()));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc
new file mode 100644
index 00000000000..7a45ea4670a
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc
@@ -0,0 +1,108 @@
+// 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 "build/build_config.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/kiosk_mode_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+class ExtensionManifestKioskModeTest : public ChromeManifestTest {
+};
+
+TEST_F(ExtensionManifestKioskModeTest, InvalidKioskEnabled) {
+ LoadAndExpectError("kiosk_enabled_invalid.json",
+ manifest_errors::kInvalidKioskEnabled);
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskEnabledHostedApp) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("kiosk_enabled_hosted_app.json"));
+ EXPECT_FALSE(KioskModeInfo::IsKioskEnabled(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskEnabledPackagedApp) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("kiosk_enabled_packaged_app.json"));
+ EXPECT_FALSE(KioskModeInfo::IsKioskEnabled(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskEnabledExtension) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("kiosk_enabled_extension.json"));
+ EXPECT_FALSE(KioskModeInfo::IsKioskEnabled(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskEnabledPlatformApp) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("kiosk_enabled_platform_app.json"));
+ EXPECT_TRUE(KioskModeInfo::IsKioskEnabled(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskDisabledPlatformApp) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("kiosk_disabled_platform_app.json"));
+ EXPECT_FALSE(KioskModeInfo::IsKioskEnabled(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskDefaultPlatformApp) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("kiosk_default_platform_app.json"));
+ EXPECT_FALSE(KioskModeInfo::IsKioskEnabled(extension.get()));
+ EXPECT_FALSE(KioskModeInfo::IsKioskOnly(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskEnabledDefaultRequired) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("kiosk_enabled_platform_app.json"));
+ EXPECT_TRUE(KioskModeInfo::IsKioskEnabled(extension.get()));
+ EXPECT_FALSE(KioskModeInfo::IsKioskOnly(extension.get()));
+}
+
+// 'kiosk_only' key should be set only from ChromeOS.
+#if defined(OS_CHROMEOS)
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyPlatformApp) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("kiosk_only_platform_app.json"));
+ EXPECT_TRUE(KioskModeInfo::IsKioskOnly(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyInvalid) {
+ LoadAndExpectError("kiosk_only_invalid.json",
+ manifest_errors::kInvalidKioskOnly);
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyButNotEnabled) {
+ LoadAndExpectError("kiosk_only_not_enabled.json",
+ manifest_errors::kInvalidKioskOnlyButNotEnabled);
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyHostedApp) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("kiosk_only_hosted_app.json"));
+ EXPECT_FALSE(KioskModeInfo::IsKioskOnly(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyPackagedApp) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("kiosk_only_packaged_app.json"));
+ EXPECT_FALSE(KioskModeInfo::IsKioskOnly(extension.get()));
+}
+
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyExtension) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("kiosk_only_extension.json"));
+ EXPECT_FALSE(KioskModeInfo::IsKioskOnly(extension.get()));
+}
+#else
+TEST_F(ExtensionManifestKioskModeTest, KioskOnlyFromNonChromeos) {
+ LoadAndExpectWarning("kiosk_only_platform_app.json",
+ "'kiosk_only' is not allowed for specified platform.");
+}
+#endif // defined(OS_CHROMEOS)
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc
new file mode 100644
index 00000000000..9da6ddb14d7
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_launch_unittest.cc
@@ -0,0 +1,131 @@
+// 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 "base/command_line.h"
+#include "base/stl_util.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace errors = manifest_errors;
+namespace keys = manifest_keys;
+
+class AppLaunchManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(AppLaunchManifestTest, AppLaunchContainer) {
+ scoped_refptr<Extension> extension;
+
+ extension = LoadAndExpectSuccess("launch_tab.json");
+ EXPECT_EQ(LaunchContainer::kLaunchContainerTab,
+ AppLaunchInfo::GetLaunchContainer(extension.get()));
+
+ extension = LoadAndExpectSuccess("launch_panel.json");
+ EXPECT_EQ(LaunchContainer::kLaunchContainerPanelDeprecated,
+ AppLaunchInfo::GetLaunchContainer(extension.get()));
+
+ extension = LoadAndExpectSuccess("launch_default.json");
+ EXPECT_EQ(LaunchContainer::kLaunchContainerTab,
+ AppLaunchInfo::GetLaunchContainer(extension.get()));
+
+ extension = LoadAndExpectSuccess("launch_width.json");
+ EXPECT_EQ(640, AppLaunchInfo::GetLaunchWidth(extension.get()));
+
+ extension = LoadAndExpectSuccess("launch_height.json");
+ EXPECT_EQ(480, AppLaunchInfo::GetLaunchHeight(extension.get()));
+
+ Testcase testcases[] = {
+ Testcase("launch_window.json", errors::kInvalidLaunchContainer),
+ Testcase("launch_container_invalid_type.json",
+ errors::kInvalidLaunchContainer),
+ Testcase("launch_container_invalid_value.json",
+ errors::kInvalidLaunchContainer),
+ Testcase("launch_container_without_launch_url.json",
+ errors::kLaunchURLRequired),
+ Testcase("launch_width_invalid.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValueContainer,
+ keys::kLaunchWidth)),
+ Testcase("launch_width_negative.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWidth)),
+ Testcase("launch_height_invalid.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValueContainer,
+ keys::kLaunchHeight)),
+ Testcase("launch_height_negative.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchHeight))
+ };
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
+}
+
+TEST_F(AppLaunchManifestTest, AppLaunchURL) {
+ Testcase testcases[] = {
+ Testcase("launch_path_and_url.json",
+ errors::kLaunchPathAndURLAreExclusive),
+ Testcase("launch_path_and_extent.json",
+ errors::kLaunchPathAndExtentAreExclusive),
+ Testcase("launch_path_invalid_type.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchLocalPath)),
+ Testcase("launch_path_invalid_value.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchLocalPath)),
+ Testcase("launch_path_invalid_localized.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchLocalPath)),
+ Testcase("launch_url_invalid_type_1.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWebURL)),
+ Testcase("launch_url_invalid_type_2.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWebURL)),
+ Testcase("launch_url_invalid_type_3.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWebURL)),
+ Testcase("launch_url_invalid_localized.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWebURL))
+ };
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
+
+ scoped_refptr<Extension> extension;
+ extension = LoadAndExpectSuccess("launch_local_path.json");
+ EXPECT_EQ(extension->url().spec() + "launch.html",
+ AppLaunchInfo::GetFullLaunchURL(extension.get()).spec());
+
+ extension = LoadAndExpectSuccess("launch_local_path_localized.json");
+ EXPECT_EQ(extension->url().spec() + "launch.html",
+ AppLaunchInfo::GetFullLaunchURL(extension.get()).spec());
+
+ LoadAndExpectError("launch_web_url_relative.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidLaunchValue,
+ keys::kLaunchWebURL));
+
+ extension = LoadAndExpectSuccess("launch_web_url_absolute.json");
+ EXPECT_EQ(GURL("http://www.google.com/launch.html"),
+ AppLaunchInfo::GetFullLaunchURL(extension.get()));
+ extension = LoadAndExpectSuccess("launch_web_url_localized.json");
+ EXPECT_EQ(GURL("http://www.google.com/launch.html"),
+ AppLaunchInfo::GetFullLaunchURL(extension.get()));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_manifest_version_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_manifest_version_unittest.cc
new file mode 100644
index 00000000000..6d4809a4bd0
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_manifest_version_unittest.cc
@@ -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.
+
+#include <memory>
+
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using extensions::Extension;
+
+namespace errors = extensions::manifest_errors;
+
+TEST_F(ChromeManifestTest, ManifestVersionError) {
+ std::unique_ptr<base::DictionaryValue> manifest1(new base::DictionaryValue());
+ manifest1->SetString("name", "Miles");
+ manifest1->SetString("version", "0.55");
+
+ std::unique_ptr<base::DictionaryValue> manifest2(manifest1->DeepCopy());
+ manifest2->SetInteger("manifest_version", 1);
+
+ std::unique_ptr<base::DictionaryValue> manifest3(manifest1->DeepCopy());
+ manifest3->SetInteger("manifest_version", 2);
+
+ struct {
+ const char* test_name;
+ bool require_modern_manifest_version;
+ base::DictionaryValue* manifest;
+ bool expect_error;
+ } test_data[] = {
+ {"require_modern_with_default", true, manifest1.get(), true},
+ {"require_modern_with_v1", true, manifest2.get(), true},
+ {"require_modern_with_v2", true, manifest3.get(), false},
+ {"dont_require_modern_with_default", false, manifest1.get(), true},
+ {"dont_require_modern_with_v1", false, manifest2.get(), true},
+ {"dont_require_modern_with_v2", false, manifest3.get(), false},
+ };
+
+ for (auto& entry : test_data) {
+ int create_flags = Extension::NO_FLAGS;
+ if (entry.require_modern_manifest_version)
+ create_flags |= Extension::REQUIRE_MODERN_MANIFEST_VERSION;
+ if (entry.expect_error) {
+ LoadAndExpectError(ManifestData(entry.manifest, entry.test_name),
+ errors::kInvalidManifestVersionOld,
+ extensions::Manifest::UNPACKED, create_flags);
+ } else {
+ LoadAndExpectSuccess(ManifestData(entry.manifest, entry.test_name),
+ extensions::Manifest::UNPACKED, create_flags);
+ }
+ }
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_offline_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_offline_unittest.cc
new file mode 100644
index 00000000000..67934e43d9e
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_offline_unittest.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 "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/offline_enabled_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace errors = manifest_errors;
+
+class ExtensionManifestOfflineEnabledTest : public ChromeManifestTest {
+};
+
+TEST_F(ExtensionManifestOfflineEnabledTest, OfflineEnabled) {
+ LoadAndExpectError("offline_enabled_invalid.json",
+ errors::kInvalidOfflineEnabled);
+ scoped_refptr<Extension> extension_0(
+ LoadAndExpectSuccess("offline_enabled_extension.json"));
+ EXPECT_TRUE(OfflineEnabledInfo::IsOfflineEnabled(extension_0.get()));
+ scoped_refptr<Extension> extension_1(
+ LoadAndExpectSuccess("offline_enabled_packaged_app.json"));
+ EXPECT_TRUE(OfflineEnabledInfo::IsOfflineEnabled(extension_1.get()));
+ scoped_refptr<Extension> extension_2(
+ LoadAndExpectSuccess("offline_disabled_packaged_app.json"));
+ EXPECT_FALSE(OfflineEnabledInfo::IsOfflineEnabled(extension_2.get()));
+ scoped_refptr<Extension> extension_3(
+ LoadAndExpectSuccess("offline_default_packaged_app.json"));
+ EXPECT_FALSE(OfflineEnabledInfo::IsOfflineEnabled(extension_3.get()));
+ scoped_refptr<Extension> extension_4(
+ LoadAndExpectSuccess("offline_enabled_hosted_app.json"));
+ EXPECT_TRUE(OfflineEnabledInfo::IsOfflineEnabled(extension_4.get()));
+ scoped_refptr<Extension> extension_5(
+ LoadAndExpectSuccess("offline_default_platform_app.json"));
+ EXPECT_TRUE(OfflineEnabledInfo::IsOfflineEnabled(extension_5.get()));
+ scoped_refptr<Extension> extension_6(
+ LoadAndExpectSuccess("offline_default_platform_app_with_webview.json"));
+ EXPECT_FALSE(OfflineEnabledInfo::IsOfflineEnabled(extension_6.get()));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_old_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_old_unittest.cc
new file mode 100644
index 00000000000..e9fd914e173
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_old_unittest.cc
@@ -0,0 +1,19 @@
+// 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 "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+
+#include "extensions/common/extension.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Tests that the old permission name "unlimited_storage" still works for
+// backwards compatibility (we renamed it to "unlimitedStorage").
+TEST_F(ChromeManifestTest, OldUnlimitedStoragePermission) {
+ scoped_refptr<extensions::Extension> extension = LoadAndExpectSuccess(
+ "old_unlimited_storage.json", extensions::Manifest::INTERNAL,
+ extensions::Extension::NO_FLAGS);
+ EXPECT_TRUE(extension->permissions_data()->HasAPIPermission(
+ extensions::APIPermission::kUnlimitedStorage));
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_options_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_options_unittest.cc
new file mode 100644
index 00000000000..e6d0e819466
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_options_unittest.cc
@@ -0,0 +1,141 @@
+// 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 "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/feature_switch.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/options_page_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using extensions::FeatureSwitch;
+using extensions::OptionsPageInfo;
+
+namespace {
+
+class OptionsPageManifestTest : public ChromeManifestTest {
+ protected:
+ // Tests how the options_ui manifest key affects the open-in-tab and
+ // chromes-style behaviour.
+ testing::AssertionResult TestOptionsUIChromeStyleAndOpenInTab() {
+ // Explicitly specifying true in the manifest for options_ui.chrome_style
+ // and options_ui.open_in_tab sets them both to true.
+ scoped_refptr<extensions::Extension> extension =
+ LoadAndExpectSuccess("options_ui_flags_true.json");
+ EXPECT_TRUE(OptionsPageInfo::ShouldUseChromeStyle(extension.get()));
+ EXPECT_TRUE(OptionsPageInfo::ShouldOpenInTab(extension.get()));
+
+ // Explicitly specifying false in the manifest for options_ui.chrome_style
+ // and options_ui.open_in_tab sets them both to false.
+ extension = LoadAndExpectSuccess("options_ui_flags_false.json");
+ EXPECT_FALSE(OptionsPageInfo::ShouldUseChromeStyle(extension.get()));
+ EXPECT_FALSE(OptionsPageInfo::ShouldOpenInTab(extension.get()));
+
+ // Specifying an options_ui key but neither options_ui.chrome_style nor
+ // options_ui.open_in_tab uses the default values: false for open-in-tab,
+ // false for use-chrome-style.
+ extension = LoadAndExpectSuccess("options_ui_page_basic.json");
+ EXPECT_FALSE(OptionsPageInfo::ShouldUseChromeStyle(extension.get()));
+ EXPECT_FALSE(OptionsPageInfo::ShouldOpenInTab(extension.get()));
+
+ // This extension has both options_page and options_ui specified. The
+ // options_ui key should take precedence.
+ extension = LoadAndExpectSuccess("options_ui_page_with_legacy_page.json");
+ EXPECT_FALSE(OptionsPageInfo::ShouldUseChromeStyle(extension.get()));
+ EXPECT_FALSE(OptionsPageInfo::ShouldOpenInTab(extension.get()));
+
+ return testing::AssertionSuccess();
+ }
+
+ // Tests how the options_page manifest key affects the open-in-tab and
+ // chromes-style behaviour.
+ testing::AssertionResult TestOptionsPageChromeStyleAndOpenInTab(
+ bool expect_open_in_tab) {
+ scoped_refptr<extensions::Extension> extension =
+ LoadAndExpectSuccess("init_valid_options.json");
+ EXPECT_FALSE(OptionsPageInfo::ShouldUseChromeStyle(extension.get()));
+ if (expect_open_in_tab) {
+ EXPECT_TRUE(OptionsPageInfo::ShouldOpenInTab(extension.get()));
+ } else {
+ EXPECT_FALSE(OptionsPageInfo::ShouldOpenInTab(extension.get()));
+ }
+ return testing::AssertionSuccess();
+ }
+};
+
+TEST_F(OptionsPageManifestTest, OptionsPageInApps) {
+ // Allow options page with absolute URL in hosted apps.
+ scoped_refptr<extensions::Extension> extension =
+ LoadAndExpectSuccess("hosted_app_absolute_options.json");
+ EXPECT_EQ("http://example.com/options.html",
+ OptionsPageInfo::GetOptionsPage(extension.get()).spec());
+
+ extension = LoadAndExpectSuccess("platform_app_with_options_page.json");
+ EXPECT_TRUE(!OptionsPageInfo::HasOptionsPage(extension.get()));
+
+ Testcase testcases[] = {
+ // Forbid options page with relative URL in hosted apps.
+ Testcase("hosted_app_relative_options.json",
+ extensions::manifest_errors::kInvalidOptionsPageInHostedApp),
+
+ // Forbid options page with non-(http|https) scheme in hosted app.
+ Testcase("hosted_app_file_options.json",
+ extensions::manifest_errors::kInvalidOptionsPageInHostedApp),
+
+ // Forbid absolute URL for options page in packaged apps.
+ Testcase(
+ "packaged_app_absolute_options.json",
+ extensions::manifest_errors::kInvalidOptionsPageExpectUrlInPackage)};
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
+}
+
+// Tests for the options_ui.page manifest field.
+TEST_F(OptionsPageManifestTest, OptionsUIPage) {
+ FeatureSwitch::ScopedOverride enable_flag(
+ FeatureSwitch::embedded_extension_options(), true);
+
+ scoped_refptr<extensions::Extension> extension =
+ LoadAndExpectSuccess("options_ui_page_basic.json");
+ EXPECT_EQ(base::StringPrintf("chrome-extension://%s/options.html",
+ extension->id().c_str()),
+ OptionsPageInfo::GetOptionsPage(extension.get()).spec());
+
+ extension = LoadAndExpectSuccess("options_ui_page_with_legacy_page.json");
+ EXPECT_EQ(base::StringPrintf("chrome-extension://%s/newoptions.html",
+ extension->id().c_str()),
+ OptionsPageInfo::GetOptionsPage(extension.get()).spec());
+
+ Testcase testcases[] = {Testcase("options_ui_page_bad_url.json",
+ "'page': expected page, got null")};
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_WARNING);
+}
+
+// Runs TestOptionsUIChromeStyleAndOpenInTab with and without the
+// embedded-extension-options flag. The results should always be the same.
+TEST_F(OptionsPageManifestTest, OptionsUIChromeStyleAndOpenInTab) {
+ ASSERT_FALSE(FeatureSwitch::embedded_extension_options()->IsEnabled());
+ EXPECT_TRUE(TestOptionsUIChromeStyleAndOpenInTab());
+ {
+ FeatureSwitch::ScopedOverride enable_flag(
+ FeatureSwitch::embedded_extension_options(), true);
+ EXPECT_TRUE(TestOptionsUIChromeStyleAndOpenInTab());
+ }
+}
+
+// Runs TestOptionsPageChromeStyleAndOpenInTab with and without the
+// embedded-extension-options flag. The default value of open-in-tab differs
+// depending on the flag's value.
+TEST_F(OptionsPageManifestTest, OptionsPageChromeStyleAndOpenInTab) {
+ ASSERT_FALSE(FeatureSwitch::embedded_extension_options()->IsEnabled());
+ EXPECT_TRUE(TestOptionsPageChromeStyleAndOpenInTab(true));
+ {
+ FeatureSwitch::ScopedOverride enable_flag(
+ FeatureSwitch::embedded_extension_options(), true);
+ EXPECT_TRUE(TestOptionsPageChromeStyleAndOpenInTab(false));
+ }
+}
+
+} // namespace
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_override_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_override_unittest.cc
new file mode 100644
index 00000000000..f3df018d00f
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_override_unittest.cc
@@ -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.
+
+#include "base/stl_util.h"
+#include "chrome/common/extensions/chrome_manifest_url_handlers.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace errors = extensions::manifest_errors;
+
+class URLOverridesManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(URLOverridesManifestTest, Override) {
+ Testcase testcases[] = {
+ Testcase("override_newtab_and_history.json", errors::kMultipleOverrides),
+ Testcase("override_invalid_page.json", errors::kInvalidChromeURLOverrides)
+ };
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
+
+ scoped_refptr<extensions::Extension> extension;
+
+ extension = LoadAndExpectSuccess("override_new_tab.json");
+ EXPECT_EQ(extension->url().spec() + "newtab.html",
+ extensions::URLOverrides::GetChromeURLOverrides(extension.get())
+ .find("newtab")->second.spec());
+
+ extension = LoadAndExpectSuccess("override_history.json");
+ EXPECT_EQ(extension->url().spec() + "history.html",
+ extensions::URLOverrides::GetChromeURLOverrides(extension.get())
+ .find("history")->second.spec());
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
new file mode 100644
index 00000000000..4d1d897167c
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_platformapp_unittest.cc
@@ -0,0 +1,149 @@
+// 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 "base/command_line.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/stl_util.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/features/simple_feature.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/app_isolation_info.h"
+#include "extensions/common/manifest_handlers/csp_info.h"
+#include "extensions/common/manifest_handlers/incognito_info.h"
+#include "extensions/common/switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace errors = manifest_errors;
+namespace keys = manifest_keys;
+
+class PlatformAppsManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(PlatformAppsManifestTest, PlatformApps) {
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("init_valid_platform_app.json");
+ EXPECT_TRUE(AppIsolationInfo::HasIsolatedStorage(extension.get()));
+ EXPECT_FALSE(IncognitoInfo::IsSplitMode(extension.get()));
+
+ extension =
+ LoadAndExpectSuccess("init_valid_platform_app_no_manifest_version.json");
+ EXPECT_EQ(2, extension->manifest_version());
+
+ extension = LoadAndExpectSuccess("incognito_valid_platform_app.json");
+ EXPECT_FALSE(IncognitoInfo::IsSplitMode(extension.get()));
+
+ Testcase error_testcases[] = {
+ Testcase("init_invalid_platform_app_2.json",
+ errors::kBackgroundRequiredForPlatformApps),
+ Testcase("init_invalid_platform_app_3.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidManifestVersionOld, "2", "apps")),
+ };
+ RunTestcases(error_testcases, base::size(error_testcases), EXPECT_TYPE_ERROR);
+
+ Testcase warning_testcases[] = {
+ Testcase(
+ "init_invalid_platform_app_1.json",
+ "'app.launch' is only allowed for legacy packaged apps and hosted "
+ "apps, but this is a packaged app."),
+ Testcase("init_invalid_platform_app_4.json",
+ "'background' is only allowed for extensions, legacy packaged "
+ "apps, hosted apps, and login screen extensions, but this is a "
+ "packaged app."),
+ Testcase("init_invalid_platform_app_5.json",
+ "'background' is only allowed for extensions, legacy packaged "
+ "apps, hosted apps, and login screen extensions, but this is a "
+ "packaged app."),
+ Testcase("incognito_invalid_platform_app.json",
+ "'incognito' is only allowed for extensions and legacy packaged "
+ "apps, "
+ "but this is a packaged app."),
+ };
+ RunTestcases(warning_testcases, base::size(warning_testcases),
+ EXPECT_TYPE_WARNING);
+}
+
+TEST_F(PlatformAppsManifestTest, PlatformAppContentSecurityPolicy) {
+ // Normal platform apps can't specify a CSP value.
+ Testcase warning_testcases[] = {
+ Testcase(
+ "init_platform_app_csp_warning_1.json",
+ "'content_security_policy' is only allowed for extensions and legacy "
+ "packaged apps, but this is a packaged app."),
+ Testcase(
+ "init_platform_app_csp_warning_2.json",
+ "'app.content_security_policy' is not allowed for specified extension "
+ "ID.")
+ };
+ RunTestcases(warning_testcases, base::size(warning_testcases),
+ EXPECT_TYPE_WARNING);
+
+ // Allowlisted ones can (this is the ID corresponding to the base 64 encoded
+ // key in the init_platform_app_csp.json manifest.)
+ SimpleFeature::ScopedThreadUnsafeAllowlistForTest allowlist(
+ "ahplfneplbnjcflhdgkkjeiglkkfeelb");
+ scoped_refptr<Extension> extension =
+ LoadAndExpectSuccess("init_platform_app_csp.json");
+ EXPECT_EQ(0U, extension->install_warnings().size())
+ << "Unexpected warning " << extension->install_warnings()[0].message;
+ EXPECT_TRUE(extension->is_platform_app());
+ EXPECT_EQ("default-src 'self' https://www.google.com;",
+ CSPInfo::GetResourceContentSecurityPolicy(extension.get(),
+ std::string()));
+
+ // But even allowlisted ones must specify a secure policy.
+ LoadAndExpectWarning(
+ "init_platform_app_csp_insecure.json",
+ ErrorUtils::FormatErrorMessage(errors::kInvalidCSPInsecureValueIgnored,
+ keys::kPlatformAppContentSecurityPolicy,
+ "http://www.google.com", "default-src"));
+}
+
+TEST_F(PlatformAppsManifestTest, CertainApisRequirePlatformApps) {
+ // Put APIs here that should be restricted to platform apps, but that haven't
+ // yet graduated from experimental.
+ const char* const kPlatformAppExperimentalApis[] = {
+ "dns",
+ "serial",
+ };
+ // TODO(miket): When the first platform-app API leaves experimental, write
+ // similar code that tests without the experimental flag.
+
+ // This manifest is a skeleton used to build more specific manifests for
+ // testing. The requirements are that (1) it be a valid platform app, and (2)
+ // it contain no permissions dictionary.
+ std::string error;
+ base::Value manifest = LoadManifest("init_valid_platform_app.json", &error);
+
+ std::vector<std::unique_ptr<ManifestData>> manifests;
+ // Create each manifest.
+ for (const char* api_name : kPlatformAppExperimentalApis) {
+ base::Value permissions(base::Value::Type::LIST);
+ permissions.Append(base::Value("experimental"));
+ permissions.Append(base::Value(api_name));
+ manifest.SetKey("permissions", std::move(permissions));
+ manifests.push_back(
+ std::make_unique<ManifestData>(manifest.CreateDeepCopy(), ""));
+ }
+ // First try to load without any flags. This should warn for every API.
+ for (const std::unique_ptr<ManifestData>& manifest : manifests) {
+ LoadAndExpectWarning(
+ *manifest,
+ "'experimental' requires the 'experimental-extension-apis' "
+ "command line switch to be enabled.");
+ }
+
+ // Now try again with the experimental flag set.
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalExtensionApis);
+ for (const std::unique_ptr<ManifestData>& manifest : manifests)
+ LoadAndExpectSuccess(*manifest);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_portsinpermissions_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_portsinpermissions_unittest.cc
new file mode 100644
index 00000000000..874d7e80130
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_portsinpermissions_unittest.cc
@@ -0,0 +1,12 @@
+// 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 "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST_F(ChromeManifestTest, PortsInPermissions) {
+ // Loading as a user would shoud not trigger an error.
+ LoadAndExpectSuccess("ports_in_permissions.json");
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_requirements_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_requirements_unittest.cc
new file mode 100644
index 00000000000..bd7e5aa4d1e
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_requirements_unittest.cc
@@ -0,0 +1,70 @@
+// 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 "base/stl_util.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/requirements_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace errors = manifest_errors;
+
+class RequirementsManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(RequirementsManifestTest, RequirementsInvalid) {
+ Testcase testcases[] = {
+ Testcase("requirements_invalid_requirements.json",
+ errors::kInvalidRequirements),
+ Testcase("requirements_invalid_keys.json", errors::kInvalidRequirements),
+ Testcase("requirements_invalid_3d.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidRequirement, "3D")),
+ Testcase("requirements_invalid_3d_features.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidRequirement, "3D")),
+ Testcase("requirements_invalid_3d_features_value.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidRequirement, "3D")),
+ Testcase("requirements_invalid_3d_no_features.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidRequirement, "3D")),
+ };
+
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
+}
+
+TEST_F(RequirementsManifestTest, RequirementsValid) {
+ // Test the defaults.
+ scoped_refptr<Extension> extension(LoadAndExpectSuccess(
+ "requirements_valid_empty.json"));
+ ASSERT_TRUE(extension.get());
+ EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).webgl, false);
+
+ // Test loading all the requirements.
+ extension = LoadAndExpectSuccess("requirements_valid_full.json");
+ ASSERT_TRUE(extension.get());
+ EXPECT_EQ(RequirementsInfo::GetRequirements(extension.get()).webgl, true);
+}
+
+// Tests the deprecated plugin requirement.
+TEST_F(RequirementsManifestTest, RequirementsPlugin) {
+ // Using the plugins requirement should cause an install warning.
+ RunTestcase({"requirements_invalid_plugins_value.json",
+ errors::kPluginsRequirementDeprecated},
+ EXPECT_TYPE_WARNING);
+ RunTestcase(
+ {"requirements_npapi_false.json", errors::kPluginsRequirementDeprecated},
+ EXPECT_TYPE_WARNING);
+
+ // Explicitly requesting the npapi requirement should cause an error.
+ RunTestcase(
+ {"requirements_npapi_true.json", errors::kNPAPIPluginsNotSupported},
+ EXPECT_TYPE_ERROR);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_ui_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_ui_unittest.cc
new file mode 100644
index 00000000000..264eb9d8ce4
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_ui_unittest.cc
@@ -0,0 +1,19 @@
+// 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 "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+class UIManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(UIManifestTest, DisallowMultipleUISurfaces) {
+ LoadAndExpectError("multiple_ui_surfaces.json",
+ manifest_errors::kOneUISurfaceOnly);
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_update_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_update_unittest.cc
new file mode 100644
index 00000000000..383b8f41916
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_update_unittest.cc
@@ -0,0 +1,42 @@
+// 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 "base/stl_util.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_url_handlers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using extensions::Extension;
+
+namespace errors = extensions::manifest_errors;
+
+class UpdateURLManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(UpdateURLManifestTest, UpdateUrls) {
+ // Test several valid update urls
+ Testcase testcases[] = {
+ Testcase("update_url_valid_1.json", extensions::Manifest::INTERNAL,
+ Extension::NO_FLAGS),
+ Testcase("update_url_valid_2.json", extensions::Manifest::INTERNAL,
+ Extension::NO_FLAGS),
+ Testcase("update_url_valid_3.json", extensions::Manifest::INTERNAL,
+ Extension::NO_FLAGS),
+ Testcase("update_url_valid_4.json", extensions::Manifest::INTERNAL,
+ Extension::NO_FLAGS)
+ };
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_SUCCESS);
+
+ // Test some invalid update urls
+ Testcase testcases2[] = {
+ Testcase("update_url_invalid_1.json", errors::kInvalidUpdateURL,
+ extensions::Manifest::INTERNAL, Extension::NO_FLAGS),
+ Testcase("update_url_invalid_2.json", errors::kInvalidUpdateURL,
+ extensions::Manifest::INTERNAL, Extension::NO_FLAGS),
+ Testcase("update_url_invalid_3.json", errors::kInvalidUpdateURL,
+ extensions::Manifest::INTERNAL, Extension::NO_FLAGS)
+ };
+ RunTestcases(testcases2, base::size(testcases2), EXPECT_TYPE_ERROR);
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_validapp_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_validapp_unittest.cc
new file mode 100644
index 00000000000..6b53be3f325
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_validapp_unittest.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 <memory>
+#include <utility>
+
+#include "base/values.h"
+#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+typedef ChromeManifestTest ValidAppManifestTest;
+
+TEST_F(ValidAppManifestTest, ValidApp) {
+ scoped_refptr<extensions::Extension> extension(
+ LoadAndExpectSuccess("valid_app.json"));
+ extensions::URLPatternSet expected_patterns;
+ AddPattern(&expected_patterns, "http://www.google.com/mail/*");
+ AddPattern(&expected_patterns, "http://www.google.com/foobar/*");
+ EXPECT_EQ(expected_patterns, extension->web_extent());
+ EXPECT_EQ(extensions::LaunchContainer::kLaunchContainerTab,
+ extensions::AppLaunchInfo::GetLaunchContainer(extension.get()));
+ EXPECT_EQ(GURL("http://www.google.com/mail/"),
+ extensions::AppLaunchInfo::GetLaunchWebURL(extension.get()));
+}
+
+TEST_F(ValidAppManifestTest, AllowUnrecognizedPermissions) {
+ std::string error;
+ base::Value manifest = LoadManifest("valid_app.json", &error);
+ base::Value* permissions =
+ manifest.FindKeyOfType("permissions", base::Value::Type::LIST);
+ ASSERT_TRUE(permissions);
+ permissions->Append("not-a-valid-permission");
+ LoadAndExpectSuccess(ManifestData(std::move(manifest), ""));
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_web_accessible_resources_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_web_accessible_resources_unittest.cc
new file mode 100644
index 00000000000..7dcd8b9b911
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_web_accessible_resources_unittest.cc
@@ -0,0 +1,55 @@
+// 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 "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using extensions::Extension;
+using extensions::WebAccessibleResourcesInfo;
+
+class WebAccessibleResourcesManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(WebAccessibleResourcesManifestTest, WebAccessibleResources) {
+ // No web_accessible_resources.
+ scoped_refptr<Extension> none(
+ LoadAndExpectSuccess("web_accessible_resources_none.json"));
+ EXPECT_FALSE(
+ WebAccessibleResourcesInfo::HasWebAccessibleResources(none.get()));
+ EXPECT_FALSE(
+ WebAccessibleResourcesInfo::IsResourceWebAccessible(none.get(), "test"));
+
+ // web_accessible_resources: ["test"].
+ scoped_refptr<Extension> single(
+ LoadAndExpectSuccess("web_accessible_resources_single.json"));
+ EXPECT_TRUE(
+ WebAccessibleResourcesInfo::HasWebAccessibleResources(single.get()));
+ EXPECT_TRUE(WebAccessibleResourcesInfo::IsResourceWebAccessible(single.get(),
+ "test"));
+ EXPECT_FALSE(WebAccessibleResourcesInfo::IsResourceWebAccessible(single.get(),
+ "other"));
+
+ // web_accessible_resources: ["*"].
+ scoped_refptr<Extension> wildcard(
+ LoadAndExpectSuccess("web_accessible_resources_wildcard.json"));
+ EXPECT_TRUE(
+ WebAccessibleResourcesInfo::HasWebAccessibleResources(wildcard.get()));
+ EXPECT_TRUE(WebAccessibleResourcesInfo::IsResourceWebAccessible(
+ wildcard.get(), "anything"));
+ EXPECT_TRUE(WebAccessibleResourcesInfo::IsResourceWebAccessible(
+ wildcard.get(), "path/anything"));
+
+ // web_accessible_resources: ["path/*.ext"].
+ scoped_refptr<Extension> pattern(
+ LoadAndExpectSuccess("web_accessible_resources_pattern.json"));
+ EXPECT_TRUE(
+ WebAccessibleResourcesInfo::HasWebAccessibleResources(pattern.get()));
+ EXPECT_TRUE(WebAccessibleResourcesInfo::IsResourceWebAccessible(
+ pattern.get(), "path/anything.ext"));
+ EXPECT_FALSE(WebAccessibleResourcesInfo::IsResourceWebAccessible(
+ pattern.get(), "anything.ext"));
+ EXPECT_FALSE(WebAccessibleResourcesInfo::IsResourceWebAccessible(
+ pattern.get(), "path/anything.badext"));
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_web_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_web_unittest.cc
new file mode 100644
index 00000000000..b491b978ec8
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_web_unittest.cc
@@ -0,0 +1,52 @@
+// 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 "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using extensions::ErrorUtils;
+using extensions::Extension;
+
+namespace errors = extensions::manifest_errors;
+
+TEST_F(ChromeManifestTest, AppWebUrls) {
+ Testcase testcases[] = {
+ Testcase("web_urls_wrong_type.json", errors::kInvalidWebURLs),
+ Testcase("web_urls_invalid_1.json",
+ ErrorUtils::FormatErrorMessage(errors::kInvalidWebURL,
+ base::NumberToString(0),
+ errors::kExpectString)),
+ Testcase("web_urls_invalid_2.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidWebURL, base::NumberToString(0),
+ URLPattern::GetParseResultString(
+ URLPattern::ParseResult::kMissingSchemeSeparator))),
+ Testcase("web_urls_invalid_3.json",
+ ErrorUtils::FormatErrorMessage(errors::kInvalidWebURL,
+ base::NumberToString(0),
+ errors::kNoWildCardsInPaths)),
+ Testcase("web_urls_invalid_4.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidWebURL, base::NumberToString(0),
+ errors::kCannotClaimAllURLsInExtent)),
+ Testcase("web_urls_invalid_5.json",
+ ErrorUtils::FormatErrorMessage(
+ errors::kInvalidWebURL, base::NumberToString(1),
+ errors::kCannotClaimAllHostsInExtent))};
+ RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR);
+
+ LoadAndExpectSuccess("web_urls_has_port.json");
+
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("web_urls_default.json"));
+ ASSERT_EQ(1u, extension->web_extent().patterns().size());
+ EXPECT_EQ("*://www.google.com/*",
+ extension->web_extent().patterns().begin()->GetAsString());
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/extension_manifests_webview_accessible_resources_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_webview_accessible_resources_unittest.cc
new file mode 100644
index 00000000000..8d1826812e2
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/extension_manifests_webview_accessible_resources_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright 2014 The Chromium Authors. 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/string_number_conversions.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+#include "extensions/common/manifest_handlers/webview_info.h"
+
+using extensions::ErrorUtils;
+using extensions::Extension;
+using extensions::WebviewInfo;
+namespace errors = extensions::manifest_errors;
+
+class WebviewAccessibleResourcesManifestTest : public ChromeManifestTest {
+};
+
+TEST_F(WebviewAccessibleResourcesManifestTest, WebviewAccessibleResources) {
+ // Manifest version 2 with webview accessible resources specified.
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("webview_accessible_resources_1.json"));
+
+ EXPECT_FALSE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "fail", "a.html"));
+ EXPECT_FALSE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "fail", "b.html"));
+ EXPECT_FALSE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "fail", "c.html"));
+ EXPECT_FALSE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "fail", "d.html"));
+
+ EXPECT_TRUE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "foo", "a.html"));
+ EXPECT_TRUE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "foo", "b.html"));
+ EXPECT_FALSE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "foo", "c.html"));
+ EXPECT_FALSE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "foo", "d.html"));
+
+ EXPECT_TRUE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "bar", "a.html"));
+ EXPECT_FALSE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "bar", "b.html"));
+ EXPECT_TRUE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "bar", "c.html"));
+ EXPECT_FALSE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "bar", "d.html"));
+
+ EXPECT_TRUE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "foobar", "a.html"));
+ EXPECT_TRUE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "foobar", "b.html"));
+ EXPECT_TRUE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "foobar", "c.html"));
+ EXPECT_FALSE(WebviewInfo::IsResourceWebviewAccessible(extension.get(),
+ "foobar", "d.html"));
+
+ EXPECT_FALSE(WebviewInfo::IsResourceWebviewAccessible(nullptr,
+ "foobar", "a.html"));
+}
+
+TEST_F(WebviewAccessibleResourcesManifestTest, InvalidManifest) {
+ LoadAndExpectError("webview_accessible_resources_invalid1.json",
+ errors::kInvalidWebview);
+ LoadAndExpectError("webview_accessible_resources_invalid2.json",
+ errors::kInvalidWebviewPartitionsList);
+ LoadAndExpectError("webview_accessible_resources_invalid3.json",
+ errors::kInvalidWebviewPartitionsList);
+ LoadAndExpectError(
+ "webview_accessible_resources_invalid4.json",
+ ErrorUtils::FormatErrorMessage(errors::kInvalidWebviewPartition,
+ base::NumberToString(0)));
+ LoadAndExpectError("webview_accessible_resources_invalid5.json",
+ errors::kInvalidWebviewPartitionName);
+ LoadAndExpectError("webview_accessible_resources_invalid6.json",
+ errors::kInvalidWebviewAccessibleResourcesList);
+ LoadAndExpectError("webview_accessible_resources_invalid7.json",
+ errors::kInvalidWebviewAccessibleResourcesList);
+ LoadAndExpectError(
+ "webview_accessible_resources_invalid8.json",
+ ErrorUtils::FormatErrorMessage(errors::kInvalidWebviewAccessibleResource,
+ base::NumberToString(0)));
+}
diff --git a/chromium/chrome/common/extensions/manifest_tests/permissions_parser_unittest.cc b/chromium/chrome/common/extensions/manifest_tests/permissions_parser_unittest.cc
new file mode 100644
index 00000000000..a87649ba8f3
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_tests/permissions_parser_unittest.cc
@@ -0,0 +1,138 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/common/manifest_handlers/permissions_parser.h"
+#include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace {
+
+// Install warning for tests running Manifest v3. The current highest
+// supported manifest version is 2.
+constexpr char kManifestVersionWarning[] =
+ "The maximum currently-supported manifest version is 2, but this is 3. "
+ "Certain features may not work as expected.";
+} // namespace
+
+using PermissionsParserTest = ChromeManifestTest;
+
+TEST_F(PermissionsParserTest, RemoveOverlappingAPIPermissions) {
+ scoped_refptr<Extension> extension(LoadAndExpectWarning(
+ "permissions_overlapping_api_permissions.json",
+ ErrorUtils::FormatErrorMessage(
+ manifest_errors::kPermissionMarkedOptionalAndRequired, "tabs")));
+
+ std::set<std::string> required_api_names =
+ PermissionsParser::GetRequiredPermissions(extension.get())
+ .GetAPIsAsStrings();
+
+ std::set<std::string> optional_api_names =
+ PermissionsParser::GetOptionalPermissions(extension.get())
+ .GetAPIsAsStrings();
+
+ // Check that required api permissions have not changed while "tabs" is
+ // removed from optional permissions as it is specified as required.
+ EXPECT_THAT(required_api_names,
+ testing::UnorderedElementsAre("tabs", "storage"));
+ EXPECT_THAT(optional_api_names, testing::UnorderedElementsAre("geolocation"));
+}
+
+TEST_F(PermissionsParserTest, RemoveOverlappingHostPermissions) {
+ scoped_refptr<Extension> extension(LoadAndExpectWarning(
+ "permissions_overlapping_host_permissions.json",
+ ErrorUtils::FormatErrorMessage(
+ manifest_errors::kPermissionMarkedOptionalAndRequired,
+ "https://google.com/*")));
+
+ const URLPatternSet& required_hosts =
+ PermissionsParser::GetRequiredPermissions(extension.get())
+ .explicit_hosts();
+
+ const URLPatternSet& optional_hosts =
+ PermissionsParser::GetOptionalPermissions(extension.get())
+ .explicit_hosts();
+
+ // Check that required hosts have not changed at all while
+ // "https://google.com/maps" is removed from optional hosts as it is a strict
+ // subset of hosts specified as required.
+ EXPECT_THAT(*required_hosts.ToStringVector(),
+ testing::UnorderedElementsAre("https://example.com/*",
+ "https://*.google.com/*"));
+ EXPECT_THAT(*optional_hosts.ToStringVector(),
+ testing::UnorderedElementsAre("*://chromium.org/*"));
+}
+
+TEST_F(PermissionsParserTest, RequiredHostPermissionsAllURLs) {
+ scoped_refptr<Extension> extension(LoadAndExpectWarning(
+ "permissions_all_urls_host_permissions.json",
+ ErrorUtils::FormatErrorMessage(
+ manifest_errors::kPermissionMarkedOptionalAndRequired,
+ "http://*/*")));
+
+ const URLPatternSet& optional_hosts =
+ PermissionsParser::GetOptionalPermissions(extension.get())
+ .explicit_hosts();
+
+ // Since we specified <all_urls> as a required host permission,
+ // there should be no optional host permissions.
+ EXPECT_THAT(*optional_hosts.ToStringVector(), testing::IsEmpty());
+}
+
+TEST_F(PermissionsParserTest, OptionalHostPermissionsAllURLs) {
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("permissions_optional_all_urls_permissions.json"));
+
+ const URLPatternSet& required_hosts =
+ PermissionsParser::GetRequiredPermissions(extension.get())
+ .explicit_hosts();
+
+ const URLPatternSet& optional_hosts =
+ PermissionsParser::GetOptionalPermissions(extension.get())
+ .explicit_hosts();
+
+ // This time, required permissions are a subset of optional permissions
+ // so we make sure that permissions remain the same
+ // as what's specified in the manifest.
+ EXPECT_THAT(*required_hosts.ToStringVector(),
+ testing::UnorderedElementsAre("https://*.google.com/*"));
+
+ EXPECT_THAT(*optional_hosts.ToStringVector(),
+ testing::UnorderedElementsAre("*://*/*"));
+}
+
+TEST_F(PermissionsParserTest, HostPermissionsKey) {
+ std::vector<std::string> expected_warnings;
+ expected_warnings.push_back(ErrorUtils::FormatErrorMessage(
+ manifest_errors::kPermissionUnknownOrMalformed, "https://google.com/*"));
+
+ expected_warnings.push_back(kManifestVersionWarning);
+
+ scoped_refptr<Extension> extension(
+ LoadAndExpectWarnings("host_permissions_key.json", expected_warnings));
+
+ // Expect that the host specified in |host_permissions| is parsed.
+ const URLPatternSet& required_hosts =
+ PermissionsParser::GetRequiredPermissions(extension.get())
+ .explicit_hosts();
+
+ EXPECT_THAT(*required_hosts.ToStringVector(),
+ testing::UnorderedElementsAre("https://example.com/*"));
+}
+
+TEST_F(PermissionsParserTest, HostPermissionsKeyInvalidHosts) {
+ std::vector<std::string> expected_warnings;
+ expected_warnings.push_back(ErrorUtils::FormatErrorMessage(
+ manifest_errors::kPermissionUnknownOrMalformed, "malformed_host"));
+
+ expected_warnings.push_back(kManifestVersionWarning);
+
+ scoped_refptr<Extension> extension(LoadAndExpectWarnings(
+ "host_permissions_key_invalid_hosts.json", expected_warnings));
+}
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/manifest_unittest.cc b/chromium/chrome/common/extensions/manifest_unittest.cc
new file mode 100644
index 00000000000..ea51906eb54
--- /dev/null
+++ b/chromium/chrome/common/extensions/manifest_unittest.cc
@@ -0,0 +1,222 @@
+// 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 "extensions/common/manifest.h"
+
+#include <algorithm>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/features/feature.h"
+#include "extensions/common/features/simple_feature.h"
+#include "extensions/common/install_warning.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace errors = manifest_errors;
+namespace keys = manifest_keys;
+
+// Not named "ManifestTest" because a test utility class has that name.
+class ManifestUnitTest : public testing::Test {
+ public:
+ ManifestUnitTest() : default_value_("test") {}
+
+ protected:
+ void AssertType(Manifest* manifest, Manifest::Type type) {
+ EXPECT_EQ(type, manifest->type());
+ EXPECT_EQ(type == Manifest::TYPE_THEME, manifest->is_theme());
+ EXPECT_EQ(type == Manifest::TYPE_PLATFORM_APP,
+ manifest->is_platform_app());
+ EXPECT_EQ(type == Manifest::TYPE_LEGACY_PACKAGED_APP,
+ manifest->is_legacy_packaged_app());
+ EXPECT_EQ(type == Manifest::TYPE_HOSTED_APP, manifest->is_hosted_app());
+ EXPECT_EQ(type == Manifest::TYPE_SHARED_MODULE,
+ manifest->is_shared_module());
+ EXPECT_EQ(type == Manifest::TYPE_LOGIN_SCREEN_EXTENSION,
+ manifest->is_login_screen_extension());
+ }
+
+ // Helper function that replaces the Manifest held by |manifest| with a copy
+ // with its |key| changed to |value|. If |value| is nullptr, then |key| will
+ // instead be deleted.
+ void MutateManifest(std::unique_ptr<Manifest>* manifest,
+ const std::string& key,
+ std::unique_ptr<base::Value> value) {
+ auto manifest_value = manifest->get()->value()->CreateDeepCopy();
+ if (value)
+ manifest_value->Set(key, std::move(value));
+ else
+ manifest_value->Remove(key, nullptr);
+ manifest->reset(
+ new Manifest(Manifest::INTERNAL, std::move(manifest_value)));
+ }
+
+ // Helper function that replaces the manifest held by |manifest| with a copy
+ // and uses the |for_login_screen| during creation to determine its type.
+ void MutateManifestForLoginScreen(std::unique_ptr<Manifest>* manifest,
+ bool for_login_screen) {
+ auto manifest_value = manifest->get()->value()->CreateDeepCopy();
+ if (for_login_screen) {
+ *manifest = Manifest::CreateManifestForLoginScreen(
+ Manifest::EXTERNAL_POLICY, std::move(manifest_value));
+ } else {
+ *manifest = std::make_unique<Manifest>(Manifest::INTERNAL,
+ std::move(manifest_value));
+ }
+ }
+
+ std::string default_value_;
+};
+
+// Verifies that extensions can access the correct keys.
+TEST_F(ManifestUnitTest, Extension) {
+ std::unique_ptr<base::DictionaryValue> manifest_value(
+ new base::DictionaryValue());
+ manifest_value->SetString(keys::kName, "extension");
+ manifest_value->SetString(keys::kVersion, "1");
+ manifest_value->SetInteger(keys::kManifestVersion, 2);
+ manifest_value->SetString(keys::kBackgroundPage, "bg.html");
+ manifest_value->SetString("unknown_key", "foo");
+
+ std::unique_ptr<Manifest> manifest(
+ new Manifest(Manifest::INTERNAL, std::move(manifest_value)));
+ std::string error;
+ std::vector<InstallWarning> warnings;
+ EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings));
+ EXPECT_TRUE(error.empty());
+ ASSERT_EQ(1u, warnings.size());
+ AssertType(manifest.get(), Manifest::TYPE_EXTENSION);
+
+ // The known key 'background.page' should be accessible.
+ std::string value;
+ EXPECT_TRUE(manifest->GetString(keys::kBackgroundPage, &value));
+ EXPECT_EQ("bg.html", value);
+
+ // The unknown key 'unknown_key' should be accesible.
+ value.clear();
+ EXPECT_TRUE(manifest->GetString("unknown_key", &value));
+ EXPECT_EQ("foo", value);
+
+ // Test CreateDeepCopy and Equals.
+ std::unique_ptr<Manifest> manifest2 = manifest->CreateDeepCopy();
+ EXPECT_TRUE(manifest->Equals(manifest2.get()));
+ EXPECT_TRUE(manifest2->Equals(manifest.get()));
+ MutateManifest(&manifest, "foo", std::make_unique<base::Value>("blah"));
+ EXPECT_FALSE(manifest->Equals(manifest2.get()));
+}
+
+// Verifies that key restriction based on type works.
+TEST_F(ManifestUnitTest, ExtensionTypes) {
+ std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue());
+ value->SetString(keys::kName, "extension");
+ value->SetString(keys::kVersion, "1");
+
+ std::unique_ptr<Manifest> manifest(
+ new Manifest(Manifest::INTERNAL, std::move(value)));
+ std::string error;
+ std::vector<InstallWarning> warnings;
+ EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings));
+ EXPECT_TRUE(error.empty());
+ EXPECT_TRUE(warnings.empty());
+
+ // By default, the type is Extension.
+ AssertType(manifest.get(), Manifest::TYPE_EXTENSION);
+
+ // Login screen extension
+ MutateManifestForLoginScreen(&manifest, true);
+ AssertType(manifest.get(), Manifest::TYPE_LOGIN_SCREEN_EXTENSION);
+ MutateManifestForLoginScreen(&manifest, false);
+
+ // Theme.
+ MutateManifest(&manifest, keys::kTheme,
+ std::make_unique<base::DictionaryValue>());
+ AssertType(manifest.get(), Manifest::TYPE_THEME);
+ MutateManifest(&manifest, keys::kTheme, nullptr);
+
+ // Shared module.
+ MutateManifest(&manifest, keys::kExport,
+ std::make_unique<base::DictionaryValue>());
+ AssertType(manifest.get(), Manifest::TYPE_SHARED_MODULE);
+ MutateManifest(&manifest, keys::kExport, nullptr);
+
+ // Packaged app.
+ MutateManifest(&manifest, keys::kApp,
+ std::make_unique<base::DictionaryValue>());
+ AssertType(manifest.get(), Manifest::TYPE_LEGACY_PACKAGED_APP);
+
+ // Packaged app for login screen remains a packaged app.
+ MutateManifestForLoginScreen(&manifest, true);
+ AssertType(manifest.get(), Manifest::TYPE_LEGACY_PACKAGED_APP);
+ MutateManifestForLoginScreen(&manifest, false);
+
+ // Platform app with event page.
+ MutateManifest(&manifest, keys::kPlatformAppBackground,
+ std::make_unique<base::DictionaryValue>());
+ AssertType(manifest.get(), Manifest::TYPE_PLATFORM_APP);
+ MutateManifest(&manifest, keys::kPlatformAppBackground, nullptr);
+
+ // Hosted app.
+ MutateManifest(&manifest, keys::kWebURLs,
+ std::make_unique<base::ListValue>());
+ AssertType(manifest.get(), Manifest::TYPE_HOSTED_APP);
+ MutateManifest(&manifest, keys::kWebURLs, nullptr);
+ MutateManifest(&manifest, keys::kLaunchWebURL,
+ std::make_unique<base::Value>("foo"));
+ AssertType(manifest.get(), Manifest::TYPE_HOSTED_APP);
+ MutateManifest(&manifest, keys::kLaunchWebURL, nullptr);
+}
+
+// Verifies that the getters filter restricted keys.
+TEST_F(ManifestUnitTest, RestrictedKeys) {
+ std::unique_ptr<base::DictionaryValue> value(new base::DictionaryValue());
+ value->SetString(keys::kName, "extension");
+ value->SetString(keys::kVersion, "1");
+
+ std::unique_ptr<Manifest> manifest(
+ new Manifest(Manifest::INTERNAL, std::move(value)));
+ std::string error;
+ std::vector<InstallWarning> warnings;
+ EXPECT_TRUE(manifest->ValidateManifest(&error, &warnings));
+ EXPECT_TRUE(error.empty());
+ EXPECT_TRUE(warnings.empty());
+
+ // "Commands" requires manifest version 2.
+ const base::Value* output = nullptr;
+ MutateManifest(&manifest, keys::kCommands,
+ std::make_unique<base::DictionaryValue>());
+ EXPECT_FALSE(manifest->HasKey(keys::kCommands));
+ EXPECT_FALSE(manifest->Get(keys::kCommands, &output));
+
+ MutateManifest(&manifest, keys::kManifestVersion,
+ std::make_unique<base::Value>(2));
+ EXPECT_TRUE(manifest->HasKey(keys::kCommands));
+ EXPECT_TRUE(manifest->Get(keys::kCommands, &output));
+
+ MutateManifest(&manifest, keys::kPageAction,
+ std::make_unique<base::DictionaryValue>());
+ AssertType(manifest.get(), Manifest::TYPE_EXTENSION);
+ EXPECT_TRUE(manifest->HasKey(keys::kPageAction));
+ EXPECT_TRUE(manifest->Get(keys::kPageAction, &output));
+
+ // Platform apps cannot have a "page_action" key.
+ MutateManifest(&manifest, keys::kPlatformAppBackground,
+ std::make_unique<base::DictionaryValue>());
+ AssertType(manifest.get(), Manifest::TYPE_PLATFORM_APP);
+ EXPECT_FALSE(manifest->HasKey(keys::kPageAction));
+ EXPECT_FALSE(manifest->Get(keys::kPageAction, &output));
+ MutateManifest(&manifest, keys::kPlatformAppBackground, nullptr);
+
+ // Platform apps also can't have a "Commands" key.
+ EXPECT_FALSE(manifest->HasKey(keys::kCommands));
+ EXPECT_FALSE(manifest->Get(keys::kCommands, &output));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/sync_helper.cc b/chromium/chrome/common/extensions/sync_helper.cc
new file mode 100644
index 00000000000..05a8df68c47
--- /dev/null
+++ b/chromium/chrome/common/extensions/sync_helper.cc
@@ -0,0 +1,79 @@
+// 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 "chrome/common/extensions/sync_helper.h"
+
+#include "base/logging.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/features/behavior_feature.h"
+#include "extensions/common/features/feature.h"
+#include "extensions/common/features/feature_provider.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_url_handlers.h"
+
+namespace extensions {
+namespace sync_helper {
+
+bool IsSyncable(const Extension* extension) {
+ const Feature* feature =
+ FeatureProvider::GetBehaviorFeature(behavior_feature::kDoNotSync);
+ if (feature && feature->IsAvailableToExtension(extension).is_available())
+ return false;
+
+ // Default apps are not synced because otherwise they will pollute profiles
+ // that don't already have them. Specially, if a user doesn't have default
+ // apps, creates a new profile (which get default apps) and then enables sync
+ // for it, then their profile everywhere gets the default apps.
+ bool is_syncable = (extension->location() == Manifest::INTERNAL &&
+ !extension->was_installed_by_default());
+ if (!is_syncable && !IsSyncableComponentExtension(extension)) {
+ // We have a non-standard location.
+ return false;
+ }
+
+ // Disallow extensions with non-gallery auto-update URLs for now.
+ //
+ // TODO(akalin): Relax this restriction once we've put in UI to
+ // approve synced extensions.
+ if (!ManifestURL::GetUpdateURL(extension).is_empty() &&
+ !ManifestURL::UpdatesFromGallery(extension)) {
+ return false;
+ }
+
+ switch (extension->GetType()) {
+ case Manifest::TYPE_EXTENSION:
+ case Manifest::TYPE_HOSTED_APP:
+ case Manifest::TYPE_LEGACY_PACKAGED_APP:
+ case Manifest::TYPE_PLATFORM_APP:
+ case Manifest::TYPE_THEME:
+ return true;
+
+ case Manifest::TYPE_USER_SCRIPT:
+ // We only want to sync user scripts with gallery update URLs.
+ if (ManifestURL::UpdatesFromGallery(extension))
+ return true;
+ return false;
+
+ case Manifest::TYPE_UNKNOWN:
+ case Manifest::TYPE_SHARED_MODULE:
+ case Manifest::TYPE_LOGIN_SCREEN_EXTENSION:
+ return false;
+
+ case Manifest::NUM_LOAD_TYPES:
+ NOTREACHED();
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool IsSyncableComponentExtension(const Extension* extension) {
+ if (!Manifest::IsComponentLocation(extension->location()))
+ return false;
+ return (extension->id() == extensions::kWebStoreAppId) ||
+ (extension->id() == extension_misc::kChromeAppId);
+}
+
+} // namespace sync_helper
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/sync_helper.h b/chromium/chrome/common/extensions/sync_helper.h
new file mode 100644
index 00000000000..c3c3741a3b8
--- /dev/null
+++ b/chromium/chrome/common/extensions/sync_helper.h
@@ -0,0 +1,29 @@
+// 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 CHROME_COMMON_EXTENSIONS_SYNC_HELPER_H_
+#define CHROME_COMMON_EXTENSIONS_SYNC_HELPER_H_
+
+namespace extensions {
+
+class Extension;
+
+namespace sync_helper {
+
+// NOTE: The check in the functions here only considers the data in extension
+// itself, not the environment it is in. To determine whether an extension
+// should be synced, you probably want to use util::ShouldSync.
+
+// Returns true if |extension| should be synced.
+bool IsSyncable(const Extension* extension);
+
+// Component extensions usually aren't synced, but some are so that they'll
+// retain their position in the app list. Returns true for component extensions
+// on that whitelist.
+bool IsSyncableComponentExtension(const Extension* extension);
+
+} // namespace sync_helper
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_SYNC_HELPER_H_
diff --git a/chromium/chrome/common/extensions/sync_type_unittest.cc b/chromium/chrome/common/extensions/sync_type_unittest.cc
new file mode 100644
index 00000000000..2150a485ca1
--- /dev/null
+++ b/chromium/chrome/common/extensions/sync_type_unittest.cc
@@ -0,0 +1,233 @@
+// 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 <utility>
+
+#include "base/files/file_path.h"
+#include "base/values.h"
+#include "chrome/common/extensions/sync_helper.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/features/simple_feature.h"
+#include "extensions/common/manifest.h"
+#include "extensions/common/manifest_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+namespace keys = manifest_keys;
+namespace errors = manifest_errors;
+
+class ExtensionSyncTypeTest : public testing::Test {
+ protected:
+ enum SyncTestExtensionType {
+ EXTENSION,
+ APP,
+ USER_SCRIPT,
+ THEME
+ };
+
+ static scoped_refptr<Extension> MakeSyncTestExtension(
+ SyncTestExtensionType type,
+ const GURL& update_url,
+ const GURL& launch_url,
+ Manifest::Location location,
+ const base::FilePath& extension_path,
+ int creation_flags) {
+ base::DictionaryValue source;
+ source.SetString(keys::kName, "PossiblySyncableExtension");
+ source.SetString(keys::kVersion, "0.0.0.0");
+ source.SetInteger(keys::kManifestVersion, 2);
+ if (type == APP)
+ source.SetString(keys::kApp, "true");
+ if (type == THEME)
+ source.Set(keys::kTheme, std::make_unique<base::DictionaryValue>());
+ if (!update_url.is_empty()) {
+ source.SetString(keys::kUpdateURL, update_url.spec());
+ }
+ if (!launch_url.is_empty()) {
+ source.SetString(keys::kLaunchWebURL, launch_url.spec());
+ }
+ if (type != THEME)
+ source.SetBoolean(keys::kConvertedFromUserScript, type == USER_SCRIPT);
+
+ std::string error;
+ scoped_refptr<Extension> extension = Extension::Create(
+ extension_path, location, source, creation_flags, &error);
+ EXPECT_TRUE(extension.get());
+ EXPECT_TRUE(error.empty());
+ return extension;
+ }
+
+ static const char kValidUpdateUrl1[];
+ static const char kValidUpdateUrl2[];
+};
+
+const char ExtensionSyncTypeTest::kValidUpdateUrl1[] =
+ "http://clients2.google.com/service/update2/crx";
+const char ExtensionSyncTypeTest::kValidUpdateUrl2[] =
+ "https://clients2.google.com/service/update2/crx";
+
+TEST_F(ExtensionSyncTypeTest, NormalExtensionNoUpdateUrl) {
+ scoped_refptr<Extension> extension(
+ MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
+ Manifest::INTERNAL, base::FilePath(),
+ Extension::NO_FLAGS));
+ EXPECT_TRUE(extension->is_extension());
+ EXPECT_TRUE(sync_helper::IsSyncable(extension.get()));
+}
+
+TEST_F(ExtensionSyncTypeTest, UserScriptValidUpdateUrl) {
+ scoped_refptr<Extension> extension(
+ MakeSyncTestExtension(USER_SCRIPT, GURL(kValidUpdateUrl1), GURL(),
+ Manifest::INTERNAL, base::FilePath(),
+ Extension::NO_FLAGS));
+ EXPECT_TRUE(extension->is_extension());
+ EXPECT_TRUE(sync_helper::IsSyncable(extension.get()));
+}
+
+TEST_F(ExtensionSyncTypeTest, UserScriptNoUpdateUrl) {
+ scoped_refptr<Extension> extension(
+ MakeSyncTestExtension(USER_SCRIPT, GURL(), GURL(),
+ Manifest::INTERNAL, base::FilePath(),
+ Extension::NO_FLAGS));
+ EXPECT_TRUE(extension->is_extension());
+ EXPECT_FALSE(sync_helper::IsSyncable(extension.get()));
+}
+
+TEST_F(ExtensionSyncTypeTest, ThemeNoUpdateUrl) {
+ scoped_refptr<Extension> extension(
+ MakeSyncTestExtension(THEME, GURL(), GURL(),
+ Manifest::INTERNAL, base::FilePath(),
+ Extension::NO_FLAGS));
+ EXPECT_TRUE(extension->is_theme());
+ EXPECT_TRUE(sync_helper::IsSyncable(extension.get()));
+}
+
+TEST_F(ExtensionSyncTypeTest, AppWithLaunchUrl) {
+ scoped_refptr<Extension> extension(
+ MakeSyncTestExtension(EXTENSION, GURL(), GURL("http://www.google.com"),
+ Manifest::INTERNAL, base::FilePath(),
+ Extension::NO_FLAGS));
+ EXPECT_TRUE(extension->is_app());
+ EXPECT_TRUE(sync_helper::IsSyncable(extension.get()));
+}
+
+TEST_F(ExtensionSyncTypeTest, ExtensionExternal) {
+ scoped_refptr<Extension> extension(
+ MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
+ Manifest::EXTERNAL_PREF, base::FilePath(),
+ Extension::NO_FLAGS));
+ EXPECT_TRUE(extension->is_extension());
+ EXPECT_FALSE(sync_helper::IsSyncable(extension.get()));
+}
+
+TEST_F(ExtensionSyncTypeTest, UserScriptThirdPartyUpdateUrl) {
+ scoped_refptr<Extension> extension(
+ MakeSyncTestExtension(
+ USER_SCRIPT, GURL("http://third-party.update_url.com"), GURL(),
+ Manifest::INTERNAL, base::FilePath(), Extension::NO_FLAGS));
+ EXPECT_TRUE(extension->is_extension());
+ EXPECT_FALSE(sync_helper::IsSyncable(extension.get()));
+}
+
+TEST_F(ExtensionSyncTypeTest, OnlyDisplayAppsInLauncher) {
+ scoped_refptr<Extension> extension(
+ MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
+ Manifest::INTERNAL, base::FilePath(),
+ Extension::NO_FLAGS));
+
+ EXPECT_FALSE(extension->ShouldDisplayInAppLauncher());
+ EXPECT_FALSE(extension->ShouldDisplayInNewTabPage());
+
+ scoped_refptr<Extension> app(
+ MakeSyncTestExtension(APP, GURL(), GURL("http://www.google.com"),
+ Manifest::INTERNAL, base::FilePath(),
+ Extension::NO_FLAGS));
+ EXPECT_TRUE(app->ShouldDisplayInAppLauncher());
+ EXPECT_TRUE(app->ShouldDisplayInNewTabPage());
+}
+
+TEST_F(ExtensionSyncTypeTest, DisplayInXManifestProperties) {
+ base::DictionaryValue manifest;
+ manifest.SetString(keys::kName, "TestComponentApp");
+ manifest.SetString(keys::kVersion, "0.0.0.0");
+ manifest.SetString(keys::kApp, "true");
+ manifest.SetString(keys::kPlatformAppBackgroundPage, std::string());
+
+ std::string error;
+ scoped_refptr<Extension> app;
+
+ // Default to true.
+ app = Extension::Create(
+ base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
+ EXPECT_EQ(error, std::string());
+ EXPECT_TRUE(app->ShouldDisplayInAppLauncher());
+ EXPECT_TRUE(app->ShouldDisplayInNewTabPage());
+
+ // Value display_in_NTP defaults to display_in_launcher.
+ manifest.SetBoolean(keys::kDisplayInLauncher, false);
+ app = Extension::Create(
+ base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
+ EXPECT_EQ(error, std::string());
+ EXPECT_FALSE(app->ShouldDisplayInAppLauncher());
+ EXPECT_FALSE(app->ShouldDisplayInNewTabPage());
+
+ // Value display_in_NTP = true overriding display_in_launcher = false.
+ manifest.SetBoolean(keys::kDisplayInNewTabPage, true);
+ app = Extension::Create(
+ base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
+ EXPECT_EQ(error, std::string());
+ EXPECT_FALSE(app->ShouldDisplayInAppLauncher());
+ EXPECT_TRUE(app->ShouldDisplayInNewTabPage());
+
+ // Value display_in_NTP = false only, overrides default = true.
+ manifest.Remove(keys::kDisplayInLauncher, NULL);
+ manifest.SetBoolean(keys::kDisplayInNewTabPage, false);
+ app = Extension::Create(
+ base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
+ EXPECT_EQ(error, std::string());
+ EXPECT_TRUE(app->ShouldDisplayInAppLauncher());
+ EXPECT_FALSE(app->ShouldDisplayInNewTabPage());
+
+ // Error checking.
+ manifest.SetString(keys::kDisplayInNewTabPage, "invalid");
+ app = Extension::Create(
+ base::FilePath(), Manifest::COMPONENT, manifest, 0, &error);
+ EXPECT_EQ(error, std::string(errors::kInvalidDisplayInNewTabPage));
+}
+
+TEST_F(ExtensionSyncTypeTest, OnlySyncInternal) {
+ scoped_refptr<Extension> extension_internal(
+ MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
+ Manifest::INTERNAL, base::FilePath(),
+ Extension::NO_FLAGS));
+ EXPECT_TRUE(sync_helper::IsSyncable(extension_internal.get()));
+
+ scoped_refptr<Extension> extension_noninternal(
+ MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
+ Manifest::COMPONENT, base::FilePath(),
+ Extension::NO_FLAGS));
+ EXPECT_FALSE(sync_helper::IsSyncable(extension_noninternal.get()));
+}
+
+TEST_F(ExtensionSyncTypeTest, DontSyncDefault) {
+ scoped_refptr<Extension> extension_default(
+ MakeSyncTestExtension(EXTENSION, GURL(), GURL(),
+ Manifest::INTERNAL, base::FilePath(),
+ Extension::WAS_INSTALLED_BY_DEFAULT));
+ EXPECT_FALSE(sync_helper::IsSyncable(extension_default.get()));
+}
+
+TEST_F(ExtensionSyncTypeTest, DontSyncExtensionInDoNotSyncList) {
+ scoped_refptr<Extension> extension(
+ MakeSyncTestExtension(EXTENSION, GURL(), GURL(), Manifest::INTERNAL,
+ base::FilePath(), Extension::NO_FLAGS));
+ EXPECT_TRUE(extension->is_extension());
+ EXPECT_TRUE(sync_helper::IsSyncable(extension.get()));
+ SimpleFeature::ScopedThreadUnsafeAllowlistForTest allowlist(extension->id());
+ EXPECT_FALSE(sync_helper::IsSyncable(extension.get()));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/webstore_install_result.cc b/chromium/chrome/common/extensions/webstore_install_result.cc
new file mode 100644
index 00000000000..25194190ea7
--- /dev/null
+++ b/chromium/chrome/common/extensions/webstore_install_result.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 "chrome/common/extensions/webstore_install_result.h"
+
+namespace extensions {
+namespace webstore_install {
+
+const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
+const char kWebstoreRequestError[] =
+ "Could not fetch data from the Chrome Web Store";
+const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
+const char kInvalidManifestError[] = "Invalid manifest";
+const char kUserCancelledError[] = "User cancelled install";
+const char kExtensionIsBlacklisted[] = "Extension is blacklisted";
+const char kInstallInProgressError[] = "An install is already in progress";
+
+} // namespace webstore_install
+} // namespace extensions
diff --git a/chromium/chrome/common/extensions/webstore_install_result.h b/chromium/chrome/common/extensions/webstore_install_result.h
new file mode 100644
index 00000000000..74d81848567
--- /dev/null
+++ b/chromium/chrome/common/extensions/webstore_install_result.h
@@ -0,0 +1,87 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_EXTENSIONS_WEBSTORE_INSTALL_RESULT_H_
+#define CHROME_COMMON_EXTENSIONS_WEBSTORE_INSTALL_RESULT_H_
+
+namespace extensions {
+
+namespace webstore_install {
+
+extern const char kInvalidWebstoreItemId[];
+extern const char kWebstoreRequestError[];
+extern const char kInvalidWebstoreResponseError[];
+extern const char kInvalidManifestError[];
+extern const char kUserCancelledError[];
+extern const char kExtensionIsBlacklisted[];
+extern const char kInstallInProgressError[];
+
+// Result codes returned by WebstoreStandaloneInstaller and its subclasses.
+enum Result {
+ // Successful operation.
+ SUCCESS,
+
+ // Unknown error.
+ OTHER_ERROR,
+
+ // The operation was aborted as the requestor is no longer alive.
+ ABORTED,
+
+ // An installation of the same extension is in progress.
+ INSTALL_IN_PROGRESS,
+
+ // The installation is not permitted.
+ NOT_PERMITTED,
+
+ // Invalid Chrome Web Store item ID.
+ INVALID_ID,
+
+ // Failed to retrieve extension metadata from the Web Store.
+ WEBSTORE_REQUEST_ERROR,
+
+ // The extension metadata retrieved from the Web Store was invalid.
+ INVALID_WEBSTORE_RESPONSE,
+
+ // An error occurred while parsing the extension manifest retrieved from the
+ // Web Store.
+ INVALID_MANIFEST,
+
+ // Failed to retrieve the extension's icon from the Web Store, or the icon
+ // was invalid.
+ ICON_ERROR,
+
+ // The user cancelled the operation.
+ USER_CANCELLED,
+
+ // The extension is blacklisted.
+ BLACKLISTED,
+
+ // Unsatisfied dependencies, such as shared modules.
+ MISSING_DEPENDENCIES,
+
+ // Unsatisfied requirements, such as webgl.
+ REQUIREMENT_VIOLATIONS,
+
+ // The extension is blocked by management policies.
+ BLOCKED_BY_POLICY,
+
+ // The launch feature is not available.
+ LAUNCH_FEATURE_DISABLED,
+
+ // The launch feature is not supported for the extension type.
+ LAUNCH_UNSUPPORTED_EXTENSION_TYPE,
+
+ // A launch of the same extension is in progress.
+ LAUNCH_IN_PROGRESS,
+
+ // The final (and unused) result type for enum verification.
+ // New results should go above this entry, and this entry should be updated.
+ RESULT_LAST = LAUNCH_IN_PROGRESS,
+};
+
+} // namespace webstore_install
+
+} // namespace extensions
+
+#endif // CHROME_COMMON_EXTENSIONS_WEBSTORE_INSTALL_RESULT_H_
diff --git a/chromium/chrome/common/extra_defines.vsprops b/chromium/chrome/common/extra_defines.vsprops
new file mode 100644
index 00000000000..6db717f1ea1
--- /dev/null
+++ b/chromium/chrome/common/extra_defines.vsprops
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="extra"
+ >
+</VisualStudioPropertySheet>
diff --git a/chromium/chrome/common/google_url_loader_throttle.cc b/chromium/chrome/common/google_url_loader_throttle.cc
new file mode 100644
index 00000000000..0a565575f36
--- /dev/null
+++ b/chromium/chrome/common/google_url_loader_throttle.cc
@@ -0,0 +1,114 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/google_url_loader_throttle.h"
+
+#include "chrome/common/net/safe_search_util.h"
+#include "components/variations/net/variations_http_headers.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "extensions/common/extension_urls.h"
+#endif
+
+GoogleURLLoaderThrottle::GoogleURLLoaderThrottle(
+ bool is_off_the_record,
+ chrome::mojom::DynamicParams dynamic_params)
+ : is_off_the_record_(is_off_the_record),
+ dynamic_params_(std::move(dynamic_params)) {}
+
+GoogleURLLoaderThrottle::~GoogleURLLoaderThrottle() {}
+
+void GoogleURLLoaderThrottle::DetachFromCurrentSequence() {}
+
+void GoogleURLLoaderThrottle::WillStartRequest(
+ network::ResourceRequest* request,
+ bool* defer) {
+ variations::AppendVariationsHeaderWithCustomValue(
+ request->url,
+ is_off_the_record_ ? variations::InIncognito::kYes
+ : variations::InIncognito::kNo,
+ dynamic_params_.variation_ids_header, request);
+
+ if (dynamic_params_.force_safe_search) {
+ GURL new_url;
+ safe_search_util::ForceGoogleSafeSearch(request->url, &new_url);
+ if (!new_url.is_empty())
+ request->url = new_url;
+ }
+
+ static_assert(safe_search_util::YOUTUBE_RESTRICT_OFF == 0,
+ "OFF must be first");
+ if (dynamic_params_.youtube_restrict >
+ safe_search_util::YOUTUBE_RESTRICT_OFF &&
+ dynamic_params_.youtube_restrict <
+ safe_search_util::YOUTUBE_RESTRICT_COUNT) {
+ safe_search_util::ForceYouTubeRestrict(
+ request->url, &request->headers,
+ static_cast<safe_search_util::YouTubeRestrictMode>(
+ dynamic_params_.youtube_restrict));
+ }
+
+ if (!dynamic_params_.allowed_domains_for_apps.empty() &&
+ request->url.DomainIs("google.com")) {
+ request->headers.SetHeader(safe_search_util::kGoogleAppsAllowedDomains,
+ dynamic_params_.allowed_domains_for_apps);
+ }
+}
+
+void GoogleURLLoaderThrottle::WillRedirectRequest(
+ net::RedirectInfo* redirect_info,
+ const network::ResourceResponseHead& response_head,
+ bool* /* defer */,
+ std::vector<std::string>* to_be_removed_headers,
+ net::HttpRequestHeaders* modified_headers) {
+ network::mojom::URLResponseHeadPtr response_head_ptr = response_head;
+ variations::RemoveVariationsHeaderIfNeeded(*redirect_info, *response_head_ptr,
+ to_be_removed_headers);
+
+ // URLLoaderThrottles can only change the redirect URL when the network
+ // service is enabled. The non-network service path handles this in
+ // ChromeNetworkDelegate.
+ if (dynamic_params_.force_safe_search) {
+ safe_search_util::ForceGoogleSafeSearch(redirect_info->new_url,
+ &redirect_info->new_url);
+ }
+
+ if (dynamic_params_.youtube_restrict >
+ safe_search_util::YOUTUBE_RESTRICT_OFF &&
+ dynamic_params_.youtube_restrict <
+ safe_search_util::YOUTUBE_RESTRICT_COUNT) {
+ safe_search_util::ForceYouTubeRestrict(
+ redirect_info->new_url, modified_headers,
+ static_cast<safe_search_util::YouTubeRestrictMode>(
+ dynamic_params_.youtube_restrict));
+ }
+
+ if (!dynamic_params_.allowed_domains_for_apps.empty() &&
+ redirect_info->new_url.DomainIs("google.com")) {
+ modified_headers->SetHeader(safe_search_util::kGoogleAppsAllowedDomains,
+ dynamic_params_.allowed_domains_for_apps);
+ }
+}
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+void GoogleURLLoaderThrottle::WillProcessResponse(
+ const GURL& response_url,
+ network::ResourceResponseHead* response_head,
+ bool* defer) {
+ // Built-in additional protection for the chrome web store origin.
+ GURL webstore_url(extension_urls::GetWebstoreLaunchURL());
+ if (response_url.SchemeIsHTTPOrHTTPS() &&
+ response_url.DomainIs(webstore_url.host_piece())) {
+ if (response_head && response_head->headers &&
+ !response_head->headers->HasHeaderValue("x-frame-options", "deny") &&
+ !response_head->headers->HasHeaderValue("x-frame-options",
+ "sameorigin")) {
+ response_head->headers->RemoveHeader("x-frame-options");
+ response_head->headers->AddHeader("x-frame-options: sameorigin");
+ }
+ }
+}
+#endif
diff --git a/chromium/chrome/common/google_url_loader_throttle.h b/chromium/chrome/common/google_url_loader_throttle.h
new file mode 100644
index 00000000000..2bc4b573b71
--- /dev/null
+++ b/chromium/chrome/common/google_url_loader_throttle.h
@@ -0,0 +1,43 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_GOOGLE_URL_LOADER_THROTTLE_H_
+#define CHROME_COMMON_GOOGLE_URL_LOADER_THROTTLE_H_
+
+#include "chrome/common/renderer_configuration.mojom.h"
+#include "extensions/buildflags/buildflags.h"
+#include "third_party/blink/public/common/loader/url_loader_throttle.h"
+
+// This class changes requests for Google-specific features (e.g. adding &
+// removing Varitaions headers, Safe Search & Restricted YouTube & restricting
+// consumer accounts through group policy.
+class GoogleURLLoaderThrottle
+ : public blink::URLLoaderThrottle,
+ public base::SupportsWeakPtr<GoogleURLLoaderThrottle> {
+ public:
+ GoogleURLLoaderThrottle(bool is_off_the_record,
+ chrome::mojom::DynamicParams dynamic_params);
+ ~GoogleURLLoaderThrottle() override;
+
+ private:
+ // blink::URLLoaderThrottle:
+ void DetachFromCurrentSequence() override;
+ void WillStartRequest(network::ResourceRequest* request,
+ bool* defer) override;
+ void WillRedirectRequest(net::RedirectInfo* redirect_info,
+ const network::ResourceResponseHead& response_head,
+ bool* defer,
+ std::vector<std::string>* to_be_removed_headers,
+ net::HttpRequestHeaders* modified_headers) override;
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ void WillProcessResponse(const GURL& response_url,
+ network::ResourceResponseHead* response_head,
+ bool* defer) override;
+#endif
+
+ bool is_off_the_record_;
+ const chrome::mojom::DynamicParams dynamic_params_;
+};
+
+#endif // CHROME_COMMON_GOOGLE_URL_LOADER_THROTTLE_H_
diff --git a/chromium/chrome/common/heap_profiler_controller.cc b/chromium/chrome/common/heap_profiler_controller.cc
new file mode 100644
index 00000000000..bfa3b11f72f
--- /dev/null
+++ b/chromium/chrome/common/heap_profiler_controller.cc
@@ -0,0 +1,114 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/heap_profiler_controller.h"
+
+#include <cmath>
+
+#include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/process/process_metrics.h"
+#include "base/rand_util.h"
+#include "base/sampling_heap_profiler/module_cache.h"
+#include "base/sampling_heap_profiler/sampling_heap_profiler.h"
+#include "base/task/post_task.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "components/metrics/call_stack_profile_builder.h"
+#include "components/metrics/call_stack_profile_metrics_provider.h"
+
+namespace {
+
+// Sets heap sampling interval in bytes.
+const char kHeapProfilerSamplingRate[] = "sampling-rate";
+
+constexpr base::TimeDelta kHeapCollectionInterval =
+ base::TimeDelta::FromHours(24);
+
+base::TimeDelta RandomInterval(base::TimeDelta mean) {
+ // Time intervals between profile collections form a Poisson stream with
+ // given mean interval.
+ return -std::log(base::RandDouble()) * mean;
+}
+
+} // namespace
+
+HeapProfilerController::HeapProfilerController()
+ : stopped_(base::MakeRefCounted<StoppedFlag>()) {}
+
+HeapProfilerController::~HeapProfilerController() {
+ stopped_->data.Set();
+}
+
+void HeapProfilerController::Start() {
+ if (!base::FeatureList::IsEnabled(
+ metrics::CallStackProfileMetricsProvider::kHeapProfilerReporting)) {
+ return;
+ }
+ int sampling_rate = base::GetFieldTrialParamByFeatureAsInt(
+ metrics::CallStackProfileMetricsProvider::kHeapProfilerReporting,
+ kHeapProfilerSamplingRate, 0);
+ if (sampling_rate > 0)
+ base::SamplingHeapProfiler::Get()->SetSamplingInterval(sampling_rate);
+ base::SamplingHeapProfiler::Get()->Start();
+ ScheduleNextSnapshot(stopped_);
+}
+
+// static
+void HeapProfilerController::ScheduleNextSnapshot(
+ scoped_refptr<StoppedFlag> stopped) {
+ base::PostDelayedTask(
+ FROM_HERE, {base::ThreadPool(), base::TaskPriority::BEST_EFFORT},
+ base::BindOnce(&HeapProfilerController::TakeSnapshot, std::move(stopped)),
+ RandomInterval(kHeapCollectionInterval));
+}
+
+// static
+void HeapProfilerController::TakeSnapshot(
+ scoped_refptr<StoppedFlag> stopped) {
+ if (stopped->data.IsSet())
+ return;
+ RetrieveAndSendSnapshot();
+ ScheduleNextSnapshot(std::move(stopped));
+}
+
+// static
+void HeapProfilerController::RetrieveAndSendSnapshot() {
+ std::vector<base::SamplingHeapProfiler::Sample> samples =
+ base::SamplingHeapProfiler::Get()->GetSamples(0);
+ if (samples.empty())
+ return;
+
+ size_t malloc_usage =
+ base::ProcessMetrics::CreateCurrentProcessMetrics()->GetMallocUsage();
+ int malloc_usage_mb = static_cast<int>(malloc_usage >> 20);
+ base::UmaHistogramMemoryLargeMB("Memory.HeapProfiler.Browser.Malloc",
+ malloc_usage_mb);
+
+ base::ModuleCache module_cache;
+ metrics::CallStackProfileParams params(
+ metrics::CallStackProfileParams::BROWSER_PROCESS,
+ metrics::CallStackProfileParams::UNKNOWN_THREAD,
+ metrics::CallStackProfileParams::PERIODIC_HEAP_COLLECTION);
+ metrics::CallStackProfileBuilder profile_builder(params);
+
+ for (const base::SamplingHeapProfiler::Sample& sample : samples) {
+ std::vector<base::Frame> frames;
+ frames.reserve(sample.stack.size());
+ for (const void* frame : sample.stack) {
+ uintptr_t address = reinterpret_cast<uintptr_t>(frame);
+ const base::ModuleCache::Module* module =
+ module_cache.GetModuleForAddress(address);
+ frames.emplace_back(address, module);
+ }
+ size_t count = std::max<size_t>(
+ static_cast<size_t>(
+ std::llround(static_cast<double>(sample.total) / sample.size)),
+ 1);
+ profile_builder.OnSampleCompleted(std::move(frames), sample.total, count);
+ }
+
+ profile_builder.OnProfileCompleted(base::TimeDelta(), base::TimeDelta());
+}
diff --git a/chromium/chrome/common/heap_profiler_controller.h b/chromium/chrome/common/heap_profiler_controller.h
new file mode 100644
index 00000000000..a2c1511fc98
--- /dev/null
+++ b/chromium/chrome/common/heap_profiler_controller.h
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_HEAP_PROFILER_CONTROLLER_H_
+#define CHROME_COMMON_HEAP_PROFILER_CONTROLLER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/atomic_flag.h"
+
+// HeapProfilerController controls collection of sampled heap allocation
+// snapshots for the current process.
+class HeapProfilerController {
+ public:
+ HeapProfilerController();
+ ~HeapProfilerController();
+
+ // Starts periodic heap snapshot collection.
+ void Start();
+
+ private:
+ using StoppedFlag = base::RefCountedData<base::AtomicFlag>;
+
+ static void ScheduleNextSnapshot(scoped_refptr<StoppedFlag> stopped);
+ static void TakeSnapshot(scoped_refptr<StoppedFlag> stopped);
+ static void RetrieveAndSendSnapshot();
+
+ scoped_refptr<StoppedFlag> stopped_;
+
+ DISALLOW_COPY_AND_ASSIGN(HeapProfilerController);
+};
+
+#endif // CHROME_COMMON_HEAP_PROFILER_CONTROLLER_H_
diff --git a/chromium/chrome/common/heap_profiler_controller_unittest.cc b/chromium/chrome/common/heap_profiler_controller_unittest.cc
new file mode 100644
index 00000000000..c0ff97dd2f6
--- /dev/null
+++ b/chromium/chrome/common/heap_profiler_controller_unittest.cc
@@ -0,0 +1,91 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/heap_profiler_controller.h"
+
+#include "base/sampling_heap_profiler/sampling_heap_profiler.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/task_environment.h"
+#include "build/build_config.h"
+#include "components/metrics/call_stack_profile_builder.h"
+#include "components/metrics/call_stack_profile_metrics_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/metrics_proto/sampled_profile.pb.h"
+
+// TODO(crbug.com/961073): Fix memory leaks in tests and re-enable on LSAN.
+#ifdef LEAK_SANITIZER
+#define MAYBE_EmptyProfileIsNotEmitted DISABLED_EmptyProfileIsNotEmitted
+#else
+#define MAYBE_EmptyProfileIsNotEmitted EmptyProfileIsNotEmitted
+#endif
+
+class HeapProfilerControllerTest : public testing::Test {
+ protected:
+ base::test::TaskEnvironment task_environment{
+ base::test::TaskEnvironment::TimeSource::MOCK_TIME};
+};
+
+TEST_F(HeapProfilerControllerTest, MAYBE_EmptyProfileIsNotEmitted) {
+ HeapProfilerController controller;
+ metrics::CallStackProfileBuilder::SetBrowserProcessReceiverCallback(
+ base::BindLambdaForTesting(
+ [](base::TimeTicks time, metrics::SampledProfile profile) {
+ ADD_FAILURE();
+ }));
+ controller.Start();
+
+ task_environment.FastForwardBy(base::TimeDelta::FromDays(365));
+}
+
+// Sampling profiler is not capable of unwinding stack on Android under tests.
+#if !defined(OS_ANDROID)
+TEST_F(HeapProfilerControllerTest, ProfileCollectionsScheduler) {
+ constexpr size_t kAllocationSize = 42 * 1024;
+ constexpr int kSnapshotsToCollect = 3;
+
+ auto controller = std::make_unique<HeapProfilerController>();
+ int profile_count = 0;
+
+ auto check_profile = [&](base::TimeTicks time,
+ metrics::SampledProfile profile) {
+ EXPECT_EQ(metrics::SampledProfile::PERIODIC_HEAP_COLLECTION,
+ profile.trigger_event());
+ EXPECT_LT(0, profile.call_stack_profile().stack_sample_size());
+
+ bool found = false;
+ for (const metrics::CallStackProfile::StackSample& sample :
+ profile.call_stack_profile().stack_sample()) {
+ if (sample.has_weight() &&
+ static_cast<size_t>(sample.weight()) >= kAllocationSize) {
+ found = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(found);
+
+ if (++profile_count == kSnapshotsToCollect)
+ controller.reset();
+ };
+
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ metrics::CallStackProfileMetricsProvider::kHeapProfilerReporting);
+ metrics::CallStackProfileBuilder::SetBrowserProcessReceiverCallback(
+ base::BindLambdaForTesting(check_profile));
+ base::SamplingHeapProfiler::Get()->SetSamplingInterval(1024);
+
+ controller->Start();
+
+ auto* sampler = base::PoissonAllocationSampler::Get();
+ sampler->SuppressRandomnessForTest(true);
+ sampler->RecordAlloc(reinterpret_cast<void*>(0x1337), kAllocationSize,
+ base::PoissonAllocationSampler::kMalloc, nullptr);
+ sampler->RecordAlloc(reinterpret_cast<void*>(0x7331), kAllocationSize,
+ base::PoissonAllocationSampler::kMalloc, nullptr);
+
+ task_environment.FastForwardUntilNoTasksRemain();
+ EXPECT_LE(kSnapshotsToCollect, profile_count);
+}
+#endif
diff --git a/chromium/chrome/common/importer/DEPS b/chromium/chrome/common/importer/DEPS
new file mode 100644
index 00000000000..3daf8ae6239
--- /dev/null
+++ b/chromium/chrome/common/importer/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/favicon_base",
+]
diff --git a/chromium/chrome/common/importer/OWNERS b/chromium/chrome/common/importer/OWNERS
new file mode 100644
index 00000000000..4c26573d6df
--- /dev/null
+++ b/chromium/chrome/common/importer/OWNERS
@@ -0,0 +1,13 @@
+gab@chromium.org
+isherman@chromium.org
+
+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
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# COMPONENT: UI>Browser>Import
diff --git a/chromium/chrome/common/importer/edge_importer_utils_win.cc b/chromium/chrome/common/importer/edge_importer_utils_win.cc
new file mode 100644
index 00000000000..c92159f1405
--- /dev/null
+++ b/chromium/chrome/common/importer/edge_importer_utils_win.cc
@@ -0,0 +1,91 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/importer/edge_importer_utils_win.h"
+
+#include <Shlobj.h>
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/win/registry.h"
+#include "base/win/windows_version.h"
+#include "chrome/common/importer/importer_test_registry_overrider_win.h"
+
+namespace {
+
+const base::char16 kEdgeSettingsMainKey[] = L"MicrosoftEdge\\Main";
+
+const base::char16 kEdgePackageName[] =
+ L"microsoft.microsoftedge_8wekyb3d8bbwe";
+
+// We assume at the moment that the package name never changes for Edge.
+base::string16 GetEdgePackageName() {
+ return kEdgePackageName;
+}
+
+base::string16 GetEdgeRegistryKey(const base::string16& key_name) {
+ base::string16 registry_key =
+ L"Software\\Classes\\Local Settings\\"
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\AppContainer\\"
+ L"Storage\\";
+ registry_key += GetEdgePackageName();
+ registry_key += L"\\";
+ registry_key += key_name;
+ return registry_key;
+}
+
+base::string16 GetPotentiallyOverridenEdgeKey(
+ const base::string16& desired_key_path) {
+ base::string16 test_registry_override(
+ ImporterTestRegistryOverrider::GetTestRegistryOverride());
+ return test_registry_override.empty() ? GetEdgeRegistryKey(desired_key_path)
+ : test_registry_override;
+}
+
+} // namespace
+
+namespace importer {
+
+base::string16 GetEdgeSettingsKey() {
+ return GetPotentiallyOverridenEdgeKey(kEdgeSettingsMainKey);
+}
+
+base::FilePath GetEdgeDataFilePath() {
+ wchar_t buffer[MAX_PATH];
+ if (::SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
+ buffer) != S_OK)
+ return base::FilePath();
+
+ base::FilePath base_path(buffer);
+ base::string16 rel_path = L"Packages\\";
+ rel_path += GetEdgePackageName();
+ rel_path += L"\\AC\\MicrosoftEdge\\User\\Default";
+ return base_path.Append(rel_path);
+}
+
+bool IsEdgeFavoritesLegacyMode() {
+ base::win::RegKey key(HKEY_CURRENT_USER, GetEdgeSettingsKey().c_str(),
+ KEY_READ);
+ DWORD ese_enabled = 0;
+ // Check whether Edge is using the new Extensible Store Engine (ESE) format
+ // for its favorites.
+
+ if (key.ReadValueDW(L"FavoritesESEEnabled", &ese_enabled) == ERROR_SUCCESS)
+ return !ese_enabled;
+ // If the registry key is missing, check the Windows version.
+ // Edge switched to ESE in Windows 10 Build 10565 (somewhere between
+ // Windows 10 RTM and Windows 10 November 1511 Update).
+ return base::win::GetVersion() < base::win::Version::WIN10_TH2;
+}
+
+bool EdgeImporterCanImport() {
+ base::File::Info file_info;
+ if (base::win::GetVersion() < base::win::Version::WIN10)
+ return false;
+ return base::GetFileInfo(GetEdgeDataFilePath(), &file_info) &&
+ file_info.is_directory;
+}
+
+} // namespace importer
diff --git a/chromium/chrome/common/importer/edge_importer_utils_win.h b/chromium/chrome/common/importer/edge_importer_utils_win.h
new file mode 100644
index 00000000000..4d54be7cdc0
--- /dev/null
+++ b/chromium/chrome/common/importer/edge_importer_utils_win.h
@@ -0,0 +1,28 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_IMPORTER_EDGE_IMPORTER_UTILS_WIN_H_
+#define CHROME_COMMON_IMPORTER_EDGE_IMPORTER_UTILS_WIN_H_
+
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+
+namespace importer {
+
+// Returns the key to be used in HKCU to look for Edge's settings.
+// Overridable by tests via ImporterTestRegistryOverrider.
+base::string16 GetEdgeSettingsKey();
+
+// Returns the data path for the Edge browser. Returns an empty path on error.
+base::FilePath GetEdgeDataFilePath();
+
+// Returns true if Edge favorites is currently in legacy (pre-Edge 13) mode.
+bool IsEdgeFavoritesLegacyMode();
+
+// Returns true if the Edge browser is installed and available for import.
+bool EdgeImporterCanImport();
+
+} // namespace importer
+
+#endif // CHROME_COMMON_IMPORTER_EDGE_IMPORTER_UTILS_WIN_H_
diff --git a/chromium/chrome/common/importer/firefox_importer_utils.cc b/chromium/chrome/common/importer/firefox_importer_utils.cc
new file mode 100644
index 00000000000..e1f5ada7771
--- /dev/null
+++ b/chromium/chrome/common/importer/firefox_importer_utils.cc
@@ -0,0 +1,330 @@
+// 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 "chrome/common/importer/firefox_importer_utils.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <map>
+#include <string>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "chrome/common/ini_parser.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Retrieves the file system path of the profile name.
+base::FilePath GetProfilePath(const base::DictionaryValue& root,
+ const std::string& profile_name) {
+ base::string16 path16;
+ std::string is_relative;
+ if (!root.GetStringASCII(profile_name + ".IsRelative", &is_relative) ||
+ !root.GetString(profile_name + ".Path", &path16))
+ return base::FilePath();
+
+#if defined(OS_WIN)
+ base::ReplaceSubstringsAfterOffset(
+ &path16, 0, base::ASCIIToUTF16("/"), base::ASCIIToUTF16("\\"));
+#endif
+ base::FilePath path = base::FilePath::FromUTF16Unsafe(path16);
+
+ // IsRelative=1 means the folder path would be relative to the
+ // path of profiles.ini. IsRelative=0 refers to a custom profile
+ // location.
+ if (is_relative == "1")
+ path = GetProfilesINI().DirName().Append(path);
+
+ return path;
+}
+
+// Checks if the named profile is the default profile.
+bool IsDefaultProfile(const base::DictionaryValue& root,
+ const std::string& profile_name) {
+ std::string is_default;
+ root.GetStringASCII(profile_name + ".Default", &is_default);
+ return is_default == "1";
+}
+
+} // namespace
+
+base::FilePath GetFirefoxProfilePath() {
+ base::FilePath ini_file = GetProfilesINI();
+ std::string content;
+ base::ReadFileToString(ini_file, &content);
+ DictionaryValueINIParser ini_parser;
+ ini_parser.Parse(content);
+ return GetFirefoxProfilePathFromDictionary(ini_parser.root());
+}
+
+base::FilePath GetFirefoxProfilePathFromDictionary(
+ const base::DictionaryValue& root) {
+ std::vector<std::string> profiles;
+ for (int i = 0; ; ++i) {
+ std::string current_profile = base::StringPrintf("Profile%d", i);
+ if (root.HasKey(current_profile)) {
+ profiles.push_back(current_profile);
+ } else {
+ // Profiles are continuously numbered. So we exit when we can't
+ // find the i-th one.
+ break;
+ }
+ }
+
+ if (profiles.empty())
+ return base::FilePath();
+
+ // When multiple profiles exist, the path to the default profile is returned,
+ // since the other profiles are used mostly by developers for testing.
+ for (std::vector<std::string>::const_iterator it = profiles.begin();
+ it != profiles.end(); ++it)
+ if (IsDefaultProfile(root, *it))
+ return GetProfilePath(root, *it);
+
+ // If no default profile is found, the path to Profile0 will be returned.
+ return GetProfilePath(root, profiles.front());
+}
+
+#if defined(OS_MACOSX)
+// Find the "*.app" component of the path and build up from there.
+// The resulting path will be .../Firefox.app/Contents/MacOS.
+// We do this because we don't trust LastAppDir to always be
+// this particular path, without any subdirs, and we want to make
+// our assumption about Firefox's root being in that path explicit.
+bool ComposeMacAppPath(const std::string& path_from_file,
+ base::FilePath* output) {
+ base::FilePath path(path_from_file);
+ typedef std::vector<base::FilePath::StringType> ComponentVector;
+ ComponentVector path_components;
+ path.GetComponents(&path_components);
+ if (path_components.empty())
+ return false;
+ // The first path component is special because it may be absolute. Calling
+ // Append with an absolute path component will trigger an assert, so we
+ // must handle it differently and initialize output with it.
+ *output = base::FilePath(path_components[0]);
+ // Append next path components untill we find the *.app component. When we do,
+ // append Contents/MacOS.
+ for (size_t i = 1; i < path_components.size(); ++i) {
+ *output = output->Append(path_components[i]);
+ if (base::EndsWith(path_components[i], ".app",
+ base::CompareCase::SENSITIVE)) {
+ *output = output->Append("Contents");
+ *output = output->Append("MacOS");
+ return true;
+ }
+ }
+ LOG(ERROR) << path_from_file << " doesn't look like a valid Firefox "
+ << "installation path: missing /*.app/ directory.";
+ return false;
+}
+#endif // OS_MACOSX
+
+bool GetFirefoxVersionAndPathFromProfile(const base::FilePath& profile_path,
+ int* version,
+ base::FilePath* app_path) {
+ bool ret = false;
+ base::FilePath compatibility_file =
+ profile_path.AppendASCII("compatibility.ini");
+ std::string content;
+ base::ReadFileToString(compatibility_file, &content);
+ base::ReplaceSubstringsAfterOffset(&content, 0, "\r\n", "\n");
+
+ for (const std::string& line : base::SplitString(
+ content, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+ if (line.empty() || line[0] == '#' || line[0] == ';')
+ continue;
+ size_t equal = line.find('=');
+ if (equal != std::string::npos) {
+ std::string key = line.substr(0, equal);
+ if (key == "LastVersion") {
+ base::StringToInt(line.substr(equal + 1), version);
+ ret = true;
+ } else if (key == "LastAppDir") {
+ // TODO(evanm): If the path in question isn't convertible to
+ // UTF-8, what does Firefox do? If it puts raw bytes in the
+ // file, we could go straight from bytes -> filepath;
+ // otherwise, we're out of luck here.
+#if defined(OS_MACOSX)
+ // Extract path from "LastAppDir=/actual/path"
+ size_t separator_pos = line.find_first_of('=');
+ const std::string& path_from_ini = line.substr(separator_pos + 1);
+ if (!ComposeMacAppPath(path_from_ini, app_path))
+ return false;
+#else // !OS_MACOSX
+ *app_path = base::FilePath::FromUTF8Unsafe(line.substr(equal + 1));
+#endif // OS_MACOSX
+ }
+ }
+ }
+ return ret;
+}
+
+bool ReadPrefFile(const base::FilePath& path, std::string* content) {
+ if (content == NULL)
+ return false;
+
+ base::ReadFileToString(path, content);
+
+ if (content->empty()) {
+ LOG(WARNING) << "Firefox preference file " << path.value() << " is empty.";
+ return false;
+ }
+
+ return true;
+}
+
+std::string ReadBrowserConfigProp(const base::FilePath& app_path,
+ const std::string& pref_key) {
+ std::string content;
+ if (!ReadPrefFile(app_path.AppendASCII("browserconfig.properties"), &content))
+ return std::string();
+
+ // This file has the syntax: key=value.
+ size_t prop_index = content.find(pref_key + "=");
+ if (prop_index == std::string::npos)
+ return std::string();
+
+ size_t start = prop_index + pref_key.length();
+ size_t stop = std::string::npos;
+ if (start != std::string::npos)
+ stop = content.find("\n", start + 1);
+
+ if (start == std::string::npos ||
+ stop == std::string::npos || (start == stop)) {
+ LOG(WARNING) << "Firefox property " << pref_key << " could not be parsed.";
+ return std::string();
+ }
+
+ return content.substr(start + 1, stop - start - 1);
+}
+
+std::string ReadPrefsJsValue(const base::FilePath& profile_path,
+ const std::string& pref_key) {
+ std::string content;
+ if (!ReadPrefFile(profile_path.AppendASCII("prefs.js"), &content))
+ return std::string();
+
+ return GetPrefsJsValue(content, pref_key);
+}
+
+GURL GetHomepage(const base::FilePath& profile_path) {
+ std::string home_page_list =
+ ReadPrefsJsValue(profile_path, "browser.startup.homepage");
+
+ size_t seperator = home_page_list.find_first_of('|');
+ if (seperator == std::string::npos)
+ return GURL(home_page_list);
+
+ return GURL(home_page_list.substr(0, seperator));
+}
+
+bool IsDefaultHomepage(const GURL& homepage, const base::FilePath& app_path) {
+ if (!homepage.is_valid())
+ return false;
+
+ std::string default_homepages =
+ ReadBrowserConfigProp(app_path, "browser.startup.homepage");
+
+ size_t seperator = default_homepages.find_first_of('|');
+ if (seperator == std::string::npos)
+ return homepage.spec() == GURL(default_homepages).spec();
+
+ // Crack the string into separate homepage urls.
+ for (const std::string& url : base::SplitString(
+ default_homepages, "|",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+ if (homepage.spec() == GURL(url).spec())
+ return true;
+ }
+
+ return false;
+}
+
+std::string GetPrefsJsValue(const std::string& content,
+ const std::string& pref_key) {
+ // This file has the syntax: user_pref("key", value);
+ std::string search_for = std::string("user_pref(\"") + pref_key +
+ std::string("\", ");
+ size_t prop_index = content.find(search_for);
+ if (prop_index == std::string::npos)
+ return std::string();
+
+ size_t start = prop_index + search_for.length();
+ size_t stop = std::string::npos;
+ if (start != std::string::npos) {
+ // Stop at the last ')' on this line.
+ stop = content.find("\n", start + 1);
+ stop = content.rfind(")", stop);
+ }
+
+ if (start == std::string::npos || stop == std::string::npos ||
+ stop < start) {
+ LOG(WARNING) << "Firefox property " << pref_key << " could not be parsed.";
+ return std::string();
+ }
+
+ // String values have double quotes we don't need to return to the caller.
+ if (content[start] == '\"' && content[stop - 1] == '\"') {
+ ++start;
+ --stop;
+ }
+
+ return content.substr(start, stop - start);
+}
+
+// The branding name is obtained from the application.ini file from the Firefox
+// application directory. A sample application.ini file is the following:
+// [App]
+// Vendor=Mozilla
+// Name=Iceweasel
+// Profile=mozilla/firefox
+// Version=3.5.16
+// BuildID=20120421070307
+// Copyright=Copyright (c) 1998 - 2010 mozilla.org
+// ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
+// .........................................
+// In this example the function returns "Iceweasel" (or a localized equivalent).
+base::string16 GetFirefoxImporterName(const base::FilePath& app_path) {
+ const base::FilePath app_ini_file = app_path.AppendASCII("application.ini");
+ std::string branding_name;
+ if (base::PathExists(app_ini_file)) {
+ std::string content;
+ base::ReadFileToString(app_ini_file, &content);
+
+ const std::string name_attr("Name=");
+ bool in_app_section = false;
+ for (const base::StringPiece& line : base::SplitStringPiece(
+ content, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+ if (line == "[App]") {
+ in_app_section = true;
+ } else if (in_app_section) {
+ if (base::StartsWith(line, name_attr, base::CompareCase::SENSITIVE)) {
+ line.substr(name_attr.size()).CopyToString(&branding_name);
+ break;
+ }
+ if (line.length() > 0 && line[0] == '[') {
+ // No longer in the [App] section.
+ break;
+ }
+ }
+ }
+ }
+
+ branding_name = base::ToLowerASCII(branding_name);
+ if (branding_name.find("iceweasel") != std::string::npos)
+ return l10n_util::GetStringUTF16(IDS_IMPORT_FROM_ICEWEASEL);
+ return l10n_util::GetStringUTF16(IDS_IMPORT_FROM_FIREFOX);
+}
diff --git a/chromium/chrome/common/importer/firefox_importer_utils.h b/chromium/chrome/common/importer/firefox_importer_utils.h
new file mode 100644
index 00000000000..ec57c179271
--- /dev/null
+++ b/chromium/chrome/common/importer/firefox_importer_utils.h
@@ -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.
+
+#ifndef CHROME_COMMON_IMPORTER_FIREFOX_IMPORTER_UTILS_H_
+#define CHROME_COMMON_IMPORTER_FIREFOX_IMPORTER_UTILS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+class GURL;
+
+namespace base {
+class DictionaryValue;
+class FilePath;
+}
+
+#if defined(OS_WIN)
+// Detects which version of Firefox is installed from registry. Returns its
+// major version, and drops the minor version. Returns 0 if failed. If there are
+// indicators of both Firefox 2 and Firefox 3 it is biased to return the biggest
+// version.
+int GetCurrentFirefoxMajorVersionFromRegistry();
+
+// Detects where Firefox lives. Returns an empty path if Firefox is not
+// installed.
+base::FilePath GetFirefoxInstallPathFromRegistry();
+#endif // OS_WIN
+
+#if defined(OS_MACOSX)
+// Get the directory in which the Firefox .dylibs live, we need to load these
+// in order to decoded FF profile passwords.
+// The Path is usuall FF App Bundle/Contents/Mac OS/
+// Returns empty path on failure.
+base::FilePath GetFirefoxDylibPath();
+#endif // OS_MACOSX
+
+// Returns the path to the Firefox profile.
+base::FilePath GetFirefoxProfilePath();
+
+// Returns the path to the Firefox profile, using a custom dictionary.
+// Exposed for testing.
+base::FilePath GetFirefoxProfilePathFromDictionary(
+ const base::DictionaryValue& root);
+
+// Detects version of Firefox and installation path for the given Firefox
+// profile.
+bool GetFirefoxVersionAndPathFromProfile(const base::FilePath& profile_path,
+ int* version,
+ base::FilePath* app_path);
+
+// Gets the full path of the profiles.ini file. This file records the profiles
+// that can be used by Firefox. Returns an empty path if failed.
+base::FilePath GetProfilesINI();
+
+// Parses the profile.ini file, and stores its information in |root|.
+// This file is a plain-text file. Key/value pairs are stored one per line, and
+// they are separated in different sections. For example:
+// [General]
+// StartWithLastProfile=1
+//
+// [Profile0]
+// Name=default
+// IsRelative=1
+// Path=Profiles/abcdefeg.default
+// We set "[value]" in path "<Section>.<Key>". For example, the path
+// "Genenral.StartWithLastProfile" has the value "1".
+void ParseProfileINI(const base::FilePath& file, base::DictionaryValue* root);
+
+// Returns the home page set in Firefox in a particular profile.
+GURL GetHomepage(const base::FilePath& profile_path);
+
+// Checks to see if this home page is a default home page, as specified by
+// the resource file browserconfig.properties in the Firefox application
+// directory.
+bool IsDefaultHomepage(const GURL& homepage, const base::FilePath& app_path);
+
+// Parses the value of a particular firefox preference from a string that is the
+// contents of the prefs file.
+std::string GetPrefsJsValue(const std::string& prefs,
+ const std::string& pref_key);
+
+// Returns the localized Firefox branding name.
+// This is useful to differentiate between Firefox and Iceweasel.
+// If anything goes wrong while trying to obtain the branding name,
+// the function assumes it's Firefox.
+base::string16 GetFirefoxImporterName(const base::FilePath& app_path);
+
+#endif // CHROME_COMMON_IMPORTER_FIREFOX_IMPORTER_UTILS_H_
diff --git a/chromium/chrome/common/importer/firefox_importer_utils_linux.cc b/chromium/chrome/common/importer/firefox_importer_utils_linux.cc
new file mode 100644
index 00000000000..1935dcb3b96
--- /dev/null
+++ b/chromium/chrome/common/importer/firefox_importer_utils_linux.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/importer/firefox_importer_utils.h"
+
+#include "base/base_paths.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+
+base::FilePath GetProfilesINI() {
+ base::FilePath ini_file;
+ // The default location of the profile folder containing user data is
+ // under user HOME directory in .mozilla/firefox folder on Linux.
+ base::FilePath home;
+ base::PathService::Get(base::DIR_HOME, &home);
+ if (!home.empty()) {
+ ini_file = home.Append(".mozilla/firefox/profiles.ini");
+ }
+ if (base::PathExists(ini_file))
+ return ini_file;
+
+ return base::FilePath();
+}
diff --git a/chromium/chrome/common/importer/firefox_importer_utils_mac.mm b/chromium/chrome/common/importer/firefox_importer_utils_mac.mm
new file mode 100644
index 00000000000..1152a5645ed
--- /dev/null
+++ b/chromium/chrome/common/importer/firefox_importer_utils_mac.mm
@@ -0,0 +1,45 @@
+// 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 <Cocoa/Cocoa.h>
+#include <sys/param.h>
+
+#include "chrome/common/importer/firefox_importer_utils.h"
+
+#include "base/files/file_util.h"
+#include "base/mac/foundation_util.h"
+#include "base/path_service.h"
+
+base::FilePath GetProfilesINI() {
+ base::FilePath app_data_path;
+ if (!base::PathService::Get(base::DIR_APP_DATA, &app_data_path)) {
+ return base::FilePath();
+ }
+ base::FilePath ini_file =
+ app_data_path.Append("Firefox").Append("profiles.ini");
+ if (!base::PathExists(ini_file)) {
+ return base::FilePath();
+ }
+ return ini_file;
+}
+
+base::FilePath GetFirefoxDylibPath() {
+ base::ScopedCFTypeRef<CFErrorRef> out_err;
+ base::ScopedCFTypeRef<CFArrayRef> app_urls(
+ LSCopyApplicationURLsForBundleIdentifier(CFSTR("org.mozilla.firefox"),
+ out_err.InitializeInto()));
+ if (out_err || CFArrayGetCount(app_urls) == 0) {
+ return base::FilePath();
+ }
+ CFURLRef app_url =
+ base::mac::CFCastStrict<CFURLRef>(CFArrayGetValueAtIndex(app_urls, 0));
+ NSBundle* ff_bundle =
+ [NSBundle bundleWithPath:[base::mac::CFToNSCast(app_url) path]];
+ NSString *ff_library_path =
+ [[ff_bundle executablePath] stringByDeletingLastPathComponent];
+ char buf[MAXPATHLEN];
+ if (![ff_library_path getFileSystemRepresentation:buf maxLength:sizeof(buf)])
+ return base::FilePath();
+ return base::FilePath(buf);
+}
diff --git a/chromium/chrome/common/importer/firefox_importer_utils_unittest.cc b/chromium/chrome/common/importer/firefox_importer_utils_unittest.cc
new file mode 100644
index 00000000000..6fdf99de260
--- /dev/null
+++ b/chromium/chrome/common/importer/firefox_importer_utils_unittest.cc
@@ -0,0 +1,163 @@
+// 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 "chrome/common/importer/firefox_importer_utils.h"
+
+#include <stddef.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "chrome/grit/generated_resources.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+struct GetPrefsJsValueCase {
+ std::string prefs_content;
+ std::string pref_name;
+ std::string pref_value;
+} GetPrefsJsValueCases[] = {
+ // Basic case. Single pref, unquoted value.
+ { "user_pref(\"foo.bar\", 1);", "foo.bar", "1" },
+ // Value is quoted. Quotes should be stripped.
+ { "user_pref(\"foo.bar\", \"1\");", "foo.bar", "1" },
+ // Value has parens.
+ { "user_pref(\"foo.bar\", \"Value (detail)\");",
+ "foo.bar", "Value (detail)" },
+ // Multi-line case.
+ { "user_pref(\"foo.bar\", 1);\n"
+ "user_pref(\"foo.baz\", 2);\n"
+ "user_pref(\"foo.bag\", 3);",
+ "foo.baz", "2" },
+ // Malformed content.
+ { "user_pref(\"foo.bar\", 1);\n"
+ "user_pref(\"foo.baz\", 2;\n"
+ "user_pref(\"foo.bag\", 3);",
+ "foo.baz", "" },
+ // Malformed content.
+ { "uesr_pref(\"foo.bar\", 1);", "foo.bar", "" },
+};
+
+struct GetFirefoxImporterNameCase {
+ std::string app_ini_content;
+ int resource_id;
+} GetFirefoxImporterNameCases[] = {
+ // Basic case
+ { "[App]\n"
+ "Vendor=Mozilla\n"
+ "Name=iceweasel\n"
+ "Version=10.0.6\n"
+ "BuildID=20120717115048\n"
+ "ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
+ IDS_IMPORT_FROM_ICEWEASEL },
+ // Whitespace
+ { " \t[App] \n"
+ "Vendor=Mozilla\n"
+ " Name=Firefox\t \r\n"
+ "Version=10.0.6\n",
+ IDS_IMPORT_FROM_FIREFOX },
+ // No Name setting
+ { "[App]\n"
+ "Vendor=Mozilla\n"
+ "Version=10.0.6\n"
+ "BuildID=20120717115048\n"
+ "ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
+ IDS_IMPORT_FROM_FIREFOX },
+ // No [App] section
+ { "[Foo]\n"
+ "Vendor=Mozilla\n"
+ "Name=Foo\n",
+ IDS_IMPORT_FROM_FIREFOX },
+ // Multiple Name settings in different sections
+ { "[Foo]\n"
+ "Vendor=Mozilla\n"
+ "Name=Firefox\n"
+ "[App]\n"
+ "Profile=mozilla/firefox\n"
+ "Name=iceweasel\n"
+ "[Bar]\n"
+ "Name=Bar\n"
+ "ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}",
+ IDS_IMPORT_FROM_ICEWEASEL },
+ // Case-insensitivity
+ { "[App]\n"
+ "Vendor=Mozilla\n"
+ "Name=IceWeasel\n"
+ "Version=10.0.6\n",
+ IDS_IMPORT_FROM_ICEWEASEL },
+ // Empty file
+ { "", IDS_IMPORT_FROM_FIREFOX }
+};
+
+} // anonymous namespace
+
+TEST(FirefoxImporterUtilsTest, GetPrefsJsValue) {
+ for (size_t i = 0; i < base::size(GetPrefsJsValueCases); ++i) {
+ EXPECT_EQ(
+ GetPrefsJsValueCases[i].pref_value,
+ GetPrefsJsValue(GetPrefsJsValueCases[i].prefs_content,
+ GetPrefsJsValueCases[i].pref_name));
+ }
+}
+
+TEST(FirefoxImporterUtilsTest, GetFirefoxImporterName) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ const base::FilePath app_ini_file(
+ temp_dir.GetPath().AppendASCII("application.ini"));
+ for (size_t i = 0; i < base::size(GetFirefoxImporterNameCases); ++i) {
+ base::WriteFile(app_ini_file,
+ GetFirefoxImporterNameCases[i].app_ini_content.c_str(),
+ GetFirefoxImporterNameCases[i].app_ini_content.size());
+ EXPECT_EQ(
+ GetFirefoxImporterName(temp_dir.GetPath()),
+ l10n_util::GetStringUTF16(GetFirefoxImporterNameCases[i].resource_id));
+ }
+ EXPECT_EQ(l10n_util::GetStringUTF16(
+ IDS_IMPORT_FROM_FIREFOX),
+ GetFirefoxImporterName(base::FilePath(
+ FILE_PATH_LITERAL("/invalid/path"))));
+}
+
+TEST(FirefoxImporterUtilsTest, GetFirefoxProfilePath) {
+ base::DictionaryValue no_profiles;
+ EXPECT_EQ("",
+ GetFirefoxProfilePathFromDictionary(no_profiles).MaybeAsASCII());
+
+ base::DictionaryValue single_profile;
+ single_profile.SetString("Profile0.Path", "first");
+ single_profile.SetString("Profile0.IsRelative", "0");
+ single_profile.SetString("Profile0.Default", "1");
+ EXPECT_EQ("first",
+ GetFirefoxProfilePathFromDictionary(single_profile).MaybeAsASCII());
+
+ base::DictionaryValue no_default;
+ no_default.SetString("Profile0.Path", "first");
+ no_default.SetString("Profile0.IsRelative", "0");
+ no_default.SetString("Profile1.Path", "second");
+ no_default.SetString("Profile1.IsRelative", "0");
+ EXPECT_EQ("first",
+ GetFirefoxProfilePathFromDictionary(no_default).MaybeAsASCII());
+
+ base::DictionaryValue default_first;
+ default_first.SetString("Profile0.Path", "first");
+ default_first.SetString("Profile0.IsRelative", "0");
+ default_first.SetString("Profile0.Default", "1");
+ default_first.SetString("Profile1.Path", "second");
+ default_first.SetString("Profile1.IsRelative", "0");
+ EXPECT_EQ("first",
+ GetFirefoxProfilePathFromDictionary(default_first).MaybeAsASCII());
+
+ base::DictionaryValue default_second;
+ default_second.SetString("Profile0.Path", "first");
+ default_second.SetString("Profile0.IsRelative", "0");
+ default_second.SetString("Profile1.Path", "second");
+ default_second.SetString("Profile1.IsRelative", "0");
+ default_second.SetString("Profile1.Default", "1");
+ EXPECT_EQ("second",
+ GetFirefoxProfilePathFromDictionary(default_second).MaybeAsASCII());
+}
diff --git a/chromium/chrome/common/importer/firefox_importer_utils_win.cc b/chromium/chrome/common/importer/firefox_importer_utils_win.cc
new file mode 100644
index 00000000000..a44104f9b26
--- /dev/null
+++ b/chromium/chrome/common/importer/firefox_importer_utils_win.cc
@@ -0,0 +1,82 @@
+// 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 "chrome/common/importer/firefox_importer_utils.h"
+
+#include <shlobj.h>
+
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/strings/string16.h"
+#include "base/win/registry.h"
+
+namespace {
+
+// NOTE: Keep these in order since we need test all those paths according
+// to priority. For example. One machine has multiple users. One non-admin
+// user installs Firefox 2, which causes there is a Firefox2 entry under HKCU.
+// One admin user installs Firefox 3, which causes there is a Firefox 3 entry
+// under HKLM. So when the non-admin user log in, we should deal with Firefox 2
+// related data instead of Firefox 3.
+const HKEY kFireFoxRegistryPaths[] = {HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE};
+
+constexpr const wchar_t* kFirefoxPath = L"Software\\Mozilla\\Mozilla Firefox";
+constexpr const wchar_t* kCurrentVersion = L"CurrentVersion";
+
+} // namespace
+
+int GetCurrentFirefoxMajorVersionFromRegistry() {
+ TCHAR ver_buffer[128];
+ DWORD ver_buffer_length = sizeof(ver_buffer);
+ int highest_version = 0;
+ // When installing Firefox with admin account, the product keys will be
+ // written under HKLM\Mozilla. Otherwise it the keys will be written under
+ // HKCU\Mozilla.
+ for (const HKEY kFireFoxRegistryPath : kFireFoxRegistryPaths) {
+ base::win::RegKey reg_key(kFireFoxRegistryPath, kFirefoxPath, KEY_READ);
+
+ LONG result = reg_key.ReadValue(kCurrentVersion, ver_buffer,
+ &ver_buffer_length, NULL);
+ if (result != ERROR_SUCCESS)
+ continue;
+ highest_version = std::max(highest_version, _wtoi(ver_buffer));
+ }
+ return highest_version;
+}
+
+base::FilePath GetFirefoxInstallPathFromRegistry() {
+ // Detects the path that Firefox is installed in.
+ base::string16 registry_path = kFirefoxPath;
+ wchar_t buffer[MAX_PATH];
+ DWORD buffer_length = sizeof(buffer);
+ base::win::RegKey reg_key(HKEY_LOCAL_MACHINE, registry_path.c_str(),
+ KEY_READ);
+ LONG result = reg_key.ReadValue(kCurrentVersion, buffer,
+ &buffer_length, NULL);
+ if (result != ERROR_SUCCESS)
+ return base::FilePath();
+
+ registry_path += L"\\" + base::string16(buffer) + L"\\Main";
+ buffer_length = sizeof(buffer);
+ base::win::RegKey reg_key_directory(HKEY_LOCAL_MACHINE,
+ registry_path.c_str(), KEY_READ);
+ result = reg_key_directory.ReadValue(L"Install Directory", buffer,
+ &buffer_length, NULL);
+
+ return (result != ERROR_SUCCESS) ? base::FilePath() : base::FilePath(buffer);
+}
+
+base::FilePath GetProfilesINI() {
+ base::FilePath ini_file;
+ // The default location of the profile folder containing user data is
+ // under the "Application Data" folder in Windows XP, Vista, and 7.
+ if (!base::PathService::Get(base::DIR_APP_DATA, &ini_file))
+ return base::FilePath();
+
+ ini_file = ini_file.AppendASCII("Mozilla");
+ ini_file = ini_file.AppendASCII("Firefox");
+ ini_file = ini_file.AppendASCII("profiles.ini");
+
+ return base::PathExists(ini_file) ? ini_file : base::FilePath();
+}
diff --git a/chromium/chrome/common/importer/ie_importer_utils_win.cc b/chromium/chrome/common/importer/ie_importer_utils_win.cc
new file mode 100644
index 00000000000..726e5b01668
--- /dev/null
+++ b/chromium/chrome/common/importer/ie_importer_utils_win.cc
@@ -0,0 +1,48 @@
+// 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 "chrome/common/importer/ie_importer_utils_win.h"
+
+#include "chrome/common/importer/importer_test_registry_overrider_win.h"
+
+namespace {
+
+const base::char16 kIEFavoritesOrderKey[] =
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\"
+ L"MenuOrder\\Favorites";
+
+const base::char16 kIEStorage2Key[] =
+ L"Software\\Microsoft\\Internet Explorer\\IntelliForms\\Storage2";
+
+const base::char16 kIESettingsMainKey[] =
+ L"Software\\Microsoft\\Internet Explorer\\Main";
+
+base::string16 GetPotentiallyOverridenIEKey(
+ const base::string16& desired_key_path) {
+ base::string16 test_reg_override(
+ ImporterTestRegistryOverrider::GetTestRegistryOverride());
+ return test_reg_override.empty() ? desired_key_path : test_reg_override;
+}
+
+} // namespace
+
+namespace importer {
+
+base::string16 GetIEFavoritesOrderKey() {
+ // Return kIEFavoritesOrderKey unless an override has been set for tests.
+ return GetPotentiallyOverridenIEKey(kIEFavoritesOrderKey);
+}
+
+base::string16 GetIE7PasswordsKey() {
+ // Return kIEStorage2Key unless an override has been set for tests.
+ return GetPotentiallyOverridenIEKey(kIEStorage2Key);
+}
+
+base::string16 GetIESettingsKey() {
+ // Return kIESettingsMainKey unless an override has been set for tests.
+ return GetPotentiallyOverridenIEKey(kIESettingsMainKey);
+}
+
+} // namespace importer
+
diff --git a/chromium/chrome/common/importer/ie_importer_utils_win.h b/chromium/chrome/common/importer/ie_importer_utils_win.h
new file mode 100644
index 00000000000..8e43bbaee4c
--- /dev/null
+++ b/chromium/chrome/common/importer/ie_importer_utils_win.h
@@ -0,0 +1,26 @@
+// 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 CHROME_COMMON_IMPORTER_IE_IMPORTER_UTILS_WIN_H_
+#define CHROME_COMMON_IMPORTER_IE_IMPORTER_UTILS_WIN_H_
+
+#include "base/strings/string16.h"
+
+namespace importer {
+
+// Returns the key to be used in HKCU to look for IE's favorites order blob.
+// Overridable by tests via ImporterTestRegistryOverrider.
+base::string16 GetIEFavoritesOrderKey();
+
+// Returns the key to be used in HKCU to look for IE7 passwords.
+// Overridable by tests via ImporterTestRegistryOverrider.
+base::string16 GetIE7PasswordsKey();
+
+// Returns the key to be used in HKCU to look for IE settings.
+// Overridable by tests via ImporterTestRegistryOverrider.
+base::string16 GetIESettingsKey();
+
+} // namespace importer
+
+#endif // CHROME_COMMON_IMPORTER_IE_IMPORTER_UTILS_WIN_H_
diff --git a/chromium/chrome/common/importer/imported_bookmark_entry.cc b/chromium/chrome/common/importer/imported_bookmark_entry.cc
new file mode 100644
index 00000000000..a82e1cd85c0
--- /dev/null
+++ b/chromium/chrome/common/importer/imported_bookmark_entry.cc
@@ -0,0 +1,24 @@
+// 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 "chrome/common/importer/imported_bookmark_entry.h"
+
+ImportedBookmarkEntry::ImportedBookmarkEntry()
+ : in_toolbar(false),
+ is_folder(false) {}
+
+ImportedBookmarkEntry::ImportedBookmarkEntry(
+ const ImportedBookmarkEntry& other) = default;
+
+ImportedBookmarkEntry::~ImportedBookmarkEntry() {}
+
+bool ImportedBookmarkEntry::operator==(
+ const ImportedBookmarkEntry& other) const {
+ return (in_toolbar == other.in_toolbar &&
+ is_folder == other.is_folder &&
+ url == other.url &&
+ path == other.path &&
+ title == other.title &&
+ creation_time == other.creation_time);
+}
diff --git a/chromium/chrome/common/importer/imported_bookmark_entry.h b/chromium/chrome/common/importer/imported_bookmark_entry.h
new file mode 100644
index 00000000000..abb9ea0ba3e
--- /dev/null
+++ b/chromium/chrome/common/importer/imported_bookmark_entry.h
@@ -0,0 +1,29 @@
+// 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 CHROME_COMMON_IMPORTER_IMPORTED_BOOKMARK_ENTRY_H_
+#define CHROME_COMMON_IMPORTER_IMPORTED_BOOKMARK_ENTRY_H_
+
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "url/gurl.h"
+
+struct ImportedBookmarkEntry {
+ ImportedBookmarkEntry();
+ ImportedBookmarkEntry(const ImportedBookmarkEntry& other);
+ ~ImportedBookmarkEntry();
+
+ bool operator==(const ImportedBookmarkEntry& other) const;
+
+ bool in_toolbar;
+ bool is_folder;
+ GURL url;
+ std::vector<base::string16> path;
+ base::string16 title;
+ base::Time creation_time;
+};
+
+#endif // CHROME_COMMON_IMPORTER_IMPORTED_BOOKMARK_ENTRY_H_
diff --git a/chromium/chrome/common/importer/importer_autofill_form_data_entry.cc b/chromium/chrome/common/importer/importer_autofill_form_data_entry.cc
new file mode 100644
index 00000000000..5dd4c5a3742
--- /dev/null
+++ b/chromium/chrome/common/importer/importer_autofill_form_data_entry.cc
@@ -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.
+
+#include "chrome/common/importer/importer_autofill_form_data_entry.h"
+
+ImporterAutofillFormDataEntry::ImporterAutofillFormDataEntry() : times_used(0) {
+}
+
+ImporterAutofillFormDataEntry::~ImporterAutofillFormDataEntry() {
+}
diff --git a/chromium/chrome/common/importer/importer_autofill_form_data_entry.h b/chromium/chrome/common/importer/importer_autofill_form_data_entry.h
new file mode 100644
index 00000000000..af35195ae43
--- /dev/null
+++ b/chromium/chrome/common/importer/importer_autofill_form_data_entry.h
@@ -0,0 +1,33 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_IMPORTER_IMPORTER_AUTOFILL_FORM_DATA_ENTRY_H_
+#define CHROME_COMMON_IMPORTER_IMPORTER_AUTOFILL_FORM_DATA_ENTRY_H_
+
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+
+// Used as the target for importing form history from other browsers' profiles
+// in the utility process.
+struct ImporterAutofillFormDataEntry {
+ ImporterAutofillFormDataEntry();
+ ~ImporterAutofillFormDataEntry();
+
+ // Name of input element.
+ base::string16 name;
+
+ // Value of input element.
+ base::string16 value;
+
+ // Number of times this name-value pair has been used.
+ int times_used;
+
+ // The date of the first time when this name-value pair was used.
+ base::Time first_used;
+
+ // The date of the last time when this name-value pair was used.
+ base::Time last_used;
+};
+
+#endif // CHROME_COMMON_IMPORTER_IMPORTER_AUTOFILL_FORM_DATA_ENTRY_H_
diff --git a/chromium/chrome/common/importer/importer_bridge.cc b/chromium/chrome/common/importer/importer_bridge.cc
new file mode 100644
index 00000000000..15b7f745cfa
--- /dev/null
+++ b/chromium/chrome/common/importer/importer_bridge.cc
@@ -0,0 +1,9 @@
+// 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 "chrome/common/importer/importer_bridge.h"
+
+ImporterBridge::ImporterBridge() {}
+
+ImporterBridge::~ImporterBridge() {}
diff --git a/chromium/chrome/common/importer/importer_bridge.h b/chromium/chrome/common/importer/importer_bridge.h
new file mode 100644
index 00000000000..b4250c91d1b
--- /dev/null
+++ b/chromium/chrome/common/importer/importer_bridge.h
@@ -0,0 +1,89 @@
+// 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 CHROME_COMMON_IMPORTER_IMPORTER_BRIDGE_H_
+#define CHROME_COMMON_IMPORTER_IMPORTER_BRIDGE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+#include "chrome/common/importer/importer_data_types.h"
+#include "chrome/common/importer/importer_url_row.h"
+#include "components/favicon_base/favicon_usage_data.h"
+
+class GURL;
+struct ImportedBookmarkEntry;
+struct ImporterAutofillFormDataEntry;
+
+namespace autofill {
+struct PasswordForm;
+}
+
+namespace importer {
+struct SearchEngineInfo;
+}
+
+class ImporterBridge : public base::RefCountedThreadSafe<ImporterBridge> {
+ public:
+ ImporterBridge();
+
+ virtual void AddBookmarks(
+ const std::vector<ImportedBookmarkEntry>& bookmarks,
+ const base::string16& first_folder_name) = 0;
+
+ virtual void AddHomePage(const GURL& home_page) = 0;
+
+ virtual void SetFavicons(
+ const favicon_base::FaviconUsageDataList& favicons) = 0;
+
+ virtual void SetHistoryItems(const std::vector<ImporterURLRow>& rows,
+ importer::VisitSource visit_source) = 0;
+
+ virtual void SetKeywords(
+ const std::vector<importer::SearchEngineInfo>& search_engines,
+ bool unique_on_host_and_path) = 0;
+
+ // The search_engine_data vector contains XML data retrieved from the Firefox
+ // profile and its sqlite db.
+ virtual void SetFirefoxSearchEnginesXMLData(
+ const std::vector<std::string>& search_engine_data) = 0;
+
+ virtual void SetPasswordForm(const autofill::PasswordForm& form) = 0;
+
+ virtual void SetAutofillFormData(
+ const std::vector<ImporterAutofillFormDataEntry>& entries) = 0;
+
+ // Notifies the coordinator that the import operation has begun.
+ virtual void NotifyStarted() = 0;
+
+ // Notifies the coordinator that the collection of data for the specified
+ // item has begun.
+ virtual void NotifyItemStarted(importer::ImportItem item) = 0;
+
+ // Notifies the coordinator that the collection of data for the specified
+ // item has completed.
+ virtual void NotifyItemEnded(importer::ImportItem item) = 0;
+
+ // Notifies the coordinator that the entire import operation has completed.
+ virtual void NotifyEnded() = 0;
+
+ // For InProcessImporters this calls l10n_util. For ExternalProcessImporters
+ // this calls the set of strings we've ported over to the external process.
+ // It's good to avoid having to create a separate ResourceBundle for the
+ // external import process, since the importer only needs a few strings.
+ virtual base::string16 GetLocalizedString(int message_id) = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<ImporterBridge>;
+
+ virtual ~ImporterBridge();
+
+ DISALLOW_COPY_AND_ASSIGN(ImporterBridge);
+};
+
+#endif // CHROME_COMMON_IMPORTER_IMPORTER_BRIDGE_H_
diff --git a/chromium/chrome/common/importer/importer_data_types.cc b/chromium/chrome/common/importer/importer_data_types.cc
new file mode 100644
index 00000000000..25e4444dd05
--- /dev/null
+++ b/chromium/chrome/common/importer/importer_data_types.cc
@@ -0,0 +1,32 @@
+// 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 "build/build_config.h"
+#include "chrome/common/importer/importer_data_types.h"
+
+namespace importer {
+
+SourceProfile::SourceProfile()
+ : importer_type(TYPE_UNKNOWN),
+ services_supported(0) {
+}
+
+SourceProfile::SourceProfile(const SourceProfile& other) = default;
+
+SourceProfile::~SourceProfile() {
+}
+
+ImporterIE7PasswordInfo::ImporterIE7PasswordInfo() {
+}
+
+ImporterIE7PasswordInfo::ImporterIE7PasswordInfo(
+ const ImporterIE7PasswordInfo& other) = default;
+
+ImporterIE7PasswordInfo::~ImporterIE7PasswordInfo() {
+}
+
+ImporterIE7PasswordInfo& ImporterIE7PasswordInfo::operator=(
+ const ImporterIE7PasswordInfo& other) = default;
+
+} // namespace importer
diff --git a/chromium/chrome/common/importer/importer_data_types.h b/chromium/chrome/common/importer/importer_data_types.h
new file mode 100644
index 00000000000..0fc90c62398
--- /dev/null
+++ b/chromium/chrome/common/importer/importer_data_types.h
@@ -0,0 +1,90 @@
+// 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 CHROME_COMMON_IMPORTER_IMPORTER_DATA_TYPES_H_
+#define CHROME_COMMON_IMPORTER_IMPORTER_DATA_TYPES_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "chrome/common/importer/importer_type.h"
+#include "url/gurl.h"
+
+// Types needed for importing data from other browsers and the Google Toolbar.
+namespace importer {
+
+// An enumeration of the type of data that can be imported.
+enum ImportItem {
+ NONE = 0,
+ HISTORY = 1 << 0,
+ FAVORITES = 1 << 1,
+ COOKIES = 1 << 2, // Not supported yet.
+ PASSWORDS = 1 << 3,
+ SEARCH_ENGINES = 1 << 4,
+ HOME_PAGE = 1 << 5,
+ AUTOFILL_FORM_DATA = 1 << 6,
+ ALL = (1 << 7) - 1 // All the bits should be 1, hence the -1.
+};
+
+// Information about a profile needed by an importer to do import work.
+struct SourceProfile {
+ SourceProfile();
+ SourceProfile(const SourceProfile& other);
+ ~SourceProfile();
+
+ base::string16 importer_name;
+ ImporterType importer_type;
+ base::FilePath source_path;
+ base::FilePath app_path;
+ uint16_t services_supported; // Bitmask of ImportItem.
+ // The application locale. Stored because we can only access it from the UI
+ // thread on the browser process. This is only used by the Firefox importer.
+ std::string locale;
+};
+
+// Contains information needed for importing search engine urls.
+struct SearchEngineInfo {
+ // |url| is a string instead of a GURL since it may not actually be a valid
+ // GURL directly (e.g. for "http://%s.com").
+ base::string16 url;
+ base::string16 keyword;
+ base::string16 display_name;
+};
+
+// Contains the information read from the IE7/IE8 Storage2 key in the registry.
+struct ImporterIE7PasswordInfo {
+ ImporterIE7PasswordInfo();
+ ImporterIE7PasswordInfo(const ImporterIE7PasswordInfo& other);
+ ~ImporterIE7PasswordInfo();
+ ImporterIE7PasswordInfo& operator=(const ImporterIE7PasswordInfo& other);
+
+ // Hash of the url.
+ base::string16 url_hash;
+
+ // Encrypted data containing the username, password and some more
+ // undocumented fields.
+ std::vector<unsigned char> encrypted_data;
+
+ // When the login was imported.
+ base::Time date_created;
+};
+
+// Mapped to history::VisitSource after import in the browser.
+enum VisitSource {
+ VISIT_SOURCE_BROWSED = 0,
+ VISIT_SOURCE_FIREFOX_IMPORTED = 1,
+ VISIT_SOURCE_IE_IMPORTED = 2,
+ VISIT_SOURCE_SAFARI_IMPORTED = 3,
+};
+
+} // namespace importer
+
+#endif // CHROME_COMMON_IMPORTER_IMPORTER_DATA_TYPES_H_
diff --git a/chromium/chrome/common/importer/importer_test_registry_overrider_win.cc b/chromium/chrome/common/importer/importer_test_registry_overrider_win.cc
new file mode 100644
index 00000000000..0f881968259
--- /dev/null
+++ b/chromium/chrome/common/importer/importer_test_registry_overrider_win.cc
@@ -0,0 +1,70 @@
+// 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 "chrome/common/importer/importer_test_registry_overrider_win.h"
+
+#include <windows.h>
+
+#include <memory>
+#include <string>
+
+#include "base/environment.h"
+#include "base/guid.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/registry.h"
+
+namespace {
+
+// The key to which a random subkey will be appended. This key itself will never
+// be deleted.
+const wchar_t kTestHKCUOverrideKeyPrefix[] = L"SOFTWARE\\Chromium Unit Tests\\";
+const char kTestHKCUOverrideEnvironmentVariable[] =
+ "IE_IMPORTER_TEST_OVERRIDE_HKCU";
+
+// Reads the environment variable set by a previous call to
+// SetTestRegistryOverride() into |key| if it exists and |key| is not NULL.
+// Returns true if the variable was successfully read.
+bool GetTestKeyFromEnvironment(base::string16* key) {
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ std::string value;
+ bool result = env->GetVar(kTestHKCUOverrideEnvironmentVariable, &value);
+ if (result)
+ *key = base::UTF8ToUTF16(value);
+ return result;
+}
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// ImporterTestRegistryOverrider, public:
+
+ImporterTestRegistryOverrider::ImporterTestRegistryOverrider()
+ : temporary_key_(kTestHKCUOverrideKeyPrefix +
+ base::UTF8ToUTF16(base::GenerateGUID())) {
+ DCHECK(!GetTestKeyFromEnvironment(NULL));
+
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ bool success = env->SetVar(kTestHKCUOverrideEnvironmentVariable,
+ base::UTF16ToUTF8(temporary_key_));
+ DCHECK(success);
+}
+
+ImporterTestRegistryOverrider::~ImporterTestRegistryOverrider() {
+ base::win::RegKey reg_key(HKEY_CURRENT_USER, temporary_key_.c_str(),
+ KEY_ALL_ACCESS);
+ DCHECK(reg_key.Valid());
+ reg_key.DeleteKey(L"");
+
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ bool success = env->UnSetVar(kTestHKCUOverrideEnvironmentVariable);
+ DCHECK(success);
+}
+
+// static
+base::string16 ImporterTestRegistryOverrider::GetTestRegistryOverride() {
+ base::string16 key;
+ if (!GetTestKeyFromEnvironment(&key))
+ return base::string16();
+ return key;
+}
diff --git a/chromium/chrome/common/importer/importer_test_registry_overrider_win.h b/chromium/chrome/common/importer/importer_test_registry_overrider_win.h
new file mode 100644
index 00000000000..f814382ca3a
--- /dev/null
+++ b/chromium/chrome/common/importer/importer_test_registry_overrider_win.h
@@ -0,0 +1,34 @@
+// 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 CHROME_COMMON_IMPORTER_IMPORTER_TEST_REGISTRY_OVERRIDER_WIN_H_
+#define CHROME_COMMON_IMPORTER_IMPORTER_TEST_REGISTRY_OVERRIDER_WIN_H_
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+
+// A helper class to let tests generate a random registry key to be used in
+// HKEY_CURRENT_USER in tests. After the key has been generated by constructing
+// an ImporterTestRegistryOverrider, consumers in this process (or in any
+// child processes created after the key has been generated) can obtain the key
+// via GetTestRegistryOverride(). ImporterTestRegistryOverrider will delete
+// the temporary key upon being deleted itself. Only one
+// ImporterTestRegistryOverrider should live at once in a given process
+// hiearchy.
+class ImporterTestRegistryOverrider {
+ public:
+ ImporterTestRegistryOverrider();
+ ~ImporterTestRegistryOverrider();
+
+ // Returns a test key if one was chosen and set by a call to
+ // SetTestRegistryOverride(); returns the empty string if none.
+ static base::string16 GetTestRegistryOverride();
+
+ private:
+ base::string16 temporary_key_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImporterTestRegistryOverrider);
+};
+
+#endif // CHROME_COMMON_IMPORTER_IMPORTER_TEST_REGISTRY_OVERRIDER_WIN_H_
diff --git a/chromium/chrome/common/importer/importer_type.h b/chromium/chrome/common/importer/importer_type.h
new file mode 100644
index 00000000000..c172f8a5bc5
--- /dev/null
+++ b/chromium/chrome/common/importer/importer_type.h
@@ -0,0 +1,36 @@
+// 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 CHROME_COMMON_IMPORTER_IMPORTER_TYPE_H_
+#define CHROME_COMMON_IMPORTER_IMPORTER_TYPE_H_
+
+#include "build/build_config.h"
+
+namespace importer {
+
+// An enumeration of the type of importers that we support to import
+// settings and data from (browsers, google toolbar and a bookmarks html file).
+// NOTE: Numbers added so that data can be reliably cast to ints and passed
+// across IPC.
+enum ImporterType {
+ TYPE_UNKNOWN = -1,
+#if defined(OS_WIN)
+ TYPE_IE = 0,
+#endif
+ // Value 1 was the (now deleted) Firefox 2 profile importer.
+ TYPE_FIREFOX = 2,
+#if defined(OS_MACOSX)
+ TYPE_SAFARI = 3,
+#endif
+ // Value 4 was the (now deleted) Google Toolbar importer.
+ TYPE_BOOKMARKS_FILE = 5, // Identifies a 'bookmarks.html' file.
+#if defined(OS_WIN)
+ TYPE_EDGE = 6,
+#endif
+};
+
+} // namespace importer
+
+
+#endif // CHROME_COMMON_IMPORTER_IMPORTER_TYPE_H_
diff --git a/chromium/chrome/common/importer/importer_url_row.cc b/chromium/chrome/common/importer/importer_url_row.cc
new file mode 100644
index 00000000000..26a3414a6c0
--- /dev/null
+++ b/chromium/chrome/common/importer/importer_url_row.cc
@@ -0,0 +1,21 @@
+// 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 "chrome/common/importer/importer_url_row.h"
+
+ImporterURLRow::ImporterURLRow()
+ : visit_count(0),
+ typed_count(0),
+ hidden(false) {
+}
+
+ImporterURLRow::ImporterURLRow(const GURL& url)
+ : url(url),
+ visit_count(0),
+ typed_count(0),
+ hidden(false) {
+}
+
+ImporterURLRow::ImporterURLRow(const ImporterURLRow& other) = default;
+
diff --git a/chromium/chrome/common/importer/importer_url_row.h b/chromium/chrome/common/importer/importer_url_row.h
new file mode 100644
index 00000000000..f7e0a6dd8e8
--- /dev/null
+++ b/chromium/chrome/common/importer/importer_url_row.h
@@ -0,0 +1,39 @@
+// 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 CHROME_COMMON_IMPORTER_IMPORTER_URL_ROW_H_
+#define CHROME_COMMON_IMPORTER_IMPORTER_URL_ROW_H_
+
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "url/gurl.h"
+
+// Used as the target for importing history URLs from other browser's profiles
+// in the utility process. Converted to history::URLRow after being passed via
+// IPC to the browser.
+struct ImporterURLRow {
+ public:
+ ImporterURLRow();
+ explicit ImporterURLRow(const GURL& url);
+ ImporterURLRow(const ImporterURLRow& other);
+
+ GURL url;
+ base::string16 title;
+
+ // Total number of times this URL has been visited.
+ int visit_count;
+
+ // Number of times this URL has been manually entered in the URL bar.
+ int typed_count;
+
+ // The date of the last visit of this URL, which saves us from having to
+ // loop up in the visit table for things like autocomplete and expiration.
+ base::Time last_visit;
+
+ // Indicates this entry should now be shown in typical UI or queries, this
+ // is usually for subframes.
+ bool hidden;
+};
+
+#endif // CHROME_COMMON_IMPORTER_IMPORTER_URL_ROW_H_
diff --git a/chromium/chrome/common/importer/mock_importer_bridge.cc b/chromium/chrome/common/importer/mock_importer_bridge.cc
new file mode 100644
index 00000000000..69fd927a1fa
--- /dev/null
+++ b/chromium/chrome/common/importer/mock_importer_bridge.cc
@@ -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.
+
+#include "chrome/common/importer/mock_importer_bridge.h"
+
+MockImporterBridge::MockImporterBridge() {}
+
+MockImporterBridge::~MockImporterBridge() {}
diff --git a/chromium/chrome/common/importer/mock_importer_bridge.h b/chromium/chrome/common/importer/mock_importer_bridge.h
new file mode 100644
index 00000000000..104c44b4847
--- /dev/null
+++ b/chromium/chrome/common/importer/mock_importer_bridge.h
@@ -0,0 +1,45 @@
+// 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 CHROME_COMMON_IMPORTER_MOCK_IMPORTER_BRIDGE_H_
+#define CHROME_COMMON_IMPORTER_MOCK_IMPORTER_BRIDGE_H_
+
+#include <string>
+#include <vector>
+
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/importer_autofill_form_data_entry.h"
+#include "chrome/common/importer/importer_bridge.h"
+#include "components/autofill/core/common/password_form.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+class MockImporterBridge : public ImporterBridge {
+ public:
+ MockImporterBridge();
+
+ MOCK_METHOD2(AddBookmarks,
+ void(const std::vector<ImportedBookmarkEntry>&,
+ const base::string16&));
+ MOCK_METHOD1(AddHomePage, void(const GURL&));
+ MOCK_METHOD1(SetFavicons, void(const favicon_base::FaviconUsageDataList&));
+ MOCK_METHOD2(SetHistoryItems,
+ void(const std::vector<ImporterURLRow>&, importer::VisitSource));
+ MOCK_METHOD2(SetKeywords,
+ void(const std::vector<importer::SearchEngineInfo>&, bool));
+ MOCK_METHOD1(SetFirefoxSearchEnginesXMLData,
+ void(const std::vector<std::string>&));
+ MOCK_METHOD1(SetPasswordForm, void(const autofill::PasswordForm&));
+ MOCK_METHOD1(SetAutofillFormData,
+ void(const std::vector<ImporterAutofillFormDataEntry>&));
+ MOCK_METHOD0(NotifyStarted, void());
+ MOCK_METHOD1(NotifyItemStarted, void(importer::ImportItem));
+ MOCK_METHOD1(NotifyItemEnded, void(importer::ImportItem));
+ MOCK_METHOD0(NotifyEnded, void());
+ MOCK_METHOD1(GetLocalizedString, base::string16(int));
+
+ private:
+ ~MockImporterBridge() override;
+};
+
+#endif // CHROME_COMMON_IMPORTER_MOCK_IMPORTER_BRIDGE_H_
diff --git a/chromium/chrome/common/importer/profile_import_process_param_traits.cc b/chromium/chrome/common/importer/profile_import_process_param_traits.cc
new file mode 100644
index 00000000000..424a17f9e32
--- /dev/null
+++ b/chromium/chrome/common/importer/profile_import_process_param_traits.cc
@@ -0,0 +1,33 @@
+// 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.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "chrome/common/importer/profile_import_process_param_traits_macros.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#undef CHROME_COMMON_IMPORTER_PROFILE_IMPORT_PROCESS_PARAM_TRAITS_MACROS_H_
+#include "chrome/common/importer/profile_import_process_param_traits_macros.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#undef CHROME_COMMON_IMPORTER_PROFILE_IMPORT_PROCESS_PARAM_TRAITS_MACROS_H_
+#include "chrome/common/importer/profile_import_process_param_traits_macros.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#undef CHROME_COMMON_IMPORTER_PROFILE_IMPORT_PROCESS_PARAM_TRAITS_MACROS_H_
+#include "chrome/common/importer/profile_import_process_param_traits_macros.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#undef CHROME_COMMON_IMPORTER_PROFILE_IMPORT_PROCESS_PARAM_TRAITS_MACROS_H_
+#include "chrome/common/importer/profile_import_process_param_traits_macros.h"
+} // namespace IPC
diff --git a/chromium/chrome/common/importer/profile_import_process_param_traits.h b/chromium/chrome/common/importer/profile_import_process_param_traits.h
new file mode 100644
index 00000000000..46ed09336af
--- /dev/null
+++ b/chromium/chrome/common/importer/profile_import_process_param_traits.h
@@ -0,0 +1,10 @@
+// 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 CHROME_COMMON_IMPORTER_PROFILE_IMPORT_PROCESS_PARAM_TRAITS_H_
+#define CHROME_COMMON_IMPORTER_PROFILE_IMPORT_PROCESS_PARAM_TRAITS_H_
+
+#include "chrome/common/importer/profile_import_process_param_traits_macros.h"
+
+#endif // CHROME_COMMON_IMPORTER_PROFILE_IMPORT_PROCESS_PARAM_TRAITS_H_
diff --git a/chromium/chrome/common/importer/profile_import_process_param_traits_macros.h b/chromium/chrome/common/importer/profile_import_process_param_traits_macros.h
new file mode 100644
index 00000000000..dd005641f43
--- /dev/null
+++ b/chromium/chrome/common/importer/profile_import_process_param_traits_macros.h
@@ -0,0 +1,94 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Singly or Multiply-included shared traits file depending on circumstances.
+// This allows the use of IPC serialization macros in more than one IPC message
+// file.
+#ifndef CHROME_COMMON_IMPORTER_PROFILE_IMPORT_PROCESS_PARAM_TRAITS_MACROS_H_
+#define CHROME_COMMON_IMPORTER_PROFILE_IMPORT_PROCESS_PARAM_TRAITS_MACROS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "chrome/common/common_param_traits_macros.h"
+#include "chrome/common/importer/imported_bookmark_entry.h"
+#include "chrome/common/importer/importer_autofill_form_data_entry.h"
+#include "chrome/common/importer/importer_data_types.h"
+#include "chrome/common/importer/importer_url_row.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/favicon_base/favicon_usage_data.h"
+#include "content/public/common/common_param_traits.h"
+#include "ipc/ipc_message_macros.h"
+
+#if defined(OS_WIN)
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(importer::ImporterType,
+ importer::TYPE_UNKNOWN,
+ importer::TYPE_EDGE)
+#else
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(importer::ImporterType,
+ importer::TYPE_UNKNOWN,
+ importer::TYPE_BOOKMARKS_FILE)
+#endif
+
+IPC_ENUM_TRAITS_MIN_MAX_VALUE(importer::ImportItem,
+ importer::NONE,
+ importer::ALL)
+
+IPC_STRUCT_TRAITS_BEGIN(importer::SourceProfile)
+ IPC_STRUCT_TRAITS_MEMBER(importer_name)
+ IPC_STRUCT_TRAITS_MEMBER(importer_type)
+ IPC_STRUCT_TRAITS_MEMBER(source_path)
+ IPC_STRUCT_TRAITS_MEMBER(app_path)
+ IPC_STRUCT_TRAITS_MEMBER(services_supported)
+ IPC_STRUCT_TRAITS_MEMBER(locale)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(ImporterURLRow)
+ IPC_STRUCT_TRAITS_MEMBER(url)
+ IPC_STRUCT_TRAITS_MEMBER(title)
+ IPC_STRUCT_TRAITS_MEMBER(visit_count)
+ IPC_STRUCT_TRAITS_MEMBER(typed_count)
+ IPC_STRUCT_TRAITS_MEMBER(last_visit)
+ IPC_STRUCT_TRAITS_MEMBER(hidden)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(ImportedBookmarkEntry)
+ IPC_STRUCT_TRAITS_MEMBER(in_toolbar)
+ IPC_STRUCT_TRAITS_MEMBER(is_folder)
+ IPC_STRUCT_TRAITS_MEMBER(url)
+ IPC_STRUCT_TRAITS_MEMBER(path)
+ IPC_STRUCT_TRAITS_MEMBER(title)
+ IPC_STRUCT_TRAITS_MEMBER(creation_time)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(favicon_base::FaviconUsageData)
+ IPC_STRUCT_TRAITS_MEMBER(favicon_url)
+ IPC_STRUCT_TRAITS_MEMBER(png_data)
+ IPC_STRUCT_TRAITS_MEMBER(urls)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(importer::SearchEngineInfo)
+ IPC_STRUCT_TRAITS_MEMBER(url)
+ IPC_STRUCT_TRAITS_MEMBER(keyword)
+ IPC_STRUCT_TRAITS_MEMBER(display_name)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(ImporterAutofillFormDataEntry)
+ IPC_STRUCT_TRAITS_MEMBER(name)
+ IPC_STRUCT_TRAITS_MEMBER(value)
+ IPC_STRUCT_TRAITS_MEMBER(times_used)
+ IPC_STRUCT_TRAITS_MEMBER(first_used)
+ IPC_STRUCT_TRAITS_MEMBER(last_used)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(importer::ImporterIE7PasswordInfo)
+ IPC_STRUCT_TRAITS_MEMBER(url_hash)
+ IPC_STRUCT_TRAITS_MEMBER(encrypted_data)
+ IPC_STRUCT_TRAITS_MEMBER(date_created)
+IPC_STRUCT_TRAITS_END()
+
+#endif // CHROME_COMMON_IMPORTER_PROFILE_IMPORT_PROCESS_PARAM_TRAITS_MACROS_H_
diff --git a/chromium/chrome/common/importer/pstore_declarations.h b/chromium/chrome/common/importer/pstore_declarations.h
new file mode 100644
index 00000000000..74b5954da7c
--- /dev/null
+++ b/chromium/chrome/common/importer/pstore_declarations.h
@@ -0,0 +1,188 @@
+// 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 CHROME_COMMON_IMPORTER_PSTORE_DECLARATIONS_H_
+#define CHROME_COMMON_IMPORTER_PSTORE_DECLARATIONS_H_
+
+#ifdef __PSTORE_H__
+#error Should not include pstore.h and this file simultaneously.
+#endif
+
+#include <ole2.h>
+
+// pstore.h is no longer shipped in the Windows 8 SDK. Define a minimal set
+// here.
+
+// These types are referenced in interfaces we use, but our code does not use
+// refer to these types, so simply make them opaque.
+class IEnumPStoreTypes;
+struct PST_ACCESSRULESET;
+struct PST_PROMPTINFO;
+struct PST_PROVIDERINFO;
+struct PST_TYPEINFO;
+
+EXTERN_C const IID IID_IPStore;
+EXTERN_C const IID IID_IEnumPStoreItems;
+
+typedef DWORD PST_KEY;
+typedef DWORD PST_ACCESSMODE;
+#define PST_E_OK _HRESULT_TYPEDEF_(0x00000000L)
+
+interface
+#ifdef __clang__
+ [[clang::lto_visibility_public]]
+#endif
+ IEnumPStoreItems : public IUnknown {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ DWORD celt,
+ LPWSTR __RPC_FAR *rgelt,
+ DWORD __RPC_FAR *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(DWORD celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset(void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ IEnumPStoreItems __RPC_FAR *__RPC_FAR *ppenum) = 0;
+};
+
+interface
+#ifdef __clang__
+ [[clang::lto_visibility_public]]
+#endif
+ IPStore : public IUnknown {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetInfo(
+ PST_PROVIDERINFO* __RPC_FAR *ppProperties) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetProvParam(
+ DWORD dwParam,
+ DWORD __RPC_FAR *pcbData,
+ BYTE __RPC_FAR *__RPC_FAR *ppbData,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetProvParam(
+ DWORD dwParam,
+ DWORD cbData,
+ BYTE __RPC_FAR *pbData,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateType(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pType,
+ PST_TYPEINFO* pInfo,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pType,
+ PST_TYPEINFO* __RPC_FAR *ppInfo,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeleteType(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pType,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateSubtype(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pType,
+ const GUID __RPC_FAR *pSubtype,
+ PST_TYPEINFO* pInfo,
+ PST_ACCESSRULESET* pRules,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSubtypeInfo(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pType,
+ const GUID __RPC_FAR *pSubtype,
+ PST_TYPEINFO* __RPC_FAR *ppInfo,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeleteSubtype(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pType,
+ const GUID __RPC_FAR *pSubtype,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReadAccessRuleset(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pType,
+ const GUID __RPC_FAR *pSubtype,
+ PST_ACCESSRULESET* __RPC_FAR *ppRules,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteAccessRuleset(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pType,
+ const GUID __RPC_FAR *pSubtype,
+ PST_ACCESSRULESET* pRules,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumTypes(
+ PST_KEY Key,
+ DWORD dwFlags,
+ IEnumPStoreTypes __RPC_FAR *__RPC_FAR *ppenum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumSubtypes(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pType,
+ DWORD dwFlags,
+ IEnumPStoreTypes __RPC_FAR *__RPC_FAR *ppenum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeleteItem(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pItemType,
+ const GUID __RPC_FAR *pItemSubtype,
+ LPCWSTR szItemName,
+ PST_PROMPTINFO* pPromptInfo,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReadItem(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pItemType,
+ const GUID __RPC_FAR *pItemSubtype,
+ LPCWSTR szItemName,
+ DWORD __RPC_FAR *pcbData,
+ BYTE __RPC_FAR *__RPC_FAR *ppbData,
+ PST_PROMPTINFO* pPromptInfo,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteItem(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pItemType,
+ const GUID __RPC_FAR *pItemSubtype,
+ LPCWSTR szItemName,
+ DWORD cbData,
+ BYTE __RPC_FAR *pbData,
+ PST_PROMPTINFO* pPromptInfo,
+ DWORD dwDefaultConfirmationStyle,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OpenItem(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pItemType,
+ const GUID __RPC_FAR *pItemSubtype,
+ LPCWSTR szItemName,
+ PST_ACCESSMODE ModeFlags,
+ PST_PROMPTINFO* pPromptInfo,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CloseItem(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pItemType,
+ const GUID __RPC_FAR *pItemSubtype,
+ LPCWSTR szItemName,
+ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumItems(
+ PST_KEY Key,
+ const GUID __RPC_FAR *pItemType,
+ const GUID __RPC_FAR *pItemSubtype,
+ DWORD dwFlags,
+ IEnumPStoreItems __RPC_FAR *__RPC_FAR *ppenum) = 0;
+};
+
+#endif // CHROME_COMMON_IMPORTER_PSTORE_DECLARATIONS_H_
diff --git a/chromium/chrome/common/importer/safari_importer_utils.h b/chromium/chrome/common/importer/safari_importer_utils.h
new file mode 100644
index 00000000000..6885251a62b
--- /dev/null
+++ b/chromium/chrome/common/importer/safari_importer_utils.h
@@ -0,0 +1,22 @@
+// 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 CHROME_COMMON_IMPORTER_SAFARI_IMPORTER_UTILS_H_
+#define CHROME_COMMON_IMPORTER_SAFARI_IMPORTER_UTILS_H_
+
+#include <stdint.h>
+
+namespace base {
+class FilePath;
+}
+
+// Does this user account have a Safari Profile and if so, what items
+// are supported?
+// in: library_dir - ~/Library or a standin for testing purposes.
+// out: services_supported - the service supported for import.
+// Returns true if we can import the Safari profile.
+bool SafariImporterCanImport(const base::FilePath& library_dir,
+ uint16_t* services_supported);
+
+#endif // CHROME_COMMON_IMPORTER_SAFARI_IMPORTER_UTILS_H_
diff --git a/chromium/chrome/common/importer/safari_importer_utils.mm b/chromium/chrome/common/importer/safari_importer_utils.mm
new file mode 100644
index 00000000000..b69506abbae
--- /dev/null
+++ b/chromium/chrome/common/importer/safari_importer_utils.mm
@@ -0,0 +1,29 @@
+// 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 "chrome/common/importer/safari_importer_utils.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "chrome/common/importer/importer_data_types.h"
+
+bool SafariImporterCanImport(const base::FilePath& library_dir,
+ uint16_t* services_supported) {
+ DCHECK(services_supported);
+ *services_supported = importer::NONE;
+
+ // Import features are toggled by the following:
+ // bookmarks import: existence of ~/Library/Safari/Bookmarks.plist file.
+ // history import: existence of ~/Library/Safari/History.plist file.
+ base::FilePath safari_dir = library_dir.Append("Safari");
+ base::FilePath bookmarks_path = safari_dir.Append("Bookmarks.plist");
+ base::FilePath history_path = safari_dir.Append("History.plist");
+
+ if (base::PathExists(bookmarks_path))
+ *services_supported |= importer::FAVORITES;
+ if (base::PathExists(history_path))
+ *services_supported |= importer::HISTORY;
+
+ return *services_supported != importer::NONE;
+}
diff --git a/chromium/chrome/common/ini_parser.cc b/chromium/chrome/common/ini_parser.cc
new file mode 100644
index 00000000000..91f2d7ad021
--- /dev/null
+++ b/chromium/chrome/common/ini_parser.cc
@@ -0,0 +1,64 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/ini_parser.h"
+
+#include <stddef.h>
+
+#include "base/logging.h"
+#include "base/strings/string_tokenizer.h"
+
+INIParser::INIParser() : used_(false) {}
+
+INIParser::~INIParser() {}
+
+void INIParser::Parse(const std::string& content) {
+ DCHECK(!used_);
+ used_ = true;
+ base::StringTokenizer tokenizer(content, "\r\n");
+
+ std::string current_section;
+ while (tokenizer.GetNext()) {
+ std::string line = tokenizer.token();
+ if (line.empty()) {
+ // Skips the empty line.
+ continue;
+ }
+ if (line[0] == '#' || line[0] == ';') {
+ // This line is a comment.
+ continue;
+ }
+ if (line[0] == '[') {
+ // It is a section header.
+ current_section = line.substr(1);
+ size_t end = current_section.rfind(']');
+ if (end != std::string::npos)
+ current_section.erase(end);
+ } else {
+ std::string key, value;
+ size_t equal = line.find('=');
+ if (equal != std::string::npos) {
+ key = line.substr(0, equal);
+ value = line.substr(equal + 1);
+ HandleTriplet(current_section, key, value);
+ }
+ }
+ }
+}
+
+DictionaryValueINIParser::DictionaryValueINIParser() {}
+
+DictionaryValueINIParser::~DictionaryValueINIParser() {}
+
+void DictionaryValueINIParser::HandleTriplet(const std::string& section,
+ const std::string& key,
+ const std::string& value) {
+
+ // Checks whether the section and key contain a '.' character.
+ // Those sections and keys break DictionaryValue's path format when not
+ // using the *WithoutPathExpansion methods.
+ if (section.find('.') == std::string::npos &&
+ key.find('.') == std::string::npos)
+ root_.SetString(section + "." + key, value);
+}
diff --git a/chromium/chrome/common/ini_parser.h b/chromium/chrome/common/ini_parser.h
new file mode 100644
index 00000000000..2f8ef16079c
--- /dev/null
+++ b/chromium/chrome/common/ini_parser.h
@@ -0,0 +1,64 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_INI_PARSER_H_
+#define CHROME_COMMON_INI_PARSER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/values.h"
+
+// Parses INI files in a string. Users should in inherit from this class.
+// This is a very basic INI parser with these characteristics:
+// - Ignores blank lines.
+// - Ignores comment lines beginning with '#' or ';'.
+// - Duplicate key names in the same section will simply cause repeated calls
+// to HandleTriplet with the same |section| and |key| parameters.
+// - No escape characters supported.
+// - Global properties result in calls to HandleTriplet with an empty string in
+// the |section| argument.
+// - Section headers begin with a '[' character. It is recommended, but
+// not required to close the header bracket with a ']' character. All
+// characters after a closing ']' character is ignored.
+// - Key value pairs are indicated with an '=' character. Whitespace is not
+// ignored. Quoting is not supported. Everything before the first '='
+// is considered the |key|, and everything after is the |value|.
+class INIParser {
+ public:
+ INIParser();
+ virtual ~INIParser();
+
+ // May only be called once per instance.
+ void Parse(const std::string& content);
+
+ private:
+ virtual void HandleTriplet(const std::string& section,
+ const std::string& key,
+ const std::string& value) = 0;
+
+ bool used_;
+};
+
+// Parsed values are stored as strings at the "section.key" path. Triplets with
+// |section| or |key| parameters containing '.' are ignored.
+class DictionaryValueINIParser : public INIParser {
+ public:
+ DictionaryValueINIParser();
+ ~DictionaryValueINIParser() override;
+
+ const base::DictionaryValue& root() const { return root_; }
+
+ private:
+ // INIParser implementation.
+ void HandleTriplet(const std::string& section,
+ const std::string& key,
+ const std::string& value) override;
+
+ base::DictionaryValue root_;
+
+ DISALLOW_COPY_AND_ASSIGN(DictionaryValueINIParser);
+};
+
+#endif // CHROME_COMMON_INI_PARSER_H_
diff --git a/chromium/chrome/common/ini_parser_unittest.cc b/chromium/chrome/common/ini_parser_unittest.cc
new file mode 100644
index 00000000000..b2a2cb26820
--- /dev/null
+++ b/chromium/chrome/common/ini_parser_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2014 The Chromium Authors. 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 "chrome/common/ini_parser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+struct TestTriplet {
+ TestTriplet(const std::string& section,
+ const std::string& key,
+ const std::string& value)
+ : section(section),
+ key(key),
+ value(value) {
+ }
+
+ std::string section;
+ std::string key;
+ std::string value;
+};
+
+class TestINIParser : public INIParser {
+ public:
+ explicit TestINIParser(
+ const std::vector<TestTriplet>& expected_triplets)
+ : expected_triplets_(expected_triplets),
+ pair_i_(0) {
+ }
+ ~TestINIParser() override {}
+
+ size_t pair_i() {
+ return pair_i_;
+ }
+
+ private:
+ void HandleTriplet(const std::string& section,
+ const std::string& key,
+ const std::string& value) override {
+ EXPECT_EQ(expected_triplets_[pair_i_].section, section);
+ EXPECT_EQ(expected_triplets_[pair_i_].key, key);
+ EXPECT_EQ(expected_triplets_[pair_i_].value, value);
+ ++pair_i_;
+ }
+
+ std::vector<TestTriplet> expected_triplets_;
+ size_t pair_i_;
+};
+
+TEST(INIParserTest, BasicValid) {
+ std::vector<TestTriplet> expected_triplets;
+ expected_triplets.push_back(TestTriplet("section1", "key1", "value1"));
+ expected_triplets.push_back(TestTriplet("section1", "key2", "value2"));
+ expected_triplets.push_back(TestTriplet("section1", "key3", "value3"));
+ expected_triplets.push_back(TestTriplet("section2", "key4", "value4"));
+ expected_triplets.push_back(TestTriplet("section2", "key5",
+ "value=with=equals"));
+ expected_triplets.push_back(TestTriplet("section2", "key6", "value6"));
+ TestINIParser test_parser(expected_triplets);
+
+ test_parser.Parse(
+ "[section1]\n"
+ "key1=value1\n"
+ "key2=value2\r\n" // Testing DOS "\r\n" line endings.
+ "key3=value3\n"
+ "[section2\n" // Testing omitted closing bracket.
+ "key4=value4\r" // Testing "\r" line endings.
+ "key5=value=with=equals\n"
+ "key6=value6"); // Testing omitted final line ending.
+}
+
+TEST(INIParserTest, IgnoreBlankLinesAndComments) {
+ std::vector<TestTriplet> expected_triplets;
+ expected_triplets.push_back(TestTriplet("section1", "key1", "value1"));
+ expected_triplets.push_back(TestTriplet("section1", "key2", "value2"));
+ expected_triplets.push_back(TestTriplet("section1", "key3", "value3"));
+ expected_triplets.push_back(TestTriplet("section2", "key4", "value4"));
+ expected_triplets.push_back(TestTriplet("section2", "key5", "value5"));
+ expected_triplets.push_back(TestTriplet("section2", "key6", "value6"));
+ TestINIParser test_parser(expected_triplets);
+
+ test_parser.Parse(
+ "\n"
+ "[section1]\n"
+ "key1=value1\n"
+ "\n"
+ "\n"
+ "key2=value2\n"
+ "key3=value3\n"
+ "\n"
+ ";Comment1"
+ "\n"
+ "[section2]\n"
+ "key4=value4\n"
+ "#Comment2\n"
+ "key5=value5\n"
+ "\n"
+ "key6=value6\n");
+}
+
+TEST(INIParserTest, DictionaryValueINIParser) {
+ DictionaryValueINIParser test_parser;
+
+ test_parser.Parse(
+ "[section1]\n"
+ "key1=value1\n"
+ "key.2=value2\n"
+ "key3=va.lue3\n"
+ "[se.ction2]\n"
+ "key.4=value4\n"
+ "key5=value5\n");
+
+ const base::DictionaryValue& root = test_parser.root();
+ std::string value;
+ EXPECT_TRUE(root.GetString("section1.key1", &value));
+ EXPECT_EQ("value1", value);
+ EXPECT_FALSE(root.GetString("section1.key.2", &value));
+ EXPECT_TRUE(root.GetString("section1.key3", &value));
+ EXPECT_EQ("va.lue3", value);
+ EXPECT_FALSE(root.GetString("se.ction2.key.4", &value));
+ EXPECT_FALSE(root.GetString("se.ction2.key5", &value));
+}
+
+} // namespace
diff --git a/chromium/chrome/common/initialize_extensions_client.cc b/chromium/chrome/common/initialize_extensions_client.cc
new file mode 100644
index 00000000000..3e9d4cf1f1b
--- /dev/null
+++ b/chromium/chrome/common/initialize_extensions_client.cc
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/initialize_extensions_client.h"
+
+#include <memory>
+
+#include "base/no_destructor.h"
+#include "chrome/common/apps/platform_apps/chrome_apps_api_provider.h"
+#include "chrome/common/extensions/chrome_extensions_client.h"
+#include "extensions/common/extensions_client.h"
+
+void EnsureExtensionsClientInitialized() {
+ static bool initialized = false;
+
+ static base::NoDestructor<extensions::ChromeExtensionsClient>
+ extensions_client;
+
+ if (!initialized) {
+ initialized = true;
+ extensions_client->AddAPIProvider(
+ std::make_unique<chrome_apps::ChromeAppsAPIProvider>());
+ extensions::ExtensionsClient::Set(extensions_client.get());
+ }
+
+ // ExtensionsClient::Set() will early-out if the client was already set, so
+ // this allows us to check that this was the only site setting it.
+ DCHECK_EQ(extensions_client.get(), extensions::ExtensionsClient::Get())
+ << "ExtensionsClient should only be initialized through "
+ << "EnsureExtensionsClientInitialized() when using "
+ << "ChromeExtensionsClient.";
+}
diff --git a/chromium/chrome/common/initialize_extensions_client.h b/chromium/chrome/common/initialize_extensions_client.h
new file mode 100644
index 00000000000..188ea65a126
--- /dev/null
+++ b/chromium/chrome/common/initialize_extensions_client.h
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_INITIALIZE_EXTENSIONS_CLIENT_H_
+#define CHROME_COMMON_INITIALIZE_EXTENSIONS_CLIENT_H_
+
+#include "extensions/buildflags/buildflags.h"
+
+#if !BUILDFLAG(ENABLE_EXTENSIONS)
+#error "Extensions must be enabled"
+#endif
+
+// Initializes the single instance of the ExtensionsClient. Safe to call
+// multiple times.
+void EnsureExtensionsClientInitialized();
+
+#endif // CHROME_COMMON_INITIALIZE_EXTENSIONS_CLIENT_H_
diff --git a/chromium/chrome/common/instant_mojom_traits.h b/chromium/chrome/common/instant_mojom_traits.h
new file mode 100644
index 00000000000..93ee65be138
--- /dev/null
+++ b/chromium/chrome/common/instant_mojom_traits.h
@@ -0,0 +1,90 @@
+// 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.
+
+// NOLINT(build/header_guard)
+// no-include-guard-because-multiply-included
+#include "chrome/common/search/instant_types.h"
+#include "chrome/common/search/ntp_logging_events.h"
+#include "components/favicon_base/favicon_types.h"
+#include "components/ntp_tiles/ntp_tile_impression.h"
+#include "components/ntp_tiles/tile_source.h"
+#include "components/ntp_tiles/tile_title_source.h"
+#include "components/ntp_tiles/tile_visual_type.h"
+#include "components/omnibox/common/omnibox_focus_state.h"
+#include "ipc/ipc_message_macros.h"
+
+IPC_ENUM_TRAITS_MAX_VALUE(OmniboxFocusState, OMNIBOX_FOCUS_STATE_LAST)
+
+IPC_ENUM_TRAITS_MAX_VALUE(OmniboxFocusChangeReason,
+ OMNIBOX_FOCUS_CHANGE_REASON_LAST)
+
+IPC_ENUM_TRAITS_MAX_VALUE(NTPLoggingEventType, NTP_EVENT_TYPE_LAST)
+
+IPC_ENUM_TRAITS_MAX_VALUE(NTPSuggestionsLoggingEventType,
+ NTPSuggestionsLoggingEventType::kMaxValue)
+
+IPC_ENUM_TRAITS_MAX_VALUE(ntp_tiles::TileTitleSource,
+ ntp_tiles::TileTitleSource::LAST)
+
+IPC_ENUM_TRAITS_MAX_VALUE(ntp_tiles::TileSource, ntp_tiles::TileSource::LAST)
+
+IPC_ENUM_TRAITS_MAX_VALUE(ntp_tiles::TileVisualType, ntp_tiles::TILE_TYPE_MAX)
+
+IPC_ENUM_TRAITS_MAX_VALUE(ThemeBackgroundImageAlignment,
+ THEME_BKGRND_IMAGE_ALIGN_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(ThemeBackgroundImageTiling, THEME_BKGRND_IMAGE_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(favicon_base::IconType, favicon_base::IconType::kMax)
+
+IPC_STRUCT_TRAITS_BEGIN(ntp_tiles::NTPTileImpression)
+ IPC_STRUCT_TRAITS_MEMBER(index)
+ IPC_STRUCT_TRAITS_MEMBER(source)
+ IPC_STRUCT_TRAITS_MEMBER(title_source)
+ IPC_STRUCT_TRAITS_MEMBER(visual_type)
+ IPC_STRUCT_TRAITS_MEMBER(icon_type)
+ IPC_STRUCT_TRAITS_MEMBER(data_generation_time)
+ IPC_STRUCT_TRAITS_MEMBER(url_for_rappor)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(InstantMostVisitedItem)
+ IPC_STRUCT_TRAITS_MEMBER(url)
+ IPC_STRUCT_TRAITS_MEMBER(title)
+ IPC_STRUCT_TRAITS_MEMBER(favicon)
+ IPC_STRUCT_TRAITS_MEMBER(title_source)
+ IPC_STRUCT_TRAITS_MEMBER(source)
+ IPC_STRUCT_TRAITS_MEMBER(data_generation_time)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(InstantMostVisitedInfo)
+ IPC_STRUCT_TRAITS_MEMBER(items)
+ IPC_STRUCT_TRAITS_MEMBER(items_are_custom_links)
+ IPC_STRUCT_TRAITS_MEMBER(use_most_visited)
+ IPC_STRUCT_TRAITS_MEMBER(is_visible)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(ThemeBackgroundInfo)
+ IPC_STRUCT_TRAITS_MEMBER(using_default_theme)
+ IPC_STRUCT_TRAITS_MEMBER(using_dark_colors)
+ IPC_STRUCT_TRAITS_MEMBER(custom_background_url)
+ IPC_STRUCT_TRAITS_MEMBER(custom_background_attribution_line_1)
+ IPC_STRUCT_TRAITS_MEMBER(custom_background_attribution_line_2)
+ IPC_STRUCT_TRAITS_MEMBER(custom_background_attribution_action_url)
+ IPC_STRUCT_TRAITS_MEMBER(collection_id)
+ IPC_STRUCT_TRAITS_MEMBER(background_color)
+ IPC_STRUCT_TRAITS_MEMBER(text_color)
+ IPC_STRUCT_TRAITS_MEMBER(text_color_light)
+ IPC_STRUCT_TRAITS_MEMBER(theme_id)
+ IPC_STRUCT_TRAITS_MEMBER(image_horizontal_alignment)
+ IPC_STRUCT_TRAITS_MEMBER(image_vertical_alignment)
+ IPC_STRUCT_TRAITS_MEMBER(image_tiling)
+ IPC_STRUCT_TRAITS_MEMBER(has_attribution)
+ IPC_STRUCT_TRAITS_MEMBER(logo_alternate)
+ IPC_STRUCT_TRAITS_MEMBER(has_theme_image)
+ IPC_STRUCT_TRAITS_MEMBER(theme_name)
+ IPC_STRUCT_TRAITS_MEMBER(color_id)
+ IPC_STRUCT_TRAITS_MEMBER(color_dark)
+ IPC_STRUCT_TRAITS_MEMBER(color_light)
+ IPC_STRUCT_TRAITS_MEMBER(color_picked)
+ IPC_STRUCT_TRAITS_MEMBER(logo_color)
+ IPC_STRUCT_TRAITS_MEMBER(shortcut_color)
+IPC_STRUCT_TRAITS_END()
diff --git a/chromium/chrome/common/logging_chrome.cc b/chromium/chrome/common/logging_chrome.cc
new file mode 100644
index 00000000000..56c9d572c3e
--- /dev/null
+++ b/chromium/chrome/common/logging_chrome.cc
@@ -0,0 +1,434 @@
+// 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 "build/build_config.h"
+
+// Need to include this before most other files because it defines
+// IPC_MESSAGE_LOG_ENABLED. We need to use it to define
+// IPC_MESSAGE_MACROS_LOG_ENABLED so render_messages.h will generate the
+// ViewMsgLog et al. functions.
+#include "ipc/ipc_buildflags.h"
+
+// On Windows, the about:ipc dialog shows IPCs; on POSIX, we hook up a
+// logger in this file. (We implement about:ipc on Mac but implement
+// the loggers here anyway). We need to do this real early to be sure
+// IPC_MESSAGE_MACROS_LOG_ENABLED doesn't get undefined.
+#if defined(OS_POSIX) && BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
+#define IPC_MESSAGE_MACROS_LOG_ENABLED
+#include "content/public/common/content_ipc_logging.h"
+#define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \
+ content::RegisterIPCLogger(msg_id, logger)
+#include "chrome/common/all_messages.h"
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include "chrome/common/logging_chrome.h"
+
+#include <fstream> // NOLINT
+#include <memory> // NOLINT
+#include <string> // NOLINT
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/debug/debugger.h"
+#include "base/debug/dump_without_crashing.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/metrics/statistics_recorder.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 "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/env_vars.h"
+#include "content/public/common/content_switches.h"
+#include "ipc/ipc_logging.h"
+
+#if defined(OS_CHROMEOS)
+#include "chromeos/constants/chromeos_switches.h"
+#endif
+
+#if defined(OS_WIN)
+#include <initguid.h>
+#include "base/logging_win.h"
+#include "base/syslog_logging.h"
+#include "chrome/common/win/eventlog_messages.h"
+#include "chrome/install_static/install_details.h"
+#endif
+
+namespace logging {
+namespace {
+
+// When true, this means that error dialogs should not be shown.
+bool dialogs_are_suppressed_ = false;
+ScopedLogAssertHandler* assert_handler_ = nullptr;
+
+// This should be true for exactly the period between the end of
+// InitChromeLogging() and the beginning of CleanupChromeLogging().
+bool chrome_logging_initialized_ = false;
+
+// Set if we called InitChromeLogging() but failed to initialize.
+bool chrome_logging_failed_ = false;
+
+// This should be true for exactly the period between the end of
+// InitChromeLogging() and the beginning of CleanupChromeLogging().
+bool chrome_logging_redirected_ = false;
+
+#if defined(OS_WIN)
+// {7FE69228-633E-4f06-80C1-527FEA23E3A7}
+const GUID kChromeTraceProviderName = {
+ 0x7fe69228, 0x633e, 0x4f06,
+ { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } };
+#endif
+
+// Assertion handler for logging errors that occur when dialogs are
+// silenced. To record a new error, pass the log string associated
+// with that error in the str parameter.
+NOINLINE void SilentRuntimeAssertHandler(const char* file,
+ int line,
+ const base::StringPiece message,
+ const base::StringPiece stack_trace) {
+ base::debug::BreakDebugger();
+}
+
+// Suppresses error/assertion dialogs and enables the logging of
+// those errors into silenced_errors_.
+void SuppressDialogs() {
+ if (dialogs_are_suppressed_)
+ return;
+
+ assert_handler_ =
+ new ScopedLogAssertHandler(base::Bind(SilentRuntimeAssertHandler));
+
+#if defined(OS_WIN)
+ UINT new_flags = SEM_FAILCRITICALERRORS |
+ SEM_NOGPFAULTERRORBOX |
+ SEM_NOOPENFILEERRORBOX;
+
+ // Preserve existing error mode, as discussed at http://t/dmea
+ UINT existing_flags = SetErrorMode(new_flags);
+ SetErrorMode(existing_flags | new_flags);
+#endif
+
+ dialogs_are_suppressed_ = true;
+}
+
+} // anonymous namespace
+
+LoggingDestination DetermineLoggingDestination(
+ const base::CommandLine& command_line) {
+// only use OutputDebugString in debug mode
+#ifdef NDEBUG
+ bool enable_logging = false;
+ const char *kInvertLoggingSwitch = switches::kEnableLogging;
+ const LoggingDestination kDefaultLoggingMode = LOG_TO_FILE;
+#else
+ bool enable_logging = true;
+ const char *kInvertLoggingSwitch = switches::kDisableLogging;
+ const LoggingDestination kDefaultLoggingMode = LOG_TO_ALL;
+#endif
+
+ if (command_line.HasSwitch(kInvertLoggingSwitch))
+ enable_logging = !enable_logging;
+
+ LoggingDestination log_mode;
+ if (enable_logging) {
+ // Let --enable-logging=stderr force only stderr, particularly useful for
+ // non-debug builds where otherwise you can't get logs to stderr at all.
+ if (command_line.GetSwitchValueASCII(switches::kEnableLogging) == "stderr")
+ log_mode = LOG_TO_SYSTEM_DEBUG_LOG | LOG_TO_STDERR;
+ else
+ log_mode = kDefaultLoggingMode;
+ } else {
+ log_mode = LOG_NONE;
+ }
+ return log_mode;
+}
+
+#if defined(OS_CHROMEOS)
+base::FilePath SetUpSymlinkIfNeeded(const base::FilePath& symlink_path,
+ bool new_log) {
+ DCHECK(!symlink_path.empty());
+ // For backward compatibility, set up a .../chrome symlink to
+ // .../chrome.LATEST as needed. This code needs to run only
+ // after the migration (i.e. the addition of chrome.LATEST).
+ if (symlink_path.Extension() == ".LATEST") {
+ base::FilePath extensionless_path = symlink_path.ReplaceExtension("");
+ base::FilePath target_path;
+ bool extensionless_symlink_exists =
+ base::ReadSymbolicLink(extensionless_path, &target_path);
+
+ if (target_path != symlink_path) {
+ // No link, or wrong link. Clean up. This should happen only once in
+ // each log directory after the OS version update, but some of those
+ // directories may not be accessed for a long time, so this code needs to
+ // stay in forever :/
+ if (extensionless_symlink_exists &&
+ !base::DeleteFile(extensionless_path, false)) {
+ DPLOG(WARNING) << "Cannot delete " << extensionless_path.value();
+ }
+ // After cleaning up, create the symlink.
+ if (!base::CreateSymbolicLink(symlink_path, extensionless_path)) {
+ DPLOG(ERROR) << "Cannot create " << extensionless_path.value();
+ }
+ }
+ }
+
+ // If not starting a new log, then just log through the existing symlink, but
+ // if the symlink doesn't exist, create it.
+ //
+ // If starting a new log, then rename the old symlink as
+ // symlink_path.PREVIOUS and make a new symlink to a fresh log file.
+
+ // Check for existence of the symlink.
+ base::FilePath target_path;
+ bool symlink_exists = base::ReadSymbolicLink(symlink_path, &target_path);
+
+ if (symlink_exists && !new_log)
+ return target_path;
+
+ // Remove any extension before time-stamping.
+ target_path = GenerateTimestampedName(symlink_path.RemoveExtension(),
+ base::Time::Now());
+
+ if (symlink_exists) {
+ base::FilePath previous_symlink_path =
+ symlink_path.ReplaceExtension(".PREVIOUS");
+ // Rename symlink to .PREVIOUS. This nukes an existing symlink just like
+ // the rename(2) syscall does.
+ if (!base::ReplaceFile(symlink_path, previous_symlink_path, nullptr)) {
+ DPLOG(WARNING) << "Cannot rename " << symlink_path.value() << " to "
+ << previous_symlink_path.value();
+ }
+ }
+ // If all went well, the symlink no longer exists. Recreate it.
+ base::FilePath relative_target_path = target_path.BaseName();
+ if (!base::CreateSymbolicLink(relative_target_path, symlink_path)) {
+ DPLOG(ERROR) << "Unable to create symlink " << symlink_path.value()
+ << " pointing at " << relative_target_path.value();
+ }
+ return target_path;
+}
+
+void RemoveSymlinkAndLog(const base::FilePath& link_path,
+ const base::FilePath& target_path) {
+ if (::unlink(link_path.value().c_str()) == -1)
+ DPLOG(WARNING) << "Unable to unlink symlink " << link_path.value();
+ if (::unlink(target_path.value().c_str()) == -1)
+ DPLOG(WARNING) << "Unable to unlink log file " << target_path.value();
+}
+
+base::FilePath GetSessionLogDir(const base::CommandLine& command_line) {
+ base::FilePath log_dir;
+ std::string log_dir_str;
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ if (env->GetVar(env_vars::kSessionLogDir, &log_dir_str) &&
+ !log_dir_str.empty()) {
+ log_dir = base::FilePath(log_dir_str);
+ } else if (command_line.HasSwitch(chromeos::switches::kLoginProfile)) {
+ base::PathService::Get(chrome::DIR_USER_DATA, &log_dir);
+ base::FilePath profile_dir;
+ std::string login_profile_value =
+ command_line.GetSwitchValueASCII(chromeos::switches::kLoginProfile);
+ if (login_profile_value == chrome::kLegacyProfileDir ||
+ login_profile_value == chrome::kTestUserProfileDir) {
+ profile_dir = base::FilePath(login_profile_value);
+ } else {
+ // We could not use g_browser_process > profile_helper() here.
+ std::string profile_dir_str = chrome::kProfileDirPrefix;
+ profile_dir_str.append(login_profile_value);
+ profile_dir = base::FilePath(profile_dir_str);
+ }
+ log_dir = log_dir.Append(profile_dir);
+ }
+ return log_dir;
+}
+
+base::FilePath GetSessionLogFile(const base::CommandLine& command_line) {
+ return GetSessionLogDir(command_line)
+ .Append(GetLogFileName(command_line).BaseName());
+}
+
+#endif // defined(OS_CHROMEOS)
+
+void InitChromeLogging(const base::CommandLine& command_line,
+ OldFileDeletionState delete_old_log_file) {
+ DCHECK(!chrome_logging_initialized_) <<
+ "Attempted to initialize logging when it was already initialized.";
+ LoggingDestination logging_dest = DetermineLoggingDestination(command_line);
+ LogLockingState log_locking_state = LOCK_LOG_FILE;
+ base::FilePath log_path;
+#if defined(OS_CHROMEOS)
+ base::FilePath target_path;
+#endif
+
+ // Don't resolve the log path unless we need to. Otherwise we leave an open
+ // ALPC handle after sandbox lockdown on Windows.
+ if ((logging_dest & LOG_TO_FILE) != 0) {
+ log_path = GetLogFileName(command_line);
+
+#if defined(OS_CHROMEOS)
+ // For BWSI (Incognito) logins, we want to put the logs in the user
+ // profile directory that is created for the temporary session instead
+ // of in the system log directory, for privacy reasons.
+ if (command_line.HasSwitch(chromeos::switches::kGuestSession))
+ log_path = GetSessionLogFile(command_line);
+
+ // On ChromeOS we log to the symlink. We force creation of a new
+ // symlink if we've been asked to delete the old log, since that
+ // indicates the start of a new session.
+ target_path = SetUpSymlinkIfNeeded(
+ log_path, delete_old_log_file == DELETE_OLD_LOG_FILE);
+
+ // Because ChromeOS manages the move to a new session by redirecting
+ // the link, it shouldn't remove the old file in the logging code,
+ // since that will remove the newly created link instead.
+ delete_old_log_file = APPEND_TO_OLD_LOG_FILE;
+#endif // defined(OS_CHROMEOS)
+ } else {
+ log_locking_state = DONT_LOCK_LOG_FILE;
+ }
+
+ LoggingSettings settings;
+ settings.logging_dest = logging_dest;
+ settings.log_file_path = log_path.value().c_str();
+ settings.lock_log = log_locking_state;
+ settings.delete_old = delete_old_log_file;
+ bool success = InitLogging(settings);
+
+#if defined(OS_CHROMEOS)
+ if (!success) {
+ DPLOG(ERROR) << "Unable to initialize logging to " << log_path.value()
+ << " (which should be a link to " << target_path.value() << ")";
+ RemoveSymlinkAndLog(log_path, target_path);
+ chrome_logging_failed_ = true;
+ return;
+ }
+#else // defined(OS_CHROMEOS)
+ if (!success) {
+ DPLOG(ERROR) << "Unable to initialize logging to " << log_path.value();
+ chrome_logging_failed_ = true;
+ return;
+ }
+#endif // defined(OS_CHROMEOS)
+
+ // We call running in unattended mode "headless", and allow headless mode to
+ // be configured either by the Environment Variable or by the Command Line
+ // Switch. This is for automated test purposes.
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ const bool is_headless = env->HasVar(env_vars::kHeadless) ||
+ command_line.HasSwitch(switches::kNoErrorDialogs);
+
+ // Show fatal log messages in a dialog in debug builds when not headless.
+ if (!is_headless)
+ SetShowErrorDialogs(true);
+
+ // we want process and thread IDs because we have a lot of things running
+ SetLogItems(true, // enable_process_id
+ true, // enable_thread_id
+ true, // enable_timestamp
+ false); // enable_tickcount
+
+ // Suppress system error dialogs when headless.
+ if (is_headless)
+ SuppressDialogs();
+
+ // Use a minimum log level if the command line asks for one. Ignore this
+ // switch if there's vlog level switch present too (as both of these switches
+ // refer to the same underlying log level, and the vlog level switch has
+ // already been processed inside InitLogging). If there is neither
+ // log level nor vlog level specified, then just leave the default level
+ // (INFO).
+ if (command_line.HasSwitch(switches::kLoggingLevel) &&
+ GetMinLogLevel() >= 0) {
+ std::string log_level =
+ command_line.GetSwitchValueASCII(switches::kLoggingLevel);
+ int level = 0;
+ if (base::StringToInt(log_level, &level) && level >= 0 &&
+ level < LOG_NUM_SEVERITIES) {
+ SetMinLogLevel(level);
+ } else {
+ DLOG(WARNING) << "Bad log level: " << log_level;
+ }
+ }
+
+#if defined(OS_WIN)
+ // Enable trace control and transport through event tracing for Windows.
+ LogEventProvider::Initialize(kChromeTraceProviderName);
+
+ // Enable logging to the Windows Event Log.
+ SetEventSource(base::UTF16ToASCII(
+ install_static::InstallDetails::Get().install_full_name()),
+ BROWSER_CATEGORY, MSG_LOG_MESSAGE);
+#endif
+
+ base::StatisticsRecorder::InitLogOnShutdown();
+
+ chrome_logging_initialized_ = true;
+}
+
+// This is a no-op, but we'll keep it around in case
+// we need to do more cleanup in the future.
+void CleanupChromeLogging() {
+ if (chrome_logging_failed_)
+ return; // We failed to initiailize logging, no cleanup.
+
+ DCHECK(chrome_logging_initialized_) <<
+ "Attempted to clean up logging when it wasn't initialized.";
+
+ CloseLogFile();
+
+ chrome_logging_initialized_ = false;
+ chrome_logging_redirected_ = false;
+}
+
+base::FilePath GetLogFileName(const base::CommandLine& command_line) {
+ std::string filename = command_line.GetSwitchValueASCII(switches::kLogFile);
+ if (filename.empty())
+ base::Environment::Create()->GetVar(env_vars::kLogFileName, &filename);
+ if (!filename.empty())
+ return base::FilePath::FromUTF8Unsafe(filename);
+
+ const base::FilePath log_filename(FILE_PATH_LITERAL("chrome_debug.log"));
+ base::FilePath log_path;
+
+ if (base::PathService::Get(chrome::DIR_LOGS, &log_path)) {
+ log_path = log_path.Append(log_filename);
+ return log_path;
+ } else {
+ // error with path service, just use some default file somewhere
+ return log_filename;
+ }
+}
+
+bool DialogsAreSuppressed() {
+ return dialogs_are_suppressed_;
+}
+
+#if defined(OS_CHROMEOS)
+base::FilePath GenerateTimestampedName(const base::FilePath& base_path,
+ base::Time timestamp) {
+ base::Time::Exploded time_deets;
+ timestamp.LocalExplode(&time_deets);
+ std::string suffix = base::StringPrintf("_%02d%02d%02d-%02d%02d%02d",
+ time_deets.year,
+ time_deets.month,
+ time_deets.day_of_month,
+ time_deets.hour,
+ time_deets.minute,
+ time_deets.second);
+ return base_path.InsertBeforeExtensionASCII(suffix);
+}
+#endif // defined(OS_CHROMEOS)
+
+} // namespace logging
diff --git a/chromium/chrome/common/logging_chrome.h b/chromium/chrome/common/logging_chrome.h
new file mode 100644
index 00000000000..f727faa5f83
--- /dev/null
+++ b/chromium/chrome/common/logging_chrome.h
@@ -0,0 +1,72 @@
+// 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 CHROME_COMMON_LOGGING_CHROME_H_
+#define CHROME_COMMON_LOGGING_CHROME_H_
+
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+namespace base {
+class CommandLine;
+class FilePath;
+}
+
+namespace logging {
+
+// Call to initialize logging for Chrome. This sets up the chrome-specific
+// logfile naming scheme and might do other things like log modules and
+// setting levels in the future.
+//
+// The main process might want to delete any old log files on startup by
+// setting delete_old_log_file, but the renderer processes should not, or
+// they will delete each others' logs.
+//
+// XXX
+// Setting suppress_error_dialogs to true disables any dialogs that would
+// normally appear for assertions and crashes, and makes any catchable
+// errors (namely assertions) available via GetSilencedErrorCount()
+// and GetSilencedError().
+void InitChromeLogging(const base::CommandLine& command_line,
+ OldFileDeletionState delete_old_log_file);
+
+LoggingDestination DetermineLoggingDestination(
+ const base::CommandLine& command_line);
+
+#if defined(OS_CHROMEOS)
+// Point the logging symlink to the system log or the user session log.
+base::FilePath SetUpSymlinkIfNeeded(const base::FilePath& symlink_path,
+ bool new_log);
+
+// Remove the logging symlink.
+void RemoveSymlinkAndLog(const base::FilePath& link_path,
+ const base::FilePath& target_path);
+
+// Get the log file directory path.
+base::FilePath GetSessionLogDir(const base::CommandLine& command_line);
+
+// Get the log file location.
+base::FilePath GetSessionLogFile(const base::CommandLine& command_line);
+#endif
+
+// Call when done using logging for Chrome.
+void CleanupChromeLogging();
+
+// Returns the fully-qualified name of the log file.
+base::FilePath GetLogFileName(const base::CommandLine& command_line);
+
+// Returns true when error/assertion dialogs are not to be shown, false
+// otherwise.
+bool DialogsAreSuppressed();
+
+#if defined(OS_CHROMEOS)
+// Inserts timestamp before file extension (if any) in the form
+// "_yymmdd-hhmmss".
+base::FilePath GenerateTimestampedName(const base::FilePath& base_path,
+ base::Time timestamp);
+#endif // OS_CHROMEOS
+} // namespace logging
+
+#endif // CHROME_COMMON_LOGGING_CHROME_H_
diff --git a/chromium/chrome/common/mac/DEPS b/chromium/chrome/common/mac/DEPS
new file mode 100644
index 00000000000..d6b1434b64d
--- /dev/null
+++ b/chromium/chrome/common/mac/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+third_party/google_toolbox_for_mac/src",
+]
diff --git a/chromium/chrome/common/mac/OWNERS b/chromium/chrome/common/mac/OWNERS
new file mode 100644
index 00000000000..011c2b60a9e
--- /dev/null
+++ b/chromium/chrome/common/mac/OWNERS
@@ -0,0 +1,15 @@
+mark@chromium.org
+rsesek@chromium.org
+tapted@chromium.org
+thomasvl@chromium.org
+thakis@chromium.org
+
+per-file *_param_traits*.*=set noparent
+per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS
+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
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
+# COMPONENT: Internals>PlatformIntegration
diff --git a/chromium/chrome/common/mac/app_mode_chrome_locator.h b/chromium/chrome/common/mac/app_mode_chrome_locator.h
new file mode 100644
index 00000000000..1abe7e07015
--- /dev/null
+++ b/chromium/chrome/common/mac/app_mode_chrome_locator.h
@@ -0,0 +1,40 @@
+// 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 CHROME_COMMON_MAC_APP_MODE_CHROME_LOCATOR_H_
+#define CHROME_COMMON_MAC_APP_MODE_CHROME_LOCATOR_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/strings/string16.h"
+
+@class NSString;
+
+namespace base {
+class FilePath;
+}
+
+namespace app_mode {
+
+// Given a bundle id, return the path of the corresponding bundle.
+// Returns true if the bundle was found, false otherwise.
+bool FindBundleById(NSString* bundle_id, base::FilePath* out_bundle);
+
+// Given the path to the Chrome bundle, and an optional framework version, read
+// the following information:
+// |executable_path| - Path to the Chrome executable.
+// |framework_path| - Path of the Chrome Framework.framework.
+// |framework_dylib_path| - Path to the Chrome Framework's shared library.
+// If |version_str| is not given, this will return this data for the current
+// Chrome version. Returns true if all information read successfully; false
+// otherwise.
+bool GetChromeBundleInfo(const base::FilePath& chrome_bundle,
+ const std::string& version_str,
+ base::FilePath* executable_path,
+ base::FilePath* framework_path,
+ base::FilePath* framework_dylib_path);
+
+} // namespace app_mode
+
+#endif // CHROME_COMMON_MAC_APP_MODE_CHROME_LOCATOR_H_
diff --git a/chromium/chrome/common/mac/app_mode_chrome_locator.mm b/chromium/chrome/common/mac/app_mode_chrome_locator.mm
new file mode 100644
index 00000000000..7e5f3fa0b7e
--- /dev/null
+++ b/chromium/chrome/common/mac/app_mode_chrome_locator.mm
@@ -0,0 +1,153 @@
+// 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.
+
+#import "chrome/common/mac/app_mode_chrome_locator.h"
+
+#import <AppKit/AppKit.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/mac/foundation_util.h"
+#include "base/optional.h"
+#include "base/strings/sys_string_conversions.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/mac/app_mode_common.h"
+
+namespace app_mode {
+
+namespace {
+
+struct PathAndStructure {
+ NSString* framework_dylib_path; // weak
+ bool is_new_app_structure;
+};
+
+base::Optional<PathAndStructure> GetFrameworkDylibPathAndStructure(
+ NSString* bundle_path,
+ NSString* version) {
+ // NEW STYLE:
+ // Chromium.app/Contents/Frameworks/Chromium Framework.framework/
+ // Versions/<version>/Chromium Framework
+ NSString* path = [NSString pathWithComponents:@[
+ bundle_path, @"Contents", @"Frameworks", @(chrome::kFrameworkName),
+ @"Versions", version, @(chrome::kFrameworkExecutableName)
+ ]];
+
+ if ([[NSFileManager defaultManager] fileExistsAtPath:path])
+ return PathAndStructure{path, true};
+
+ // OLD STYLE:
+ // Chromium.app/Contents/Versions/<version>/Chromium Framework.framework/
+ // Versions/A/Chromium Framework
+ path = [NSString pathWithComponents:@[
+ bundle_path, @"Contents", @"Versions", version, @(chrome::kFrameworkName),
+ @"Versions", @"A", @(chrome::kFrameworkExecutableName)
+ ]];
+
+ if ([[NSFileManager defaultManager] fileExistsAtPath:path])
+ return PathAndStructure{path, false};
+
+ return base::nullopt;
+}
+
+} // namespace
+
+bool FindBundleById(NSString* bundle_id, base::FilePath* out_bundle) {
+ NSWorkspace* ws = [NSWorkspace sharedWorkspace];
+ NSString *bundlePath = [ws absolutePathForAppBundleWithIdentifier:bundle_id];
+ if (!bundlePath)
+ return false;
+
+ *out_bundle = base::mac::NSStringToFilePath(bundlePath);
+ return true;
+}
+
+bool GetChromeBundleInfo(const base::FilePath& chrome_bundle,
+ const std::string& version_str,
+ base::FilePath* executable_path,
+ base::FilePath* framework_path,
+ base::FilePath* framework_dylib_path) {
+ NSString* cr_bundle_path = base::mac::FilePathToNSString(chrome_bundle);
+ NSBundle* cr_bundle = [NSBundle bundleWithPath:cr_bundle_path];
+ if (!cr_bundle)
+ return false;
+
+ // Try to get the version requested, if present.
+ base::Optional<PathAndStructure> framework_path_and_structure;
+ if (!version_str.empty()) {
+ framework_path_and_structure = GetFrameworkDylibPathAndStructure(
+ cr_bundle_path, base::SysUTF8ToNSString(version_str));
+ }
+
+ // If the version requested is not present, or no specific version was
+ // requested, fall back to the "current" version. For new-style bundle
+ // structures, use the "Current" symlink. (This will intentionally return nil
+ // with the old bundle structure.)
+ //
+ // Note that the scenario where a specific version was requested but is not
+ // present is a "should not happen" scenario. Chromium, while it is running,
+ // maintains a link to the currently running version, and this function's
+ // caller checked to see if the Chromium was still running. However, even in
+ // this bizarre case, it's best to find _some_ Chromium.
+ if (!framework_path_and_structure) {
+ framework_path_and_structure =
+ GetFrameworkDylibPathAndStructure(cr_bundle_path, @"Current");
+ if (framework_path_and_structure) {
+ framework_path_and_structure->framework_dylib_path =
+ [framework_path_and_structure
+ ->framework_dylib_path stringByResolvingSymlinksInPath];
+ }
+ }
+
+ // At this point it is known that it is an old-style bundle structure (or a
+ // rather broken new-style bundle). Try explicitly specifying the version of
+ // the framework matching the outer bundle version.
+ if (!framework_path_and_structure) {
+ NSString* cr_version = base::mac::ObjCCast<NSString>([cr_bundle
+ objectForInfoDictionaryKey:app_mode::kCFBundleShortVersionStringKey]);
+ if (cr_version) {
+ framework_path_and_structure =
+ GetFrameworkDylibPathAndStructure(cr_bundle_path, cr_version);
+ }
+ }
+
+ if (!framework_path_and_structure)
+ return false;
+
+ // A few sanity checks.
+ BOOL is_directory;
+ BOOL exists = [[NSFileManager defaultManager]
+ fileExistsAtPath:framework_path_and_structure->framework_dylib_path
+ isDirectory:&is_directory];
+ if (!exists || is_directory)
+ return false;
+
+ NSString* cr_framework_path;
+
+ if (framework_path_and_structure->is_new_app_structure) {
+ // For the path to the framework version itself, remove the framework name.
+ cr_framework_path =
+ [framework_path_and_structure
+ ->framework_dylib_path stringByDeletingLastPathComponent];
+ } else {
+ // For the path to the framework itself, remove the framework name ...
+ cr_framework_path =
+ [framework_path_and_structure
+ ->framework_dylib_path stringByDeletingLastPathComponent];
+ // ... the "A" ...
+ cr_framework_path = [cr_framework_path stringByDeletingLastPathComponent];
+ // ... and the "Versions" directory.
+ cr_framework_path = [cr_framework_path stringByDeletingLastPathComponent];
+ }
+
+ // Everything is OK; copy the output parameters.
+ *executable_path = base::mac::NSStringToFilePath([cr_bundle executablePath]);
+ *framework_path = base::mac::NSStringToFilePath(cr_framework_path);
+ *framework_dylib_path = base::mac::NSStringToFilePath(
+ framework_path_and_structure->framework_dylib_path);
+ return true;
+}
+
+} // namespace app_mode
diff --git a/chromium/chrome/common/mac/app_mode_chrome_locator_browsertest.mm b/chromium/chrome/common/mac/app_mode_chrome_locator_browsertest.mm
new file mode 100644
index 00000000000..e38fa55ee0e
--- /dev/null
+++ b/chromium/chrome/common/mac/app_mode_chrome_locator_browsertest.mm
@@ -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.
+
+#import "chrome/common/mac/app_mode_chrome_locator.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_constants.h"
+#include "components/version_info/version_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// This needs to be a browser test because it expects to find a Chrome.app
+// bundle in the output directory.
+
+// Return the path to the Chrome/Chromium app bundle compiled along with the
+// test executable.
+void GetChromeBundlePath(base::FilePath* chrome_bundle) {
+ base::FilePath path;
+ base::PathService::Get(base::DIR_MODULE, &path);
+ path = path.Append(chrome::kBrowserProcessExecutableName);
+ path = path.ReplaceExtension(base::FilePath::StringType("app"));
+ *chrome_bundle = path;
+}
+
+} // namespace
+
+TEST(ChromeLocatorTest, FindBundle) {
+ base::FilePath finder_bundle_path;
+ EXPECT_TRUE(
+ app_mode::FindBundleById(@"com.apple.finder", &finder_bundle_path));
+ EXPECT_TRUE(base::DirectoryExists(finder_bundle_path));
+}
+
+TEST(ChromeLocatorTest, FindNonExistentBundle) {
+ base::FilePath dummy;
+ EXPECT_FALSE(app_mode::FindBundleById(@"this.doesnt.exist", &dummy));
+}
+
+TEST(ChromeLocatorTest, GetNonExistentBundleInfo) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ base::FilePath executable_path;
+ base::FilePath framework_path;
+ base::FilePath framework_dylib_path;
+ EXPECT_FALSE(app_mode::GetChromeBundleInfo(temp_dir.GetPath(), std::string(),
+ &executable_path, &framework_path,
+ &framework_dylib_path));
+}
+
+TEST(ChromeLocatorTest, GetChromeBundleInfo) {
+ base::FilePath chrome_bundle_path;
+ GetChromeBundlePath(&chrome_bundle_path);
+ ASSERT_TRUE(base::DirectoryExists(chrome_bundle_path));
+
+ base::FilePath executable_path;
+ base::FilePath framework_path;
+ base::FilePath framework_dylib_path;
+ EXPECT_TRUE(app_mode::GetChromeBundleInfo(chrome_bundle_path, std::string(),
+ &executable_path, &framework_path,
+ &framework_dylib_path));
+ EXPECT_TRUE(base::PathExists(executable_path));
+ EXPECT_TRUE(base::DirectoryExists(framework_path));
+ EXPECT_TRUE(base::PathExists(framework_dylib_path));
+}
+
+TEST(ChromeLocatorTest, GetChromeBundleInfoWithLatestVersion) {
+ base::FilePath chrome_bundle_path;
+ GetChromeBundlePath(&chrome_bundle_path);
+ ASSERT_TRUE(base::DirectoryExists(chrome_bundle_path));
+
+ base::FilePath executable_path;
+ base::FilePath framework_path;
+ base::FilePath framework_dylib_path;
+ EXPECT_TRUE(app_mode::GetChromeBundleInfo(
+ chrome_bundle_path, version_info::GetVersionNumber(), &executable_path,
+ &framework_path, &framework_dylib_path));
+ EXPECT_TRUE(base::PathExists(executable_path));
+ EXPECT_TRUE(base::DirectoryExists(framework_path));
+ EXPECT_TRUE(base::PathExists(framework_dylib_path));
+}
+
+TEST(ChromeLocatorTest, GetChromeBundleInfoWithInvalidVersion) {
+ base::FilePath chrome_bundle_path;
+ GetChromeBundlePath(&chrome_bundle_path);
+ ASSERT_TRUE(base::DirectoryExists(chrome_bundle_path));
+
+ base::FilePath executable_path;
+ base::FilePath framework_path;
+ base::FilePath framework_dylib_path;
+ // This still passes because it should default to the latest version.
+ EXPECT_TRUE(app_mode::GetChromeBundleInfo(
+ chrome_bundle_path, std::string("invalid_version"), &executable_path,
+ &framework_path, &framework_dylib_path));
+ EXPECT_TRUE(base::PathExists(executable_path));
+ EXPECT_TRUE(base::DirectoryExists(framework_path));
+ EXPECT_TRUE(base::PathExists(framework_dylib_path));
+}
+
+TEST(ChromeLocatorTest, GetChromeBundleInfoWithPreviousVersion) {
+ base::FilePath chrome_bundle_path;
+ GetChromeBundlePath(&chrome_bundle_path);
+ ASSERT_TRUE(base::DirectoryExists(chrome_bundle_path));
+
+ // Make a symlink that pretends to be a previous version.
+ base::FilePath fake_version_directory = chrome_bundle_path.Append("Contents")
+ .Append("Frameworks")
+ .Append(chrome::kFrameworkName)
+ .Append("Versions")
+ .Append("previous_version");
+ EXPECT_TRUE(
+ base::CreateSymbolicLink(base::FilePath(version_info::GetVersionNumber()),
+ fake_version_directory));
+
+ base::FilePath executable_path;
+ base::FilePath framework_path;
+ base::FilePath framework_dylib_path;
+ EXPECT_TRUE(app_mode::GetChromeBundleInfo(
+ chrome_bundle_path, std::string("previous_version"), &executable_path,
+ &framework_path, &framework_dylib_path));
+ EXPECT_TRUE(base::PathExists(executable_path));
+ EXPECT_TRUE(base::DirectoryExists(framework_path));
+ EXPECT_TRUE(base::PathExists(framework_dylib_path));
+
+ base::DeleteFile(fake_version_directory, false);
+}
diff --git a/chromium/chrome/common/mac/app_mode_common.h b/chromium/chrome/common/mac/app_mode_common.h
new file mode 100644
index 00000000000..0fb689d325e
--- /dev/null
+++ b/chromium/chrome/common/mac/app_mode_common.h
@@ -0,0 +1,187 @@
+// 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 CHROME_COMMON_MAC_APP_MODE_COMMON_H_
+#define CHROME_COMMON_MAC_APP_MODE_COMMON_H_
+
+#include <CoreServices/CoreServices.h>
+
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+#include "base/strings/stringize_macros.h"
+
+#ifdef __OBJC__
+@class NSString;
+#else
+class NSString;
+#endif
+
+// This file contains constants, interfaces, etc. which are common to the
+// browser application and the app mode loader (a.k.a. shim).
+
+// The version of the ChromeAppModeInfo struct below. If the format of the
+// struct ever changes, be sure to update the APP_SHIM_VERSION_NUMBER here and
+// the corresponding line in //chrome/app/framework.order .
+#define APP_SHIM_VERSION_NUMBER 6
+
+// All the other macro magic to make APP_SHIM_VERSION_NUMBER usable.
+#define APP_MODE_CONCAT(a, b) a##b
+#define APP_MODE_CONCAT2(a, b) APP_MODE_CONCAT(a, b)
+#define APP_SHIM_ENTRY_POINT_NAME \
+ APP_MODE_CONCAT2(ChromeAppModeStart_v, APP_SHIM_VERSION_NUMBER)
+#define APP_SHIM_ENTRY_POINT_NAME_STRING STRINGIZE(APP_SHIM_ENTRY_POINT_NAME)
+
+namespace app_mode {
+
+// Mach message ID used by the shim to connect to Chrome.
+constexpr mach_msg_id_t kBootstrapMsgId = 'apps';
+
+// Name fragment of the Mach server endpoint published in the bootstrap
+// namespace. The full name is "<bundle-id>.apps.<profile_path_hash>".
+// <bundle-id> is the BaseBundleID() and <profile_path_hash> is an MD5 hash
+// of the full profile directory path.
+extern const char kAppShimBootstrapNameFragment[];
+
+// A symlink used to store the version string of the currently running Chrome.
+// The shim will read this to determine which version of the framework to load.
+extern const char kRunningChromeVersionSymlinkName[];
+
+// The process ID of the Chrome process that launched the app shim.
+// The presence of this switch instructs the app shim to send LaunchApp with
+// launch_now = false. This associates the shim without launching the app.
+extern const char kLaunchedByChromeProcessId[];
+
+// Indicates to the shim that it was launched for a test, so don't attempt to
+// launch Chrome.
+extern const char kLaunchedForTest[];
+
+// Indicates to the shim that this Chrome has rebuilt it once already, i.e. if
+// it fails to launch again, don't trigger another rebuild.
+extern const char kLaunchedAfterRebuild[];
+
+// Path to an app shim bundle. Indicates to Chrome that this shim attempted to
+// launch but failed.
+extern const char kAppShimError[];
+
+// Keys for specifying the file types handled by an app.
+extern NSString* const kCFBundleDocumentTypesKey;
+extern NSString* const kCFBundleTypeExtensionsKey;
+extern NSString* const kCFBundleTypeIconFileKey;
+extern NSString* const kCFBundleTypeNameKey;
+extern NSString* const kCFBundleTypeMIMETypesKey;
+extern NSString* const kCFBundleTypeRoleKey;
+extern NSString* const kBundleTypeRoleViewer;
+
+// The display name of the bundle as shown in Finder and the Dock. For localized
+// bundles, this overrides the bundle's file name.
+extern NSString* const kCFBundleDisplayNameKey;
+
+// When Chrome is built, any app bundles (e.g. the app shim template bundle)
+// will have their CFBundleShortVersionString set to the full version string of
+// that build. Since, this string is used by OSX when displaying an app bundle's
+// version, we override it in app shim bundles to show the app's version
+// instead.
+extern NSString* const kCFBundleShortVersionStringKey;
+
+// Key for the Chrome version that built the app shim bundle. This needs to be
+// added since we override CFBundleShortVersionString with the version of the
+// app.
+extern NSString* const kCrBundleVersionKey;
+
+// The key specifying whether the display name should be localized. This makes
+// Finder look in localization folders in the app bundle for a display name.
+// (e.g. Content/Resources/en.lproj/)
+extern NSString* const kLSHasLocalizedDisplayNameKey;
+
+// Key specifying whether or not high DPI display is supported at all. If this
+// is not set to true then all graphics (including system dialogs and display
+// property queries) will behave as though all displays are low DPI.
+extern NSString* const kNSHighResolutionCapableKey;
+
+// The key under which the browser's bundle ID will be stored in the
+// app mode launcher bundle's Info.plist.
+extern NSString* const kBrowserBundleIDKey;
+
+// Key for the shortcut ID.
+extern NSString* const kCrAppModeShortcutIDKey;
+
+// Key for the app's name.
+extern NSString* const kCrAppModeShortcutNameKey;
+
+// Key for the app's URL.
+extern NSString* const kCrAppModeShortcutURLKey;
+
+// Key for the app user data directory.
+extern NSString* const kCrAppModeUserDataDirKey;
+
+// Key for the app's extension path.
+extern NSString* const kCrAppModeProfileDirKey;
+
+// Key for the app's profile display name.
+extern NSString* const kCrAppModeProfileNameKey;
+
+// When the Chrome browser is run, it stores its location in the defaults
+// system using this key.
+extern NSString* const kLastRunAppBundlePathPrefsKey;
+
+// The key for the major and minor version of an app.
+extern NSString* const kCrAppModeMajorVersionKey;
+extern NSString* const kCrAppModeMinorVersionKey;
+
+// Placeholders used in the app mode loader bundle' Info.plist:
+extern NSString* const kShortcutIdPlaceholder; // Extension shortcut ID.
+extern NSString* const kShortcutNamePlaceholder; // Extension name.
+extern NSString* const kShortcutURLPlaceholder;
+// Bundle ID of the Chrome browser bundle.
+extern NSString* const kShortcutBrowserBundleIDPlaceholder;
+
+// The structure used to pass information from the app mode loader to the
+// (browser) framework via the entry point ChromeAppModeStart_vN.
+//
+// As long as the name of the entry point is kept constant and
+// APP_SHIM_VERSION_NUMBER does not change, the layout of this structure
+// **MUST NOT CHANGE**, even across Chromium versions. This implies that no
+// base/ or std:: types may be used in this structure.
+//
+// However, this structure *may* be changed as long as the
+// APP_SHIM_VERSION_NUMBER above is updated; don't forget to also update the
+// corresponding line in //chrome/app/framework.order .
+struct ChromeAppModeInfo {
+ // Original |argc| and |argv| of the App Mode shortcut.
+ int argc;
+ char** argv;
+
+ // Path of the Chromium Framework, as UTF-8. This will be the input to
+ // SetOverrideFrameworkBundlePath().
+ const char* chrome_framework_path;
+
+ // Path to Chromium app bundle, as UTF-8.
+ const char* chrome_outer_bundle_path;
+
+ // Information about the App Mode shortcut:
+
+ // Path to the App Mode Loader application bundle that launched the process,
+ // as UTF-8.
+ const char* app_mode_bundle_path;
+
+ // Short UTF-8 ID string, preferably derived from |app_mode_short_name|.
+ // Should be safe for the file system.
+ const char* app_mode_id;
+
+ // Unrestricted (e.g., several-word) UTF-8-encoded name for the shortcut.
+ const char* app_mode_name;
+
+ // URL for the shortcut. Must be a valid UTF-8-encoded URL.
+ const char* app_mode_url;
+
+ // Path to the app's user data directory, as UTF-8.
+ const char* user_data_dir;
+
+ // Directory of the profile associated with the app, as UTF-8.
+ const char* profile_dir;
+};
+
+} // namespace app_mode
+
+#endif // CHROME_COMMON_MAC_APP_MODE_COMMON_H_
diff --git a/chromium/chrome/common/mac/app_mode_common.mm b/chromium/chrome/common/mac/app_mode_common.mm
new file mode 100644
index 00000000000..80fffbd9032
--- /dev/null
+++ b/chromium/chrome/common/mac/app_mode_common.mm
@@ -0,0 +1,73 @@
+// 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 "chrome/common/mac/app_mode_common.h"
+
+#import <Foundation/Foundation.h>
+#include <type_traits>
+
+namespace app_mode {
+
+const char kAppShimBootstrapNameFragment[] = "apps";
+
+const char kRunningChromeVersionSymlinkName[] = "RunningChromeVersion";
+
+const char kLaunchedByChromeProcessId[] = "launched-by-chrome-process-id";
+const char kLaunchedForTest[] = "launched-for-test";
+const char kLaunchedAfterRebuild[] = "launched-after-rebuild";
+
+const char kAppShimError[] = "app-shim-error";
+
+NSString* const kCFBundleDocumentTypesKey = @"CFBundleDocumentTypes";
+NSString* const kCFBundleTypeExtensionsKey = @"CFBundleTypeExtensions";
+NSString* const kCFBundleTypeIconFileKey = @"CFBundleTypeIconFile";
+NSString* const kCFBundleTypeNameKey = @"CFBundleTypeName";
+NSString* const kCFBundleTypeMIMETypesKey = @"CFBundleTypeMIMETypes";
+NSString* const kCFBundleTypeRoleKey = @"CFBundleTypeRole";
+NSString* const kBundleTypeRoleViewer = @"Viewer";
+
+NSString* const kCFBundleDisplayNameKey = @"CFBundleDisplayName";
+NSString* const kCFBundleShortVersionStringKey = @"CFBundleShortVersionString";
+NSString* const kCrBundleVersionKey = @"CrBundleVersion";
+NSString* const kLSHasLocalizedDisplayNameKey = @"LSHasLocalizedDisplayName";
+NSString* const kNSHighResolutionCapableKey = @"NSHighResolutionCapable";
+NSString* const kBrowserBundleIDKey = @"CrBundleIdentifier";
+NSString* const kCrAppModeShortcutIDKey = @"CrAppModeShortcutID";
+NSString* const kCrAppModeShortcutNameKey = @"CrAppModeShortcutName";
+NSString* const kCrAppModeShortcutURLKey = @"CrAppModeShortcutURL";
+NSString* const kCrAppModeUserDataDirKey = @"CrAppModeUserDataDir";
+NSString* const kCrAppModeProfileDirKey = @"CrAppModeProfileDir";
+NSString* const kCrAppModeProfileNameKey = @"CrAppModeProfileName";
+NSString* const kCrAppModeMajorVersionKey = @"CrAppModeMajorVersionKey";
+NSString* const kCrAppModeMinorVersionKey = @"CrAppModeMinorVersionKey";
+
+NSString* const kLastRunAppBundlePathPrefsKey = @"LastRunAppBundlePath";
+
+NSString* const kShortcutIdPlaceholder = @"APP_MODE_SHORTCUT_ID";
+NSString* const kShortcutNamePlaceholder = @"APP_MODE_SHORTCUT_NAME";
+NSString* const kShortcutURLPlaceholder = @"APP_MODE_SHORTCUT_URL";
+NSString* const kShortcutBrowserBundleIDPlaceholder =
+ @"APP_MODE_BROWSER_BUNDLE_ID";
+
+static_assert(std::is_pod<ChromeAppModeInfo>::value == true,
+ "ChromeAppModeInfo must be a POD type");
+
+// ChromeAppModeInfo is built into the app_shim_loader binary that is not
+// updated with Chrome. If the layout of this structure changes, then Chrome
+// must rebuild all app shims. See https://crrev.com/362634 as an example.
+static_assert(
+ offsetof(ChromeAppModeInfo, argc) == 0x0 &&
+ offsetof(ChromeAppModeInfo, argv) == 0x8 &&
+ offsetof(ChromeAppModeInfo, chrome_framework_path) == 0x10 &&
+ offsetof(ChromeAppModeInfo, chrome_outer_bundle_path) == 0x18 &&
+ offsetof(ChromeAppModeInfo, app_mode_bundle_path) == 0x20 &&
+ offsetof(ChromeAppModeInfo, app_mode_id) == 0x28 &&
+ offsetof(ChromeAppModeInfo, app_mode_name) == 0x30 &&
+ offsetof(ChromeAppModeInfo, app_mode_url) == 0x38 &&
+ offsetof(ChromeAppModeInfo, user_data_dir) == 0x40 &&
+ offsetof(ChromeAppModeInfo, profile_dir) == 0x48,
+ "ChromeAppModeInfo layout has changed; bump the APP_SHIM_VERSION_NUMBER "
+ "in chrome/common/mac/app_mode_common.h. (And fix this static_assert.)");
+
+} // namespace app_mode
diff --git a/chromium/chrome/common/mac/app_shim_launch.h b/chromium/chrome/common/mac/app_shim_launch.h
new file mode 100644
index 00000000000..c2a8c58772c
--- /dev/null
+++ b/chromium/chrome/common/mac/app_shim_launch.h
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MAC_APP_SHIM_LAUNCH_H_
+#define CHROME_COMMON_MAC_APP_SHIM_LAUNCH_H_
+
+namespace apps {
+
+enum AppShimLaunchType {
+ // Process the app shim's LaunchAppmessage and associate the shim with the
+ // given profile and app id.
+ APP_SHIM_LAUNCH_REGISTER_ONLY = 0,
+ // Do the above and launch the app.
+ APP_SHIM_LAUNCH_NORMAL,
+ // Counter and end marker.
+ APP_SHIM_LAUNCH_NUM_TYPES
+};
+
+enum AppShimLaunchResult {
+ // App launched successfully.
+ APP_SHIM_LAUNCH_SUCCESS = 0,
+ // There is already a host registered for this app.
+ APP_SHIM_LAUNCH_DUPLICATE_HOST,
+ // The profile was not found.
+ APP_SHIM_LAUNCH_PROFILE_NOT_FOUND,
+ // The app was not found.
+ APP_SHIM_LAUNCH_APP_NOT_FOUND,
+ // The profile was locked.
+ APP_SHIM_LAUNCH_PROFILE_LOCKED,
+ // The app shim did not pass code signing validation.
+ APP_SHIM_LAUNCH_FAILED_VALIDATION,
+ // Counter and end marker.
+ APP_SHIM_LAUNCH_NUM_RESULTS
+};
+
+enum AppShimFocusType {
+ // Just focus the app.
+ APP_SHIM_FOCUS_NORMAL = 0,
+ // Focus the app or launch it if it has no windows open.
+ APP_SHIM_FOCUS_REOPEN,
+ // Open the given file in the app.
+ APP_SHIM_FOCUS_OPEN_FILES,
+ // Counter and end marker.
+ APP_SHIM_FOCUS_NUM_TYPES
+};
+
+enum AppShimAttentionType {
+ // Removes any active attention request.
+ APP_SHIM_ATTENTION_CANCEL = 0,
+ // Bounces the shim in the dock briefly.
+ APP_SHIM_ATTENTION_INFORMATIONAL,
+ // Bounces the shim in the dock continuously.
+ APP_SHIM_ATTENTION_CRITICAL,
+ // Counter and end marker.
+ APP_SHIM_ATTENTION_NUM_TYPES
+};
+
+} // namespace apps
+
+#endif // CHROME_COMMON_MAC_APP_SHIM_LAUNCH_H_
diff --git a/chromium/chrome/common/mac/app_shim_param_traits.h b/chromium/chrome/common/mac/app_shim_param_traits.h
new file mode 100644
index 00000000000..0cbae58f299
--- /dev/null
+++ b/chromium/chrome/common/mac/app_shim_param_traits.h
@@ -0,0 +1,26 @@
+// 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 CHROME_COMMON_MAC_APP_SHIM_PARAM_TRAITS_H_
+#define CHROME_COMMON_MAC_APP_SHIM_PARAM_TRAITS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "chrome/common/mac/app_shim_launch.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_utils.h"
+#include "ipc/param_traits_macros.h"
+
+IPC_ENUM_TRAITS_MAX_VALUE(apps::AppShimLaunchType,
+ apps::APP_SHIM_LAUNCH_NUM_TYPES - 1)
+IPC_ENUM_TRAITS_MAX_VALUE(apps::AppShimLaunchResult,
+ apps::APP_SHIM_LAUNCH_NUM_RESULTS - 1)
+IPC_ENUM_TRAITS_MAX_VALUE(apps::AppShimFocusType,
+ apps::APP_SHIM_FOCUS_NUM_TYPES - 1)
+IPC_ENUM_TRAITS_MAX_VALUE(apps::AppShimAttentionType,
+ apps::APP_SHIM_ATTENTION_NUM_TYPES - 1)
+
+#endif // CHROME_COMMON_MAC_APP_SHIM_PARAM_TRAITS_H_
diff --git a/chromium/chrome/common/mac/launchd.h b/chromium/chrome/common/mac/launchd.h
new file mode 100644
index 00000000000..2eb4dad5d1b
--- /dev/null
+++ b/chromium/chrome/common/mac/launchd.h
@@ -0,0 +1,95 @@
+// 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 CHROME_COMMON_MAC_LAUNCHD_H_
+#define CHROME_COMMON_MAC_LAUNCHD_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/macros.h"
+#include "base/memory/singleton.h"
+#include "chrome/common/mac/service_management.h"
+
+class Launchd {
+ public:
+ enum Type {
+ Agent, // LaunchAgent
+ Daemon // LaunchDaemon
+ };
+
+ // Domains map to NSSearchPathDomainMask so Foundation does not need to be
+ // included.
+ enum Domain {
+ User = 1, // ~/Library/Launch*
+ Local = 2, // /Library/Launch*
+ Network = 4, // /Network/Library/Launch*
+ System = 8 // /System/Library/Launch*
+ };
+
+ // TODO(dmaclach): Get rid of this pseudo singleton, and inject it
+ // appropriately wherever it is used.
+ // http://crbug.com/76925
+ static Launchd* GetInstance();
+
+ virtual ~Launchd();
+
+ virtual bool GetJobInfo(const std::string& label,
+ mac::services::JobInfo* info);
+
+ // Remove a launchd process from launchd.
+ virtual bool RemoveJob(const std::string& label);
+
+ // Used by a process controlled by launchd to restart itself.
+ // |session_type| can be "Aqua", "LoginWindow", "Background", "StandardIO" or
+ // "System".
+ // RestartLaunchdJob starts up a separate process to tell launchd to
+ // send this process a SIGTERM. This call will return, but a SIGTERM will be
+ // received shortly.
+ virtual bool RestartJob(Domain domain,
+ Type type,
+ CFStringRef name,
+ CFStringRef session_type);
+
+ // Read a launchd plist from disk.
+ // |name| should not have an extension.
+ virtual CFMutableDictionaryRef CreatePlistFromFile(Domain domain,
+ Type type,
+ CFStringRef name);
+ // Write a launchd plist to disk.
+ // |name| should not have an extension.
+ virtual bool WritePlistToFile(Domain domain,
+ Type type,
+ CFStringRef name,
+ CFDictionaryRef dict);
+
+ // Delete a launchd plist.
+ // |name| should not have an extension.
+ virtual bool DeletePlist(Domain domain, Type type, CFStringRef name);
+
+ // TODO(dmaclach): remove this once http://crbug.com/76925 is fixed.
+ // Scaffolding for doing unittests with our singleton.
+ static void SetInstance(Launchd* instance);
+ class ScopedInstance {
+ public:
+ explicit ScopedInstance(Launchd* instance) {
+ Launchd::SetInstance(instance);
+ }
+ ~ScopedInstance() {
+ Launchd::SetInstance(NULL);
+ }
+ };
+
+ protected:
+ Launchd() { }
+
+ private:
+ // TODO(dmaclach): remove this once http://crbug.com/76925 is fixed.
+ // Scaffolding for doing unittests with our singleton.
+ friend struct base::DefaultSingletonTraits<Launchd>;
+ static Launchd* g_instance_;
+
+ DISALLOW_COPY_AND_ASSIGN(Launchd);
+};
+
+#endif // CHROME_COMMON_MAC_LAUNCHD_H_
diff --git a/chromium/chrome/common/mac/launchd.mm b/chromium/chrome/common/mac/launchd.mm
new file mode 100644
index 00000000000..5eab6f98467
--- /dev/null
+++ b/chromium/chrome/common/mac/launchd.mm
@@ -0,0 +1,165 @@
+// 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 "chrome/common/mac/launchd.h"
+
+#import <Foundation/Foundation.h>
+#include <launch.h>
+
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/process/launch.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "chrome/common/mac/service_management.h"
+
+namespace {
+
+NSString* SanitizeShellArgument(NSString* arg) {
+ if (!arg) {
+ return nil;
+ }
+ NSString *sanitize = [arg stringByReplacingOccurrencesOfString:@"'"
+ withString:@"'\''"];
+ return [NSString stringWithFormat:@"'%@'", sanitize];
+}
+
+NSURL* GetPlistURL(Launchd::Domain domain,
+ Launchd::Type type,
+ CFStringRef name) {
+ NSArray* library_paths =
+ NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, domain, YES);
+ DCHECK_EQ([library_paths count], 1U);
+ NSString* library_path = [library_paths objectAtIndex:0];
+
+ NSString *launch_dir_name = (type == Launchd::Daemon) ? @"LaunchDaemons"
+ : @"LaunchAgents";
+ NSString* launch_dir =
+ [library_path stringByAppendingPathComponent:launch_dir_name];
+
+ NSError* err;
+ if (![[NSFileManager defaultManager] createDirectoryAtPath:launch_dir
+ withIntermediateDirectories:YES
+ attributes:nil
+ error:&err]) {
+ DLOG(ERROR) << "GetPlistURL " << base::mac::NSToCFCast(err);
+ return nil;
+ }
+
+ NSString* plist_file_path =
+ [launch_dir stringByAppendingPathComponent:base::mac::CFToNSCast(name)];
+ plist_file_path = [plist_file_path stringByAppendingPathExtension:@"plist"];
+ return [NSURL fileURLWithPath:plist_file_path isDirectory:NO];
+}
+
+} // namespace
+
+static_assert(static_cast<int>(Launchd::User) ==
+ static_cast<int>(NSUserDomainMask),
+ "NSUserDomainMask value changed");
+static_assert(static_cast<int>(Launchd::Local) ==
+ static_cast<int>(NSLocalDomainMask),
+ "NSLocalDomainMask value changed");
+static_assert(static_cast<int>(Launchd::Network) ==
+ static_cast<int>(NSNetworkDomainMask),
+ "NSNetworkDomainMask value changed");
+static_assert(static_cast<int>(Launchd::System) ==
+ static_cast<int>(NSSystemDomainMask),
+ "NSSystemDomainMask value changed");
+
+Launchd* Launchd::g_instance_ = NULL;
+
+Launchd* Launchd::GetInstance() {
+ if (!g_instance_) {
+ g_instance_ = base::Singleton<Launchd>::get();
+ }
+ return g_instance_;
+}
+
+void Launchd::SetInstance(Launchd* instance) {
+ if (instance) {
+ CHECK(!g_instance_);
+ }
+ g_instance_ = instance;
+}
+
+Launchd::~Launchd() { }
+
+bool Launchd::GetJobInfo(const std::string& label,
+ mac::services::JobInfo* info) {
+ return mac::services::GetJobInfo(label, info);
+}
+
+bool Launchd::RemoveJob(const std::string& label) {
+ return mac::services::RemoveJob(label);
+}
+
+bool Launchd::RestartJob(Domain domain,
+ Type type,
+ CFStringRef name,
+ CFStringRef cf_session_type) {
+ @autoreleasepool {
+ NSURL* url = GetPlistURL(domain, type, name);
+ NSString* ns_path = [url path];
+ ns_path = SanitizeShellArgument(ns_path);
+ const char* file_path = [ns_path fileSystemRepresentation];
+
+ NSString* ns_session_type =
+ SanitizeShellArgument(base::mac::CFToNSCast(cf_session_type));
+ if (!file_path || !ns_session_type) {
+ return false;
+ }
+
+ std::vector<std::string> argv;
+ argv.push_back("/bin/bash");
+ argv.push_back("--noprofile");
+ argv.push_back("-c");
+ std::string command =
+ base::StringPrintf("/bin/launchctl unload -S %s %s;"
+ "/bin/launchctl load -S %s %s;",
+ [ns_session_type UTF8String], file_path,
+ [ns_session_type UTF8String], file_path);
+ argv.push_back(command);
+
+ base::LaunchOptions options;
+ options.new_process_group = true;
+ return base::LaunchProcess(argv, options).IsValid();
+ }
+}
+
+CFMutableDictionaryRef Launchd::CreatePlistFromFile(Domain domain,
+ Type type,
+ CFStringRef name) {
+ @autoreleasepool {
+ NSURL* ns_url = GetPlistURL(domain, type, name);
+ NSMutableDictionary* plist =
+ [[NSMutableDictionary alloc] initWithContentsOfURL:ns_url];
+ return base::mac::NSToCFCast(plist);
+ }
+}
+
+bool Launchd::WritePlistToFile(Domain domain,
+ Type type,
+ CFStringRef name,
+ CFDictionaryRef dict) {
+ @autoreleasepool {
+ NSURL* ns_url = GetPlistURL(domain, type, name);
+ return [base::mac::CFToNSCast(dict) writeToURL:ns_url atomically:YES];
+ }
+}
+
+bool Launchd::DeletePlist(Domain domain, Type type, CFStringRef name) {
+ @autoreleasepool {
+ NSURL* ns_url = GetPlistURL(domain, type, name);
+ NSError* err = nil;
+ if (![[NSFileManager defaultManager] removeItemAtPath:[ns_url path]
+ error:&err]) {
+ if ([err code] != NSFileNoSuchFileError) {
+ DLOG(ERROR) << "DeletePlist: " << base::mac::NSToCFCast(err);
+ }
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/chromium/chrome/common/mac/mock_launchd.h b/chromium/chrome/common/mac/mock_launchd.h
new file mode 100644
index 00000000000..9909703e1d0
--- /dev/null
+++ b/chromium/chrome/common/mac/mock_launchd.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 CHROME_COMMON_MAC_MOCK_LAUNCHD_H_
+#define CHROME_COMMON_MAC_MOCK_LAUNCHD_H_
+
+#include <launch.h>
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_refptr.h"
+#include "chrome/common/mac/launchd.h"
+#include "chrome/common/multi_process_lock.h"
+
+namespace base {
+class SingleThreadTaskRunner;
+}
+
+// TODO(dmaclach): Write this in terms of a real mock.
+// http://crbug.com/76923
+class MockLaunchd : public Launchd {
+ public:
+ static bool MakeABundle(const base::FilePath& dst,
+ const std::string& name,
+ base::FilePath* bundle_root,
+ base::FilePath* executable);
+
+ MockLaunchd(const base::FilePath& file,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ base::OnceClosure quit_closure,
+ bool as_service);
+ ~MockLaunchd() override;
+
+ bool GetJobInfo(const std::string& label,
+ mac::services::JobInfo* info) override;
+ bool RemoveJob(const std::string& label) override;
+ bool RestartJob(Domain domain,
+ Type type,
+ CFStringRef name,
+ CFStringRef session_type) override;
+ CFMutableDictionaryRef CreatePlistFromFile(Domain domain,
+ Type type,
+ CFStringRef name) override;
+ bool WritePlistToFile(Domain domain,
+ Type type,
+ CFStringRef name,
+ CFDictionaryRef dict) override;
+ bool DeletePlist(Domain domain, Type type, CFStringRef name) override;
+
+ void SignalReady();
+
+ bool restart_called() const { return restart_called_; }
+ bool remove_called() const { return remove_called_; }
+ bool checkin_called() const { return checkin_called_; }
+ bool write_called() const { return write_called_; }
+ bool delete_called() const { return delete_called_; }
+
+ private:
+ base::FilePath file_;
+ std::string pipe_name_;
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
+ base::OnceClosure quit_closure_;
+ std::unique_ptr<MultiProcessLock> running_lock_;
+ bool as_service_;
+ bool restart_called_;
+ bool remove_called_;
+ bool checkin_called_;
+ bool write_called_;
+ bool delete_called_;
+};
+
+#endif // CHROME_COMMON_MAC_MOCK_LAUNCHD_H_
diff --git a/chromium/chrome/common/mac/mock_launchd.mm b/chromium/chrome/common/mac/mock_launchd.mm
new file mode 100644
index 00000000000..ac3b913b974
--- /dev/null
+++ b/chromium/chrome/common/mac/mock_launchd.mm
@@ -0,0 +1,168 @@
+// 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 "chrome/common/mac/mock_launchd.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <errno.h>
+#include <stddef.h>
+#include <sys/un.h>
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "chrome/common/mac/launchd.h"
+#include "chrome/common/service_process_util.h"
+#include "components/version_info/version_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// static
+bool MockLaunchd::MakeABundle(const base::FilePath& dst,
+ const std::string& name,
+ base::FilePath* bundle_root,
+ base::FilePath* executable) {
+ *bundle_root = dst.Append(name + std::string(".app"));
+ base::FilePath contents = bundle_root->AppendASCII("Contents");
+ base::FilePath mac_os = contents.AppendASCII("MacOS");
+ *executable = mac_os.Append(name);
+ base::FilePath info_plist = contents.Append("Info.plist");
+
+ if (!base::CreateDirectory(mac_os)) {
+ return false;
+ }
+ const char* data = "#! testbundle\n";
+ int len = strlen(data);
+ if (base::WriteFile(*executable, data, len) != len) {
+ return false;
+ }
+ if (chmod(executable->value().c_str(), 0555) != 0) {
+ return false;
+ }
+
+ const char info_plist_format[] =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" "
+ "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+ "<plist version=\"1.0\">\n"
+ "<dict>\n"
+ " <key>CFBundleDevelopmentRegion</key>\n"
+ " <string>English</string>\n"
+ " <key>CFBundleExecutable</key>\n"
+ " <string>%s</string>\n"
+ " <key>CFBundleIdentifier</key>\n"
+ " <string>com.test.%s</string>\n"
+ " <key>CFBundleInfoDictionaryVersion</key>\n"
+ " <string>6.0</string>\n"
+ " <key>CFBundleShortVersionString</key>\n"
+ " <string>%s</string>\n"
+ " <key>CFBundleVersion</key>\n"
+ " <string>1</string>\n"
+ "</dict>\n"
+ "</plist>\n";
+ std::string info_plist_data =
+ base::StringPrintf(info_plist_format, name.c_str(), name.c_str(),
+ version_info::GetVersionNumber().c_str());
+ len = info_plist_data.length();
+ if (base::WriteFile(info_plist, info_plist_data.c_str(), len) != len) {
+ return false;
+ }
+ const UInt8* bundle_root_path =
+ reinterpret_cast<const UInt8*>(bundle_root->value().c_str());
+ base::ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(
+ kCFAllocatorDefault, bundle_root_path, bundle_root->value().length(),
+ true));
+ base::ScopedCFTypeRef<CFBundleRef> bundle(
+ CFBundleCreate(kCFAllocatorDefault, url));
+ return bundle.get();
+}
+
+MockLaunchd::MockLaunchd(
+ const base::FilePath& file,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ base::OnceClosure quit_closure,
+ bool as_service)
+ : file_(file),
+ pipe_name_(GetServiceProcessServerName()),
+ main_task_runner_(std::move(main_task_runner)),
+ quit_closure_(std::move(quit_closure)),
+ as_service_(as_service),
+ restart_called_(false),
+ remove_called_(false),
+ checkin_called_(false),
+ write_called_(false),
+ delete_called_(false) {}
+
+MockLaunchd::~MockLaunchd() {}
+
+bool MockLaunchd::GetJobInfo(const std::string& label,
+ mac::services::JobInfo* info) {
+ if (!as_service_) {
+ std::unique_ptr<MultiProcessLock> running_lock(
+ TakeNamedLock(pipe_name_, false));
+ if (running_lock.get())
+ return false;
+ }
+
+ info->program = file_.value();
+ info->pid = base::GetCurrentProcId();
+ return true;
+}
+
+bool MockLaunchd::RemoveJob(const std::string& label) {
+ remove_called_ = true;
+ std::move(quit_closure_).Run();
+ return true;
+}
+
+bool MockLaunchd::RestartJob(Domain domain,
+ Type type,
+ CFStringRef name,
+ CFStringRef session_type) {
+ restart_called_ = true;
+ std::move(quit_closure_).Run();
+ return true;
+}
+
+CFMutableDictionaryRef MockLaunchd::CreatePlistFromFile(Domain domain,
+ Type type,
+ CFStringRef name) {
+ NSString* ns_program = base::SysUTF8ToNSString(file_.value());
+
+ NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithDictionary:@{
+ @LAUNCH_JOBKEY_PROGRAM : ns_program,
+ @LAUNCH_JOBKEY_PROGRAMARGUMENTS : @[ ns_program ],
+ }];
+
+ // Callers expect to be given a reference but dictionaryWithDictionary: is
+ // autoreleased, so it's necessary to do a manual retain here.
+ return base::mac::NSToCFCast([dict retain]);
+}
+
+bool MockLaunchd::WritePlistToFile(Domain domain,
+ Type type,
+ CFStringRef name,
+ CFDictionaryRef dict) {
+ write_called_ = true;
+ return true;
+}
+
+bool MockLaunchd::DeletePlist(Domain domain, Type type, CFStringRef name) {
+ delete_called_ = true;
+ return true;
+}
+
+void MockLaunchd::SignalReady() {
+ ASSERT_TRUE(as_service_);
+ running_lock_.reset(TakeNamedLock(pipe_name_, true));
+}
diff --git a/chromium/chrome/common/mac/service_management.h b/chromium/chrome/common/mac/service_management.h
new file mode 100644
index 00000000000..8867df6fe63
--- /dev/null
+++ b/chromium/chrome/common/mac/service_management.h
@@ -0,0 +1,72 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MAC_SERVICE_MANAGEMENT_H_
+#define CHROME_COMMON_MAC_SERVICE_MANAGEMENT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/optional.h"
+
+namespace mac {
+namespace services {
+
+struct JobInfo {
+ JobInfo();
+ JobInfo(const JobInfo& other);
+ ~JobInfo();
+
+ std::string program;
+ base::Optional<int> pid;
+};
+
+struct JobCheckinInfo {
+ JobCheckinInfo();
+ JobCheckinInfo(const JobCheckinInfo& info);
+ ~JobCheckinInfo();
+
+ std::string program;
+};
+
+struct JobOptions {
+ JobOptions();
+ JobOptions(const JobOptions& other);
+ ~JobOptions();
+
+ std::string label;
+ // See launchd.plist(5) for details about these two fields. In short:
+ // - executable_path, if non-empty, is the absolute path to the executable
+ // for this job;
+ // - arguments[0] is the absolute *or relative* path to the executable if
+ // executable_path is empty; in either case, all of arguments is passed
+ // directly as argv to the job, meaning arguments[0] becomes argv[0]
+ // There are important caveats about the argument vector documented in the
+ // launchd.plist(5) man page.
+ std::string executable_path;
+ std::vector<std::string> arguments;
+
+ // See launchd.plist(5) "MachServices" for details about this field. The
+ // mach_service_ field corresponds to a key in the MachServices dictionary,
+ // whose value will be YES.
+ std::string mach_service_name;
+
+ // Whether to run this job immediately once it is loaded.
+ bool run_at_load;
+
+ // Whether to restart the job whenever it exits successfully. This also
+ // implicitly limits the job to interactive sessions only (i.e., the job will
+ // not run in system sessions).
+ bool auto_launch;
+};
+
+bool GetJobInfo(const std::string& label, JobInfo* info);
+
+bool SubmitJob(const JobOptions& options);
+bool RemoveJob(const std::string& label);
+
+} // namespace services
+} // namespace mac
+
+#endif // CHROME_COMMON_MAC_SERVICE_MANAGEMENT_H_
diff --git a/chromium/chrome/common/mac/service_management.mm b/chromium/chrome/common/mac/service_management.mm
new file mode 100644
index 00000000000..20fa32749f7
--- /dev/null
+++ b/chromium/chrome/common/mac/service_management.mm
@@ -0,0 +1,217 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/mac/service_management.h"
+
+#import <CoreServices/CoreServices.h>
+#import <Foundation/Foundation.h>
+#import <ServiceManagement/ServiceManagement.h>
+
+#include <errno.h>
+#include <launch.h>
+
+#include "base/compiler_specific.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/macros.h"
+#include "base/strings/sys_string_conversions.h"
+
+// This entire file is written in terms of the launch_data_t API, which is
+// deprecated with no replacement, so just ignore the warnings for now.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+namespace {
+
+class ScopedLaunchData {
+ public:
+ explicit ScopedLaunchData(launch_data_type_t type)
+ : data_(launch_data_alloc(type)) {}
+ explicit ScopedLaunchData(launch_data_t data) : data_(data) {}
+ ScopedLaunchData(ScopedLaunchData&& other) : data_(other.release()) {}
+ ~ScopedLaunchData() { reset(); }
+
+ void reset() {
+ if (data_)
+ launch_data_free(data_);
+ data_ = nullptr;
+ }
+
+ launch_data_t release() WARN_UNUSED_RESULT {
+ launch_data_t val = data_;
+ data_ = nullptr;
+ return val;
+ }
+
+ launch_data_t get() { return data_; }
+ operator launch_data_t() const { return data_; }
+ operator bool() const { return !!data_; }
+
+ private:
+ launch_data_t data_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedLaunchData);
+};
+
+ScopedLaunchData SendLaunchMessage(ScopedLaunchData&& msg) {
+ return ScopedLaunchData(launch_msg(msg));
+}
+
+ScopedLaunchData LaunchDataFromString(const std::string& string) {
+ ScopedLaunchData result(LAUNCH_DATA_STRING);
+ // launch_data_set_string() will make a copy of the passed-in string.
+ launch_data_set_string(result, string.c_str());
+ return result;
+}
+
+int ErrnoFromLaunchData(launch_data_t data) {
+ if (launch_data_get_type(data) != LAUNCH_DATA_ERRNO)
+ return EINVAL;
+ return launch_data_get_errno(data);
+}
+
+bool StringFromLaunchDataDictEntry(launch_data_t dict,
+ const char* key,
+ std::string* value) {
+ launch_data_t entry = launch_data_dict_lookup(dict, key);
+ if (!entry || launch_data_get_type(entry) != LAUNCH_DATA_STRING)
+ return false;
+ *value = std::string(launch_data_get_string(entry));
+ return true;
+}
+
+bool IntFromLaunchDataDictEntry(launch_data_t dict,
+ const char* key,
+ int* value) {
+ launch_data_t entry = launch_data_dict_lookup(dict, key);
+ if (!entry || launch_data_get_type(entry) != LAUNCH_DATA_INTEGER)
+ return false;
+ *value = launch_data_get_integer(entry);
+ return true;
+}
+
+ScopedLaunchData DoServiceOp(const char* verb,
+ const std::string& label,
+ int* error) {
+ ScopedLaunchData msg(LAUNCH_DATA_DICTIONARY);
+ launch_data_dict_insert(msg, LaunchDataFromString(label).release(), verb);
+
+ ScopedLaunchData result(SendLaunchMessage(std::move(msg)));
+ if (!result)
+ *error = errno;
+ return result;
+}
+
+NSArray* NSArrayFromStringVector(const std::vector<std::string>& vec) {
+ NSMutableArray* args = [NSMutableArray arrayWithCapacity:vec.size()];
+ for (const auto& item : vec) {
+ [args addObject:base::SysUTF8ToNSString(item)];
+ }
+ return args;
+}
+
+base::scoped_nsobject<NSDictionary> DictionaryForJobOptions(
+ const mac::services::JobOptions& options) {
+ base::scoped_nsobject<NSMutableDictionary> opts(
+ [[NSMutableDictionary alloc] init]);
+
+ [opts setObject:base::SysUTF8ToNSString(options.label)
+ forKey:@LAUNCH_JOBKEY_LABEL];
+
+ if (!options.executable_path.empty()) {
+ [opts setObject:base::SysUTF8ToNSString(options.executable_path)
+ forKey:@LAUNCH_JOBKEY_PROGRAM];
+ }
+
+ if (!options.arguments.empty()) {
+ [opts setObject:NSArrayFromStringVector(options.arguments)
+ forKey:@LAUNCH_JOBKEY_PROGRAMARGUMENTS];
+ }
+
+ if (!options.mach_service_name.empty()) {
+ NSDictionary* service_entry =
+ @{base::SysUTF8ToNSString(options.mach_service_name) : @YES};
+ [opts setObject:service_entry forKey:@LAUNCH_JOBKEY_MACHSERVICES];
+ }
+
+ if (options.run_at_load || options.auto_launch) {
+ [opts setObject:@YES forKey:@LAUNCH_JOBKEY_RUNATLOAD];
+ }
+
+ if (options.auto_launch) {
+ [opts setObject:@{
+ @LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT : @NO
+ }
+ forKey:@LAUNCH_JOBKEY_KEEPALIVE];
+ [opts setObject:@"Aqua" forKey:@LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE];
+ }
+
+ return base::scoped_nsobject<NSDictionary>(opts.release());
+}
+
+} // namespace
+
+namespace mac {
+namespace services {
+
+JobInfo::JobInfo() = default;
+JobInfo::JobInfo(const JobInfo& other) = default;
+JobInfo::~JobInfo() = default;
+
+JobCheckinInfo::JobCheckinInfo() = default;
+JobCheckinInfo::JobCheckinInfo(const JobCheckinInfo& other) = default;
+JobCheckinInfo::~JobCheckinInfo() = default;
+
+JobOptions::JobOptions() = default;
+JobOptions::JobOptions(const JobOptions& other) = default;
+JobOptions::~JobOptions() = default;
+
+bool GetJobInfo(const std::string& label, JobInfo* info) {
+ int error = 0;
+ ScopedLaunchData resp = DoServiceOp(LAUNCH_KEY_GETJOB, label, &error);
+
+ if (error)
+ return false;
+
+ std::string program;
+ if (!StringFromLaunchDataDictEntry(resp.get(), LAUNCH_JOBKEY_PROGRAM,
+ &program))
+ return false;
+
+ info->program = program;
+ int pid;
+ if (IntFromLaunchDataDictEntry(resp.get(), LAUNCH_JOBKEY_PID, &pid))
+ info->pid = pid;
+
+ return true;
+}
+
+bool SubmitJob(const JobOptions& options) {
+ base::scoped_nsobject<NSDictionary> options_dict =
+ DictionaryForJobOptions(options);
+ return SMJobSubmit(kSMDomainUserLaunchd,
+ base::mac::NSToCFCast(options_dict.get()), nullptr,
+ nullptr);
+}
+
+bool RemoveJob(const std::string& label) {
+ int error = 0;
+ ScopedLaunchData resp = DoServiceOp(LAUNCH_KEY_REMOVEJOB, label, &error);
+
+ if (!error)
+ error = ErrnoFromLaunchData(resp.get());
+
+ // On macOS 10.10+, removing a running job yields EINPROGRESS but the
+ // operation completes eventually (but not necessarily by the time RemoveJob
+ // is done). See rdar://18398683 for details.
+ if (error == EINPROGRESS)
+ error = 0;
+
+ return !error;
+}
+
+} // namespace services
+} // namespace mac
+
+#pragma clang diagnostic pop
diff --git a/chromium/chrome/common/mac/staging_watcher.h b/chromium/chrome/common/mac/staging_watcher.h
new file mode 100644
index 00000000000..14d9acc4ca3
--- /dev/null
+++ b/chromium/chrome/common/mac/staging_watcher.h
@@ -0,0 +1,72 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MAC_STAGING_WATCHER_H_
+#define CHROME_COMMON_MAC_STAGING_WATCHER_H_
+
+#import <Foundation/Foundation.h>
+
+// Chrome update works by staging a copy of Chrome near to the current bundle,
+// and then applying it when Chrome restarts to apply the update. Currently,
+// this state of "update pending" is indicated outside of Keystone by a key in
+// the CFPreferences.
+
+using StagingKeyChangedObserver = void (^)(BOOL stagingKeySet);
+
+// An object to observe the staging key. It can be used in either of two ways:
+// 1. To wait for the staging key to clear.
+// 2. To notify when the staging key changes state.
+@interface CrStagingKeyWatcher : NSObject
+
+// On macOS 10.11 and earlier, polling is used, and |pollingTime| specifies the
+// frequency of the polling. On macOS 10.12 and later, no polling is performed
+// and |pollingTime| is ignored.
+- (instancetype)initWithPollingTime:(NSTimeInterval)pollingTime;
+
+// Returns a boolean indicating whether or not the staging key is set.
+- (BOOL)isStagingKeySet;
+
+// Returns a boolean indicating whether or not the staging key is set. This will
+// not return the correct answer in testing.
++ (BOOL)isStagingKeySet;
+
+// Returns the path to the staged update, or nil if there is no staging key set.
+- (NSString*)stagingLocation;
+
+// Returns the path to the staged update, or nil if there is no staging key set.
+// This will not return the correct answer in testing.
++ (NSString*)stagingLocation;
+
+// Sleeps until the staging key is clear. If there is no staging key set,
+// returns immediately.
+- (void)waitForStagingKeyToClear;
+
+// Sets a block to be called when the staging key changes, and starts observing.
+// Only one observer may be set for a given CrStagingKeyWatcher; calling this
+// method again replaces the current observer.
+- (void)setStagingKeyChangedObserver:(StagingKeyChangedObserver)block;
+
+@end
+
+@interface CrStagingKeyWatcher (TestingInterface)
+
+// The designated initializer. Allows a non-default NSUserDefaults to be
+// specified. Also allows the use of KVO to be disabled to allow the macOS 10.11
+// and earlier code path to be tested on 10.12 and later.
+- (instancetype)initWithUserDefaults:(NSUserDefaults*)defaults
+ pollingTime:(NSTimeInterval)pollingTime
+ disableKVOForTesting:(BOOL)disableKVOForTesting;
+
+// Returns whether the last call to -waitForStagingKeyToClear blocked or
+// returned immediately.
+- (BOOL)lastWaitWasBlockedForTesting;
+
+// Returns the NSUserDefaults key that is used to indicate staging. The value to
+// be used is a dictionary of strings, with the key being the file path to the
+// existing bundle, and the value being the file path to the staged bundle.
++ (NSString*)stagingKeyForTesting;
+
+@end
+
+#endif // CHROME_COMMON_MAC_STAGING_WATCHER_H_
diff --git a/chromium/chrome/common/mac/staging_watcher.mm b/chromium/chrome/common/mac/staging_watcher.mm
new file mode 100644
index 00000000000..12fed3c9e0e
--- /dev/null
+++ b/chromium/chrome/common/mac/staging_watcher.mm
@@ -0,0 +1,191 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/mac/staging_watcher.h"
+
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_block.h"
+#include "base/mac/scoped_nsobject.h"
+
+// Best documentation / Is unofficial documentation
+//
+// Required reading for CFPreferences/NSUserDefaults is at
+// <http://dscoder.com/defaults.html>, a post by David "Catfish Man" Smith, who
+// re-wrote NSUserDefaults for 10.12 and iPad Classroom support. It is important
+// to note that KVO only notifies for changes made by other programs starting
+// with that rewrite in 10.12. In macOS 10.11 and earlier, polling is the only
+// option. Note that NSUserDefaultsDidChangeNotification never notifies about
+// changes made by other programs, not even in 10.12 and later.
+//
+// On the other hand, KVO notification was broken in the NSUserDefaults rewrite
+// for 10.14; see:
+// - https://twitter.com/Catfish_Man/status/1116185288257105925
+// - rdar://49812220
+// The bug is that a change from "no value" to "value present" doesn't notify.
+// To work around that, a default is registered to ensure that there never is
+// a "no value" situation.
+
+namespace {
+
+NSString* const kStagingKey = @"UpdatePending";
+
+} // namespace
+
+@interface CrStagingKeyWatcher () {
+ base::scoped_nsobject<NSUserDefaults> defaults_;
+ NSTimeInterval pollingTime_;
+ base::scoped_nsobject<NSTimer> pollingTimer_;
+ BOOL observing_;
+ base::mac::ScopedBlock<StagingKeyChangedObserver> callback_;
+ BOOL lastStagingKeyValue_;
+
+ BOOL lastWaitWasBlockedForTesting_;
+}
+
++ (NSString*)stagingLocationWithUserDefaults:(NSUserDefaults*)defaults;
+
+@end
+
+@implementation CrStagingKeyWatcher
+
+- (instancetype)initWithPollingTime:(NSTimeInterval)pollingTime {
+ return [self initWithUserDefaults:[NSUserDefaults standardUserDefaults]
+ pollingTime:pollingTime
+ disableKVOForTesting:NO];
+}
+
+- (instancetype)initWithUserDefaults:(NSUserDefaults*)defaults
+ pollingTime:(NSTimeInterval)pollingTime
+ disableKVOForTesting:(BOOL)disableKVOForTesting {
+ if ((self = [super init])) {
+ pollingTime_ = pollingTime;
+ defaults_.reset(defaults, base::scoped_policy::RETAIN);
+ [defaults_ registerDefaults:@{kStagingKey : @[]}];
+ lastStagingKeyValue_ = [self isStagingKeySet];
+ if (base::mac::IsAtLeastOS10_12() && !disableKVOForTesting) {
+ // If a change is made in another process (which is the use case here),
+ // the prior value is never provided in the observation callback change
+ // dictionary, whether or not NSKeyValueObservingOptionPrior is specified.
+ // Therefore, pass in 0 for the NSKeyValueObservingOptions and rely on
+ // keeping the previous value in |lastStagingKeyValue_|.
+ [defaults_ addObserver:self
+ forKeyPath:kStagingKey
+ options:0
+ context:nullptr];
+ observing_ = YES;
+ }
+ }
+ return self;
+}
+
++ (NSString*)stagingLocationWithUserDefaults:(NSUserDefaults*)defaults {
+ NSDictionary<NSString*, id>* stagedPathPairs =
+ [defaults dictionaryForKey:kStagingKey];
+ if (!stagedPathPairs)
+ return nil;
+
+ NSString* appPath = [base::mac::OuterBundle() bundlePath];
+
+ return base::mac::ObjCCast<NSString>([stagedPathPairs objectForKey:appPath]);
+}
+
+- (BOOL)isStagingKeySet {
+ return [self stagingLocation] != nil;
+}
+
++ (BOOL)isStagingKeySet {
+ return [self stagingLocation] != nil;
+}
+
+- (NSString*)stagingLocation {
+ return [CrStagingKeyWatcher stagingLocationWithUserDefaults:defaults_];
+}
+
++ (NSString*)stagingLocation {
+ return [self
+ stagingLocationWithUserDefaults:[NSUserDefaults standardUserDefaults]];
+}
+
+- (void)waitForStagingKeyToClear {
+ if (![self isStagingKeySet]) {
+ lastWaitWasBlockedForTesting_ = NO;
+ return;
+ }
+
+ NSRunLoop* runloop = [NSRunLoop currentRunLoop];
+ if (observing_) {
+ callback_.reset(
+ ^(BOOL stagingKeySet) {
+ CFRunLoopStop([runloop getCFRunLoop]);
+ },
+ base::scoped_policy::RETAIN);
+
+ while ([self isStagingKeySet] && [runloop runMode:NSDefaultRunLoopMode
+ beforeDate:[NSDate distantFuture]]) {
+ /* run! */
+ }
+ } else {
+ while ([self isStagingKeySet] &&
+ [runloop
+ runMode:NSDefaultRunLoopMode
+ beforeDate:[NSDate dateWithTimeIntervalSinceNow:pollingTime_]]) {
+ /* run! */
+ }
+ }
+
+ lastWaitWasBlockedForTesting_ = YES;
+}
+
+- (void)setStagingKeyChangedObserver:(StagingKeyChangedObserver)block {
+ callback_.reset(block, base::scoped_policy::RETAIN);
+
+ if (observing_) {
+ // Nothing to be done; the observation is already started.
+ } else {
+ pollingTimer_.reset(
+ [NSTimer scheduledTimerWithTimeInterval:pollingTime_
+ target:self
+ selector:@selector(timerFired:)
+ userInfo:nil
+ repeats:YES],
+ base::scoped_policy::RETAIN);
+ }
+}
+
+- (void)timerFired:(NSTimer*)timer {
+ [self observeValueForKeyPath:nil ofObject:nil change:nil context:nil];
+}
+
+- (void)dealloc {
+ if (observing_)
+ [defaults_ removeObserver:self forKeyPath:kStagingKey context:nullptr];
+ if (pollingTimer_)
+ [pollingTimer_ invalidate];
+
+ [super dealloc];
+}
+
+- (BOOL)lastWaitWasBlockedForTesting {
+ return lastWaitWasBlockedForTesting_;
+}
+
++ (NSString*)stagingKeyForTesting {
+ return kStagingKey;
+}
+
+- (void)observeValueForKeyPath:(NSString*)keyPath
+ ofObject:(id)object
+ change:(NSDictionary*)change
+ context:(void*)context {
+ BOOL isStagingKeySet = [self isStagingKeySet];
+ if (isStagingKeySet == lastStagingKeyValue_)
+ return;
+
+ lastStagingKeyValue_ = isStagingKeySet;
+ callback_.get()([self isStagingKeySet]);
+}
+
+@end
diff --git a/chromium/chrome/common/mac/staging_watcher_unittest.mm b/chromium/chrome/common/mac/staging_watcher_unittest.mm
new file mode 100644
index 00000000000..e3eb86ab950
--- /dev/null
+++ b/chromium/chrome/common/mac/staging_watcher_unittest.mm
@@ -0,0 +1,181 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/mac/staging_watcher.h"
+
+#include <dispatch/dispatch.h>
+
+#include "base/mac/bundle_locations.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+enum class KVOOrNot { kUseKVO, kDontUseKVO };
+
+class StagingKeyWatcherTest : public testing::TestWithParam<KVOOrNot> {
+ public:
+ StagingKeyWatcherTest() = default;
+ ~StagingKeyWatcherTest() = default;
+
+ protected:
+ void SetUp() override {
+ testingBundleID_.reset([[NSString alloc]
+ initWithFormat:@"org.chromium.StagingKeyWatcherTest.%d", getpid()]);
+ defaults_.reset(
+ [[NSUserDefaults alloc] initWithSuiteName:testingBundleID_]);
+
+ [defaults_ removeObjectForKey:[CrStagingKeyWatcher stagingKeyForTesting]];
+ }
+
+ void TearDown() override {
+ [defaults_ removeObjectForKey:[CrStagingKeyWatcher stagingKeyForTesting]];
+ }
+
+ base::scoped_nsobject<CrStagingKeyWatcher> CreateKeyWatcher() {
+ base::scoped_nsobject<CrStagingKeyWatcher> keyWatcher(
+ [[CrStagingKeyWatcher alloc]
+ initWithUserDefaults:defaults_
+ pollingTime:0.5
+ disableKVOForTesting:(GetParam() == KVOOrNot::kDontUseKVO)]);
+
+ return keyWatcher;
+ }
+
+ void SetDefaultsValue(id value) {
+ [defaults_ setObject:value
+ forKey:[CrStagingKeyWatcher stagingKeyForTesting]];
+ }
+
+ void ClearDefaultsValueInSeparateProcess() {
+ [NSTask launchedTaskWithLaunchPath:@"/usr/bin/defaults"
+ arguments:@[
+ @"delete", testingBundleID_.get(),
+ [CrStagingKeyWatcher stagingKeyForTesting]
+ ]];
+ }
+
+ void SetDefaultsValueInSeparateProcess() {
+ NSString* appPath = [base::mac::OuterBundle() bundlePath];
+
+ [NSTask launchedTaskWithLaunchPath:@"/usr/bin/defaults"
+ arguments:@[
+ @"write", testingBundleID_.get(),
+ [CrStagingKeyWatcher stagingKeyForTesting],
+ @"-dict", appPath, appPath
+ ]];
+ }
+
+ private:
+ base::scoped_nsobject<NSString> testingBundleID_;
+ base::scoped_nsobject<NSUserDefaults> defaults_;
+};
+
+INSTANTIATE_TEST_SUITE_P(KVOandNot,
+ StagingKeyWatcherTest,
+ testing::Values(KVOOrNot::kUseKVO,
+ KVOOrNot::kDontUseKVO));
+
+} // namespace
+
+TEST_P(StagingKeyWatcherTest, NoBlockingWhenNoKey) {
+ base::scoped_nsobject<CrStagingKeyWatcher> watcher = CreateKeyWatcher();
+ [watcher waitForStagingKeyToClear];
+ ASSERT_FALSE([watcher lastWaitWasBlockedForTesting]);
+}
+
+TEST_P(StagingKeyWatcherTest, NoBlockingWhenWrongKeyType) {
+ SetDefaultsValue(@"this is not a dictionary");
+
+ base::scoped_nsobject<CrStagingKeyWatcher> watcher = CreateKeyWatcher();
+ [watcher waitForStagingKeyToClear];
+ ASSERT_FALSE([watcher lastWaitWasBlockedForTesting]);
+}
+
+TEST_P(StagingKeyWatcherTest, NoBlockingWhenArrayType) {
+ SetDefaultsValue(@[ @3, @1, @4, @1, @5 ]);
+
+ base::scoped_nsobject<CrStagingKeyWatcher> watcher = CreateKeyWatcher();
+ [watcher waitForStagingKeyToClear];
+ ASSERT_FALSE([watcher lastWaitWasBlockedForTesting]);
+}
+
+TEST_P(StagingKeyWatcherTest, NoBlockingWhenEmptyArray) {
+ SetDefaultsValue(@[]);
+
+ base::scoped_nsobject<CrStagingKeyWatcher> watcher = CreateKeyWatcher();
+ [watcher waitForStagingKeyToClear];
+ ASSERT_FALSE([watcher lastWaitWasBlockedForTesting]);
+}
+
+TEST_P(StagingKeyWatcherTest, NoBlockingWhenEmptyDictionary) {
+ SetDefaultsValue(@{});
+
+ base::scoped_nsobject<CrStagingKeyWatcher> watcher = CreateKeyWatcher();
+ [watcher waitForStagingKeyToClear];
+ ASSERT_FALSE([watcher lastWaitWasBlockedForTesting]);
+}
+
+TEST_P(StagingKeyWatcherTest, BlockFunctionality) {
+ NSString* appPath = [base::mac::OuterBundle() bundlePath];
+ SetDefaultsValue(@{appPath : appPath});
+
+ NSRunLoop* runloop = [NSRunLoop currentRunLoop];
+ ASSERT_EQ(nil, [runloop currentMode]);
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ ASSERT_NE(nil, [runloop currentMode]);
+ ClearDefaultsValueInSeparateProcess();
+ });
+
+ base::scoped_nsobject<CrStagingKeyWatcher> watcher = CreateKeyWatcher();
+ [watcher waitForStagingKeyToClear];
+ ASSERT_TRUE([watcher lastWaitWasBlockedForTesting]);
+}
+
+TEST_P(StagingKeyWatcherTest, CallbackOnKeySet) {
+ // The staging key begins not set.
+
+ base::scoped_nsobject<CrStagingKeyWatcher> watcher = CreateKeyWatcher();
+ NSRunLoop* runloop = [NSRunLoop currentRunLoop];
+
+ __block bool observerCalled = false;
+ [watcher setStagingKeyChangedObserver:^(BOOL stagingKeySet) {
+ observerCalled = true;
+ CFRunLoopStop([runloop getCFRunLoop]);
+ }];
+
+ SetDefaultsValueInSeparateProcess();
+ ASSERT_FALSE([watcher isStagingKeySet]);
+ while (!observerCalled && [runloop runMode:NSDefaultRunLoopMode
+ beforeDate:[NSDate distantFuture]]) {
+ /* run! */
+ }
+
+ EXPECT_TRUE([watcher isStagingKeySet]);
+}
+
+TEST_P(StagingKeyWatcherTest, CallbackOnKeyUnset) {
+ NSString* appPath = [base::mac::OuterBundle() bundlePath];
+ SetDefaultsValue(@{appPath : appPath});
+
+ base::scoped_nsobject<CrStagingKeyWatcher> watcher = CreateKeyWatcher();
+ NSRunLoop* runloop = [NSRunLoop currentRunLoop];
+
+ __block bool observerCalled = false;
+ [watcher setStagingKeyChangedObserver:^(BOOL stagingKeySet) {
+ observerCalled = true;
+ CFRunLoopStop([runloop getCFRunLoop]);
+ }];
+
+ ClearDefaultsValueInSeparateProcess();
+ ASSERT_TRUE([watcher isStagingKeySet]);
+ while (!observerCalled && [runloop runMode:NSDefaultRunLoopMode
+ beforeDate:[NSDate distantFuture]]) {
+ /* run! */
+ }
+
+ EXPECT_FALSE([watcher isStagingKeySet]);
+}
diff --git a/chromium/chrome/common/media/OWNERS b/chromium/chrome/common/media/OWNERS
new file mode 100644
index 00000000000..64f68d00825
--- /dev/null
+++ b/chromium/chrome/common/media/OWNERS
@@ -0,0 +1,9 @@
+file://media/OWNERS
+
+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
+
+# COMPONENT: Internals>Media>Encrypted
diff --git a/chromium/chrome/common/media/cdm_host_file_path.cc b/chromium/chrome/common/media/cdm_host_file_path.cc
new file mode 100644
index 00000000000..b62e7834f09
--- /dev/null
+++ b/chromium/chrome/common/media/cdm_host_file_path.cc
@@ -0,0 +1,123 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media/cdm_host_file_path.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "build/branding_buildflags.h"
+#include "build/build_config.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_version.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/bundle_locations.h"
+#endif
+
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+
+namespace {
+
+// TODO(xhwang): Move this to a common place if needed.
+const base::FilePath::CharType kSignatureFileExtension[] =
+ FILE_PATH_LITERAL(".sig");
+
+// Returns the signature file path given the |file_path|. This function should
+// only be used when the signature file and the file are located in the same
+// directory.
+base::FilePath GetSigFilePath(const base::FilePath& file_path) {
+ return file_path.AddExtension(kSignatureFileExtension);
+}
+
+} // namespace
+
+void AddCdmHostFilePaths(
+ std::vector<media::CdmHostFilePath>* cdm_host_file_paths) {
+ DVLOG(1) << __func__;
+ DCHECK(cdm_host_file_paths);
+ DCHECK(cdm_host_file_paths->empty());
+
+#if defined(OS_WIN)
+
+ static const base::FilePath::CharType* const kUnversionedFiles[] = {
+ chrome::kBrowserProcessExecutableName};
+
+ static const base::FilePath::CharType* const kVersionedFiles[] = {
+#if defined(CHROME_MULTIPLE_DLL)
+ chrome::kBrowserResourcesDll,
+ chrome::kChildDll
+#else
+ chrome::kBrowserResourcesDll
+#endif // defined(CHROME_MULTIPLE_DLL)
+ };
+
+ // Find where chrome.exe is installed.
+ base::FilePath chrome_exe_dir;
+ if (!base::PathService::Get(base::DIR_EXE, &chrome_exe_dir))
+ NOTREACHED();
+ base::FilePath version_dir(chrome_exe_dir.AppendASCII(CHROME_VERSION_STRING));
+
+ cdm_host_file_paths->reserve(base::size(kUnversionedFiles) +
+ base::size(kVersionedFiles));
+
+ // Signature files are always in the version directory.
+ for (size_t i = 0; i < base::size(kUnversionedFiles); ++i) {
+ base::FilePath file_path = chrome_exe_dir.Append(kUnversionedFiles[i]);
+ base::FilePath sig_path =
+ GetSigFilePath(version_dir.Append(kUnversionedFiles[i]));
+ DVLOG(2) << __func__ << ": unversioned file " << i << " at "
+ << file_path.value() << ", signature file " << sig_path.value();
+ cdm_host_file_paths->emplace_back(file_path, sig_path);
+ }
+
+ for (size_t i = 0; i < base::size(kVersionedFiles); ++i) {
+ base::FilePath file_path = version_dir.Append(kVersionedFiles[i]);
+ DVLOG(2) << __func__ << ": versioned file " << i << " at "
+ << file_path.value();
+ cdm_host_file_paths->emplace_back(file_path, GetSigFilePath(file_path));
+ }
+
+#elif defined(OS_MACOSX)
+
+ base::FilePath framework_dir = base::mac::FrameworkBundlePath();
+ base::FilePath chrome_framework_path =
+ framework_dir.Append(chrome::kFrameworkExecutableName);
+ // The signature file lives inside
+ // Google Chrome Framework.framework/Versions/X/Resources/.
+ base::FilePath widevine_signature_path = framework_dir.Append("Resources");
+ base::FilePath chrome_framework_sig_path = GetSigFilePath(
+ widevine_signature_path.Append(chrome::kFrameworkExecutableName));
+
+ DVLOG(2) << __func__
+ << ": chrome_framework_path=" << chrome_framework_path.value()
+ << ", signature_path=" << chrome_framework_sig_path.value();
+ cdm_host_file_paths->emplace_back(chrome_framework_path,
+ chrome_framework_sig_path);
+
+#elif defined(OS_LINUX)
+
+ base::FilePath chrome_exe_dir;
+ if (!base::PathService::Get(base::DIR_EXE, &chrome_exe_dir))
+ NOTREACHED();
+
+ base::FilePath chrome_path =
+ chrome_exe_dir.Append(FILE_PATH_LITERAL("chrome"));
+ DVLOG(2) << __func__ << ": chrome_path=" << chrome_path.value();
+ cdm_host_file_paths->emplace_back(chrome_path, GetSigFilePath(chrome_path));
+
+#endif // defined(OS_WIN)
+}
+
+#else // BUILDFLAG(GOOGLE_CHROME_BRANDING)
+
+void AddCdmHostFilePaths(
+ std::vector<media::CdmHostFilePath>* cdm_host_file_paths) {
+ NOTIMPLEMENTED() << "CDM host file paths need to be provided for the CDM to "
+ "verify the host.";
+}
+
+#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
diff --git a/chromium/chrome/common/media/cdm_host_file_path.h b/chromium/chrome/common/media/cdm_host_file_path.h
new file mode 100644
index 00000000000..4548f39dd36
--- /dev/null
+++ b/chromium/chrome/common/media/cdm_host_file_path.h
@@ -0,0 +1,16 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_CDM_HOST_FILE_PATH_H_
+#define CHROME_COMMON_MEDIA_CDM_HOST_FILE_PATH_H_
+
+#include <vector>
+
+#include "media/cdm/cdm_host_file.h"
+
+// Gets a list of CDM host file paths and put them in |cdm_host_file_paths|.
+void AddCdmHostFilePaths(
+ std::vector<media::CdmHostFilePath>* cdm_host_file_paths);
+
+#endif // CHROME_COMMON_MEDIA_CDM_HOST_FILE_PATH_H_
diff --git a/chromium/chrome/common/media/cdm_manifest.cc b/chromium/chrome/common/media/cdm_manifest.cc
new file mode 100644
index 00000000000..e7147156dec
--- /dev/null
+++ b/chromium/chrome/common/media/cdm_manifest.cc
@@ -0,0 +1,372 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media/cdm_manifest.h"
+
+#include <stddef.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/containers/flat_set.h"
+#include "base/containers/span.h"
+#include "base/files/file_path.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "content/public/common/cdm_info.h"
+#include "extensions/common/manifest_constants.h"
+#include "media/base/content_decryption_module.h"
+#include "media/base/decrypt_config.h"
+#include "media/base/video_codecs.h"
+#include "media/cdm/cdm_proxy.h"
+#include "media/cdm/supported_cdm_versions.h"
+#include "media/media_buildflags.h"
+
+#if !BUILDFLAG(ENABLE_LIBRARY_CDMS)
+#error This file should only be compiled when library CDMs are enabled
+#endif
+
+namespace {
+
+// The CDM manifest includes several custom values, all beginning with "x-cdm-".
+// They are:
+// x-cdm-module-versions
+// x-cdm-interface-versions
+// x-cdm-host-versions
+// x-cdm-codecs
+// x-cdm-persistent-license-support
+// x-cdm-supported-encryption-schemes
+// x-cdm-supported-cdm-proxy-protocols
+// What they represent is listed below. They should never have non-backwards
+// compatible changes. All values are strings. All values that are lists are
+// delimited by commas. No trailing commas. For example, "1,2,4".
+const char kCdmValueDelimiter[] = ",";
+
+// The following entries are required.
+// Interface versions are lists of integers (e.g. "1" or "1,2,4").
+// All match the interface versions from content_decryption_module.h that the
+// CDM supports.
+// Matches CDM_MODULE_VERSION.
+const char kCdmModuleVersionsName[] = "x-cdm-module-versions";
+// Matches supported ContentDecryptionModule_* version(s).
+const char kCdmInterfaceVersionsName[] = "x-cdm-interface-versions";
+// Matches supported Host_* version(s).
+const char kCdmHostVersionsName[] = "x-cdm-host-versions";
+// The codecs list is a list of simple codec names (e.g. "vp8,vorbis").
+const char kCdmCodecsListName[] = "x-cdm-codecs";
+// Whether persistent license is supported by the CDM: "true" or "false".
+const char kCdmPersistentLicenseSupportName[] =
+ "x-cdm-persistent-license-support";
+// The list of supported encryption schemes (e.g. ["cenc","cbcs"]).
+const char kCdmSupportedEncryptionSchemesName[] =
+ "x-cdm-supported-encryption-schemes";
+// The list of supported proxy protocols (e.g. ["intel"]).
+const char kCdmSupportedCdmProxyProtocolsName[] =
+ "x-cdm-supported-cdm-proxy-protocols";
+
+// The following strings are used to specify supported codecs in the
+// parameter |kCdmCodecsListName|.
+const char kCdmSupportedCodecVp8[] = "vp8";
+// Legacy VP9, which is equivalent to VP9 profile 0.
+// TODO(xhwang): Newer CDMs should support "vp09" below. Remove this after older
+// CDMs are obsolete.
+const char kCdmSupportedCodecLegacyVp9[] = "vp9.0";
+// Supports at least VP9 profile 0 and profile 2.
+const char kCdmSupportedCodecVp9[] = "vp09";
+const char kCdmSupportedCodecAv1[] = "av01";
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+const char kCdmSupportedCodecAvc1[] = "avc1";
+#endif
+
+// The following strings are used to specify supported encryption schemes in
+// the parameter |kCdmSupportedEncryptionSchemesName|.
+const char kCdmSupportedEncryptionSchemeCenc[] = "cenc";
+const char kCdmSupportedEncryptionSchemeCbcs[] = "cbcs";
+
+// The following string(s) are used to specify supported CdmProxy protocols in
+// the parameter |kCdmSupportedCdmProxyProtocolsName|.
+const char kCdmSupportedCdmProxyProtocolIntel[] = "intel";
+
+typedef bool (*VersionCheckFunc)(int version);
+
+// Returns whether the CDM's API version, as specified in the manifest by
+// |version_name|, is supported in this Chrome binary and not disabled at run
+// time by calling |version_check_func|. If the manifest entry contains multiple
+// values, each one is checked sequentially, and if any one is supported, this
+// function returns true. If all values in the manifest entry are not supported,
+// then return false.
+bool CheckForCompatibleVersion(const base::Value& manifest,
+ const std::string version_name,
+ VersionCheckFunc version_check_func) {
+ DCHECK(manifest.is_dict());
+
+ auto* version_string = manifest.FindStringKey(version_name);
+ if (!version_string) {
+ DVLOG(1) << "CDM manifest missing " << version_name;
+ return false;
+ }
+
+ DVLOG_IF(1, version_string->empty())
+ << "CDM manifest has empty " << version_name;
+
+ for (const base::StringPiece& ver_str :
+ base::SplitStringPiece(*version_string, kCdmValueDelimiter,
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+ int version = 0;
+ if (base::StringToInt(ver_str, &version) && version_check_func(version))
+ return true;
+ }
+
+ DVLOG(1) << "CDM manifest has no supported " << version_name << " in '"
+ << *version_string << "'";
+ return false;
+}
+
+// Returns true and updates |video_codecs| if the appropriate manifest entry is
+// valid. When VP9 is supported, sets |supports_vp9_profile2| if profile 2 is
+// supported. Older CDMs may only support profile 0. Returns false and does not
+// modify |video_codecs| if the manifest entry is incorrectly formatted.
+bool GetCodecs(const base::Value& manifest,
+ std::vector<media::VideoCodec>* video_codecs,
+ bool* supports_vp9_profile2) {
+ DCHECK(manifest.is_dict());
+ DCHECK(video_codecs);
+
+ const base::Value* value = manifest.FindKey(kCdmCodecsListName);
+ if (!value) {
+ DLOG(WARNING) << "CDM manifest is missing codecs.";
+ return true;
+ }
+
+ if (!value->is_string()) {
+ DLOG(ERROR) << "CDM manifest entry " << kCdmCodecsListName
+ << " is not a string.";
+ return false;
+ }
+
+ const std::string& codecs = value->GetString();
+ if (codecs.empty()) {
+ DLOG(WARNING) << "CDM manifest has empty codecs list.";
+ return true;
+ }
+
+ std::vector<media::VideoCodec> result;
+ const std::vector<base::StringPiece> supported_codecs =
+ base::SplitStringPiece(codecs, kCdmValueDelimiter, base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+
+ // Assuming VP9 profile 2 is not supported by default. Will only be set when
+ // kCdmSupportedCodecVp9 is available below.
+ *supports_vp9_profile2 = false;
+
+ for (const auto& codec : supported_codecs) {
+ if (codec == kCdmSupportedCodecVp8) {
+ result.push_back(media::VideoCodec::kCodecVP8);
+ } else if (codec == kCdmSupportedCodecLegacyVp9) {
+ result.push_back(media::VideoCodec::kCodecVP9);
+ } else if (codec == kCdmSupportedCodecVp9) {
+ result.push_back(media::VideoCodec::kCodecVP9);
+ *supports_vp9_profile2 = true;
+ } else if (codec == kCdmSupportedCodecAv1) {
+ result.push_back(media::VideoCodec::kCodecAV1);
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+ } else if (codec == kCdmSupportedCodecAvc1) {
+ result.push_back(media::VideoCodec::kCodecH264);
+#endif
+ }
+ }
+
+ video_codecs->swap(result);
+ return true;
+}
+
+// Returns true and updates |session_types| if the appropriate manifest entry is
+// valid. Returns false if the manifest entry is incorrectly formatted.
+bool GetSessionTypes(const base::Value& manifest,
+ base::flat_set<media::CdmSessionType>* session_types) {
+ DCHECK(manifest.is_dict());
+ DCHECK(session_types);
+
+ bool is_persistent_license_supported = false;
+ const base::Value* value = manifest.FindKey(kCdmPersistentLicenseSupportName);
+ if (value) {
+ if (!value->is_bool())
+ return false;
+ is_persistent_license_supported = value->GetBool();
+ }
+
+ // Temporary session is always supported.
+ session_types->insert(media::CdmSessionType::kTemporary);
+
+ if (is_persistent_license_supported)
+ session_types->insert(media::CdmSessionType::kPersistentLicense);
+
+ return true;
+}
+
+// Returns true and updates |encryption_schemes| if the appropriate manifest
+// entry is valid. Returns false and does not modify |encryption_schemes| if the
+// manifest entry is incorrectly formatted. It is assumed that all CDMs support
+// 'cenc', so if the manifest entry is missing, the result will indicate support
+// for 'cenc' only. Incorrect types in the manifest entry will log the error and
+// fail. Unrecognized values will be reported but otherwise ignored.
+bool GetEncryptionSchemes(
+ const base::Value& manifest,
+ base::flat_set<media::EncryptionMode>* encryption_schemes) {
+ DCHECK(manifest.is_dict());
+ DCHECK(encryption_schemes);
+
+ const base::Value* value =
+ manifest.FindKey(kCdmSupportedEncryptionSchemesName);
+ if (!value) {
+ // No manifest entry found, so assume only 'cenc' supported for backwards
+ // compatibility.
+ encryption_schemes->insert(media::EncryptionMode::kCenc);
+ return true;
+ }
+
+ if (!value->is_list()) {
+ DLOG(ERROR) << "CDM manifest entry " << kCdmSupportedEncryptionSchemesName
+ << " is not a list.";
+ return false;
+ }
+
+ base::span<const base::Value> list = value->GetList();
+ base::flat_set<media::EncryptionMode> result;
+ for (const auto& item : list) {
+ if (!item.is_string()) {
+ DLOG(ERROR) << "Unrecognized item type in CDM manifest entry "
+ << kCdmSupportedEncryptionSchemesName;
+ return false;
+ }
+
+ const std::string& scheme = item.GetString();
+ if (scheme == kCdmSupportedEncryptionSchemeCenc) {
+ result.insert(media::EncryptionMode::kCenc);
+ } else if (scheme == kCdmSupportedEncryptionSchemeCbcs) {
+ result.insert(media::EncryptionMode::kCbcs);
+ } else {
+ DLOG(WARNING) << "Unrecognized encryption scheme '" << scheme
+ << "' in CDM manifest entry "
+ << kCdmSupportedEncryptionSchemesName;
+ }
+ }
+
+ // As the manifest entry exists, it must specify at least one valid value.
+ if (result.empty())
+ return false;
+
+ encryption_schemes->swap(result);
+ return true;
+}
+
+// Returns true and updates |cdm_proxy_protocols| if the appropriate manifest
+// entry is valid. Returns false and does not modify |cdm_proxy_protocols| if
+// the manifest entry is incorrectly formatted. Incorrect types in the manifest
+// entry will log the error and fail. Unrecognized values will be reported but
+// otherwise ignored.
+bool GetCdmProxyProtocols(
+ const base::Value& manifest,
+ base::flat_set<media::CdmProxy::Protocol>* cdm_proxy_protocols) {
+ DCHECK(manifest.is_dict());
+ const auto* value = manifest.FindKey(kCdmSupportedCdmProxyProtocolsName);
+ if (!value)
+ return true;
+
+ if (!value->is_list()) {
+ DLOG(ERROR) << "CDM manifest entry " << kCdmSupportedCdmProxyProtocolsName
+ << " is not a list.";
+ return false;
+ }
+
+ base::span<const base::Value> list = value->GetList();
+ base::flat_set<media::CdmProxy::Protocol> result;
+ for (const auto& item : list) {
+ if (!item.is_string()) {
+ DLOG(ERROR) << "Unrecognized item type in CDM manifest entry "
+ << kCdmSupportedCdmProxyProtocolsName;
+ return false;
+ }
+
+ const std::string& protocol = item.GetString();
+ if (protocol == kCdmSupportedCdmProxyProtocolIntel) {
+ result.insert(media::CdmProxy::Protocol::kIntel);
+ } else {
+ DLOG(WARNING) << "Unrecognized CdmProxy protocol '" << protocol
+ << "' in CDM manifest entry "
+ << kCdmSupportedCdmProxyProtocolsName;
+ }
+ }
+
+ cdm_proxy_protocols->swap(result);
+ return true;
+}
+
+bool GetVersion(const base::Value& manifest, base::Version* version) {
+ DCHECK(manifest.is_dict());
+ auto* version_string =
+ manifest.FindStringKey(extensions::manifest_keys::kVersion);
+ if (!version_string) {
+ DLOG(ERROR) << "CDM manifest missing "
+ << extensions::manifest_keys::kVersion;
+ return false;
+ }
+
+ *version = base::Version(*version_string);
+ if (!version->IsValid()) {
+ DLOG(ERROR) << "CDM manifest version " << version_string << " is invalid.";
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+bool IsCdmManifestCompatibleWithChrome(const base::Value& manifest) {
+ DCHECK(manifest.is_dict());
+
+ return CheckForCompatibleVersion(manifest, kCdmModuleVersionsName,
+ media::IsSupportedCdmModuleVersion) &&
+ CheckForCompatibleVersion(
+ manifest, kCdmInterfaceVersionsName,
+ media::IsSupportedAndEnabledCdmInterfaceVersion) &&
+ CheckForCompatibleVersion(manifest, kCdmHostVersionsName,
+ media::IsSupportedCdmHostVersion);
+}
+
+bool ParseCdmManifest(const base::Value& manifest,
+ content::CdmCapability* capability) {
+ DCHECK(manifest.is_dict());
+
+ return GetCodecs(manifest, &capability->video_codecs,
+ &capability->supports_vp9_profile2) &&
+ GetEncryptionSchemes(manifest, &capability->encryption_schemes) &&
+ GetSessionTypes(manifest, &capability->session_types) &&
+ GetCdmProxyProtocols(manifest, &capability->cdm_proxy_protocols);
+}
+
+bool ParseCdmManifestFromPath(const base::FilePath& manifest_path,
+ base::Version* version,
+ content::CdmCapability* capability) {
+ JSONFileValueDeserializer deserializer(manifest_path);
+ int error_code;
+ std::string error_message;
+ std::unique_ptr<base::Value> manifest =
+ deserializer.Deserialize(&error_code, &error_message);
+ if (!manifest || !manifest->is_dict()) {
+ DLOG(ERROR) << "Could not deserialize CDM manifest from " << manifest_path
+ << ". Error: " << error_code << " / " << error_message;
+ return false;
+ }
+
+ return IsCdmManifestCompatibleWithChrome(*manifest) &&
+ GetVersion(*manifest, version) &&
+ ParseCdmManifest(*manifest, capability);
+}
diff --git a/chromium/chrome/common/media/cdm_manifest.h b/chromium/chrome/common/media/cdm_manifest.h
new file mode 100644
index 00000000000..6ed4b5a307c
--- /dev/null
+++ b/chromium/chrome/common/media/cdm_manifest.h
@@ -0,0 +1,42 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_CDM_MANIFEST_H_
+#define CHROME_COMMON_MEDIA_CDM_MANIFEST_H_
+
+namespace base {
+class FilePath;
+class Value;
+class Version;
+}
+
+namespace content {
+struct CdmCapability;
+}
+
+// Returns whether the CDM's API versions, as specified in the manifest, are
+// supported in this Chrome binary and not disabled at run time.
+// Checks the module API, CDM interface API, and Host API.
+// This should never fail except in rare cases where the component has not been
+// updated recently or the user downgrades Chrome.
+bool IsCdmManifestCompatibleWithChrome(const base::Value& manifest);
+
+// Extracts the necessary information from |manifest| and updates |capability|.
+// Returns true on success, false if there are errors in the manifest.
+// If this method returns false, |capability| may or may not be updated.
+bool ParseCdmManifest(const base::Value& manifest,
+ content::CdmCapability* capability);
+
+// Reads the file |manifest_path| which is assumed to be a CDM manifest and
+// extracts the necessary information from it to update |version| and
+// |capability|. This also verifies that the read CDM manifest is compatible
+// with Chrome (by calling IsCdmManifestCompatibleWithChrome()). Returns true on
+// success, false if there are errors in the file or the manifest is not
+// compatible with this version of Chrome. If this method returns false,
+// |version| and |capability| may or may not be updated.
+bool ParseCdmManifestFromPath(const base::FilePath& manifest_path,
+ base::Version* version,
+ content::CdmCapability* capability);
+
+#endif // CHROME_COMMON_MEDIA_CDM_MANIFEST_H_
diff --git a/chromium/chrome/common/media/cdm_manifest_unittest.cc b/chromium/chrome/common/media/cdm_manifest_unittest.cc
new file mode 100644
index 00000000000..b12ee879fd8
--- /dev/null
+++ b/chromium/chrome/common/media/cdm_manifest_unittest.cc
@@ -0,0 +1,542 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media/cdm_manifest.h"
+
+#include <stdint.h>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "content/public/common/cdm_info.h"
+#include "extensions/common/manifest_constants.h"
+#include "media/cdm/api/content_decryption_module.h"
+#include "media/cdm/supported_cdm_versions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::CdmCapability;
+
+namespace {
+
+// These names must match what is used in cdm_manifest.cc.
+const char kCdmModuleVersionsName[] = "x-cdm-module-versions";
+const char kCdmInterfaceVersionsName[] = "x-cdm-interface-versions";
+const char kCdmHostVersionsName[] = "x-cdm-host-versions";
+const char kCdmCodecsListName[] = "x-cdm-codecs";
+const char kCdmPersistentLicenseSupportName[] =
+ "x-cdm-persistent-license-support";
+const char kCdmSupportedEncryptionSchemesName[] =
+ "x-cdm-supported-encryption-schemes";
+const char kCdmSupportedCdmProxyProtocolsName[] =
+ "x-cdm-supported-cdm-proxy-protocols";
+
+// Version checking does change over time. Deriving these values from constants
+// in the code to ensure they change when the CDM interface changes.
+// |kSupportedCdmInterfaceVersion| and |kSupportedCdmHostVersion| are the
+// minimum versions supported. There may be versions after them that are also
+// supported.
+constexpr int kSupportedCdmModuleVersion = CDM_MODULE_VERSION;
+constexpr int kSupportedCdmInterfaceVersion =
+ media::kSupportedCdmInterfaceVersions[0].version;
+static_assert(media::kSupportedCdmInterfaceVersions[0].enabled,
+ "kSupportedCdmInterfaceVersion is not enabled by default.");
+constexpr int kSupportedCdmHostVersion = media::kMinSupportedCdmHostVersion;
+
+// Make a string of the values from 0 up to and including |item|.
+std::string MakeStringList(int item) {
+ DCHECK_GT(item, 0);
+ std::vector<std::string> parts;
+ for (int i = 0; i <= item; ++i) {
+ parts.push_back(base::NumberToString(i));
+ }
+ return base::JoinString(parts, ",");
+}
+
+base::Value MakeListValue(const std::string& item) {
+ base::Value list(base::Value::Type::LIST);
+ list.GetList().push_back(base::Value(item));
+ return list;
+}
+
+base::Value MakeListValue(const std::string& item1, const std::string& item2) {
+ base::Value list(base::Value::Type::LIST);
+ list.GetList().push_back(base::Value(item1));
+ list.GetList().push_back(base::Value(item2));
+ return list;
+}
+
+// Create a default manifest with valid values for all entries.
+base::Value DefaultManifest() {
+ base::Value dict(base::Value::Type::DICTIONARY);
+ dict.SetStringKey(kCdmCodecsListName, "vp8,vp9.0,av01");
+ dict.SetBoolKey(kCdmPersistentLicenseSupportName, true);
+ dict.SetKey(kCdmSupportedEncryptionSchemesName,
+ MakeListValue("cenc", "cbcs"));
+ dict.SetKey(kCdmSupportedCdmProxyProtocolsName, MakeListValue("intel"));
+
+ // The following are dependent on what the current code supports.
+ EXPECT_TRUE(media::IsSupportedCdmModuleVersion(kSupportedCdmModuleVersion));
+ EXPECT_TRUE(media::IsSupportedAndEnabledCdmInterfaceVersion(
+ kSupportedCdmInterfaceVersion));
+ EXPECT_TRUE(media::IsSupportedCdmHostVersion(kSupportedCdmHostVersion));
+ dict.SetStringKey(kCdmModuleVersionsName,
+ base::NumberToString(kSupportedCdmModuleVersion));
+ dict.SetStringKey(kCdmInterfaceVersionsName,
+ base::NumberToString(kSupportedCdmInterfaceVersion));
+ dict.SetStringKey(kCdmHostVersionsName,
+ base::NumberToString(kSupportedCdmHostVersion));
+ return dict;
+}
+
+void CheckCodecs(const std::vector<media::VideoCodec>& actual,
+ const std::vector<media::VideoCodec>& expected) {
+ EXPECT_EQ(expected.size(), actual.size());
+ for (const auto& codec : expected) {
+ EXPECT_TRUE(base::Contains(actual, codec));
+ }
+}
+
+void CheckEncryptionSchemes(
+ const base::flat_set<media::EncryptionMode>& actual,
+ const std::vector<media::EncryptionMode>& expected) {
+ EXPECT_EQ(expected.size(), actual.size());
+ for (const auto& encryption_scheme : expected) {
+ EXPECT_TRUE(base::Contains(actual, encryption_scheme));
+ }
+}
+
+void CheckSessionTypes(const base::flat_set<media::CdmSessionType>& actual,
+ const std::vector<media::CdmSessionType>& expected) {
+ EXPECT_EQ(expected.size(), actual.size());
+ for (const auto& session_type : expected) {
+ EXPECT_TRUE(base::Contains(actual, session_type));
+ }
+}
+
+void CheckProxyProtocols(
+ const base::flat_set<media::CdmProxy::Protocol>& actual,
+ const std::vector<media::CdmProxy::Protocol>& expected) {
+ EXPECT_EQ(expected.size(), actual.size());
+ for (const auto& proxy_protocol : expected) {
+ EXPECT_TRUE(base::Contains(actual, proxy_protocol));
+ }
+}
+
+void WriteManifestToFile(const base::Value& manifest,
+ const base::FilePath& file_path) {
+ EXPECT_FALSE(base::PathExists(file_path));
+ JSONFileValueSerializer serializer(file_path);
+ EXPECT_TRUE(serializer.Serialize(manifest));
+ EXPECT_TRUE(base::PathExists(file_path));
+}
+
+} // namespace
+
+TEST(CdmManifestTest, IsCompatibleWithChrome) {
+ base::Value manifest(DefaultManifest());
+ EXPECT_TRUE(IsCdmManifestCompatibleWithChrome(manifest));
+}
+
+TEST(CdmManifestTest, InCompatibleModuleVersion) {
+ const int kUnsupportedModuleVersion = 0;
+ EXPECT_FALSE(media::IsSupportedCdmModuleVersion(kUnsupportedModuleVersion));
+
+ auto manifest = DefaultManifest();
+ manifest.SetStringKey(kCdmModuleVersionsName,
+ base::NumberToString(kUnsupportedModuleVersion));
+ EXPECT_FALSE(IsCdmManifestCompatibleWithChrome(std::move(manifest)));
+}
+
+TEST(CdmManifestTest, InCompatibleInterfaceVersion) {
+ const int kUnsupportedInterfaceVersion = kSupportedCdmInterfaceVersion - 1;
+ EXPECT_FALSE(media::IsSupportedAndEnabledCdmInterfaceVersion(
+ kUnsupportedInterfaceVersion));
+
+ auto manifest = DefaultManifest();
+ manifest.SetStringKey(kCdmInterfaceVersionsName,
+ base::NumberToString(kUnsupportedInterfaceVersion));
+ EXPECT_FALSE(IsCdmManifestCompatibleWithChrome(std::move(manifest)));
+}
+
+TEST(CdmManifestTest, InCompatibleHostVersion) {
+ const int kUnsupportedHostVersion = kSupportedCdmHostVersion - 1;
+ EXPECT_FALSE(media::IsSupportedCdmHostVersion(kUnsupportedHostVersion));
+
+ auto manifest = DefaultManifest();
+ manifest.SetStringKey(kCdmHostVersionsName,
+ base::NumberToString(kUnsupportedHostVersion));
+ EXPECT_FALSE(IsCdmManifestCompatibleWithChrome(std::move(manifest)));
+}
+
+TEST(CdmManifestTest, IsCompatibleWithMultipleValues) {
+ auto manifest = DefaultManifest();
+ manifest.SetStringKey(kCdmModuleVersionsName,
+ MakeStringList(kSupportedCdmModuleVersion));
+ manifest.SetStringKey(kCdmInterfaceVersionsName,
+ MakeStringList(kSupportedCdmInterfaceVersion));
+ manifest.SetStringKey(kCdmHostVersionsName,
+ MakeStringList(kSupportedCdmHostVersion));
+ EXPECT_TRUE(IsCdmManifestCompatibleWithChrome(std::move(manifest)));
+}
+
+TEST(CdmManifestTest, ValidManifest) {
+ auto manifest = DefaultManifest();
+ CdmCapability capability;
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckCodecs(capability.video_codecs,
+ {media::VideoCodec::kCodecVP8, media::VideoCodec::kCodecVP9,
+ media::VideoCodec::kCodecAV1});
+ CheckEncryptionSchemes(
+ capability.encryption_schemes,
+ {media::EncryptionMode::kCenc, media::EncryptionMode::kCbcs});
+ CheckSessionTypes(capability.session_types,
+ {media::CdmSessionType::kTemporary,
+ media::CdmSessionType::kPersistentLicense});
+ CheckProxyProtocols(capability.cdm_proxy_protocols,
+ {media::CdmProxy::Protocol::kIntel});
+}
+
+TEST(CdmManifestTest, EmptyManifest) {
+ base::Value manifest(base::Value::Type::DICTIONARY);
+ CdmCapability capability;
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckCodecs(capability.video_codecs, {});
+ CheckEncryptionSchemes(capability.encryption_schemes,
+ {media::EncryptionMode::kCenc});
+ CheckSessionTypes(capability.session_types,
+ {media::CdmSessionType::kTemporary});
+ CheckProxyProtocols(capability.cdm_proxy_protocols, {});
+}
+
+TEST(CdmManifestTest, ManifestCodecs) {
+ auto manifest = DefaultManifest();
+
+ // Try each valid value individually.
+ {
+ CdmCapability capability;
+ manifest.SetStringKey(kCdmCodecsListName, "vp8");
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckCodecs(capability.video_codecs, {media::VideoCodec::kCodecVP8});
+ }
+ {
+ CdmCapability capability;
+ manifest.SetStringKey(kCdmCodecsListName, "vp9.0");
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckCodecs(capability.video_codecs, {media::VideoCodec::kCodecVP9});
+ EXPECT_FALSE(capability.supports_vp9_profile2);
+ }
+ {
+ CdmCapability capability;
+ manifest.SetStringKey(kCdmCodecsListName, "vp09");
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckCodecs(capability.video_codecs, {media::VideoCodec::kCodecVP9});
+ EXPECT_TRUE(capability.supports_vp9_profile2);
+ }
+ {
+ CdmCapability capability;
+ manifest.SetStringKey(kCdmCodecsListName, "av01");
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckCodecs(capability.video_codecs, {media::VideoCodec::kCodecAV1});
+ }
+#if BUILDFLAG(USE_PROPRIETARY_CODECS)
+ {
+ CdmCapability capability;
+ manifest.SetStringKey(kCdmCodecsListName, "avc1");
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckCodecs(capability.video_codecs, {media::VideoCodec::kCodecH264});
+ }
+#endif
+ {
+ // Try list of everything (except proprietary codecs).
+ CdmCapability capability;
+ manifest.SetStringKey(kCdmCodecsListName, "vp8,vp9.0,vp09,av01");
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ // Note that kCodecVP9 is returned twice in the list.
+ CheckCodecs(capability.video_codecs,
+ {media::VideoCodec::kCodecVP8, media::VideoCodec::kCodecVP9,
+ media::VideoCodec::kCodecVP9, media::VideoCodec::kCodecAV1});
+ EXPECT_TRUE(capability.supports_vp9_profile2);
+ }
+ {
+ // Note that invalid codec values are simply skipped.
+ CdmCapability capability;
+ manifest.SetStringKey(kCdmCodecsListName, "invalid,av01");
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckCodecs(capability.video_codecs, {media::VideoCodec::kCodecAV1});
+ }
+ {
+ // Wrong types are an error.
+ CdmCapability capability;
+ manifest.SetBoolKey(kCdmCodecsListName, true);
+ EXPECT_FALSE(ParseCdmManifest(manifest, &capability));
+ }
+ {
+ // Missing entry is OK, but list is empty.
+ CdmCapability capability;
+ EXPECT_TRUE(manifest.RemoveKey(kCdmCodecsListName));
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckCodecs(capability.video_codecs, {});
+ }
+}
+
+TEST(CdmManifestTest, ManifestEncryptionSchemes) {
+ auto manifest = DefaultManifest();
+
+ // Try each valid value individually.
+ {
+ CdmCapability capability;
+ manifest.SetKey(kCdmSupportedEncryptionSchemesName, MakeListValue("cenc"));
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckEncryptionSchemes(capability.encryption_schemes,
+ {media::EncryptionMode::kCenc});
+ }
+ {
+ CdmCapability capability;
+ manifest.SetKey(kCdmSupportedEncryptionSchemesName, MakeListValue("cbcs"));
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckEncryptionSchemes(capability.encryption_schemes,
+ {media::EncryptionMode::kCbcs});
+ }
+ {
+ // Try multiple valid entries.
+ CdmCapability capability;
+ manifest.SetKey(kCdmSupportedEncryptionSchemesName,
+ MakeListValue("cenc", "cbcs"));
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckEncryptionSchemes(
+ capability.encryption_schemes,
+ {media::EncryptionMode::kCenc, media::EncryptionMode::kCbcs});
+ }
+ {
+ // Invalid encryption schemes are ignored. However, if value specified then
+ // there must be at least 1 valid value.
+ CdmCapability capability;
+ manifest.SetKey(kCdmSupportedEncryptionSchemesName,
+ MakeListValue("invalid"));
+ EXPECT_FALSE(ParseCdmManifest(manifest, &capability));
+ }
+ {
+ CdmCapability capability;
+ manifest.SetKey(kCdmSupportedEncryptionSchemesName,
+ MakeListValue("invalid", "cenc"));
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckEncryptionSchemes(capability.encryption_schemes,
+ {media::EncryptionMode::kCenc});
+ }
+ {
+ // Wrong types are an error.
+ CdmCapability capability;
+ manifest.SetBoolKey(kCdmSupportedEncryptionSchemesName, true);
+ EXPECT_FALSE(ParseCdmManifest(manifest, &capability));
+ }
+ {
+ // Missing values default to "cenc".
+ CdmCapability capability;
+ EXPECT_TRUE(manifest.RemoveKey(kCdmSupportedEncryptionSchemesName));
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckEncryptionSchemes(capability.encryption_schemes,
+ {media::EncryptionMode::kCenc});
+ }
+}
+
+TEST(CdmManifestTest, ManifestSessionTypes) {
+ auto manifest = DefaultManifest();
+
+ {
+ // Try false (persistent license not supported).
+ CdmCapability capability;
+ manifest.SetBoolKey(kCdmPersistentLicenseSupportName, false);
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckSessionTypes(capability.session_types,
+ {media::CdmSessionType::kTemporary});
+ }
+ {
+ // Try true (persistent license is supported).
+ CdmCapability capability;
+ manifest.SetBoolKey(kCdmPersistentLicenseSupportName, true);
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckSessionTypes(capability.session_types,
+ {media::CdmSessionType::kTemporary,
+ media::CdmSessionType::kPersistentLicense});
+ }
+ {
+ // Wrong types are an error.
+ CdmCapability capability;
+ manifest.SetStringKey(kCdmPersistentLicenseSupportName, "true");
+ EXPECT_FALSE(ParseCdmManifest(manifest, &capability));
+ }
+ {
+ // Missing values default to "temporary".
+ CdmCapability capability;
+ EXPECT_TRUE(manifest.RemoveKey(kCdmPersistentLicenseSupportName));
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckSessionTypes(capability.session_types,
+ {media::CdmSessionType::kTemporary});
+ }
+}
+
+TEST(CdmManifestTest, ManifestProxyProtocols) {
+ auto manifest = DefaultManifest();
+
+ {
+ // Try only supported value.
+ CdmCapability capability;
+ manifest.SetKey(kCdmSupportedCdmProxyProtocolsName, MakeListValue("intel"));
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckProxyProtocols(capability.cdm_proxy_protocols,
+ {media::CdmProxy::Protocol::kIntel});
+ }
+ {
+ // Unrecognized values are ignored.
+ CdmCapability capability;
+ manifest.SetKey(kCdmSupportedCdmProxyProtocolsName,
+ MakeListValue("unknown", "intel"));
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckProxyProtocols(capability.cdm_proxy_protocols,
+ {media::CdmProxy::Protocol::kIntel});
+ }
+ {
+ // Wrong types are an error.
+ CdmCapability capability;
+ manifest.SetStringKey(kCdmSupportedCdmProxyProtocolsName, "intel");
+ EXPECT_FALSE(ParseCdmManifest(manifest, &capability));
+ }
+ {
+ // Missing values are OK.
+ CdmCapability capability;
+ EXPECT_TRUE(manifest.RemoveKey(kCdmSupportedCdmProxyProtocolsName));
+ EXPECT_TRUE(ParseCdmManifest(manifest, &capability));
+ CheckProxyProtocols(capability.cdm_proxy_protocols, {});
+ }
+}
+
+TEST(CdmManifestTest, FileManifest) {
+ const char kVersion[] = "1.2.3.4";
+
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ auto manifest_path = temp_dir.GetPath().AppendASCII("manifest.json");
+
+ // Manifests read from a file also need a version.
+ auto manifest = DefaultManifest();
+ manifest.SetStringKey(extensions::manifest_keys::kVersion, kVersion);
+ WriteManifestToFile(manifest, manifest_path);
+
+ base::Version version;
+ CdmCapability capability;
+ EXPECT_TRUE(ParseCdmManifestFromPath(manifest_path, &version, &capability));
+ EXPECT_TRUE(version.IsValid());
+ EXPECT_EQ(version.GetString(), kVersion);
+ CheckCodecs(capability.video_codecs,
+ {media::VideoCodec::kCodecVP8, media::VideoCodec::kCodecVP9,
+ media::VideoCodec::kCodecAV1});
+ CheckEncryptionSchemes(
+ capability.encryption_schemes,
+ {media::EncryptionMode::kCenc, media::EncryptionMode::kCbcs});
+ CheckSessionTypes(capability.session_types,
+ {media::CdmSessionType::kTemporary,
+ media::CdmSessionType::kPersistentLicense});
+ CheckProxyProtocols(capability.cdm_proxy_protocols,
+ {media::CdmProxy::Protocol::kIntel});
+}
+
+TEST(CdmManifestTest, FileManifestNoVersion) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ auto manifest_path = temp_dir.GetPath().AppendASCII("manifest.json");
+
+ auto manifest = DefaultManifest();
+ WriteManifestToFile(manifest, manifest_path);
+
+ base::Version version;
+ CdmCapability capability;
+ EXPECT_FALSE(ParseCdmManifestFromPath(manifest_path, &version, &capability));
+}
+
+TEST(CdmManifestTest, FileManifestBadVersion) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ auto manifest_path = temp_dir.GetPath().AppendASCII("manifest.json");
+
+ auto manifest = DefaultManifest();
+ manifest.SetStringKey(extensions::manifest_keys::kVersion, "bad version");
+ WriteManifestToFile(manifest, manifest_path);
+
+ base::Version version;
+ CdmCapability capability;
+ EXPECT_FALSE(ParseCdmManifestFromPath(manifest_path, &version, &capability));
+}
+
+TEST(CdmManifestTest, FileManifestDoesNotExist) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ auto manifest_path = temp_dir.GetPath().AppendASCII("manifest.json");
+
+ base::Version version;
+ CdmCapability capability;
+ EXPECT_FALSE(ParseCdmManifestFromPath(manifest_path, &version, &capability));
+}
+
+TEST(CdmManifestTest, FileManifestEmpty) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ auto manifest_path = temp_dir.GetPath().AppendASCII("manifest.json");
+
+ base::Value manifest(base::Value::Type::DICTIONARY);
+ WriteManifestToFile(manifest, manifest_path);
+
+ base::Version version;
+ CdmCapability capability;
+ EXPECT_FALSE(ParseCdmManifestFromPath(manifest_path, &version, &capability));
+}
+
+TEST(CdmManifestTest, FileManifestLite) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ auto manifest_path = temp_dir.GetPath().AppendASCII("manifest.json");
+
+ // Only a version plus fields to satisfy compatibility are required in the
+ // manifest to parse correctly.
+ base::Value manifest(base::Value::Type::DICTIONARY);
+ manifest.SetStringKey(extensions::manifest_keys::kVersion, "1.2.3.4");
+ manifest.SetStringKey(kCdmModuleVersionsName,
+ base::NumberToString(kSupportedCdmModuleVersion));
+ manifest.SetStringKey(kCdmInterfaceVersionsName,
+ base::NumberToString(kSupportedCdmInterfaceVersion));
+ manifest.SetStringKey(kCdmHostVersionsName,
+ base::NumberToString(kSupportedCdmHostVersion));
+ WriteManifestToFile(manifest, manifest_path);
+
+ base::Version version;
+ CdmCapability capability;
+ EXPECT_TRUE(ParseCdmManifestFromPath(manifest_path, &version, &capability));
+ CheckCodecs(capability.video_codecs, {});
+ CheckEncryptionSchemes(capability.encryption_schemes,
+ {media::EncryptionMode::kCenc});
+ CheckSessionTypes(capability.session_types,
+ {media::CdmSessionType::kTemporary});
+ CheckProxyProtocols(capability.cdm_proxy_protocols, {});
+}
+
+TEST(CdmManifestTest, FileManifestNotDictionary) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ auto manifest_path = temp_dir.GetPath().AppendASCII("manifest.json");
+
+ base::Value manifest("not a dictionary");
+ WriteManifestToFile(manifest, manifest_path);
+
+ base::Version version;
+ CdmCapability capability;
+ EXPECT_FALSE(ParseCdmManifestFromPath(manifest_path, &version, &capability));
+}
diff --git a/chromium/chrome/common/media/chrome_media_drm_bridge_client.cc b/chromium/chrome/common/media/chrome_media_drm_bridge_client.cc
new file mode 100644
index 00000000000..54f3b45d350
--- /dev/null
+++ b/chromium/chrome/common/media/chrome_media_drm_bridge_client.cc
@@ -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.
+
+#include "chrome/common/media/chrome_media_drm_bridge_client.h"
+
+ChromeMediaDrmBridgeClient::ChromeMediaDrmBridgeClient() {}
+
+ChromeMediaDrmBridgeClient::~ChromeMediaDrmBridgeClient() {}
+
+media::MediaDrmBridgeDelegate*
+ChromeMediaDrmBridgeClient::GetMediaDrmBridgeDelegate(
+ const std::vector<uint8_t>& scheme_uuid) {
+ if (scheme_uuid == widevine_delegate_.GetUUID())
+ return &widevine_delegate_;
+ return nullptr;
+}
diff --git a/chromium/chrome/common/media/chrome_media_drm_bridge_client.h b/chromium/chrome/common/media/chrome_media_drm_bridge_client.h
new file mode 100644
index 00000000000..e7e49ec5d2b
--- /dev/null
+++ b/chromium/chrome/common/media/chrome_media_drm_bridge_client.h
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_CHROME_MEDIA_DRM_BRIDGE_CLIENT_H_
+#define CHROME_COMMON_MEDIA_CHROME_MEDIA_DRM_BRIDGE_CLIENT_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "components/cdm/common/widevine_drm_delegate_android.h"
+#include "media/base/android/media_drm_bridge_client.h"
+
+class ChromeMediaDrmBridgeClient : public media::MediaDrmBridgeClient {
+ public:
+ ChromeMediaDrmBridgeClient();
+ ~ChromeMediaDrmBridgeClient() override;
+
+ private:
+ // media::MediaDrmBridgeClient implementation:
+ media::MediaDrmBridgeDelegate* GetMediaDrmBridgeDelegate(
+ const std::vector<uint8_t>& scheme_uuid) override;
+
+ cdm::WidevineDrmDelegateAndroid widevine_delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeMediaDrmBridgeClient);
+};
+
+#endif // CHROME_COMMON_MEDIA_CHROME_MEDIA_DRM_BRIDGE_CLIENT_H_
diff --git a/chromium/chrome/common/media/component_widevine_cdm_hint_file_linux.cc b/chromium/chrome/common/media/component_widevine_cdm_hint_file_linux.cc
new file mode 100644
index 00000000000..0fdfc56c725
--- /dev/null
+++ b/chromium/chrome/common/media/component_widevine_cdm_hint_file_linux.cc
@@ -0,0 +1,89 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media/component_widevine_cdm_hint_file_linux.h"
+
+#include <memory>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/important_file_writer.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "chrome/common/chrome_paths.h"
+
+namespace {
+
+// Fields used inside the hint file.
+const char kPath[] = "Path";
+
+base::FilePath GetPath(const base::Value& dict) {
+ DCHECK(dict.is_dict());
+
+ auto* path_str = dict.FindStringKey(kPath);
+ if (!path_str) {
+ DLOG(ERROR) << "CDM hint file missing " << kPath;
+ return base::FilePath();
+ }
+
+ const base::FilePath path(*path_str);
+ DLOG_IF(ERROR, path.empty())
+ << "CDM hint file path " << path_str << " is invalid.";
+ return path;
+}
+
+} // namespace
+
+bool UpdateWidevineCdmHintFile(const base::FilePath& cdm_base_path) {
+ DCHECK(!cdm_base_path.empty());
+
+ base::FilePath hint_file_path;
+ CHECK(base::PathService::Get(chrome::FILE_COMPONENT_WIDEVINE_CDM_HINT,
+ &hint_file_path));
+
+ base::Value dict(base::Value::Type::DICTIONARY);
+ dict.SetStringPath(kPath, cdm_base_path.value());
+
+ std::string json_string;
+ JSONStringValueSerializer serializer(&json_string);
+ if (!serializer.Serialize(dict)) {
+ DLOG(ERROR) << "Could not serialize the CDM hint file.";
+ return false;
+ }
+
+ return base::ImportantFileWriter::WriteFileAtomically(hint_file_path,
+ json_string);
+}
+
+base::FilePath GetLatestComponentUpdatedWidevineCdmDirectory() {
+ base::FilePath hint_file_path;
+ CHECK(base::PathService::Get(chrome::FILE_COMPONENT_WIDEVINE_CDM_HINT,
+ &hint_file_path));
+
+ if (!base::PathExists(hint_file_path)) {
+ DVLOG(2) << "CDM hint file at " << hint_file_path << " does not exist.";
+ return base::FilePath();
+ }
+
+ std::string json_string;
+ if (!base::ReadFileToString(hint_file_path, &json_string)) {
+ DLOG(ERROR) << "Could not read the CDM hint file at " << hint_file_path;
+ return base::FilePath();
+ }
+
+ std::string error_message;
+ JSONStringValueDeserializer deserializer(json_string);
+ std::unique_ptr<base::Value> dict =
+ deserializer.Deserialize(/*error_code=*/nullptr, &error_message);
+
+ if (!dict || !dict->is_dict()) {
+ DLOG(ERROR) << "Could not deserialize the CDM hint file. Error: "
+ << error_message;
+ return base::FilePath();
+ }
+
+ return GetPath(*dict);
+}
diff --git a/chromium/chrome/common/media/component_widevine_cdm_hint_file_linux.h b/chromium/chrome/common/media/component_widevine_cdm_hint_file_linux.h
new file mode 100644
index 00000000000..122ba441144
--- /dev/null
+++ b/chromium/chrome/common/media/component_widevine_cdm_hint_file_linux.h
@@ -0,0 +1,57 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_COMPONENT_WIDEVINE_CDM_HINT_FILE_LINUX_H_
+#define CHROME_COMMON_MEDIA_COMPONENT_WIDEVINE_CDM_HINT_FILE_LINUX_H_
+
+#include "base/compiler_specific.h"
+#include "build/build_config.h"
+#include "third_party/widevine/cdm/buildflags.h"
+
+#if !BUILDFLAG(ENABLE_WIDEVINE)
+#error "This file only applies when Widevine used."
+#endif
+
+#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+#error "This file only applies to desktop Linux."
+#endif
+
+namespace base {
+class FilePath;
+} // namespace base
+
+// The APIs here wrap the component updated Widevine hint file, which lives
+// inside the WidevineCdm folder of the user-data-dir, so that the Linux zygote
+// process can preload the latest version of Widevine.
+//
+// The hint file will be a dictionary with one key:
+// {
+// "Path": $path_to_WidevineCdm_directory
+// }
+//
+// $path_to_WidevineCdm_directory will point to a directory structure
+// containing:
+// LICENSE
+// manifest.json
+// _platform_specific/
+// linux_x64/
+// libwidevinecdm.so
+// The actual executable (and directory containing it) will be platform
+// specific. There may be additional files as well as the ones listed above.
+
+// Records a new Widevine path into the hint file, replacing the current
+// contents if any. |cdm_base_path| is the directory containing the new
+// instance. Returns true if the hint file has been successfully updated,
+// otherwise false.
+bool UpdateWidevineCdmHintFile(const base::FilePath& cdm_base_path)
+ WARN_UNUSED_RESULT;
+
+// Returns the latest component updated Widevine CDM directory. If the hint file
+// exists and is valid, returns the CDM base_path with the value loaded from the
+// file. Otherwise returns empty base::FilePath(). This function does not verify
+// that the path returned exists or not.
+base::FilePath GetLatestComponentUpdatedWidevineCdmDirectory()
+ WARN_UNUSED_RESULT;
+
+#endif // CHROME_COMMON_MEDIA_COMPONENT_WIDEVINE_CDM_HINT_FILE_LINUX_H_
diff --git a/chromium/chrome/common/media/component_widevine_cdm_hint_file_linux_unittest.cc b/chromium/chrome/common/media/component_widevine_cdm_hint_file_linux_unittest.cc
new file mode 100644
index 00000000000..125bf50d21a
--- /dev/null
+++ b/chromium/chrome/common/media/component_widevine_cdm_hint_file_linux_unittest.cc
@@ -0,0 +1,119 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media/component_widevine_cdm_hint_file_linux.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/important_file_writer.h"
+#include "base/path_service.h"
+#include "base/test/scoped_path_override.h"
+#include "chrome/common/chrome_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Name of the widevine directory. Does not have to exist for testing.
+const char kWidevineDirectory[] = "WidevineCdmInstalledHere";
+
+base::FilePath CreateWidevineComponentUpdatedDirectory() {
+ base::FilePath widevine_dir;
+ CHECK(base::PathService::Get(chrome::DIR_COMPONENT_UPDATED_WIDEVINE_CDM,
+ &widevine_dir));
+
+ base::File::Error error;
+ EXPECT_TRUE(base::CreateDirectoryAndGetError(widevine_dir, &error));
+ return widevine_dir;
+}
+
+} // namespace
+
+TEST(ComponentWidevineHintFileTest, RecordUpdate) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+ CreateWidevineComponentUpdatedDirectory();
+ EXPECT_TRUE(UpdateWidevineCdmHintFile(base::FilePath(kWidevineDirectory)));
+}
+
+TEST(ComponentWidevineHintFileTest, RecordUpdateNoDir) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+ EXPECT_FALSE(UpdateWidevineCdmHintFile(base::FilePath(kWidevineDirectory)));
+}
+
+TEST(ComponentWidevineHintFileTest, Read) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+
+ CreateWidevineComponentUpdatedDirectory();
+ EXPECT_TRUE(UpdateWidevineCdmHintFile(base::FilePath(kWidevineDirectory)));
+
+ EXPECT_EQ(GetLatestComponentUpdatedWidevineCdmDirectory().value(),
+ kWidevineDirectory);
+}
+
+TEST(ComponentWidevineHintFileTest, ReadNoDir) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+
+ EXPECT_TRUE(GetLatestComponentUpdatedWidevineCdmDirectory().empty());
+}
+
+TEST(ComponentWidevineHintFileTest, ReadNoFile) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+
+ CreateWidevineComponentUpdatedDirectory();
+ EXPECT_TRUE(GetLatestComponentUpdatedWidevineCdmDirectory().empty());
+}
+
+TEST(ComponentWidevineHintFileTest, ReplaceFile) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+ const char kAltWidevineDirectory[] = "WidevineCdmInstalledOverThere";
+
+ CreateWidevineComponentUpdatedDirectory();
+ EXPECT_TRUE(UpdateWidevineCdmHintFile(base::FilePath(kWidevineDirectory)));
+ EXPECT_EQ(GetLatestComponentUpdatedWidevineCdmDirectory().value(),
+ kWidevineDirectory);
+
+ // Now write the hint file a second time.
+ EXPECT_TRUE(UpdateWidevineCdmHintFile(base::FilePath(kAltWidevineDirectory)));
+ EXPECT_EQ(GetLatestComponentUpdatedWidevineCdmDirectory().value(),
+ kAltWidevineDirectory);
+}
+
+TEST(ComponentWidevineHintFileTest, CorruptHintFile) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+
+ CreateWidevineComponentUpdatedDirectory();
+ base::FilePath hint_file_path;
+ EXPECT_TRUE(base::PathService::Get(chrome::FILE_COMPONENT_WIDEVINE_CDM_HINT,
+ &hint_file_path));
+ EXPECT_TRUE(base::ImportantFileWriter::WriteFileAtomically(
+ hint_file_path, "{not_what_is_expected}"));
+ EXPECT_TRUE(GetLatestComponentUpdatedWidevineCdmDirectory().empty());
+}
+
+TEST(ComponentWidevineHintFileTest, MissingPath) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+
+ CreateWidevineComponentUpdatedDirectory();
+ base::FilePath hint_file_path;
+ EXPECT_TRUE(base::PathService::Get(chrome::FILE_COMPONENT_WIDEVINE_CDM_HINT,
+ &hint_file_path));
+ EXPECT_TRUE(base::ImportantFileWriter::WriteFileAtomically(
+ hint_file_path, "{\"One\": true}"));
+ EXPECT_TRUE(GetLatestComponentUpdatedWidevineCdmDirectory().empty());
+}
+
+TEST(ComponentWidevineHintFileTest, ExtraFields) {
+ const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
+
+ CreateWidevineComponentUpdatedDirectory();
+ base::FilePath hint_file_path;
+ EXPECT_TRUE(base::PathService::Get(chrome::FILE_COMPONENT_WIDEVINE_CDM_HINT,
+ &hint_file_path));
+ EXPECT_TRUE(base::ImportantFileWriter::WriteFileAtomically(
+ hint_file_path,
+ "{\"One\": true, \"Path\": \"WidevineCdmInstalledHere\", \"Two\": {}}"));
+ EXPECT_FALSE(GetLatestComponentUpdatedWidevineCdmDirectory().empty());
+}
diff --git a/chromium/chrome/common/media/media_resource_provider.cc b/chromium/chrome/common/media/media_resource_provider.cc
new file mode 100644
index 00000000000..6bea66ca267
--- /dev/null
+++ b/chromium/chrome/common/media/media_resource_provider.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "chrome/common/media/media_resource_provider.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+int MediaMessageIdToGrdId(media::MessageId message_id) {
+ switch (message_id) {
+ case media::DEFAULT_AUDIO_DEVICE_NAME:
+ return IDS_DEFAULT_AUDIO_DEVICE_NAME;
+#if defined(OS_WIN)
+ case media::COMMUNICATIONS_AUDIO_DEVICE_NAME:
+ return IDS_COMMUNICATIONS_AUDIO_DEVICE_NAME;
+#endif
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+} // namespace
+
+base::string16 ChromeMediaLocalizedStringProvider(media::MessageId message_id) {
+ return l10n_util::GetStringUTF16(MediaMessageIdToGrdId(message_id));
+}
diff --git a/chromium/chrome/common/media/media_resource_provider.h b/chromium/chrome/common/media/media_resource_provider.h
new file mode 100644
index 00000000000..46f5a47da02
--- /dev/null
+++ b/chromium/chrome/common/media/media_resource_provider.h
@@ -0,0 +1,15 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_MEDIA_RESOURCE_PROVIDER_H_
+#define CHROME_COMMON_MEDIA_MEDIA_RESOURCE_PROVIDER_H_
+
+#include "base/strings/string16.h"
+#include "media/base/localized_strings.h"
+
+// This is called indirectly by the media layer to access resources.
+base::string16 ChromeMediaLocalizedStringProvider(
+ media::MessageId media_message_id);
+
+#endif // CHROME_COMMON_MEDIA_MEDIA_RESOURCE_PROVIDER_H_
diff --git a/chromium/chrome/common/media_galleries/OWNERS b/chromium/chrome/common/media_galleries/OWNERS
new file mode 100644
index 00000000000..65216a6bcad
--- /dev/null
+++ b/chromium/chrome/common/media_galleries/OWNERS
@@ -0,0 +1,2 @@
+file://chrome/browser/media_galleries/OWNERS
+# COMPONENT: Platform>Apps>MediaGalleries
diff --git a/chromium/chrome/common/media_galleries/metadata_types.h b/chromium/chrome/common/media_galleries/metadata_types.h
new file mode 100644
index 00000000000..d9aa515b6fa
--- /dev/null
+++ b/chromium/chrome/common/media_galleries/metadata_types.h
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_GALLERIES_METADATA_TYPES_H_
+#define CHROME_COMMON_MEDIA_GALLERIES_METADATA_TYPES_H_
+
+#include <string>
+
+namespace metadata {
+
+struct AttachedImage {
+ std::string type;
+ std::string data;
+};
+
+} // namespace metadata
+
+#endif // CHROME_COMMON_MEDIA_GALLERIES_METADATA_TYPES_H_
diff --git a/chromium/chrome/common/media_router/OWNERS b/chromium/chrome/common/media_router/OWNERS
new file mode 100644
index 00000000000..19600fbc8b8
--- /dev/null
+++ b/chromium/chrome/common/media_router/OWNERS
@@ -0,0 +1,2 @@
+file://chrome/browser/media/router/OWNERS
+# COMPONENT: Internals>Cast
diff --git a/chromium/chrome/common/media_router/discovery/DEPS b/chromium/chrome/common/media_router/discovery/DEPS
new file mode 100644
index 00000000000..f57b34b230c
--- /dev/null
+++ b/chromium/chrome/common/media_router/discovery/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/cast_channel"
+]
diff --git a/chromium/chrome/common/media_router/discovery/media_sink_internal.cc b/chromium/chrome/common/media_router/discovery/media_sink_internal.cc
new file mode 100644
index 00000000000..e39d0ebddbb
--- /dev/null
+++ b/chromium/chrome/common/media_router/discovery/media_sink_internal.cc
@@ -0,0 +1,211 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/discovery/media_sink_internal.h"
+
+#include <new>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace media_router {
+
+MediaSinkInternal::MediaSinkInternal(const MediaSink& sink,
+ const DialSinkExtraData& dial_data)
+ : sink_(sink), sink_type_(SinkType::DIAL), dial_data_(dial_data) {}
+
+MediaSinkInternal::MediaSinkInternal(const MediaSink& sink,
+ const CastSinkExtraData& cast_data)
+ : sink_(sink), sink_type_(SinkType::CAST), cast_data_(cast_data) {}
+
+MediaSinkInternal::MediaSinkInternal() : sink_type_(SinkType::GENERIC) {}
+
+MediaSinkInternal::MediaSinkInternal(const MediaSinkInternal& other) {
+ InternalCopyConstructFrom(other);
+}
+
+MediaSinkInternal::MediaSinkInternal(MediaSinkInternal&& other) noexcept {
+ InternalMoveConstructFrom(std::move(other));
+}
+
+MediaSinkInternal::~MediaSinkInternal() {
+ InternalCleanup();
+}
+
+MediaSinkInternal& MediaSinkInternal::operator=(
+ const MediaSinkInternal& other) {
+ if (this != &other) {
+ InternalCleanup();
+ InternalCopyConstructFrom(other);
+ }
+ return *this;
+}
+
+MediaSinkInternal& MediaSinkInternal::operator=(
+ MediaSinkInternal&& other) noexcept {
+ if (this != &other) {
+ InternalCleanup();
+ InternalMoveConstructFrom(std::move(other));
+ }
+ return *this;
+}
+
+bool MediaSinkInternal::operator==(const MediaSinkInternal& other) const {
+ if (sink_type_ != other.sink_type_)
+ return false;
+
+ if (sink_ != other.sink_)
+ return false;
+
+ switch (sink_type_) {
+ case SinkType::DIAL:
+ return dial_data_ == other.dial_data_;
+ case SinkType::CAST:
+ return cast_data_ == other.cast_data_;
+ case SinkType::GENERIC:
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool MediaSinkInternal::operator!=(const MediaSinkInternal& other) const {
+ return !operator==(other);
+}
+
+bool MediaSinkInternal::operator<(const MediaSinkInternal& other) const {
+ return sink_.id() < other.sink().id();
+}
+
+void MediaSinkInternal::set_sink(const MediaSink& sink) {
+ sink_ = sink;
+}
+
+void MediaSinkInternal::set_dial_data(const DialSinkExtraData& dial_data) {
+ DCHECK(sink_type_ != SinkType::CAST);
+ InternalCleanup();
+
+ sink_type_ = SinkType::DIAL;
+ new (&dial_data_) DialSinkExtraData(dial_data);
+}
+
+const DialSinkExtraData& MediaSinkInternal::dial_data() const {
+ DCHECK(is_dial_sink());
+ return dial_data_;
+}
+
+void MediaSinkInternal::set_cast_data(const CastSinkExtraData& cast_data) {
+ DCHECK(sink_type_ != SinkType::DIAL);
+ InternalCleanup();
+
+ sink_type_ = SinkType::CAST;
+ new (&cast_data_) CastSinkExtraData(cast_data);
+}
+
+const CastSinkExtraData& MediaSinkInternal::cast_data() const {
+ DCHECK(is_cast_sink());
+ return cast_data_;
+}
+
+CastSinkExtraData& MediaSinkInternal::cast_data() {
+ DCHECK(is_cast_sink());
+ return cast_data_;
+}
+
+// static
+bool MediaSinkInternal::IsValidSinkId(const std::string& sink_id) {
+ if (sink_id.empty() || !base::IsStringASCII(sink_id)) {
+ DLOG(WARNING) << "Invalid [sink_id]: " << sink_id;
+ return false;
+ }
+
+ return true;
+}
+
+// static
+std::string MediaSinkInternal::ProcessDeviceUUID(
+ const std::string& device_uuid) {
+ if (device_uuid.empty())
+ return std::string();
+
+ std::string result = device_uuid;
+ if (base::StartsWith(device_uuid, "uuid:", base::CompareCase::SENSITIVE))
+ result = device_uuid.substr(5);
+
+ base::RemoveChars(result, "-", &result);
+ return base::ToLowerASCII(result);
+}
+
+void MediaSinkInternal::InternalCopyConstructFrom(
+ const MediaSinkInternal& other) {
+ sink_ = other.sink_;
+ sink_type_ = other.sink_type_;
+
+ switch (sink_type_) {
+ case SinkType::DIAL:
+ new (&dial_data_) DialSinkExtraData(other.dial_data_);
+ return;
+ case SinkType::CAST:
+ new (&cast_data_) CastSinkExtraData(other.cast_data_);
+ return;
+ case SinkType::GENERIC:
+ return;
+ }
+ NOTREACHED();
+}
+
+void MediaSinkInternal::InternalMoveConstructFrom(MediaSinkInternal&& other) {
+ sink_ = std::move(other.sink_);
+ sink_type_ = other.sink_type_;
+
+ switch (sink_type_) {
+ case SinkType::DIAL:
+ new (&dial_data_) DialSinkExtraData(std::move(other.dial_data_));
+ return;
+ case SinkType::CAST:
+ new (&cast_data_) CastSinkExtraData(std::move(other.cast_data_));
+ return;
+ case SinkType::GENERIC:
+ return;
+ }
+ NOTREACHED();
+}
+
+void MediaSinkInternal::InternalCleanup() {
+ switch (sink_type_) {
+ case SinkType::DIAL:
+ dial_data_.~DialSinkExtraData();
+ return;
+ case SinkType::CAST:
+ cast_data_.~CastSinkExtraData();
+ return;
+ case SinkType::GENERIC:
+ return;
+ }
+ NOTREACHED();
+}
+
+DialSinkExtraData::DialSinkExtraData() = default;
+DialSinkExtraData::DialSinkExtraData(const DialSinkExtraData& other) = default;
+DialSinkExtraData::DialSinkExtraData(DialSinkExtraData&& other) = default;
+DialSinkExtraData::~DialSinkExtraData() = default;
+
+bool DialSinkExtraData::operator==(const DialSinkExtraData& other) const {
+ return ip_address == other.ip_address && model_name == other.model_name &&
+ app_url == other.app_url;
+}
+
+CastSinkExtraData::CastSinkExtraData() = default;
+CastSinkExtraData::CastSinkExtraData(const CastSinkExtraData& other) = default;
+CastSinkExtraData::CastSinkExtraData(CastSinkExtraData&& other) = default;
+CastSinkExtraData::~CastSinkExtraData() = default;
+
+bool CastSinkExtraData::operator==(const CastSinkExtraData& other) const {
+ return ip_endpoint == other.ip_endpoint && model_name == other.model_name &&
+ capabilities == other.capabilities &&
+ cast_channel_id == other.cast_channel_id &&
+ discovered_by_dial == other.discovered_by_dial;
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/discovery/media_sink_internal.h b/chromium/chrome/common/media_router/discovery/media_sink_internal.h
new file mode 100644
index 00000000000..5dce50cdfa0
--- /dev/null
+++ b/chromium/chrome/common/media_router/discovery/media_sink_internal.h
@@ -0,0 +1,142 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_ROUTER_DISCOVERY_MEDIA_SINK_INTERNAL_H_
+#define CHROME_COMMON_MEDIA_ROUTER_DISCOVERY_MEDIA_SINK_INTERNAL_H_
+
+#include <utility>
+
+#include "chrome/common/media_router/media_sink.h"
+#include "net/base/ip_address.h"
+#include "net/base/ip_endpoint.h"
+#include "url/gurl.h"
+
+namespace media_router {
+
+// Extra data for DIAL media sink.
+struct DialSinkExtraData {
+ net::IPAddress ip_address;
+
+ // Model name of the sink.
+ std::string model_name;
+
+ // The base URL used for DIAL operations.
+ GURL app_url;
+
+ DialSinkExtraData();
+ DialSinkExtraData(const DialSinkExtraData& other);
+ DialSinkExtraData(DialSinkExtraData&& other);
+ ~DialSinkExtraData();
+
+ bool operator==(const DialSinkExtraData& other) const;
+};
+
+// Extra data for Cast media sink.
+struct CastSinkExtraData {
+ net::IPEndPoint ip_endpoint;
+
+ int port = 0;
+
+ // Model name of the sink.
+ std::string model_name;
+
+ // A bit vector representing the capabilities of the sink. The values are
+ // defined in media_router.mojom.
+ uint8_t capabilities = 0;
+
+ // ID of Cast channel opened for the sink. The caller must set this value to a
+ // valid cast_channel_id. The cast_channel_id may change over time as the
+ // browser reconnects to a device.
+ int cast_channel_id = 0;
+
+ // True if Cast channel is opened from DIAL sink.
+ bool discovered_by_dial = false;
+
+ CastSinkExtraData();
+ CastSinkExtraData(const CastSinkExtraData& other);
+ CastSinkExtraData(CastSinkExtraData&& other);
+ ~CastSinkExtraData();
+
+ bool operator==(const CastSinkExtraData& other) const;
+};
+
+// Represents a media sink discovered by MediaSinkService. It is used by
+// MediaSinkService to push MediaSinks with extra data to the
+// MediaRouteProvider, and it is not exposed to users of MediaRouter.
+class MediaSinkInternal {
+ public:
+ // Used by mojo.
+ MediaSinkInternal();
+
+ // Used by MediaSinkService to create media sinks.
+ MediaSinkInternal(const MediaSink& sink, const DialSinkExtraData& dial_data);
+ MediaSinkInternal(const MediaSink& sink, const CastSinkExtraData& cast_data);
+
+ // Used to push instance of this class into vector.
+ MediaSinkInternal(const MediaSinkInternal& other);
+ MediaSinkInternal(MediaSinkInternal&& other) noexcept;
+
+ ~MediaSinkInternal();
+
+ MediaSinkInternal& operator=(const MediaSinkInternal& other);
+ MediaSinkInternal& operator=(MediaSinkInternal&& other) noexcept;
+ bool operator==(const MediaSinkInternal& other) const;
+ bool operator!=(const MediaSinkInternal& other) const;
+ // Sorted by sink id.
+ bool operator<(const MediaSinkInternal& other) const;
+
+ void set_sink(const MediaSink& sink);
+ const MediaSink& sink() const { return sink_; }
+ MediaSink& sink() { return sink_; }
+
+ // TOOD(jrw): Use this method where appropriate.
+ const MediaSink::Id& id() const { return sink_.id(); }
+
+ void set_dial_data(const DialSinkExtraData& dial_data);
+
+ // Must only be called if the sink is a DIAL sink.
+ const DialSinkExtraData& dial_data() const;
+
+ void set_cast_data(const CastSinkExtraData& cast_data);
+
+ // Must only be called if the sink is a Cast sink.
+ const CastSinkExtraData& cast_data() const;
+ CastSinkExtraData& cast_data();
+
+ // TOOD(jrw): Use this method where appropriate.
+ int cast_channel_id() const { return cast_data().cast_channel_id; }
+
+ bool is_dial_sink() const { return sink_type_ == SinkType::DIAL; }
+ bool is_cast_sink() const { return sink_type_ == SinkType::CAST; }
+
+ static bool IsValidSinkId(const std::string& sink_id);
+
+ // Returns processed device id without "uuid:" and "-", e.g. input
+ // "uuid:6d238518-a574-eab1-017e-d0975c039081" and output
+ // "6d238518a574eab1017ed0975c039081"
+ static std::string ProcessDeviceUUID(const std::string& device_uuid);
+
+ private:
+ void InternalCopyConstructFrom(const MediaSinkInternal& other);
+ void InternalMoveConstructFrom(MediaSinkInternal&& other);
+ void InternalCleanup();
+
+ enum class SinkType { GENERIC, DIAL, CAST };
+
+ MediaSink sink_;
+
+ SinkType sink_type_;
+
+ union {
+ // Set if sink is DIAL sink.
+ DialSinkExtraData dial_data_;
+
+ // Set if sink is Cast sink.
+ CastSinkExtraData cast_data_;
+ };
+};
+
+} // namespace media_router
+
+#endif // CHROME_COMMON_MEDIA_ROUTER_DISCOVERY_MEDIA_SINK_INTERNAL_H_
diff --git a/chromium/chrome/common/media_router/discovery/media_sink_internal_unittest.cc b/chromium/chrome/common/media_router/discovery/media_sink_internal_unittest.cc
new file mode 100644
index 00000000000..ebbb1659d9c
--- /dev/null
+++ b/chromium/chrome/common/media_router/discovery/media_sink_internal_unittest.cc
@@ -0,0 +1,141 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/discovery/media_sink_internal.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+constexpr char kSinkId[] = "sinkId123";
+constexpr char kSinkName[] = "The sink";
+constexpr char kIPAddress[] = "192.168.1.2";
+constexpr char kModelName[] = "model name";
+constexpr char kAppUrl[] = "https://example.com";
+
+media_router::DialSinkExtraData CreateDialSinkExtraData(
+ const std::string& model_name,
+ const std::string& ip_address,
+ const std::string& app_url) {
+ media_router::DialSinkExtraData dial_extra_data;
+ EXPECT_TRUE(dial_extra_data.ip_address.AssignFromIPLiteral(ip_address));
+ dial_extra_data.model_name = model_name;
+ dial_extra_data.app_url = GURL(app_url);
+
+ return dial_extra_data;
+}
+
+media_router::CastSinkExtraData CreateCastSinkExtraData(
+ const std::string& model_name,
+ const std::string& ip_address,
+ uint8_t capabilities,
+ int cast_channel_id) {
+ media_router::CastSinkExtraData cast_extra_data;
+ net::IPAddress ip;
+ EXPECT_TRUE(ip.AssignFromIPLiteral(ip_address));
+ cast_extra_data.ip_endpoint = net::IPEndPoint(ip, 1234);
+ cast_extra_data.model_name = model_name;
+ cast_extra_data.capabilities = 2;
+ cast_extra_data.cast_channel_id = 3;
+ return cast_extra_data;
+}
+
+// static
+media_router::DialSinkExtraData CreateDialSinkExtraData() {
+ return CreateDialSinkExtraData(kModelName, kIPAddress, kAppUrl);
+}
+
+// static
+media_router::CastSinkExtraData CreateCastSinkExtraData() {
+ return CreateCastSinkExtraData(kModelName, kIPAddress, 2, 3);
+}
+
+} // namespace
+
+namespace media_router {
+
+TEST(MediaSinkInternalTest, TestIsValidSinkId) {
+ EXPECT_FALSE(MediaSinkInternal::IsValidSinkId(""));
+ EXPECT_TRUE(MediaSinkInternal::IsValidSinkId("rjuKv_yxhY4jg7QBIp0kbngLjR6A"));
+}
+
+TEST(MediaSinkInternalTest, TestConstructorAndAssignment) {
+ MediaSink sink(kSinkId, kSinkName, SinkIconType::CAST);
+ DialSinkExtraData dial_extra_data = CreateDialSinkExtraData();
+ CastSinkExtraData cast_extra_data = CreateCastSinkExtraData();
+
+ MediaSinkInternal generic_sink;
+ generic_sink.set_sink(sink);
+ MediaSinkInternal dial_sink(sink, dial_extra_data);
+ MediaSinkInternal cast_sink(sink, cast_extra_data);
+
+ MediaSinkInternal copied_generic_sink(generic_sink);
+ MediaSinkInternal copied_dial_sink(dial_sink);
+ MediaSinkInternal copied_cast_sink(cast_sink);
+
+ ASSERT_TRUE(generic_sink == copied_generic_sink);
+ ASSERT_TRUE(dial_sink == copied_dial_sink);
+ ASSERT_TRUE(cast_sink == copied_cast_sink);
+
+ MediaSinkInternal assigned_empty_sink;
+ MediaSinkInternal assigned_generic_sink = generic_sink;
+ MediaSinkInternal assigned_dial_sink = dial_sink;
+ MediaSinkInternal assigned_cast_sink = cast_sink;
+
+ std::vector<MediaSinkInternal> assigned_sinks(
+ {assigned_empty_sink, assigned_generic_sink, assigned_dial_sink,
+ assigned_cast_sink});
+ std::vector<MediaSinkInternal> original_sinks(
+ {generic_sink, dial_sink, cast_sink});
+
+ for (auto& actual_sink : assigned_sinks) {
+ for (const auto& original_sink : original_sinks) {
+ actual_sink = original_sink;
+ EXPECT_EQ(original_sink, actual_sink);
+ }
+ }
+}
+
+TEST(MediaSinkInternalTest, TestSetExtraData) {
+ MediaSink sink(kSinkId, kSinkName, SinkIconType::CAST);
+ DialSinkExtraData dial_extra_data = CreateDialSinkExtraData();
+ CastSinkExtraData cast_extra_data = CreateCastSinkExtraData();
+
+ MediaSinkInternal dial_sink1;
+ dial_sink1.set_dial_data(dial_extra_data);
+ ASSERT_EQ(dial_extra_data, dial_sink1.dial_data());
+
+ MediaSinkInternal cast_sink1;
+ cast_sink1.set_cast_data(cast_extra_data);
+ ASSERT_EQ(cast_extra_data, cast_sink1.cast_data());
+
+ DialSinkExtraData dial_extra_data2 = CreateDialSinkExtraData(
+ "new_dial_model_name", "192.1.2.100", "https://example2.com");
+ CastSinkExtraData cast_extra_data2 =
+ CreateCastSinkExtraData("new_cast_model_name", "192.1.2.101", 4, 5);
+
+ MediaSinkInternal dial_sink2(sink, dial_extra_data);
+ dial_sink2.set_dial_data(dial_extra_data2);
+ ASSERT_EQ(dial_extra_data2, dial_sink2.dial_data());
+
+ MediaSinkInternal cast_sink2(sink, cast_extra_data);
+ cast_sink2.set_cast_data(cast_extra_data2);
+ ASSERT_EQ(cast_extra_data2, cast_sink2.cast_data());
+}
+
+TEST(MediaSinkInternalTest, TestProcessDeviceUUID) {
+ EXPECT_EQ("de51d94921f15f8af6dbf65592bb3610",
+ MediaSinkInternal::ProcessDeviceUUID(
+ "uuid:de51d949-21f1-5f8a-f6db-f65592bb3610"));
+ EXPECT_EQ("de51d94921f15f8af6dbf65592bb3610",
+ MediaSinkInternal::ProcessDeviceUUID(
+ "de51d94921f1-5f8a-f6db-f65592bb3610"));
+ EXPECT_EQ(
+ "de51d94921f15f8af6dbf65592bb3610",
+ MediaSinkInternal::ProcessDeviceUUID("DE51D94921F15F8AF6DBF65592BB3610"));
+ EXPECT_EQ("abc:de51d94921f15f8af6dbf65592bb3610",
+ MediaSinkInternal::ProcessDeviceUUID(
+ "abc:de51d949-21f1-5f8a-f6db-f65592bb3610"));
+ EXPECT_EQ("", MediaSinkInternal::ProcessDeviceUUID(""));
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/discovery/media_sink_service_base.cc b/chromium/chrome/common/media_router/discovery/media_sink_service_base.cc
new file mode 100644
index 00000000000..009517d7f86
--- /dev/null
+++ b/chromium/chrome/common/media_router/discovery/media_sink_service_base.cc
@@ -0,0 +1,125 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/discovery/media_sink_service_base.h"
+#include "base/bind.h"
+#include "chrome/common/media_router/media_route.h"
+
+#include <vector>
+
+namespace {
+// Timeout amount for |discovery_timer_|.
+const constexpr base::TimeDelta kDiscoveryTimeout =
+ base::TimeDelta::FromSeconds(3);
+} // namespace
+
+namespace media_router {
+
+MediaSinkServiceBase::MediaSinkServiceBase(
+ const OnSinksDiscoveredCallback& callback)
+ : discovery_timer_(std::make_unique<base::OneShotTimer>()),
+ on_sinks_discovered_cb_(callback) {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+}
+
+MediaSinkServiceBase::~MediaSinkServiceBase() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void MediaSinkServiceBase::AddObserver(Observer* observer) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ observers_.AddObserver(observer);
+}
+
+void MediaSinkServiceBase::RemoveObserver(Observer* observer) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ observers_.RemoveObserver(observer);
+}
+
+const base::flat_map<MediaSink::Id, MediaSinkInternal>&
+MediaSinkServiceBase::GetSinks() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return sinks_;
+}
+
+const MediaSinkInternal* MediaSinkServiceBase::GetSinkById(
+ const MediaSink::Id& sink_id) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ auto it = sinks_.find(sink_id);
+ return it != sinks_.end() ? &it->second : nullptr;
+}
+
+const MediaSinkInternal* MediaSinkServiceBase::GetSinkByRoute(
+ const MediaRoute& route) const {
+ return GetSinkById(route.media_sink_id());
+}
+
+void MediaSinkServiceBase::AddOrUpdateSink(const MediaSinkInternal& sink) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ sinks_.insert_or_assign(sink.sink().id(), sink);
+ for (auto& observer : observers_)
+ observer.OnSinkAddedOrUpdated(sink);
+
+ StartTimer();
+}
+
+void MediaSinkServiceBase::RemoveSink(const MediaSinkInternal& sink) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ RemoveSinkById(sink.sink().id());
+}
+
+void MediaSinkServiceBase::RemoveSinkById(const MediaSink::Id& sink_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ auto it = sinks_.find(sink_id);
+ if (it == sinks_.end())
+ return;
+
+ MediaSinkInternal sink = std::move(it->second);
+ sinks_.erase(it);
+ for (auto& observer : observers_)
+ observer.OnSinkRemoved(sink);
+
+ StartTimer();
+}
+
+void MediaSinkServiceBase::SetTimerForTest(
+ std::unique_ptr<base::OneShotTimer> timer) {
+ discovery_timer_ = std::move(timer);
+}
+
+void MediaSinkServiceBase::StartTimer() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (discovery_timer_->IsRunning())
+ return;
+
+ discovery_timer_->Start(
+ FROM_HERE, kDiscoveryTimeout,
+ base::BindRepeating(&MediaSinkServiceBase::OnDiscoveryComplete,
+ base::Unretained(this)));
+}
+
+void MediaSinkServiceBase::OnDiscoveryComplete() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ discovery_timer_->Stop();
+ RecordDeviceCounts();
+
+ // Only send discovered sinks back to MediaRouter if the list changed.
+ if (sinks_ == previous_sinks_) {
+ DVLOG(2) << "No update to sink list.";
+ return;
+ }
+
+ DVLOG(2) << "Send sinks to media router, [size]: " << sinks_.size();
+
+ std::vector<MediaSinkInternal> sinks;
+ for (const auto& sink_it : sinks_)
+ sinks.push_back(sink_it.second);
+
+ for (auto& observer : observers_)
+ observer.OnSinksDiscovered(sinks);
+ on_sinks_discovered_cb_.Run(std::move(sinks));
+ previous_sinks_ = sinks_;
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/discovery/media_sink_service_base.h b/chromium/chrome/common/media_router/discovery/media_sink_service_base.h
new file mode 100644
index 00000000000..df9547f1e28
--- /dev/null
+++ b/chromium/chrome/common/media_router/discovery/media_sink_service_base.h
@@ -0,0 +1,135 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_ROUTER_DISCOVERY_MEDIA_SINK_SERVICE_BASE_H_
+#define CHROME_COMMON_MEDIA_ROUTER_DISCOVERY_MEDIA_SINK_SERVICE_BASE_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/gtest_prod_util.h"
+#include "base/observer_list.h"
+#include "base/sequence_checker.h"
+#include "base/timer/timer.h"
+#include "chrome/common/media_router/discovery/media_sink_internal.h"
+#include "chrome/common/media_router/discovery/media_sink_service_util.h"
+
+namespace media_router {
+
+class MediaRoute;
+
+// Base class for discovering MediaSinks. Responsible for bookkeeping of
+// current set of discovered sinks, and notifying observers when there are
+// updates.
+// In addition, this class maintains a "discovery timer", used for batching
+// updates in quick succession. The timer fires when it is assumed that
+// discovery has reached a relatively steady state. When the timer fires:
+// - The batched updated sink list will be sent back to the Media Router
+// extension via |callback|. This back-channel is necessary until all logic
+// dependent on MediaSinks are moved out of the extension.
+// - Subclasses may record discovered related metrics.
+// This class may be created on any thread, but all subsequent methods must be
+// invoked on the same thread.
+class MediaSinkServiceBase {
+ public:
+ // Listens for sink updates in MediaSinkServiceBase.
+ class Observer {
+ public:
+ virtual ~Observer() = default;
+
+ // Invoked when the list of discovered sinks changes.
+ virtual void OnSinksDiscovered(
+ const std::vector<MediaSinkInternal>& sinks) {}
+
+ // Invoked when |sink| is added or updated.
+ virtual void OnSinkAddedOrUpdated(const MediaSinkInternal& sink) {}
+
+ // Invoked when |sink| is removed.
+ virtual void OnSinkRemoved(const MediaSinkInternal& sink) {}
+ };
+
+ // |callback|: Callback to inform the MediaRouter extension of discovered
+ // sinks updates. Other uses should implement Observer::OnSinksDiscovered().
+ explicit MediaSinkServiceBase(const OnSinksDiscoveredCallback& callback);
+ virtual ~MediaSinkServiceBase();
+
+ // Adds |observer| to observe |this| for sink updates.
+ // Caller is responsible for calling |RemoveObserver| before it is destroyed.
+ // Both methods are safe to call on any thread.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Overridden by subclass to initiate action triggered by user gesture, e.g.
+ // start one-off round of discovery.
+ virtual void OnUserGesture() {}
+
+ // Adds or updates, or removes a sink.
+ // Notifies |observers_| that the sink has been added, updated, or removed.
+ // Also invokes |StartTimer()|.
+ void AddOrUpdateSink(const MediaSinkInternal& sink);
+ void RemoveSink(const MediaSinkInternal& sink);
+ void RemoveSinkById(const MediaSink::Id& sink_id);
+
+ const base::flat_map<MediaSink::Id, MediaSinkInternal>& GetSinks() const;
+
+ // These methods return nullptr when no sink is found.
+ const MediaSinkInternal* GetSinkById(const MediaSink::Id& sink_id) const;
+ const MediaSinkInternal* GetSinkByRoute(const MediaRoute& route) const;
+
+ void SetTimerForTest(std::unique_ptr<base::OneShotTimer> timer);
+
+ protected:
+ // Called when |discovery_timer_| expires. Informs subclass to report device
+ // counts. Also informs Media Router of updated list of discovered sinks.
+ // May be overridden by subclass to perform additional operations, such as
+ // pruning old sinks.
+ virtual void OnDiscoveryComplete();
+
+ // Starts |discovery_timer_| to invoke |OnDiscoveryComplete()|. Subclasses
+ // may call this at the start of a round of discovery.
+ void StartTimer();
+
+ private:
+ friend class MediaSinkServiceBaseTest;
+ FRIEND_TEST_ALL_PREFIXES(MediaSinkServiceBaseTest,
+ TestOnDiscoveryComplete_SameSink);
+ FRIEND_TEST_ALL_PREFIXES(MediaSinkServiceBaseTest,
+ TestOnDiscoveryComplete_SameSinkDifferentOrders);
+
+ // Overriden by subclass to report device counts.
+ virtual void RecordDeviceCounts() {}
+
+ // The current set of discovered sinks keyed by MediaSink ID.
+ base::flat_map<MediaSink::Id, MediaSinkInternal> sinks_;
+
+ // Observers to notify when a sink is added, updated, or removed.
+ base::ObserverList<Observer>::Unchecked observers_;
+
+ // Timer for recording device counts after a sink list has changed. To ensure
+ // the metrics are recorded accurately, a small delay is introduced after a
+ // sink list change in order for the discovery process to reach a steady
+ // state before the metrics are recorded.
+ std::unique_ptr<base::OneShotTimer> discovery_timer_;
+
+ // The following fields exist temporarily for sending back discovered sinks to
+ // the Media Router extension.
+ // TODO(https://crbug.com/809249): Remove once the extension no longer need
+ // the sinks.
+
+ // Callback to MediaRouter to provide sinks to the MR extension.
+ OnSinksDiscoveredCallback on_sinks_discovered_cb_;
+
+ // Sinks saved in the previous |OnDiscoveryComplete()| invocation. Checked
+ // against |sinks_| during |OnDiscoveryComplete()| before invoking
+ // |on_sinks_discovered_cb_|.
+ base::flat_map<MediaSink::Id, MediaSinkInternal> previous_sinks_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+ DISALLOW_COPY_AND_ASSIGN(MediaSinkServiceBase);
+};
+
+} // namespace media_router
+
+#endif // CHROME_COMMON_MEDIA_ROUTER_DISCOVERY_MEDIA_SINK_SERVICE_BASE_H_
diff --git a/chromium/chrome/common/media_router/discovery/media_sink_service_base_unittest.cc b/chromium/chrome/common/media_router/discovery/media_sink_service_base_unittest.cc
new file mode 100644
index 00000000000..6f3bc33248e
--- /dev/null
+++ b/chromium/chrome/common/media_router/discovery/media_sink_service_base_unittest.cc
@@ -0,0 +1,147 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/discovery/media_sink_service_base.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/test/mock_callback.h"
+#include "base/timer/mock_timer.h"
+#include "chrome/common/media_router/test/test_helper.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace {
+
+media_router::DialSinkExtraData CreateDialSinkExtraData(
+ const std::string& model_name,
+ const std::string& ip_address,
+ const std::string& app_url) {
+ media_router::DialSinkExtraData dial_extra_data;
+ EXPECT_TRUE(dial_extra_data.ip_address.AssignFromIPLiteral(ip_address));
+ dial_extra_data.model_name = model_name;
+ dial_extra_data.app_url = GURL(app_url);
+ return dial_extra_data;
+}
+
+std::vector<media_router::MediaSinkInternal> CreateDialMediaSinks() {
+ media_router::MediaSink sink1("sink1", "sink_name_1",
+ media_router::SinkIconType::CAST);
+ media_router::DialSinkExtraData extra_data1 = CreateDialSinkExtraData(
+ "model_name1", "192.168.1.1", "https://example1.com");
+
+ media_router::MediaSink sink2("sink2", "sink_name_2",
+ media_router::SinkIconType::CAST);
+ media_router::DialSinkExtraData extra_data2 = CreateDialSinkExtraData(
+ "model_name2", "192.168.1.2", "https://example2.com");
+
+ std::vector<media_router::MediaSinkInternal> sinks;
+ sinks.push_back(media_router::MediaSinkInternal(sink1, extra_data1));
+ sinks.push_back(media_router::MediaSinkInternal(sink2, extra_data2));
+ return sinks;
+}
+
+} // namespace
+
+namespace media_router {
+
+class MediaSinkServiceBaseTest : public ::testing::Test {
+ public:
+ MediaSinkServiceBaseTest()
+ : media_sink_service_(mock_sink_discovered_cb_.Get()) {}
+ ~MediaSinkServiceBaseTest() override {}
+
+ void PopulateSinks(const std::vector<MediaSinkInternal>& old_sinks,
+ const std::vector<MediaSinkInternal>& new_sinks) {
+ media_sink_service_.previous_sinks_.clear();
+ for (const auto& old_sink : old_sinks)
+ media_sink_service_.previous_sinks_.emplace(old_sink.sink().id(),
+ old_sink);
+
+ media_sink_service_.sinks_.clear();
+ for (const auto& new_sink : new_sinks)
+ media_sink_service_.sinks_.emplace(new_sink.sink().id(), new_sink);
+ }
+
+ void TestOnDiscoveryComplete(
+ const std::vector<MediaSinkInternal>& old_sinks,
+ const std::vector<MediaSinkInternal>& new_sinks) {
+ PopulateSinks(old_sinks, new_sinks);
+ EXPECT_CALL(mock_sink_discovered_cb_, Run(new_sinks));
+ media_sink_service_.OnDiscoveryComplete();
+ }
+
+ protected:
+ base::MockCallback<OnSinksDiscoveredCallback> mock_sink_discovered_cb_;
+ TestMediaSinkService media_sink_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaSinkServiceBaseTest);
+};
+
+TEST_F(MediaSinkServiceBaseTest, TestOnDiscoveryComplete_SameSink) {
+ std::vector<MediaSinkInternal> old_sinks;
+ std::vector<MediaSinkInternal> new_sinks = CreateDialMediaSinks();
+ TestOnDiscoveryComplete(old_sinks, new_sinks);
+
+ // Same sink
+ EXPECT_CALL(mock_sink_discovered_cb_, Run(new_sinks)).Times(0);
+ media_sink_service_.OnDiscoveryComplete();
+}
+
+TEST_F(MediaSinkServiceBaseTest,
+ TestOnDiscoveryComplete_SameSinkDifferentOrders) {
+ std::vector<MediaSinkInternal> old_sinks = CreateDialMediaSinks();
+ std::vector<MediaSinkInternal> new_sinks = CreateDialMediaSinks();
+ std::reverse(new_sinks.begin(), new_sinks.end());
+
+ PopulateSinks(old_sinks, new_sinks);
+ EXPECT_CALL(mock_sink_discovered_cb_, Run(new_sinks)).Times(0);
+ media_sink_service_.OnDiscoveryComplete();
+}
+
+TEST_F(MediaSinkServiceBaseTest, TestOnDiscoveryComplete_OneNewSink) {
+ std::vector<MediaSinkInternal> old_sinks = CreateDialMediaSinks();
+ std::vector<MediaSinkInternal> new_sinks = CreateDialMediaSinks();
+ MediaSink sink3("sink3", "sink_name_3", SinkIconType::CAST);
+ DialSinkExtraData extra_data3 = CreateDialSinkExtraData(
+ "model_name3", "192.168.1.3", "https://example3.com");
+ new_sinks.push_back(MediaSinkInternal(sink3, extra_data3));
+ TestOnDiscoveryComplete(old_sinks, new_sinks);
+}
+
+TEST_F(MediaSinkServiceBaseTest, TestOnDiscoveryComplete_RemovedOneSink) {
+ std::vector<MediaSinkInternal> old_sinks = CreateDialMediaSinks();
+ std::vector<MediaSinkInternal> new_sinks = CreateDialMediaSinks();
+ new_sinks.erase(new_sinks.begin());
+ TestOnDiscoveryComplete(old_sinks, new_sinks);
+}
+
+TEST_F(MediaSinkServiceBaseTest, TestOnDiscoveryComplete_UpdatedOneSink) {
+ std::vector<MediaSinkInternal> old_sinks = CreateDialMediaSinks();
+ std::vector<MediaSinkInternal> new_sinks = CreateDialMediaSinks();
+ new_sinks[0].sink().set_name("sink_name_4");
+ TestOnDiscoveryComplete(old_sinks, new_sinks);
+}
+
+TEST_F(MediaSinkServiceBaseTest, TestOnDiscoveryComplete_Mixed) {
+ std::vector<MediaSinkInternal> old_sinks = CreateDialMediaSinks();
+
+ MediaSink sink1("sink1", "sink_name_1", SinkIconType::CAST);
+ DialSinkExtraData extra_data2 = CreateDialSinkExtraData(
+ "model_name2", "192.168.1.2", "https://example2.com");
+
+ MediaSink sink3("sink3", "sink_name_3", SinkIconType::CAST);
+ DialSinkExtraData extra_data3 = CreateDialSinkExtraData(
+ "model_name3", "192.168.1.3", "https://example3.com");
+
+ std::vector<MediaSinkInternal> new_sinks;
+ new_sinks.push_back(MediaSinkInternal(sink1, extra_data2));
+ new_sinks.push_back(MediaSinkInternal(sink3, extra_data3));
+
+ TestOnDiscoveryComplete(old_sinks, new_sinks);
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/discovery/media_sink_service_util.cc b/chromium/chrome/common/media_router/discovery/media_sink_service_util.cc
new file mode 100644
index 00000000000..5c3b63238f3
--- /dev/null
+++ b/chromium/chrome/common/media_router/discovery/media_sink_service_util.cc
@@ -0,0 +1,29 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/discovery/media_sink_service_util.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/sequenced_task_runner.h"
+
+namespace media_router {
+
+void RunSinksDiscoveredCallbackOnSequence(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+ const OnSinksDiscoveredCallback& callback,
+ std::vector<MediaSinkInternal> sinks) {
+ task_runner->PostTask(FROM_HERE, base::BindOnce(callback, std::move(sinks)));
+}
+
+void RunAvailableSinksUpdatedCallbackOnSequence(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+ const OnAvailableSinksUpdatedCallback& callback,
+ const std::string& app_name,
+ std::vector<MediaSinkInternal> available_sinks) {
+ task_runner->PostTask(FROM_HERE, base::BindOnce(callback, app_name,
+ std::move(available_sinks)));
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/discovery/media_sink_service_util.h b/chromium/chrome/common/media_router/discovery/media_sink_service_util.h
new file mode 100644
index 00000000000..0cd98f32efb
--- /dev/null
+++ b/chromium/chrome/common/media_router/discovery/media_sink_service_util.h
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_ROUTER_DISCOVERY_MEDIA_SINK_SERVICE_UTIL_H_
+#define CHROME_COMMON_MEDIA_ROUTER_DISCOVERY_MEDIA_SINK_SERVICE_UTIL_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
+#include "chrome/common/media_router/discovery/media_sink_internal.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace media_router {
+
+using OnSinksDiscoveredCallback =
+ base::RepeatingCallback<void(std::vector<MediaSinkInternal>)>;
+
+// Called when a new sink becomes available or an available sink becomes
+// unavailable for |app_name|.
+// |app_name|: app name on receiver device (e.g. YouTube)
+// |available_sinks|: list of currently available sinks for |app_name|
+using OnAvailableSinksUpdatedCallback = base::RepeatingCallback<void(
+ const std::string& app_name,
+ std::vector<MediaSinkInternal> available_sinks)>;
+
+// Runs |sinks_discovered_cb| with |sinks| on |task_runner|.
+void RunSinksDiscoveredCallbackOnSequence(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+ const OnSinksDiscoveredCallback& callback,
+ std::vector<MediaSinkInternal> sinks);
+
+void RunAvailableSinksUpdatedCallbackOnSequence(
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+ const OnAvailableSinksUpdatedCallback& callback,
+ const std::string& app_name,
+ std::vector<MediaSinkInternal> available_sinks);
+} // namespace media_router
+
+#endif // CHROME_COMMON_MEDIA_ROUTER_DISCOVERY_MEDIA_SINK_SERVICE_UTIL_H_
diff --git a/chromium/chrome/common/media_router/issue.cc b/chromium/chrome/common/media_router/issue.cc
new file mode 100644
index 00000000000..76972970aea
--- /dev/null
+++ b/chromium/chrome/common/media_router/issue.cc
@@ -0,0 +1,50 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/issue.h"
+
+#include "base/atomic_sequence_num.h"
+
+namespace media_router {
+
+namespace {
+// ID generator for Issue.
+base::AtomicSequenceNumber g_next_issue_id;
+}
+
+IssueInfo::IssueInfo()
+ : default_action(IssueInfo::Action::DISMISS),
+ severity(IssueInfo::Severity::NOTIFICATION),
+ is_blocking(false),
+ help_page_id(IssueInfo::kUnknownHelpPageId) {}
+
+IssueInfo::IssueInfo(const std::string& title,
+ const Action default_action,
+ Severity severity)
+ : title(title),
+ default_action(default_action),
+ severity(severity),
+ is_blocking(severity == IssueInfo::Severity::FATAL),
+ help_page_id(IssueInfo::kUnknownHelpPageId) {}
+
+IssueInfo::IssueInfo(const IssueInfo& other) = default;
+
+IssueInfo::~IssueInfo() = default;
+
+IssueInfo& IssueInfo::operator=(const IssueInfo& other) = default;
+
+bool IssueInfo::operator==(const IssueInfo& other) const {
+ return title == other.title && default_action == other.default_action &&
+ severity == other.severity && message == other.message &&
+ secondary_actions == other.secondary_actions &&
+ route_id == other.route_id && is_blocking == other.is_blocking &&
+ help_page_id == other.help_page_id;
+}
+
+Issue::Issue(const IssueInfo& info)
+ : id_(g_next_issue_id.GetNext()), info_(info) {}
+
+Issue::~Issue() = default;
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/issue.h b/chromium/chrome/common/media_router/issue.h
new file mode 100644
index 00000000000..8b790b6cf72
--- /dev/null
+++ b/chromium/chrome/common/media_router/issue.h
@@ -0,0 +1,102 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_ROUTER_ISSUE_H_
+#define CHROME_COMMON_MEDIA_ROUTER_ISSUE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "chrome/common/media_router/media_route.h"
+#include "chrome/common/media_router/media_sink.h"
+
+namespace media_router {
+
+// Contains the information relevant to an issue.
+struct IssueInfo {
+ public:
+ // Possible actions for an issue.
+ enum class Action {
+ DISMISS,
+ // NOTE: If LEARN_MORE is set as a possible action for an issue, then its
+ // |help_page_id_| must also be set to a valid value.
+ LEARN_MORE,
+
+ // Denotes enum value boundary. New values should be added above.
+ NUM_VALUES = LEARN_MORE
+ };
+
+ // Severity type of an issue. A FATAL issue is considered blocking. Although
+ // issues of other severity levels may also be blocking.
+ enum class Severity { FATAL, WARNING, NOTIFICATION };
+
+ static const int kUnknownHelpPageId = 0;
+
+ // Used by Mojo and testing only.
+ IssueInfo();
+
+ // |title|: The title for the issue.
+ // |default_action|: Default action user can take to resolve the issue.
+ // |severity|: The severity of the issue. If FATAL, then |is_blocking| is set
+ // to |true|.
+ IssueInfo(const std::string& title, Action default_action, Severity severity);
+ IssueInfo(const IssueInfo& other);
+ ~IssueInfo();
+
+ IssueInfo& operator=(const IssueInfo& other);
+ bool operator==(const IssueInfo& other) const;
+
+ // Fields set with values provided to the constructor.
+ std::string title;
+ Action default_action;
+ Severity severity;
+
+ // Description message for the issue.
+ std::string message;
+
+ // Options the user can take to resolve the issue in addition to the
+ // default action. Can be empty. If non-empty, currently only one secondary
+ // action is supported.
+ std::vector<Action> secondary_actions;
+
+ // ID of route associated with the Issue, or empty if no route is associated
+ // with it.
+ MediaRoute::Id route_id;
+
+ // ID of the sink associated with this issue, or empty if no sink is
+ // associated with it.
+ MediaSink::Id sink_id;
+
+ // |true| if the issue needs to be resolved before continuing. Note that a
+ // Issue of severity FATAL is considered blocking by default.
+ bool is_blocking;
+
+ // ID of help page to link to, if one of the actions is LEARN_MORE.
+ // Defaults to |kUnknownHelpPageId|.
+ int help_page_id;
+};
+
+// An issue that is associated with a globally unique ID. Created by
+// IssueManager when an IssueInfo is added to it.
+class Issue {
+ public:
+ using Id = int;
+ // ID is generated during construction.
+ explicit Issue(const IssueInfo& info);
+ Issue(const Issue& other) = default;
+ Issue& operator=(const Issue& other) = default;
+ ~Issue();
+
+ const Id& id() const { return id_; }
+ const IssueInfo& info() const { return info_; }
+
+ private:
+ Id id_;
+ IssueInfo info_;
+};
+
+} // namespace media_router
+
+#endif // CHROME_COMMON_MEDIA_ROUTER_ISSUE_H_
diff --git a/chromium/chrome/common/media_router/issue_unittest.cc b/chromium/chrome/common/media_router/issue_unittest.cc
new file mode 100644
index 00000000000..8b6235c1a2c
--- /dev/null
+++ b/chromium/chrome/common/media_router/issue_unittest.cc
@@ -0,0 +1,117 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/issue.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace media_router {
+
+namespace {
+
+IssueInfo CreateWarningIssueInfo(IssueInfo::Action action_type) {
+ IssueInfo issue("title", action_type, IssueInfo::Severity::WARNING);
+ issue.message = "message";
+ issue.help_page_id = 12345;
+ return issue;
+}
+
+IssueInfo CreateFatalRouteIssueInfoWithMessage(IssueInfo::Action action_type) {
+ IssueInfo issue("title", action_type, IssueInfo::Severity::FATAL);
+ issue.message = "message";
+ issue.route_id = "routeid";
+ issue.help_page_id = 12345;
+ return issue;
+}
+
+IssueInfo CreateFatalRouteIssueInfo(IssueInfo::Action action_type) {
+ IssueInfo issue("title", action_type, IssueInfo::Severity::FATAL);
+ issue.route_id = "routeid";
+ issue.help_page_id = 12345;
+ return issue;
+}
+
+} // namespace
+
+// Tests Issues without any secondary actions.
+TEST(IssueInfoUnitTest, CustomIssueConstructionWithNoSecondaryActions) {
+ IssueInfo issue1 = CreateWarningIssueInfo(IssueInfo::Action::DISMISS);
+
+ EXPECT_EQ("title", issue1.title);
+ EXPECT_EQ("message", issue1.message);
+ EXPECT_EQ(IssueInfo::Action::DISMISS, issue1.default_action);
+ EXPECT_TRUE(issue1.secondary_actions.empty());
+ EXPECT_EQ(IssueInfo::Severity::WARNING, issue1.severity);
+ EXPECT_EQ("", issue1.route_id);
+ EXPECT_FALSE(issue1.is_blocking);
+ EXPECT_EQ(12345, issue1.help_page_id);
+
+ IssueInfo issue2 =
+ CreateFatalRouteIssueInfoWithMessage(IssueInfo::Action::DISMISS);
+
+ EXPECT_EQ("title", issue2.title);
+ EXPECT_EQ("message", issue2.message);
+ EXPECT_EQ(IssueInfo::Action::DISMISS, issue1.default_action);
+ EXPECT_TRUE(issue2.secondary_actions.empty());
+ EXPECT_EQ(IssueInfo::Severity::FATAL, issue2.severity);
+ EXPECT_EQ("routeid", issue2.route_id);
+ EXPECT_TRUE(issue2.is_blocking);
+ EXPECT_EQ(12345, issue2.help_page_id);
+
+ IssueInfo issue3 = CreateFatalRouteIssueInfo(IssueInfo::Action::DISMISS);
+
+ EXPECT_EQ("title", issue3.title);
+ EXPECT_EQ("", issue3.message);
+ EXPECT_EQ(IssueInfo::Action::DISMISS, issue1.default_action);
+ EXPECT_TRUE(issue3.secondary_actions.empty());
+ EXPECT_EQ(IssueInfo::Severity::FATAL, issue3.severity);
+ EXPECT_EQ("routeid", issue3.route_id);
+ EXPECT_TRUE(issue3.is_blocking);
+ EXPECT_EQ(12345, issue3.help_page_id);
+}
+
+// Tests Issues with secondary actions.
+TEST(IssueInfoUnitTest, CustomIssueConstructionWithSecondaryActions) {
+ std::vector<IssueInfo::Action> secondary_actions;
+ secondary_actions.push_back(IssueInfo::Action::DISMISS);
+
+ IssueInfo issue1 = CreateWarningIssueInfo(IssueInfo::Action::LEARN_MORE);
+ issue1.secondary_actions = secondary_actions;
+
+ EXPECT_EQ("title", issue1.title);
+ EXPECT_EQ("message", issue1.message);
+ EXPECT_EQ(IssueInfo::Action::LEARN_MORE, issue1.default_action);
+ EXPECT_FALSE(issue1.secondary_actions.empty());
+ EXPECT_EQ(1u, issue1.secondary_actions.size());
+ EXPECT_EQ(IssueInfo::Severity::WARNING, issue1.severity);
+ EXPECT_EQ("", issue1.route_id);
+ EXPECT_FALSE(issue1.is_blocking);
+
+ IssueInfo issue2 =
+ CreateFatalRouteIssueInfoWithMessage(IssueInfo::Action::LEARN_MORE);
+ issue2.secondary_actions = secondary_actions;
+
+ EXPECT_EQ("title", issue2.title);
+ EXPECT_EQ("message", issue2.message);
+ EXPECT_EQ(IssueInfo::Action::LEARN_MORE, issue2.default_action);
+ EXPECT_FALSE(issue2.secondary_actions.empty());
+ EXPECT_EQ(1u, issue2.secondary_actions.size());
+ EXPECT_EQ(IssueInfo::Severity::FATAL, issue2.severity);
+ EXPECT_EQ("routeid", issue2.route_id);
+ EXPECT_TRUE(issue2.is_blocking);
+
+ IssueInfo issue3 = CreateFatalRouteIssueInfo(IssueInfo::Action::LEARN_MORE);
+ issue3.secondary_actions = secondary_actions;
+
+ EXPECT_EQ("title", issue3.title);
+ EXPECT_EQ("", issue3.message);
+ EXPECT_EQ(IssueInfo::Action::LEARN_MORE, issue3.default_action);
+ EXPECT_FALSE(issue3.secondary_actions.empty());
+ EXPECT_EQ(1u, issue3.secondary_actions.size());
+ EXPECT_EQ(IssueInfo::Severity::FATAL, issue3.severity);
+ EXPECT_EQ("routeid", issue3.route_id);
+ EXPECT_TRUE(issue3.is_blocking);
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/media_route.cc b/chromium/chrome/common/media_router/media_route.cc
new file mode 100644
index 00000000000..6e9b40c6d26
--- /dev/null
+++ b/chromium/chrome/common/media_router/media_route.cc
@@ -0,0 +1,64 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/media_route.h"
+
+#include <ostream>
+
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/common/media_router/media_source.h"
+
+namespace media_router {
+
+// static
+MediaRoute::Id MediaRoute::GetMediaRouteId(const std::string& presentation_id,
+ const MediaSink::Id& sink_id,
+ const MediaSource& source) {
+ // TODO(https://crbug.com/816628): Can the route ID just be the presentation
+ // id?
+ return base::StringPrintf("urn:x-org.chromium:media:route:%s/%s/%s",
+ presentation_id.c_str(), sink_id.c_str(),
+ source.id().c_str());
+}
+
+MediaRoute::MediaRoute(const MediaRoute::Id& media_route_id,
+ const MediaSource& media_source,
+ const MediaSink::Id& media_sink_id,
+ const std::string& description,
+ bool is_local,
+ bool for_display)
+ : media_route_id_(media_route_id),
+ media_source_(media_source),
+ media_sink_id_(media_sink_id),
+ description_(description),
+ is_local_(is_local),
+ for_display_(for_display),
+ is_incognito_(false),
+ is_local_presentation_(false) {}
+
+MediaRoute::MediaRoute(const MediaRoute& other) = default;
+
+MediaRoute::MediaRoute() {}
+MediaRoute::~MediaRoute() = default;
+
+bool MediaRoute::operator==(const MediaRoute& other) const {
+ return media_route_id_ == other.media_route_id_ &&
+ presentation_id_ == other.presentation_id_ &&
+ media_source_ == other.media_source_ &&
+ media_sink_id_ == other.media_sink_id_ &&
+ description_ == other.description_ && is_local_ == other.is_local_ &&
+ controller_type_ == other.controller_type_ &&
+ for_display_ == other.for_display_ &&
+ is_incognito_ == other.is_incognito_ &&
+ is_local_presentation_ == other.is_local_presentation_;
+}
+
+std::ostream& operator<<(std::ostream& stream, const MediaRoute& route) {
+ return stream << "MediaRoute{id=" << route.media_route_id_
+ << ",source=" << route.media_source_.id()
+ << ",sink=" << route.media_sink_id_ << "}";
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/media_route.h b/chromium/chrome/common/media_router/media_route.h
new file mode 100644
index 00000000000..0a6daf84ca5
--- /dev/null
+++ b/chromium/chrome/common/media_router/media_route.h
@@ -0,0 +1,144 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_ROUTER_MEDIA_ROUTE_H_
+#define CHROME_COMMON_MEDIA_ROUTER_MEDIA_ROUTE_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "base/logging.h"
+#include "base/values.h"
+#include "chrome/common/media_router/media_sink.h"
+#include "chrome/common/media_router/media_source.h"
+
+namespace media_router {
+
+// TODO(imcheng): Use the Mojo enum directly once we Mojo-ified
+// MediaRouterAndroid.
+enum class RouteControllerType { kNone, kGeneric, kMirroring };
+
+// MediaRoute objects contain the status and metadata of a routing
+// operation. The fields are immutable and reflect the route status
+// only at the time of object creation. Updated route statuses must
+// be retrieved as new MediaRoute objects from the Media Router.
+//
+// TODO(mfoltz): Convert to a simple struct and remove uncommon parameters from
+// the ctor.
+class MediaRoute {
+ public:
+ using Id = std::string;
+
+ static MediaRoute::Id GetMediaRouteId(const std::string& presentation_id,
+ const MediaSink::Id& sink_id,
+ const MediaSource& source);
+
+ // |media_route_id|: ID of the route.
+ // |media_source|: Description of source of the route.
+ // |media_sink|: The sink that is receiving the media.
+ // |description|: Human readable description of the casting activity.
+ // |is_local|: true if the route was created from this browser.
+ // provider. empty otherwise.
+ // |for_display|: Set to true if this route should be displayed for
+ // |media_sink_id| in UI.
+ MediaRoute(const MediaRoute::Id& media_route_id,
+ const MediaSource& media_source,
+ const MediaSink::Id& media_sink_id,
+ const std::string& description,
+ bool is_local,
+ bool for_display);
+ MediaRoute(const MediaRoute& other);
+ MediaRoute();
+
+ ~MediaRoute();
+
+ void set_media_route_id(const MediaRoute::Id& media_route_id) {
+ media_route_id_ = media_route_id;
+ }
+ const MediaRoute::Id& media_route_id() const { return media_route_id_; }
+
+ void set_presentation_id(const std::string& presentation_id) {
+ presentation_id_ = presentation_id;
+ }
+ const std::string& presentation_id() const { return presentation_id_; }
+
+ void set_media_source(const MediaSource& media_source) {
+ media_source_ = media_source;
+ }
+ const MediaSource& media_source() const { return media_source_; }
+
+ void set_media_sink_id(const MediaSink::Id& media_sink_id) {
+ media_sink_id_ = media_sink_id;
+ }
+ const MediaSink::Id& media_sink_id() const { return media_sink_id_; }
+
+ void set_description(const std::string& description) {
+ description_ = description;
+ }
+
+ // TODO(kmarshall): Do we need to pass locale for bidi rendering?
+ const std::string& description() const { return description_; }
+
+ void set_local(bool is_local) { is_local_ = is_local; }
+ bool is_local() const { return is_local_; }
+
+ void set_controller_type(RouteControllerType controller_type) {
+ controller_type_ = controller_type;
+ }
+ RouteControllerType controller_type() const { return controller_type_; }
+
+ void set_for_display(bool for_display) { for_display_ = for_display; }
+ bool for_display() const { return for_display_; }
+
+ void set_incognito(bool is_incognito) { is_incognito_ = is_incognito; }
+ bool is_incognito() const { return is_incognito_; }
+
+ void set_local_presentation(bool is_local_presentation) {
+ is_local_presentation_ = is_local_presentation;
+ }
+ bool is_local_presentation() const { return is_local_presentation_; }
+
+ bool operator==(const MediaRoute& other) const;
+
+ private:
+ friend std::ostream& operator<<(std::ostream& stream,
+ const MediaRoute& route);
+
+ // The media route identifier.
+ MediaRoute::Id media_route_id_;
+
+ // The ID of the presentation that this route is associated with.
+ std::string presentation_id_;
+
+ // The media source being routed.
+ MediaSource media_source_;
+
+ // The ID of sink being routed to.
+ MediaSink::Id media_sink_id_;
+
+ // Human readable description of the casting activity. Examples:
+ // "Mirroring tab (www.example.com)", "Casting media", "Casting YouTube"
+ std::string description_;
+
+ // |true| if the route is created locally (versus discovered by a media route
+ // provider.)
+ bool is_local_ = false;
+
+ // The type of MediaRouteController supported by this route.
+ RouteControllerType controller_type_ = RouteControllerType::kNone;
+
+ // |true| if the route can be displayed in the UI.
+ bool for_display_ = false;
+
+ // |true| if the route was created by an incognito profile.
+ bool is_incognito_ = false;
+
+ // |true| if the presentation associated with this route is a local
+ // presentation.
+ bool is_local_presentation_ = false;
+};
+
+} // namespace media_router
+
+#endif // CHROME_COMMON_MEDIA_ROUTER_MEDIA_ROUTE_H_
diff --git a/chromium/chrome/common/media_router/media_route_provider_helper.cc b/chromium/chrome/common/media_router/media_route_provider_helper.cc
new file mode 100644
index 00000000000..8190e2603ec
--- /dev/null
+++ b/chromium/chrome/common/media_router/media_route_provider_helper.cc
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/media_route_provider_helper.h"
+
+#include "base/logging.h"
+
+namespace media_router {
+
+const char* ProviderIdToString(MediaRouteProviderId provider_id) {
+ switch (provider_id) {
+ case EXTENSION:
+ return "EXTENSION";
+ case WIRED_DISPLAY:
+ return "WIRED_DISPLAY";
+ case CAST:
+ return "CAST";
+ case DIAL:
+ return "DIAL";
+ case UNKNOWN:
+ return "UNKNOWN";
+ }
+
+ NOTREACHED() << "Unknown provider_id " << static_cast<int>(provider_id);
+ return "Unknown provider_id";
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/media_route_provider_helper.h b/chromium/chrome/common/media_router/media_route_provider_helper.h
new file mode 100644
index 00000000000..5f33bc6eea0
--- /dev/null
+++ b/chromium/chrome/common/media_router/media_route_provider_helper.h
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_ROUTER_MEDIA_ROUTE_PROVIDER_HELPER_H_
+#define CHROME_COMMON_MEDIA_ROUTER_MEDIA_ROUTE_PROVIDER_HELPER_H_
+
+#include <string>
+
+namespace media_router {
+
+// Each MediaRouteProvider is associated with a unique ID. This enum must be
+// kept in sync with mojom::MediaRouteProvider::Id, except for |UNKNOWN|, which
+// is not present in the Mojo enum.
+enum MediaRouteProviderId {
+ EXTENSION,
+ WIRED_DISPLAY,
+ CAST,
+ DIAL,
+ UNKNOWN // New values must be added above this value.
+};
+
+const char* ProviderIdToString(MediaRouteProviderId provider_id);
+
+} // namespace media_router
+
+#endif // CHROME_COMMON_MEDIA_ROUTER_MEDIA_ROUTE_PROVIDER_HELPER_H_
diff --git a/chromium/chrome/common/media_router/media_route_unittest.cc b/chromium/chrome/common/media_router/media_route_unittest.cc
new file mode 100644
index 00000000000..01a94be6b1e
--- /dev/null
+++ b/chromium/chrome/common/media_router/media_route_unittest.cc
@@ -0,0 +1,57 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/media_route.h"
+
+#include "chrome/common/media_router/media_sink.h"
+#include "chrome/common/media_router/media_source.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace {
+constexpr char kRouteId1[] =
+ "urn:x-org.chromium:media:route:1/cast-sink1/http://foo.com";
+constexpr char kRouteId2[] =
+ "urn:x-org.chromium:media:route:2/cast-sink2/http://foo.com";
+constexpr char kPresentationUrl[] = "http://www.example.com/presentation.html";
+} // namespace
+
+namespace media_router {
+
+TEST(MediaRouteTest, TestEquals) {
+ const MediaSource& media_source =
+ MediaSource::ForPresentationUrl(GURL(kPresentationUrl));
+ MediaRoute route1(kRouteId1, media_source, "sinkId", "Description", false,
+ false);
+
+ MediaRoute route1_copy(route1);
+ EXPECT_EQ(route1, route1_copy);
+
+ // Same as route1 with different sink ID.
+ MediaRoute route2(kRouteId1, media_source, "differentSinkId", "Description",
+ false, false);
+ EXPECT_FALSE(route1 == route2);
+
+ // Same as route1 with different description.
+ MediaRoute route3(kRouteId1, media_source, "sinkId", "differentDescription",
+ false, false);
+ EXPECT_FALSE(route1 == route3);
+
+ // Same as route1 with different is_local.
+ MediaRoute route4(kRouteId1, media_source, "sinkId", "Description", true,
+ false);
+ EXPECT_FALSE(route1 == route4);
+
+ // The ID is different from route1's.
+ MediaRoute route5(kRouteId2, media_source, "sinkId", "Description", false,
+ false);
+ EXPECT_FALSE(route1 == route5);
+
+ // Same as route1 with different incognito.
+ MediaRoute route6(kRouteId1, media_source, "sinkId", "Description", true,
+ false);
+ route6.set_incognito(true);
+ EXPECT_FALSE(route1 == route6);
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/media_sink.cc b/chromium/chrome/common/media_router/media_sink.cc
new file mode 100644
index 00000000000..36f2183d355
--- /dev/null
+++ b/chromium/chrome/common/media_router/media_sink.cc
@@ -0,0 +1,73 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/media_sink.h"
+#include "base/i18n/string_compare.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/icu/source/i18n/unicode/coll.h"
+
+namespace media_router {
+
+MediaSink::MediaSink(const MediaSink::Id& sink_id,
+ const std::string& name,
+ SinkIconType icon_type,
+ MediaRouteProviderId provider_id)
+ : sink_id_(sink_id),
+ name_(name),
+ icon_type_(icon_type),
+ provider_id_(provider_id) {}
+
+MediaSink::MediaSink(const MediaSink& other) = default;
+MediaSink::MediaSink(MediaSink&& other) noexcept = default;
+MediaSink::MediaSink() = default;
+MediaSink::~MediaSink() = default;
+
+MediaSink& MediaSink::operator=(const MediaSink& other) = default;
+MediaSink& MediaSink::operator=(MediaSink&& other) noexcept = default;
+
+bool MediaSink::IsMaybeCloudSink() const {
+ switch (icon_type_) {
+ case SinkIconType::MEETING:
+ case SinkIconType::HANGOUT:
+ case SinkIconType::EDUCATION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool MediaSink::operator==(const MediaSink& other) const {
+ return sink_id_ == other.sink_id_ && name_ == other.name_ &&
+ description_ == other.description_ && domain_ == other.domain_ &&
+ icon_type_ == other.icon_type_ && provider_id_ == other.provider_id_;
+}
+
+bool MediaSink::operator!=(const MediaSink& other) const {
+ return !operator==(other);
+}
+
+bool MediaSink::CompareUsingCollator(const MediaSink& other,
+ const icu::Collator* collator) const {
+ if (icon_type_ != other.icon_type_)
+ return icon_type_ < other.icon_type_;
+
+ if (collator) {
+ base::string16 this_name = base::UTF8ToUTF16(name_);
+ base::string16 other_name = base::UTF8ToUTF16(other.name_);
+ UCollationResult result = base::i18n::CompareString16WithCollator(
+ *collator, this_name, other_name);
+ if (result != UCOL_EQUAL)
+ return result == UCOL_LESS;
+ } else {
+ // Fall back to simple string comparison if collator is not
+ // available.
+ int val = name_.compare(other.name_);
+ if (val)
+ return val < 0;
+ }
+
+ return sink_id_ < other.sink_id_;
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/media_sink.h b/chromium/chrome/common/media_router/media_sink.h
new file mode 100644
index 00000000000..d2546249f57
--- /dev/null
+++ b/chromium/chrome/common/media_router/media_sink.h
@@ -0,0 +1,117 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_ROUTER_MEDIA_SINK_H_
+#define CHROME_COMMON_MEDIA_ROUTER_MEDIA_SINK_H_
+
+#include <string>
+
+#include "base/optional.h"
+#include "chrome/common/media_router/media_route_provider_helper.h"
+#include "third_party/icu/source/common/unicode/uversion.h"
+
+namespace U_ICU_NAMESPACE {
+class Collator;
+} // namespace U_ICU_NAMESPACE
+
+namespace media_router {
+
+// IconTypes are listed in the order in which sinks should be sorted.
+// The order must stay in sync with
+// chrome/browser/resources/media_router/media_router_data.js.
+//
+// NOTE: This enum is used for recording the MediaRouter.Sink.SelectedType
+// metrics, so if we want to reorder it, we must create a separate enum that
+// preserves the ordering, and map from this enum to the new one in
+// MediaRouterMetrics::RecordMediaSinkType().
+enum class SinkIconType {
+ CAST = 0,
+ CAST_AUDIO_GROUP = 1,
+ CAST_AUDIO = 2,
+ MEETING = 3,
+ HANGOUT = 4,
+ EDUCATION = 5,
+ WIRED_DISPLAY = 6,
+ GENERIC = 7,
+ TOTAL_COUNT = 8 // Add new types above this line.
+};
+
+// Represents a sink to which media can be routed.
+// TODO(zhaobin): convert MediaSink into a struct.
+class MediaSink {
+ public:
+ using Id = std::string;
+
+ // TODO(takumif): Remove the default argument for |provider_id|.
+ MediaSink(const MediaSink::Id& sink_id,
+ const std::string& name,
+ SinkIconType icon_type,
+ MediaRouteProviderId provider_id = MediaRouteProviderId::UNKNOWN);
+ MediaSink(const MediaSink& other);
+ MediaSink(MediaSink&& other) noexcept;
+ MediaSink();
+ ~MediaSink();
+
+ MediaSink& operator=(const MediaSink& other);
+ MediaSink& operator=(MediaSink&& other) noexcept;
+
+ void set_sink_id(const MediaSink::Id& sink_id) { sink_id_ = sink_id; }
+ const MediaSink::Id& id() const { return sink_id_; }
+
+ void set_name(const std::string& name) { name_ = name; }
+ const std::string& name() const { return name_; }
+
+ void set_description(const std::string& description) {
+ description_ = description;
+ }
+ const base::Optional<std::string>& description() const {
+ return description_;
+ }
+
+ void set_domain(const std::string& domain) { domain_ = domain; }
+ const base::Optional<std::string>& domain() const { return domain_; }
+
+ void set_icon_type(SinkIconType icon_type) { icon_type_ = icon_type; }
+ SinkIconType icon_type() const { return icon_type_; }
+
+ void set_provider_id(MediaRouteProviderId provider_id) {
+ provider_id_ = provider_id;
+ }
+ MediaRouteProviderId provider_id() const { return provider_id_; }
+
+ // Returns true if the sink is from the Cloud MRP; however, as this is based
+ // solely on the icon type, is not guaranteed to be correct 100% of the time.
+ bool IsMaybeCloudSink() const;
+
+ bool operator==(const MediaSink& other) const;
+ bool operator!=(const MediaSink& other) const;
+
+ // Compares |this| to |other| first by their icon types, then their names
+ // using |collator|, and finally their IDs.
+ bool CompareUsingCollator(const MediaSink& other,
+ const icu::Collator* collator) const;
+
+ private:
+ // Unique identifier for the MediaSink.
+ MediaSink::Id sink_id_;
+
+ // Descriptive name of the MediaSink.
+ std::string name_;
+
+ // Optional description of the MediaSink.
+ base::Optional<std::string> description_;
+
+ // Optional domain of the MediaSink.
+ base::Optional<std::string> domain_;
+
+ // The type of icon that corresponds with the MediaSink.
+ SinkIconType icon_type_ = SinkIconType::GENERIC;
+
+ // The ID of the MediaRouteProvider that the MediaSink belongs to.
+ MediaRouteProviderId provider_id_ = MediaRouteProviderId::UNKNOWN;
+};
+
+} // namespace media_router
+
+#endif // CHROME_COMMON_MEDIA_ROUTER_MEDIA_SINK_H_
diff --git a/chromium/chrome/common/media_router/media_sink_unittest.cc b/chromium/chrome/common/media_router/media_sink_unittest.cc
new file mode 100644
index 00000000000..30b5dacb32b
--- /dev/null
+++ b/chromium/chrome/common/media_router/media_sink_unittest.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 "chrome/common/media_router/media_sink.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace media_router {
+
+TEST(MediaSinkTest, IsMaybeCloudSink) {
+ MediaSink meeting("sinkId", "Sink", SinkIconType::MEETING,
+ MediaRouteProviderId::EXTENSION);
+ MediaSink eduReceiver("sinkId2", "Sink", SinkIconType::EDUCATION,
+ MediaRouteProviderId::EXTENSION);
+ MediaSink chromeCast("sinkId3", "Sink", SinkIconType::CAST,
+ MediaRouteProviderId::EXTENSION);
+
+ EXPECT_TRUE(meeting.IsMaybeCloudSink());
+ EXPECT_TRUE(eduReceiver.IsMaybeCloudSink());
+ EXPECT_FALSE(chromeCast.IsMaybeCloudSink());
+}
+
+TEST(MediaSinkTest, TestEquals) {
+ MediaSink sink1("sinkId", "Sink", SinkIconType::CAST,
+ MediaRouteProviderId::EXTENSION);
+
+ MediaSink sink1_copy(sink1);
+ EXPECT_EQ(sink1, sink1_copy);
+
+ // No name.
+ MediaSink sink2("sinkId", "", SinkIconType::CAST,
+ MediaRouteProviderId::EXTENSION);
+ EXPECT_FALSE(sink1 == sink2);
+
+ // Sink name is different from sink1's.
+ MediaSink sink3("sinkId", "Other Sink", SinkIconType::CAST,
+ MediaRouteProviderId::EXTENSION);
+ EXPECT_FALSE(sink1 == sink3);
+
+ // Sink ID is diffrent from sink1's.
+ MediaSink sink4("otherSinkId", "Sink", SinkIconType::CAST,
+ MediaRouteProviderId::EXTENSION);
+ EXPECT_FALSE(sink1 == sink4);
+
+ // Sink icon type is diffrent from sink1's.
+ MediaSink sink5("otherSinkId", "Sink", SinkIconType::GENERIC,
+ MediaRouteProviderId::EXTENSION);
+ EXPECT_FALSE(sink1 == sink5);
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/media_source.cc b/chromium/chrome/common/media_router/media_source.cc
new file mode 100644
index 00000000000..dbad598d35f
--- /dev/null
+++ b/chromium/chrome/common/media_router/media_source.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 "chrome/common/media_router/media_source.h"
+
+#include <algorithm>
+#include <array>
+#include <cstdio>
+#include <ostream>
+#include <string>
+
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/common/media_router/media_source.h"
+#include "url/gurl.h"
+
+namespace media_router {
+
+namespace {
+
+// Prefixes used to format and detect various protocols' media source URNs.
+// See: https://www.ietf.org/rfc/rfc3406.txt
+constexpr char kTabMediaUrnFormat[] = "urn:x-org.chromium.media:source:tab:%d";
+constexpr char kDesktopMediaUrn[] = "urn:x-org.chromium.media:source:desktop";
+constexpr char kTabRemotingUrnFormat[] =
+ "urn:x-org.chromium.media:source:tab_content_remoting:%d";
+
+// List of non-http(s) schemes that are allowed in a Presentation URL.
+constexpr std::array<const char* const, 5> kAllowedSchemes{
+ {kCastPresentationUrlScheme, kCastDialPresentationUrlScheme,
+ kDialPresentationUrlScheme, kRemotePlaybackPresentationUrlScheme, "test"}};
+
+bool IsSchemeAllowed(const GURL& url) {
+ return url.SchemeIsHTTPOrHTTPS() ||
+ std::any_of(
+ kAllowedSchemes.begin(), kAllowedSchemes.end(),
+ [&url](const char* const scheme) { return url.SchemeIs(scheme); });
+}
+
+} // namespace
+
+bool IsLegacyCastPresentationUrl(const GURL& url) {
+ return base::StartsWith(url.spec(), kLegacyCastPresentationUrlPrefix,
+ base::CompareCase::INSENSITIVE_ASCII);
+}
+
+bool IsValidPresentationUrl(const GURL& url) {
+ return url.is_valid() && IsSchemeAllowed(url);
+}
+
+bool IsAutoJoinPresentationId(const std::string& presentation_id) {
+ return presentation_id == kAutoJoinPresentationId;
+}
+
+MediaSource::MediaSource() = default;
+
+MediaSource::MediaSource(const MediaSource::Id& source_id) : id_(source_id) {
+ GURL url(source_id);
+ if (IsValidPresentationUrl(url))
+ url_ = url;
+}
+
+MediaSource::MediaSource(const GURL& presentation_url)
+ : id_(presentation_url.spec()), url_(presentation_url) {}
+
+MediaSource::~MediaSource() = default;
+
+// static
+MediaSource MediaSource::ForTab(int tab_id) {
+ return MediaSource(base::StringPrintf(kTabMediaUrnFormat, tab_id));
+}
+
+// static
+MediaSource MediaSource::ForTabContentRemoting(int tab_id) {
+ return MediaSource(base::StringPrintf(kTabRemotingUrnFormat, tab_id));
+}
+
+// static
+MediaSource MediaSource::ForDesktop() {
+ return MediaSource(std::string(kDesktopMediaUrn));
+}
+
+// static
+MediaSource MediaSource::ForPresentationUrl(const GURL& presentation_url) {
+ return MediaSource(presentation_url);
+}
+
+bool MediaSource::IsDesktopMirroringSource() const {
+ return base::StartsWith(id(), kDesktopMediaUrn, base::CompareCase::SENSITIVE);
+}
+
+bool MediaSource::IsTabMirroringSource() const {
+ int tab_id;
+ return std::sscanf(id_.c_str(), kTabMediaUrnFormat, &tab_id) == 1 &&
+ tab_id > 0;
+}
+
+bool MediaSource::IsMirroringSource() const {
+ return IsDesktopMirroringSource() || IsTabMirroringSource();
+}
+
+bool MediaSource::IsCastPresentationUrl() const {
+ return url_.SchemeIs(kCastPresentationUrlScheme) ||
+ IsLegacyCastPresentationUrl(url_);
+}
+
+int MediaSource::TabId() const {
+ int tab_id;
+ if (sscanf(id_.c_str(), kTabMediaUrnFormat, &tab_id) == 1)
+ return tab_id;
+ else if (sscanf(id_.c_str(), kTabRemotingUrnFormat, &tab_id) == 1)
+ return tab_id;
+ else
+ return -1;
+}
+
+bool MediaSource::IsValid() const {
+ return TabId() > 0 || IsDesktopMirroringSource() ||
+ IsValidPresentationUrl(GURL(id_));
+}
+
+bool MediaSource::IsDialSource() const {
+ return url_.SchemeIs(kCastDialPresentationUrlScheme);
+}
+
+std::string MediaSource::AppNameFromDialSource() const {
+ return IsDialSource() ? url_.path() : "";
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/media_source.h b/chromium/chrome/common/media_router/media_source.h
new file mode 100644
index 00000000000..15fd6fd0590
--- /dev/null
+++ b/chromium/chrome/common/media_router/media_source.h
@@ -0,0 +1,122 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_ROUTER_MEDIA_SOURCE_H_
+#define CHROME_COMMON_MEDIA_ROUTER_MEDIA_SOURCE_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "base/hash/hash.h"
+#include "url/gurl.h"
+
+namespace media_router {
+
+// URL schemes used by Presentation URLs for Cast and DIAL.
+constexpr char kCastPresentationUrlScheme[] = "cast";
+constexpr char kCastDialPresentationUrlScheme[] = "cast-dial";
+constexpr char kDialPresentationUrlScheme[] = "dial";
+constexpr char kRemotePlaybackPresentationUrlScheme[] = "remote-playback";
+
+// URL prefix used by legacy Cast presentations.
+constexpr char kLegacyCastPresentationUrlPrefix[] =
+ "https://google.com/cast#__castAppId__=";
+
+// Strings used in presentation IDs by the Cast SDK implementation.
+// TODO(takumif): Move them out of this file, since they are not directly
+// related to MediaSource.
+//
+// This value must be the same as |chrome.cast.AUTO_JOIN_PRESENTATION_ID| in the
+// component extension.
+constexpr char kAutoJoinPresentationId[] = "auto-join";
+// This value must be the same as |chrome.cast.PRESENTATION_ID_PREFIX| in the
+// component extension.
+constexpr char kCastPresentationIdPrefix[] = "cast-session_";
+
+// Returns true if |url| represents a legacy Cast presentation URL, i.e., it
+// starts with |kLegacyCastPresentationUrlPrefix|.
+bool IsLegacyCastPresentationUrl(const GURL& url);
+
+// Returns true if |url| is a valid presentation URL.
+bool IsValidPresentationUrl(const GURL& url);
+
+// Returns true if |presentation_id| is an ID used by auto-join requests.
+bool IsAutoJoinPresentationId(const std::string& presentation_id);
+
+class MediaSource {
+ public:
+ using Id = std::string;
+
+ MediaSource();
+ explicit MediaSource(const MediaSource::Id& id);
+ explicit MediaSource(const GURL& presentation_url);
+ ~MediaSource();
+
+ // Gets the ID of the media source.
+ const Id& id() const { return id_; }
+
+ // If MediaSource is created from a URL, return the URL; otherwise return an
+ // empty GURL.
+ const GURL& url() const { return url_; }
+
+ // Returns true if two MediaSource objects use the same media ID.
+ bool operator==(const MediaSource& other) const { return id_ == other.id(); }
+
+ bool operator<(const MediaSource& other) const { return id_ < other.id(); }
+
+ // Hash operator for hash containers.
+ struct Hash {
+ uint32_t operator()(const MediaSource& source) const {
+ return base::Hash(source.id());
+ }
+ };
+
+ // Protocol-specific media source object creation.
+ // Returns MediaSource URI depending on the type of source.
+ static MediaSource ForTab(int tab_id);
+ static MediaSource ForTabContentRemoting(int tab_id);
+ static MediaSource ForDesktop();
+ static MediaSource ForPresentationUrl(const GURL& presentation_url);
+
+ // Returns true if source outputs its content via mirroring.
+ bool IsDesktopMirroringSource() const;
+ bool IsTabMirroringSource() const;
+ bool IsMirroringSource() const;
+
+ // Returns true if this is represents a Cast Presentation URL.
+ bool IsCastPresentationUrl() const;
+
+ // Parses the ID and returns the SessionTabHelper tab ID referencing a source
+ // tab. Returns a non-positive value on error.
+ int TabId() const;
+
+ // Checks that this is a parseable URN and is of a known type.
+ // Does not deeper protocol-level syntax checks.
+ bool IsValid() const;
+
+ // Returns true this source outputs its content via DIAL.
+ // TODO(crbug.com/804419): Move this to in-browser DIAL/Cast MRP when we have
+ // one.
+ bool IsDialSource() const;
+
+ // Returns empty string if this source is not DIAL media source, or is not a
+ // valid DIAL media source.
+ std::string AppNameFromDialSource() const;
+
+ private:
+ MediaSource::Id id_;
+ GURL url_;
+};
+
+// Only for debug logging. This operator is defined inline so it doesn't add
+// any code in release builds. (Omitting the definition entirely when NDEBUG is
+// defined causes linker errors on Android.)
+inline std::ostream& operator<<(std::ostream& stream,
+ const MediaSource& source) {
+ return stream << "MediaSource[" << source.id() << "]";
+}
+
+} // namespace media_router
+
+#endif // CHROME_COMMON_MEDIA_ROUTER_MEDIA_SOURCE_H_
diff --git a/chromium/chrome/common/media_router/media_source_unittest.cc b/chromium/chrome/common/media_router/media_source_unittest.cc
new file mode 100644
index 00000000000..7bb4dff686c
--- /dev/null
+++ b/chromium/chrome/common/media_router/media_source_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/media_source.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media_router {
+
+TEST(MediaSourceTest, IsLegacyCastPresentationUrl) {
+ EXPECT_TRUE(IsLegacyCastPresentationUrl(
+ GURL("https://google.com/cast#__castAppId__=theAppId")));
+ EXPECT_TRUE(IsLegacyCastPresentationUrl(
+ GURL("HTTPS://GOOGLE.COM/CAST#__CASTAPPID__=theAppId")));
+ EXPECT_FALSE(IsLegacyCastPresentationUrl(
+ GURL("https://google.com/cast#__castAppId__")));
+}
+
+TEST(MediaSourceTest, IsValidPresentationUrl) {
+ EXPECT_FALSE(IsValidPresentationUrl(GURL()));
+ EXPECT_FALSE(IsValidPresentationUrl(GURL("unsupported-scheme://foo")));
+
+ EXPECT_TRUE(IsValidPresentationUrl(GURL("https://google.com")));
+ EXPECT_TRUE(IsValidPresentationUrl(GURL("cast://foo")));
+ EXPECT_TRUE(IsValidPresentationUrl(GURL("cast:foo")));
+}
+
+TEST(MediaSourceTest, IsAutoJoinPresentationId) {
+ EXPECT_TRUE(IsAutoJoinPresentationId("auto-join"));
+ EXPECT_FALSE(IsAutoJoinPresentationId("not-auto-join"));
+}
+
+TEST(MediaSourceTest, Constructor) {
+ // Test that the object's getters match the constructor parameters.
+ MediaSource source1("urn:x-com.google.cast:application:DEADBEEF");
+ EXPECT_EQ("urn:x-com.google.cast:application:DEADBEEF", source1.id());
+ EXPECT_EQ(GURL(""), source1.url());
+}
+
+TEST(MediaSourceTest, ConstructorWithGURL) {
+ GURL test_url = GURL("http://google.com");
+ MediaSource source1(test_url);
+ EXPECT_EQ(test_url.spec(), source1.id());
+ EXPECT_EQ(test_url, source1.url());
+}
+
+TEST(MediaSourceTest, ConstructorWithURLString) {
+ GURL test_url = GURL("http://google.com");
+ MediaSource source1(test_url.spec());
+ EXPECT_EQ(test_url.spec(), source1.id());
+ EXPECT_EQ(test_url, source1.url());
+}
+
+TEST(MediaSourceTest, ForTab) {
+ auto source = MediaSource::ForTab(123);
+ EXPECT_EQ("urn:x-org.chromium.media:source:tab:123", source.id());
+ EXPECT_EQ(123, source.TabId());
+ EXPECT_TRUE(source.IsValid());
+ EXPECT_FALSE(source.IsDesktopMirroringSource());
+ EXPECT_TRUE(source.IsTabMirroringSource());
+ EXPECT_TRUE(source.IsMirroringSource());
+ EXPECT_FALSE(source.IsCastPresentationUrl());
+ EXPECT_FALSE(source.IsDialSource());
+}
+
+TEST(MediaSourceTest, ForTabContentRemoting) {
+ auto source = MediaSource::ForTabContentRemoting(123);
+ EXPECT_EQ(123, source.TabId());
+ EXPECT_TRUE(source.IsValid());
+ EXPECT_FALSE(source.IsDesktopMirroringSource());
+ EXPECT_FALSE(source.IsTabMirroringSource());
+ EXPECT_FALSE(source.IsMirroringSource());
+ EXPECT_FALSE(source.IsCastPresentationUrl());
+ EXPECT_FALSE(source.IsDialSource());
+}
+
+TEST(MediaSourceTest, ForDesktop) {
+ auto source = MediaSource::ForDesktop();
+ EXPECT_EQ("urn:x-org.chromium.media:source:desktop", source.id());
+ EXPECT_TRUE(source.IsValid());
+ EXPECT_TRUE(source.IsDesktopMirroringSource());
+ EXPECT_FALSE(source.IsTabMirroringSource());
+ EXPECT_TRUE(source.IsMirroringSource());
+ EXPECT_FALSE(source.IsCastPresentationUrl());
+ EXPECT_FALSE(source.IsDialSource());
+}
+
+TEST(MediaSourceTest, ForPresentationUrl) {
+ constexpr char kPresentationUrl[] =
+ "https://www.example.com/presentation.html";
+ auto source = MediaSource::ForPresentationUrl(GURL(kPresentationUrl));
+ EXPECT_EQ(kPresentationUrl, source.id());
+ EXPECT_TRUE(source.IsValid());
+ EXPECT_FALSE(source.IsDesktopMirroringSource());
+ EXPECT_FALSE(source.IsTabMirroringSource());
+ EXPECT_FALSE(source.IsMirroringSource());
+ EXPECT_FALSE(source.IsCastPresentationUrl());
+ EXPECT_FALSE(source.IsDialSource());
+}
+
+TEST(MediaSourceTest, IsValid) {
+ // Disallowed scheme
+ EXPECT_FALSE(MediaSource::ForPresentationUrl(GURL("file:///some/local/path"))
+ .IsValid());
+ // Not a URL
+ EXPECT_FALSE(
+ MediaSource::ForPresentationUrl(GURL("totally not a url")).IsValid());
+}
+
+TEST(MediaSourceTest, IsCastPresentationUrl) {
+ EXPECT_TRUE(MediaSource(GURL("cast:233637DE")).IsCastPresentationUrl());
+ EXPECT_TRUE(
+ MediaSource(GURL("https://google.com/cast#__castAppId__=233637DE"))
+ .IsCastPresentationUrl());
+ // false scheme
+ EXPECT_FALSE(
+ MediaSource(GURL("http://google.com/cast#__castAppId__=233637DE"))
+ .IsCastPresentationUrl());
+ // false domain
+ EXPECT_FALSE(
+ MediaSource(GURL("https://google2.com/cast#__castAppId__=233637DE"))
+ .IsCastPresentationUrl());
+ // empty path
+ EXPECT_FALSE(
+ MediaSource(GURL("https://www.google.com")).IsCastPresentationUrl());
+ // false path
+ EXPECT_FALSE(
+ MediaSource(GURL("https://www.google.com/path")).IsCastPresentationUrl());
+
+ EXPECT_FALSE(MediaSource(GURL("")).IsCastPresentationUrl());
+}
+
+TEST(MediaSourceTest, IsDialSource) {
+ EXPECT_TRUE(
+ MediaSource("cast-dial:YouTube?dialPostData=postData&clientId=1234")
+ .IsDialSource());
+ // false scheme
+ EXPECT_FALSE(MediaSource("https://google.com/cast#__castAppId__=233637DE")
+ .IsDialSource());
+}
+
+TEST(MediaSourceTest, AppNameFromDialSource) {
+ MediaSource media_source(
+ "cast-dial:YouTube?dialPostData=postData&clientId=1234");
+ EXPECT_EQ("YouTube", media_source.AppNameFromDialSource());
+
+ media_source = MediaSource("dial:YouTube");
+ EXPECT_TRUE(media_source.AppNameFromDialSource().empty());
+
+ media_source = MediaSource("https://google.com/cast#__castAppId__=233637DE");
+ EXPECT_TRUE(media_source.AppNameFromDialSource().empty());
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/mojom/OWNERS b/chromium/chrome/common/media_router/mojom/OWNERS
new file mode 100644
index 00000000000..ae29a36aac8
--- /dev/null
+++ b/chromium/chrome/common/media_router/mojom/OWNERS
@@ -0,0 +1,6 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/chrome/common/media_router/mojom/media_router_mojom_traits.cc b/chromium/chrome/common/media_router/mojom/media_router_mojom_traits.cc
new file mode 100644
index 00000000000..d6b4a10a932
--- /dev/null
+++ b/chromium/chrome/common/media_router/mojom/media_router_mojom_traits.cc
@@ -0,0 +1,226 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/mojom/media_router_mojom_traits.h"
+
+#include "chrome/common/media_router/media_source.h"
+#include "services/network/public/cpp/ip_address_mojom_traits.h"
+#include "services/network/public/cpp/ip_endpoint_mojom_traits.h"
+#include "url/mojom/url_gurl_mojom_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<media_router::mojom::IssueDataView, media_router::IssueInfo>::
+ Read(media_router::mojom::IssueDataView data,
+ media_router::IssueInfo* out) {
+ if (!data.ReadTitle(&out->title))
+ return false;
+
+ if (!data.ReadDefaultAction(&out->default_action))
+ return false;
+
+ if (!data.ReadSeverity(&out->severity))
+ return false;
+
+ base::Optional<std::string> message;
+ if (!data.ReadMessage(&message))
+ return false;
+
+ out->message = message.value_or(std::string());
+
+ if (!data.ReadSecondaryActions(&out->secondary_actions))
+ return false;
+
+ if (!data.ReadRouteId(&out->route_id))
+ return false;
+
+ if (!data.ReadSinkId(&out->sink_id))
+ return false;
+
+ out->is_blocking = data.is_blocking();
+ out->help_page_id = data.help_page_id();
+
+ return true;
+}
+
+// static
+media_router::mojom::MediaSinkExtraDataDataView::Tag
+UnionTraits<media_router::mojom::MediaSinkExtraDataDataView,
+ media_router::MediaSinkInternal>::
+ GetTag(const media_router::MediaSinkInternal& sink) {
+ if (sink.is_dial_sink()) {
+ return media_router::mojom::MediaSinkExtraDataDataView::Tag::
+ DIAL_MEDIA_SINK;
+ } else if (sink.is_cast_sink()) {
+ return media_router::mojom::MediaSinkExtraDataDataView::Tag::
+ CAST_MEDIA_SINK;
+ }
+ NOTREACHED();
+ return media_router::mojom::MediaSinkExtraDataDataView::Tag::CAST_MEDIA_SINK;
+}
+
+// static
+bool StructTraits<media_router::mojom::MediaSinkDataView,
+ media_router::MediaSinkInternal>::
+ Read(media_router::mojom::MediaSinkDataView data,
+ media_router::MediaSinkInternal* out) {
+ media_router::MediaSink::Id id;
+ if (!data.ReadSinkId(&id) ||
+ !media_router::MediaSinkInternal::IsValidSinkId(id)) {
+ return false;
+ }
+
+ out->sink().set_sink_id(id);
+
+ std::string name;
+ if (!data.ReadName(&name))
+ return false;
+
+ out->sink().set_name(name);
+
+ base::Optional<std::string> description;
+ if (!data.ReadDescription(&description))
+ return false;
+
+ if (description)
+ out->sink().set_description(*description);
+
+ base::Optional<std::string> domain;
+ if (!data.ReadDomain(&domain))
+ return false;
+
+ if (domain)
+ out->sink().set_domain(*domain);
+
+ media_router::SinkIconType icon_type;
+ if (!data.ReadIconType(&icon_type))
+ return false;
+
+ out->sink().set_icon_type(icon_type);
+
+ media_router::MediaRouteProviderId provider_id;
+ if (!data.ReadProviderId(&provider_id))
+ return false;
+
+ out->sink().set_provider_id(provider_id);
+
+ if (!data.ReadExtraData(out))
+ return false;
+
+ return true;
+}
+
+// static
+bool UnionTraits<media_router::mojom::MediaSinkExtraDataDataView,
+ media_router::MediaSinkInternal>::
+ Read(media_router::mojom::MediaSinkExtraDataDataView data,
+ media_router::MediaSinkInternal* out) {
+ switch (data.tag()) {
+ case media_router::mojom::MediaSinkExtraDataDataView::Tag::
+ DIAL_MEDIA_SINK: {
+ media_router::DialSinkExtraData extra_data;
+ if (!data.ReadDialMediaSink(&extra_data))
+ return false;
+ out->set_dial_data(extra_data);
+ return true;
+ }
+ case media_router::mojom::MediaSinkExtraDataDataView::Tag::
+ CAST_MEDIA_SINK: {
+ media_router::CastSinkExtraData extra_data;
+ if (!data.ReadCastMediaSink(&extra_data))
+ return false;
+ out->set_cast_data(extra_data);
+ return true;
+ }
+ }
+ NOTREACHED();
+ return false;
+}
+
+// static
+bool StructTraits<media_router::mojom::DialMediaSinkDataView,
+ media_router::DialSinkExtraData>::
+ Read(media_router::mojom::DialMediaSinkDataView data,
+ media_router::DialSinkExtraData* out) {
+ if (!data.ReadIpAddress(&out->ip_address))
+ return false;
+
+ if (!data.ReadModelName(&out->model_name))
+ return false;
+
+ if (!data.ReadAppUrl(&out->app_url))
+ return false;
+
+ return true;
+}
+
+// static
+bool StructTraits<media_router::mojom::CastMediaSinkDataView,
+ media_router::CastSinkExtraData>::
+ Read(media_router::mojom::CastMediaSinkDataView data,
+ media_router::CastSinkExtraData* out) {
+ if (!data.ReadIpEndpoint(&out->ip_endpoint))
+ return false;
+
+ if (!data.ReadModelName(&out->model_name))
+ return false;
+
+ out->capabilities = data.capabilities();
+ out->cast_channel_id = data.cast_channel_id();
+
+ return true;
+}
+
+// static
+bool StructTraits<media_router::mojom::MediaRouteDataView,
+ media_router::MediaRoute>::
+ Read(media_router::mojom::MediaRouteDataView data,
+ media_router::MediaRoute* out) {
+ media_router::MediaRoute::Id media_route_id;
+ if (!data.ReadMediaRouteId(&media_route_id))
+ return false;
+
+ out->set_media_route_id(media_route_id);
+
+ std::string presentation_id;
+ if (!data.ReadPresentationId(&presentation_id))
+ return false;
+
+ out->set_presentation_id(presentation_id);
+
+ base::Optional<media_router::MediaSource::Id> media_source_id;
+ if (!data.ReadMediaSource(&media_source_id))
+ return false;
+
+ if (media_source_id)
+ out->set_media_source(media_router::MediaSource(*media_source_id));
+
+ media_router::MediaSink::Id media_sink_id;
+ if (!data.ReadMediaSinkId(&media_sink_id))
+ return false;
+
+ out->set_media_sink_id(media_sink_id);
+
+ std::string description;
+ if (!data.ReadDescription(&description))
+ return false;
+
+ out->set_description(description);
+
+ media_router::RouteControllerType controller_type;
+ if (!data.ReadControllerType(&controller_type))
+ return false;
+
+ out->set_controller_type(controller_type);
+
+ out->set_local(data.is_local());
+ out->set_for_display(data.for_display());
+ out->set_incognito(data.is_incognito());
+ out->set_local_presentation(data.is_local_presentation());
+
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/chrome/common/media_router/mojom/media_router_mojom_traits.h b/chromium/chrome/common/media_router/mojom/media_router_mojom_traits.h
new file mode 100644
index 00000000000..21e06d7c8fe
--- /dev/null
+++ b/chromium/chrome/common/media_router/mojom/media_router_mojom_traits.h
@@ -0,0 +1,525 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_ROUTER_MOJOM_MEDIA_ROUTER_MOJOM_TRAITS_H_
+#define CHROME_COMMON_MEDIA_ROUTER_MOJOM_MEDIA_ROUTER_MOJOM_TRAITS_H_
+
+#include <string>
+
+#include "chrome/common/media_router/discovery/media_sink_internal.h"
+#include "chrome/common/media_router/issue.h"
+#include "chrome/common/media_router/mojom/media_router.mojom.h"
+#include "chrome/common/media_router/route_request_result.h"
+#include "net/base/ip_endpoint.h"
+
+namespace mojo {
+
+// Issue
+
+template <>
+struct EnumTraits<media_router::mojom::Issue::ActionType,
+ media_router::IssueInfo::Action> {
+ static media_router::mojom::Issue::ActionType ToMojom(
+ media_router::IssueInfo::Action action) {
+ switch (action) {
+ case media_router::IssueInfo::Action::DISMISS:
+ return media_router::mojom::Issue::ActionType::DISMISS;
+ case media_router::IssueInfo::Action::LEARN_MORE:
+ return media_router::mojom::Issue::ActionType::LEARN_MORE;
+ }
+ NOTREACHED() << "Unknown issue action type " << static_cast<int>(action);
+ return media_router::mojom::Issue::ActionType::DISMISS;
+ }
+
+ static bool FromMojom(media_router::mojom::Issue::ActionType input,
+ media_router::IssueInfo::Action* output) {
+ switch (input) {
+ case media_router::mojom::Issue::ActionType::DISMISS:
+ *output = media_router::IssueInfo::Action::DISMISS;
+ return true;
+ case media_router::mojom::Issue::ActionType::LEARN_MORE:
+ *output = media_router::IssueInfo::Action::LEARN_MORE;
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct EnumTraits<media_router::mojom::Issue::Severity,
+ media_router::IssueInfo::Severity> {
+ static media_router::mojom::Issue::Severity ToMojom(
+ media_router::IssueInfo::Severity severity) {
+ switch (severity) {
+ case media_router::IssueInfo::Severity::FATAL:
+ return media_router::mojom::Issue::Severity::FATAL;
+ case media_router::IssueInfo::Severity::WARNING:
+ return media_router::mojom::Issue::Severity::WARNING;
+ case media_router::IssueInfo::Severity::NOTIFICATION:
+ return media_router::mojom::Issue::Severity::NOTIFICATION;
+ }
+ NOTREACHED() << "Unknown issue severity " << static_cast<int>(severity);
+ return media_router::mojom::Issue::Severity::WARNING;
+ }
+
+ static bool FromMojom(media_router::mojom::Issue::Severity input,
+ media_router::IssueInfo::Severity* output) {
+ switch (input) {
+ case media_router::mojom::Issue::Severity::FATAL:
+ *output = media_router::IssueInfo::Severity::FATAL;
+ return true;
+ case media_router::mojom::Issue::Severity::WARNING:
+ *output = media_router::IssueInfo::Severity::WARNING;
+ return true;
+ case media_router::mojom::Issue::Severity::NOTIFICATION:
+ *output = media_router::IssueInfo::Severity::NOTIFICATION;
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct UnionTraits<media_router::mojom::MediaSinkExtraDataDataView,
+ media_router::MediaSinkInternal> {
+ static media_router::mojom::MediaSinkExtraDataDataView::Tag GetTag(
+ const media_router::MediaSinkInternal& sink);
+
+ static bool IsNull(const media_router::MediaSinkInternal& sink) {
+ return !sink.is_cast_sink() && !sink.is_dial_sink();
+ }
+
+ static void SetToNull(media_router::MediaSinkInternal* out) {}
+
+ static const media_router::DialSinkExtraData& dial_media_sink(
+ const media_router::MediaSinkInternal& sink) {
+ return sink.dial_data();
+ }
+
+ static const media_router::CastSinkExtraData& cast_media_sink(
+ const media_router::MediaSinkInternal& sink) {
+ return sink.cast_data();
+ }
+
+ static bool Read(media_router::mojom::MediaSinkExtraDataDataView data,
+ media_router::MediaSinkInternal* out);
+};
+
+template <>
+struct StructTraits<media_router::mojom::DialMediaSinkDataView,
+ media_router::DialSinkExtraData> {
+ static const std::string& model_name(
+ const media_router::DialSinkExtraData& extra_data) {
+ return extra_data.model_name;
+ }
+
+ static const net::IPAddress& ip_address(
+ const media_router::DialSinkExtraData& extra_data) {
+ return extra_data.ip_address;
+ }
+
+ static const GURL& app_url(
+ const media_router::DialSinkExtraData& extra_data) {
+ return extra_data.app_url;
+ }
+
+ static bool Read(media_router::mojom::DialMediaSinkDataView data,
+ media_router::DialSinkExtraData* out);
+};
+
+template <>
+struct StructTraits<media_router::mojom::CastMediaSinkDataView,
+ media_router::CastSinkExtraData> {
+ static const std::string& model_name(
+ const media_router::CastSinkExtraData& extra_data) {
+ return extra_data.model_name;
+ }
+
+ static const net::IPEndPoint& ip_endpoint(
+ const media_router::CastSinkExtraData& extra_data) {
+ return extra_data.ip_endpoint;
+ }
+
+ static uint8_t capabilities(
+ const media_router::CastSinkExtraData& extra_data) {
+ return extra_data.capabilities;
+ }
+
+ static int32_t cast_channel_id(
+ const media_router::CastSinkExtraData& extra_data) {
+ return extra_data.cast_channel_id;
+ }
+
+ static bool Read(media_router::mojom::CastMediaSinkDataView data,
+ media_router::CastSinkExtraData* out);
+};
+
+template <>
+struct StructTraits<media_router::mojom::IssueDataView,
+ media_router::IssueInfo> {
+ static bool Read(media_router::mojom::IssueDataView data,
+ media_router::IssueInfo* out);
+
+ static const std::string& route_id(const media_router::IssueInfo& issue) {
+ return issue.route_id;
+ }
+
+ static const std::string& sink_id(const media_router::IssueInfo& issue) {
+ return issue.sink_id;
+ }
+
+ static media_router::IssueInfo::Severity severity(
+ const media_router::IssueInfo& issue) {
+ return issue.severity;
+ }
+
+ static bool is_blocking(const media_router::IssueInfo& issue) {
+ return issue.is_blocking;
+ }
+
+ static const std::string& title(const media_router::IssueInfo& issue) {
+ return issue.title;
+ }
+
+ static const std::string& message(const media_router::IssueInfo& issue) {
+ return issue.message;
+ }
+
+ static media_router::IssueInfo::Action default_action(
+ const media_router::IssueInfo& issue) {
+ return issue.default_action;
+ }
+
+ static const std::vector<media_router::IssueInfo::Action>& secondary_actions(
+ const media_router::IssueInfo& issue) {
+ return issue.secondary_actions;
+ }
+
+ static int32_t help_page_id(const media_router::IssueInfo& issue) {
+ return issue.help_page_id;
+ }
+};
+
+// MediaSink
+
+template <>
+struct EnumTraits<media_router::mojom::SinkIconType,
+ media_router::SinkIconType> {
+ static media_router::mojom::SinkIconType ToMojom(
+ media_router::SinkIconType icon_type) {
+ switch (icon_type) {
+ case media_router::SinkIconType::CAST:
+ return media_router::mojom::SinkIconType::CAST;
+ case media_router::SinkIconType::CAST_AUDIO_GROUP:
+ return media_router::mojom::SinkIconType::CAST_AUDIO_GROUP;
+ case media_router::SinkIconType::CAST_AUDIO:
+ return media_router::mojom::SinkIconType::CAST_AUDIO;
+ case media_router::SinkIconType::MEETING:
+ return media_router::mojom::SinkIconType::MEETING;
+ case media_router::SinkIconType::HANGOUT:
+ return media_router::mojom::SinkIconType::HANGOUT;
+ case media_router::SinkIconType::EDUCATION:
+ return media_router::mojom::SinkIconType::EDUCATION;
+ case media_router::SinkIconType::WIRED_DISPLAY:
+ return media_router::mojom::SinkIconType::WIRED_DISPLAY;
+ case media_router::SinkIconType::GENERIC:
+ return media_router::mojom::SinkIconType::GENERIC;
+ case media_router::SinkIconType::TOTAL_COUNT:
+ break;
+ }
+ NOTREACHED() << "Unknown sink icon type " << static_cast<int>(icon_type);
+ return media_router::mojom::SinkIconType::GENERIC;
+ }
+
+ static bool FromMojom(media_router::mojom::SinkIconType input,
+ media_router::SinkIconType* output) {
+ switch (input) {
+ case media_router::mojom::SinkIconType::CAST:
+ *output = media_router::SinkIconType::CAST;
+ return true;
+ case media_router::mojom::SinkIconType::CAST_AUDIO_GROUP:
+ *output = media_router::SinkIconType::CAST_AUDIO_GROUP;
+ return true;
+ case media_router::mojom::SinkIconType::CAST_AUDIO:
+ *output = media_router::SinkIconType::CAST_AUDIO;
+ return true;
+ case media_router::mojom::SinkIconType::MEETING:
+ *output = media_router::SinkIconType::MEETING;
+ return true;
+ case media_router::mojom::SinkIconType::HANGOUT:
+ *output = media_router::SinkIconType::HANGOUT;
+ return true;
+ case media_router::mojom::SinkIconType::EDUCATION:
+ *output = media_router::SinkIconType::EDUCATION;
+ return true;
+ case media_router::mojom::SinkIconType::WIRED_DISPLAY:
+ *output = media_router::SinkIconType::WIRED_DISPLAY;
+ return true;
+ case media_router::mojom::SinkIconType::GENERIC:
+ *output = media_router::SinkIconType::GENERIC;
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct StructTraits<media_router::mojom::MediaSinkDataView,
+ media_router::MediaSinkInternal> {
+ static bool Read(media_router::mojom::MediaSinkDataView data,
+ media_router::MediaSinkInternal* out);
+
+ static const std::string& sink_id(
+ const media_router::MediaSinkInternal& sink_internal) {
+ return sink_internal.sink().id();
+ }
+
+ static const std::string& name(
+ const media_router::MediaSinkInternal& sink_internal) {
+ return sink_internal.sink().name();
+ }
+
+ static const base::Optional<std::string>& description(
+ const media_router::MediaSinkInternal& sink_internal) {
+ return sink_internal.sink().description();
+ }
+
+ static const base::Optional<std::string>& domain(
+ const media_router::MediaSinkInternal& sink_internal) {
+ return sink_internal.sink().domain();
+ }
+
+ static media_router::SinkIconType icon_type(
+ const media_router::MediaSinkInternal& sink_internal) {
+ return sink_internal.sink().icon_type();
+ }
+
+ static media_router::MediaRouteProviderId provider_id(
+ const media_router::MediaSinkInternal& sink_internal) {
+ return sink_internal.sink().provider_id();
+ }
+
+ static const media_router::MediaSinkInternal& extra_data(
+ const media_router::MediaSinkInternal& sink_internal) {
+ return sink_internal;
+ }
+};
+
+// MediaRoute
+
+template <>
+struct EnumTraits<media_router::mojom::RouteControllerType,
+ media_router::RouteControllerType> {
+ static media_router::mojom::RouteControllerType ToMojom(
+ media_router::RouteControllerType controller_type) {
+ switch (controller_type) {
+ case media_router::RouteControllerType::kNone:
+ return media_router::mojom::RouteControllerType::kNone;
+ case media_router::RouteControllerType::kGeneric:
+ return media_router::mojom::RouteControllerType::kGeneric;
+ case media_router::RouteControllerType::kMirroring:
+ return media_router::mojom::RouteControllerType::kMirroring;
+ }
+ NOTREACHED() << "Unknown controller type "
+ << static_cast<int>(controller_type);
+ return media_router::mojom::RouteControllerType::kNone;
+ }
+
+ static bool FromMojom(media_router::mojom::RouteControllerType input,
+ media_router::RouteControllerType* output) {
+ switch (input) {
+ case media_router::mojom::RouteControllerType::kNone:
+ *output = media_router::RouteControllerType::kNone;
+ return true;
+ case media_router::mojom::RouteControllerType::kGeneric:
+ *output = media_router::RouteControllerType::kGeneric;
+ return true;
+ case media_router::mojom::RouteControllerType::kMirroring:
+ *output = media_router::RouteControllerType::kMirroring;
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct StructTraits<media_router::mojom::MediaRouteDataView,
+ media_router::MediaRoute> {
+ static bool Read(media_router::mojom::MediaRouteDataView data,
+ media_router::MediaRoute* out);
+
+ static const std::string& media_route_id(
+ const media_router::MediaRoute& route) {
+ return route.media_route_id();
+ }
+
+ static const std::string& presentation_id(
+ const media_router::MediaRoute& route) {
+ return route.presentation_id();
+ }
+
+ static base::Optional<std::string> media_source(
+ const media_router::MediaRoute& route) {
+ // TODO(imcheng): If we ever convert from C++ to Mojo outside of unit tests,
+ // it would be better to make the |media_source_| field on MediaRoute a
+ // base::Optional<MediaSource::Id> instead so it can be returned directly
+ // here.
+ return route.media_source().id().empty()
+ ? base::Optional<std::string>()
+ : base::make_optional(route.media_source().id());
+ }
+
+ static const std::string& media_sink_id(
+ const media_router::MediaRoute& route) {
+ return route.media_sink_id();
+ }
+
+ static const std::string& description(const media_router::MediaRoute& route) {
+ return route.description();
+ }
+
+ static bool is_local(const media_router::MediaRoute& route) {
+ return route.is_local();
+ }
+
+ static media_router::RouteControllerType controller_type(
+ const media_router::MediaRoute& route) {
+ return route.controller_type();
+ }
+
+ static bool for_display(const media_router::MediaRoute& route) {
+ return route.for_display();
+ }
+
+ static bool is_incognito(const media_router::MediaRoute& route) {
+ return route.is_incognito();
+ }
+
+ static bool is_local_presentation(const media_router::MediaRoute& route) {
+ return route.is_local_presentation();
+ }
+};
+
+// RouteRequestResultCode
+
+template <>
+struct EnumTraits<media_router::mojom::RouteRequestResultCode,
+ media_router::RouteRequestResult::ResultCode> {
+ static media_router::mojom::RouteRequestResultCode ToMojom(
+ media_router::RouteRequestResult::ResultCode code) {
+ switch (code) {
+ case media_router::RouteRequestResult::UNKNOWN_ERROR:
+ return media_router::mojom::RouteRequestResultCode::UNKNOWN_ERROR;
+ case media_router::RouteRequestResult::OK:
+ return media_router::mojom::RouteRequestResultCode::OK;
+ case media_router::RouteRequestResult::TIMED_OUT:
+ return media_router::mojom::RouteRequestResultCode::TIMED_OUT;
+ case media_router::RouteRequestResult::ROUTE_NOT_FOUND:
+ return media_router::mojom::RouteRequestResultCode::ROUTE_NOT_FOUND;
+ case media_router::RouteRequestResult::SINK_NOT_FOUND:
+ return media_router::mojom::RouteRequestResultCode::SINK_NOT_FOUND;
+ case media_router::RouteRequestResult::INVALID_ORIGIN:
+ return media_router::mojom::RouteRequestResultCode::INVALID_ORIGIN;
+ case media_router::RouteRequestResult::INCOGNITO_MISMATCH:
+ return media_router::mojom::RouteRequestResultCode::INCOGNITO_MISMATCH;
+ case media_router::RouteRequestResult::NO_SUPPORTED_PROVIDER:
+ return media_router::mojom::RouteRequestResultCode::
+ NO_SUPPORTED_PROVIDER;
+ case media_router::RouteRequestResult::CANCELLED:
+ return media_router::mojom::RouteRequestResultCode::CANCELLED;
+ case media_router::RouteRequestResult::ROUTE_ALREADY_EXISTS:
+ return media_router::mojom::RouteRequestResultCode::
+ ROUTE_ALREADY_EXISTS;
+ default:
+ NOTREACHED() << "Unknown RouteRequestResultCode "
+ << static_cast<int>(code);
+ return media_router::mojom::RouteRequestResultCode::UNKNOWN_ERROR;
+ }
+ }
+
+ static bool FromMojom(media_router::mojom::RouteRequestResultCode input,
+ media_router::RouteRequestResult::ResultCode* output) {
+ switch (input) {
+ case media_router::mojom::RouteRequestResultCode::UNKNOWN_ERROR:
+ *output = media_router::RouteRequestResult::UNKNOWN_ERROR;
+ return true;
+ case media_router::mojom::RouteRequestResultCode::OK:
+ *output = media_router::RouteRequestResult::OK;
+ return true;
+ case media_router::mojom::RouteRequestResultCode::TIMED_OUT:
+ *output = media_router::RouteRequestResult::TIMED_OUT;
+ return true;
+ case media_router::mojom::RouteRequestResultCode::ROUTE_NOT_FOUND:
+ *output = media_router::RouteRequestResult::ROUTE_NOT_FOUND;
+ return true;
+ case media_router::mojom::RouteRequestResultCode::SINK_NOT_FOUND:
+ *output = media_router::RouteRequestResult::SINK_NOT_FOUND;
+ return true;
+ case media_router::mojom::RouteRequestResultCode::INVALID_ORIGIN:
+ *output = media_router::RouteRequestResult::INVALID_ORIGIN;
+ return true;
+ case media_router::mojom::RouteRequestResultCode::INCOGNITO_MISMATCH:
+ *output = media_router::RouteRequestResult::INCOGNITO_MISMATCH;
+ return true;
+ case media_router::mojom::RouteRequestResultCode::NO_SUPPORTED_PROVIDER:
+ *output = media_router::RouteRequestResult::NO_SUPPORTED_PROVIDER;
+ return true;
+ case media_router::mojom::RouteRequestResultCode::CANCELLED:
+ *output = media_router::RouteRequestResult::CANCELLED;
+ return true;
+ case media_router::mojom::RouteRequestResultCode::ROUTE_ALREADY_EXISTS:
+ *output = media_router::RouteRequestResult::ROUTE_ALREADY_EXISTS;
+ return true;
+ }
+ return false;
+ }
+};
+
+// MediaRouteProvider
+
+template <>
+struct EnumTraits<media_router::mojom::MediaRouteProvider::Id,
+ media_router::MediaRouteProviderId> {
+ static media_router::mojom::MediaRouteProvider::Id ToMojom(
+ media_router::MediaRouteProviderId provider_id) {
+ switch (provider_id) {
+ case media_router::MediaRouteProviderId::EXTENSION:
+ return media_router::mojom::MediaRouteProvider::Id::EXTENSION;
+ case media_router::MediaRouteProviderId::WIRED_DISPLAY:
+ return media_router::mojom::MediaRouteProvider::Id::WIRED_DISPLAY;
+ case media_router::MediaRouteProviderId::CAST:
+ return media_router::mojom::MediaRouteProvider::Id::CAST;
+ case media_router::MediaRouteProviderId::DIAL:
+ return media_router::mojom::MediaRouteProvider::Id::DIAL;
+ case media_router::MediaRouteProviderId::UNKNOWN:
+ break;
+ }
+ NOTREACHED() << "Invalid MediaRouteProvider::Id: "
+ << static_cast<int>(provider_id);
+ return media_router::mojom::MediaRouteProvider::Id::EXTENSION;
+ }
+
+ static bool FromMojom(media_router::mojom::MediaRouteProvider::Id input,
+ media_router::MediaRouteProviderId* provider_id) {
+ switch (input) {
+ case media_router::mojom::MediaRouteProvider::Id::EXTENSION:
+ *provider_id = media_router::MediaRouteProviderId::EXTENSION;
+ return true;
+ case media_router::mojom::MediaRouteProvider::Id::WIRED_DISPLAY:
+ *provider_id = media_router::MediaRouteProviderId::WIRED_DISPLAY;
+ return true;
+ case media_router::mojom::MediaRouteProvider::Id::CAST:
+ *provider_id = media_router::MediaRouteProviderId::CAST;
+ return true;
+ case media_router::mojom::MediaRouteProvider::Id::DIAL:
+ *provider_id = media_router::MediaRouteProviderId::DIAL;
+ return true;
+ }
+ return false;
+ }
+};
+
+} // namespace mojo
+
+#endif // CHROME_COMMON_MEDIA_ROUTER_MOJOM_MEDIA_ROUTER_MOJOM_TRAITS_H_
diff --git a/chromium/chrome/common/media_router/mojom/media_router_mojom_traits_unittest.cc b/chromium/chrome/common/media_router/mojom/media_router_mojom_traits_unittest.cc
new file mode 100644
index 00000000000..b00e1bcb1fe
--- /dev/null
+++ b/chromium/chrome/common/media_router/mojom/media_router_mojom_traits_unittest.cc
@@ -0,0 +1,112 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/mojom/media_router_mojom_traits.h"
+
+#include <utility>
+
+#include "base/test/task_environment.h"
+#include "chrome/common/media_router/discovery/media_sink_internal.h"
+#include "chrome/common/media_router/mojom/media_router.mojom.h"
+#include "chrome/common/media_router/mojom/media_router_traits_test_service.mojom.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media_router {
+
+class MediaRouterStructTraitsTest
+ : public testing::Test,
+ public media_router::mojom::MediaRouterTraitsTestService {
+ public:
+ MediaRouterStructTraitsTest() {}
+
+ protected:
+ mojo::Remote<mojom::MediaRouterTraitsTestService> GetTraitsTestRemote() {
+ mojo::Remote<mojom::MediaRouterTraitsTestService> remote;
+ traits_test_receivers_.Add(this, remote.BindNewPipeAndPassReceiver());
+ return remote;
+ }
+
+ private:
+ // MediaRouterTraitsTestService Impl
+ void EchoMediaSink(const MediaSinkInternal& sink,
+ EchoMediaSinkCallback callback) override {
+ std::move(callback).Run(sink);
+ }
+
+ base::test::TaskEnvironment task_environment_;
+ mojo::ReceiverSet<MediaRouterTraitsTestService> traits_test_receivers_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaRouterStructTraitsTest);
+};
+
+TEST_F(MediaRouterStructTraitsTest, DialMediaSink) {
+ MediaSink::Id sink_id("sinkId123");
+ std::string sink_name("The sink");
+ SinkIconType icon_type(SinkIconType::CAST);
+ MediaRouteProviderId provider_id(MediaRouteProviderId::EXTENSION);
+ std::string ip_address("192.168.1.2");
+ std::string model_name("model name");
+ GURL app_url("https://example.com");
+
+ MediaSink sink(sink_id, sink_name, icon_type, provider_id);
+ DialSinkExtraData extra_data;
+ EXPECT_TRUE(extra_data.ip_address.AssignFromIPLiteral(ip_address));
+ extra_data.model_name = model_name;
+ extra_data.app_url = app_url;
+
+ MediaSinkInternal dial_sink(sink, extra_data);
+
+ mojo::Remote<mojom::MediaRouterTraitsTestService> remote =
+ GetTraitsTestRemote();
+ MediaSinkInternal output;
+ remote->EchoMediaSink(dial_sink, &output);
+
+ EXPECT_EQ(dial_sink, output);
+}
+
+TEST_F(MediaRouterStructTraitsTest, CastMediaSink) {
+ MediaSink::Id sink_id("sinkId123");
+ std::string sink_name("The sink");
+ SinkIconType icon_type(SinkIconType::CAST);
+ MediaRouteProviderId provider_id(MediaRouteProviderId::EXTENSION);
+ std::string model_name("model name");
+
+ MediaSink sink(sink_id, sink_name, icon_type, provider_id);
+ CastSinkExtraData extra_data;
+ extra_data.ip_endpoint = net::IPEndPoint(net::IPAddress(192, 168, 1, 2), 0);
+ extra_data.model_name = model_name;
+ extra_data.capabilities = 2;
+ extra_data.cast_channel_id = 3;
+
+ MediaSinkInternal cast_sink(sink, extra_data);
+
+ mojo::Remote<mojom::MediaRouterTraitsTestService> remote =
+ GetTraitsTestRemote();
+ MediaSinkInternal output;
+ remote->EchoMediaSink(cast_sink, &output);
+
+ EXPECT_EQ(cast_sink, output);
+}
+
+TEST_F(MediaRouterStructTraitsTest, GenericMediaSink) {
+ MediaSink::Id sink_id("sinkId123");
+ std::string sink_name("The sink");
+ SinkIconType icon_type(SinkIconType::CAST);
+ MediaRouteProviderId provider_id(MediaRouteProviderId::EXTENSION);
+
+ MediaSink sink(sink_id, sink_name, icon_type, provider_id);
+ MediaSinkInternal generic_sink;
+ generic_sink.set_sink(sink);
+
+ mojo::Remote<mojom::MediaRouterTraitsTestService> remote =
+ GetTraitsTestRemote();
+ MediaSinkInternal output;
+ remote->EchoMediaSink(generic_sink, &output);
+
+ EXPECT_EQ(generic_sink, output);
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/providers/cast/DEPS b/chromium/chrome/common/media_router/providers/cast/DEPS
new file mode 100644
index 00000000000..b2288536d23
--- /dev/null
+++ b/chromium/chrome/common/media_router/providers/cast/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/cast_channel",
+]
diff --git a/chromium/chrome/common/media_router/providers/cast/cast_media_source.cc b/chromium/chrome/common/media_router/providers/cast/cast_media_source.cc
new file mode 100644
index 00000000000..e5acec59b84
--- /dev/null
+++ b/chromium/chrome/common/media_router/providers/cast/cast_media_source.cc
@@ -0,0 +1,388 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/providers/cast/cast_media_source.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/containers/flat_map.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/common/media_router/media_source.h"
+#include "components/cast_channel/enum_table.h"
+#include "net/base/escape.h"
+#include "net/base/url_util.h"
+#include "url/gurl.h"
+#include "url/url_util.h"
+
+using cast_channel::BroadcastRequest;
+using cast_channel::CastDeviceCapability;
+
+namespace cast_util {
+
+using media_router::AutoJoinPolicy;
+using media_router::DefaultActionPolicy;
+
+template <>
+const EnumTable<AutoJoinPolicy> EnumTable<AutoJoinPolicy>::instance(
+ {
+ {AutoJoinPolicy::kPageScoped, "page_scoped"},
+ {AutoJoinPolicy::kTabAndOriginScoped, "tab_and_origin_scoped"},
+ {AutoJoinPolicy::kOriginScoped, "origin_scoped"},
+ },
+ AutoJoinPolicy::kMaxValue);
+
+template <>
+const EnumTable<DefaultActionPolicy> EnumTable<DefaultActionPolicy>::instance(
+ {
+ {DefaultActionPolicy::kCreateSession, "create_session"},
+ {DefaultActionPolicy::kCastThisTab, "cast_this_tab"},
+ },
+ DefaultActionPolicy::kMaxValue);
+
+template <>
+const EnumTable<CastDeviceCapability> EnumTable<CastDeviceCapability>::instance(
+ {
+ {CastDeviceCapability::MULTIZONE_GROUP, "multizone_group"},
+ {CastDeviceCapability::DEV_MODE, "dev_mode"},
+ {CastDeviceCapability::AUDIO_IN, "audio_in"},
+ {CastDeviceCapability::AUDIO_OUT, "audio_out"},
+ {CastDeviceCapability::VIDEO_IN, "video_in"},
+ {CastDeviceCapability::VIDEO_OUT, "video_out"},
+ // NONE deliberately omitted
+ },
+ NonConsecutiveEnumTable);
+
+} // namespace cast_util
+
+namespace media_router {
+
+namespace {
+
+// A nonmember version of base::Optional::value_or that works on pointers as
+// well as instance of base::Optional.
+template <typename T>
+inline auto value_or(const T& optional,
+ const std::decay_t<decltype(*optional)>& default_value)
+ -> std::decay_t<decltype(*optional)> {
+ return optional ? *optional : default_value;
+}
+
+// FindValue() looks up the value associated with a key |key| in a map-like
+// object |map| and returns a pointer to the value if |key| is found, or nullptr
+// otherwise.
+//
+// The type of |map| can be anything that supports a find() method like
+// std::map::find, or any iterable object whose values are key/value pairs.
+//
+// See also FindValueOr().
+
+// Overload for types with a find() method.
+template <typename Map, typename = typename Map::key_type>
+inline const typename Map::mapped_type* FindValue(
+ const Map& map,
+ const typename Map::key_type& key) {
+ auto it = map.find(key);
+ if (it == map.end())
+ return nullptr;
+ return &it->second;
+}
+
+// Overload for types without a find() method.
+template <typename Map, typename Key>
+auto FindValue(const Map& map, const Key& key) -> const
+ decltype(begin(map)->second)* {
+ for (const auto& item : map) {
+ if (item.first == key)
+ return &item.second;
+ }
+ return nullptr;
+}
+
+// Looks up the value associated with a key |key| in a map-like object |map| and
+// returns a reference to the value if |key| is found, or |default_value|
+// otherwise.
+//
+// The type of |map| can be anything that supports a find() method like
+// std::map::find, or any iterable object whose values are key/value pairs.
+template <typename Map, typename Key, typename T>
+inline auto FindValueOr(const Map& map, const Key& key, const T& default_value)
+ -> std::decay_t<decltype(*FindValue(map, key))> {
+ return value_or(FindValue(map, key), default_value);
+}
+
+// Creates a map from the query parameters of |url|. If |url| contains multiple
+// values for the same parameter, the last value is used.
+base::flat_map<std::string, std::string> MakeQueryMap(const GURL& url) {
+ base::flat_map<std::string, std::string> result;
+ for (net::QueryIterator query_it(url); !query_it.IsAtEnd();
+ query_it.Advance()) {
+ result[query_it.GetKey()] = query_it.GetUnescapedValue();
+ }
+ return result;
+}
+
+// TODO(jrw): Move to common utils?
+//
+// TODO(jrw): Should this use net::UnescapeURLComponent instead of
+// url::DecodeURLEscapeSequences?
+std::string DecodeURLComponent(const std::string& encoded) {
+ url::RawCanonOutputT<base::char16> unescaped;
+ std::string output;
+ url::DecodeURLEscapeSequences(encoded.data(), encoded.size(),
+ url::DecodeURLMode::kUTF8OrIsomorphic,
+ &unescaped);
+ if (base::UTF16ToUTF8(unescaped.data(), unescaped.length(), &output))
+ return output;
+
+ return std::string();
+}
+
+// Converts a string containing a comma-separated list of capabilities into a
+// bitwise OR of CastDeviceCapability values.
+BitwiseOr<CastDeviceCapability> CastDeviceCapabilitiesFromString(
+ const base::StringPiece& s) {
+ BitwiseOr<CastDeviceCapability> result{};
+ for (const auto& capability_str : base::SplitStringPiece(
+ s, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
+ const auto capability =
+ cast_util::StringToEnum<CastDeviceCapability>(capability_str);
+ if (capability) {
+ result.Add(*capability);
+ } else {
+ DLOG(ERROR) << "Unkown capability name: " << capability_str;
+ }
+ }
+ return result;
+}
+
+std::unique_ptr<CastMediaSource> CastMediaSourceForTabMirroring(
+ const MediaSource::Id& source_id) {
+ return std::make_unique<CastMediaSource>(
+ source_id,
+ std::vector<CastAppInfo>({CastAppInfo(kCastStreamingAppId),
+ CastAppInfo(kCastStreamingAudioAppId)}));
+}
+
+std::unique_ptr<CastMediaSource> CastMediaSourceForDesktopMirroring(
+ const MediaSource::Id& source_id) {
+ // TODO(https://crbug.com/849335): Add back audio-only devices for desktop
+ // mirroring when proper support is implemented.
+ return std::make_unique<CastMediaSource>(
+ source_id, std::vector<CastAppInfo>({CastAppInfo(kCastStreamingAppId)}));
+}
+
+// The logic shared by ParseCastUrl() and ParseLegacyCastUrl().
+std::unique_ptr<CastMediaSource> CreateFromURLParams(
+ const MediaSource::Id& source_id,
+ const std::vector<CastAppInfo>& app_infos,
+ const std::string& auto_join_policy_str,
+ const std::string& default_action_policy_str,
+ const std::string& client_id,
+ const std::string& broadcast_namespace,
+ const std::string& encoded_broadcast_message,
+ const std::string& launch_timeout_str) {
+ if (app_infos.empty())
+ return nullptr;
+
+ auto cast_source = std::make_unique<CastMediaSource>(
+ source_id, app_infos,
+ cast_util::StringToEnum<AutoJoinPolicy>(auto_join_policy_str)
+ .value_or(AutoJoinPolicy::kPageScoped),
+ cast_util::StringToEnum<DefaultActionPolicy>(default_action_policy_str)
+ .value_or(DefaultActionPolicy::kCreateSession));
+ cast_source->set_client_id(client_id);
+ if (!broadcast_namespace.empty() && !encoded_broadcast_message.empty()) {
+ cast_source->set_broadcast_request(BroadcastRequest(
+ broadcast_namespace, DecodeURLComponent(encoded_broadcast_message)));
+ }
+
+ int launch_timeout_millis;
+ if (base::StringToInt(launch_timeout_str, &launch_timeout_millis) &&
+ launch_timeout_millis > 0) {
+ cast_source->set_launch_timeout(
+ base::TimeDelta::FromMilliseconds(launch_timeout_millis));
+ }
+
+ return cast_source;
+}
+
+std::unique_ptr<CastMediaSource> ParseCastUrl(const MediaSource::Id& source_id,
+ const GURL& url) {
+ std::string app_id = url.path();
+ // App ID must be non-empty.
+ if (app_id.empty())
+ return nullptr;
+
+ auto params{MakeQueryMap(url)};
+ return CreateFromURLParams(
+ source_id,
+ {CastAppInfo(app_id, CastDeviceCapabilitiesFromString(
+ FindValueOr(params, "capabilities", "")))},
+ FindValueOr(params, "autoJoinPolicy", ""),
+ FindValueOr(params, "defaultActionPolicy", ""),
+ FindValueOr(params, "clientId", ""),
+ FindValueOr(params, "broadcastNamespace", ""),
+ FindValueOr(params, "broadcastMessage", ""),
+ FindValueOr(params, "launchTimeout", ""));
+}
+
+std::unique_ptr<CastMediaSource> ParseLegacyCastUrl(
+ const MediaSource::Id& source_id,
+ const GURL& url) {
+ base::StringPairs params;
+ base::SplitStringIntoKeyValuePairs(url.ref(), '=', '/', &params);
+ for (auto& pair : params) {
+ pair.second = net::UnescapeURLComponent(
+ pair.second,
+ net::UnescapeRule::SPACES | net::UnescapeRule::PATH_SEPARATORS |
+ net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS |
+ net::UnescapeRule::REPLACE_PLUS_WITH_SPACE);
+ }
+
+ // Legacy URLs can specify multiple apps.
+ std::vector<std::string> app_id_params;
+ for (const auto& param : params) {
+ if (param.first == "__castAppId__")
+ app_id_params.push_back(param.second);
+ }
+
+ std::vector<CastAppInfo> app_infos;
+ for (const auto& app_id_param : app_id_params) {
+ std::string app_id;
+ std::string capabilities;
+ auto cap_start_index = app_id_param.find('(');
+ // If |cap_start_index| is |npos|, then this will return the entire string.
+ app_id = app_id_param.substr(0, cap_start_index);
+ if (cap_start_index != std::string::npos) {
+ auto cap_end_index = app_id_param.find(')', cap_start_index);
+ if (cap_end_index != std::string::npos &&
+ cap_end_index > cap_start_index) {
+ capabilities = app_id_param.substr(cap_start_index + 1,
+ cap_end_index - cap_start_index - 1);
+ }
+ }
+
+ if (app_id.empty())
+ continue;
+
+ CastAppInfo app_info(app_id,
+ CastDeviceCapabilitiesFromString(capabilities));
+
+ app_infos.push_back(app_info);
+ }
+
+ if (app_infos.empty())
+ return nullptr;
+
+ return CreateFromURLParams(
+ source_id, app_infos, FindValueOr(params, "__castAutoJoinPolicy__", ""),
+ FindValueOr(params, "__castDefaultActionPolicy__", ""),
+ FindValueOr(params, "__castClientId__", ""),
+ FindValueOr(params, "__castBroadcastNamespace__", ""),
+ FindValueOr(params, "__castBroadcastMessage__", ""),
+ FindValueOr(params, "__castLaunchTimeout__", ""));
+}
+
+} // namespace
+
+bool IsAutoJoinAllowed(AutoJoinPolicy policy,
+ const url::Origin& origin1,
+ int tab_id1,
+ const url::Origin& origin2,
+ int tab_id2) {
+ switch (policy) {
+ case AutoJoinPolicy::kPageScoped:
+ return false;
+ case AutoJoinPolicy::kTabAndOriginScoped:
+ return origin1 == origin2 && tab_id1 == tab_id2;
+ case AutoJoinPolicy::kOriginScoped:
+ return origin1 == origin2;
+ }
+}
+
+CastAppInfo::CastAppInfo(
+ const std::string& app_id,
+ BitwiseOr<cast_channel::CastDeviceCapability> required_capabilities)
+ : app_id(app_id), required_capabilities(required_capabilities) {}
+CastAppInfo::~CastAppInfo() = default;
+
+CastAppInfo::CastAppInfo(const CastAppInfo& other) = default;
+
+// static
+std::unique_ptr<CastMediaSource> CastMediaSource::FromMediaSource(
+ const MediaSource& source) {
+ if (source.IsTabMirroringSource())
+ return CastMediaSourceForTabMirroring(source.id());
+
+ if (source.IsDesktopMirroringSource())
+ return CastMediaSourceForDesktopMirroring(source.id());
+
+ const GURL& url = source.url();
+ if (!url.is_valid())
+ return nullptr;
+
+ if (url.SchemeIs(kCastPresentationUrlScheme)) {
+ return ParseCastUrl(source.id(), url);
+ } else if (IsLegacyCastPresentationUrl(url)) {
+ return ParseLegacyCastUrl(source.id(), url);
+ } else if (url.SchemeIsHTTPOrHTTPS()) {
+ // Arbitrary https URLs are supported via 1-UA mode which uses tab
+ // mirroring.
+ return CastMediaSourceForTabMirroring(source.id());
+ }
+
+ return nullptr;
+}
+
+// static
+std::unique_ptr<CastMediaSource> CastMediaSource::FromMediaSourceId(
+ const MediaSource::Id& source_id) {
+ return FromMediaSource(MediaSource(source_id));
+}
+
+// static
+std::unique_ptr<CastMediaSource> CastMediaSource::FromAppId(
+ const std::string& app_id) {
+ return FromMediaSourceId(kCastPresentationUrlScheme + (":" + app_id));
+}
+
+CastMediaSource::CastMediaSource(const MediaSource::Id& source_id,
+ const std::vector<CastAppInfo>& app_infos,
+ AutoJoinPolicy auto_join_policy,
+ DefaultActionPolicy default_action_policy)
+ : source_id_(source_id),
+ app_infos_(app_infos),
+ auto_join_policy_(auto_join_policy),
+ default_action_policy_(default_action_policy) {}
+CastMediaSource::CastMediaSource(const CastMediaSource& other) = default;
+CastMediaSource::~CastMediaSource() = default;
+
+bool CastMediaSource::ContainsApp(const std::string& app_id) const {
+ for (const auto& info : app_infos_) {
+ if (info.app_id == app_id)
+ return true;
+ }
+ return false;
+}
+
+bool CastMediaSource::ContainsAnyAppFrom(
+ const std::vector<std::string>& app_ids) const {
+ return std::any_of(
+ app_ids.begin(), app_ids.end(),
+ [this](const std::string& app_id) { return ContainsApp(app_id); });
+}
+
+std::vector<std::string> CastMediaSource::GetAppIds() const {
+ std::vector<std::string> app_ids;
+ for (const auto& info : app_infos_)
+ app_ids.push_back(info.app_id);
+
+ return app_ids;
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/providers/cast/cast_media_source.h b/chromium/chrome/common/media_router/providers/cast/cast_media_source.h
new file mode 100644
index 00000000000..b0c2552dc33
--- /dev/null
+++ b/chromium/chrome/common/media_router/providers/cast/cast_media_source.h
@@ -0,0 +1,178 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_MEDIA_ROUTER_PROVIDERS_CAST_CAST_MEDIA_SOURCE_H_
+#define CHROME_COMMON_MEDIA_ROUTER_PROVIDERS_CAST_CAST_MEDIA_SOURCE_H_
+
+#include <initializer_list>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/optional.h"
+#include "chrome/common/media_router/media_source.h"
+#include "components/cast_channel/cast_message_util.h"
+#include "components/cast_channel/cast_socket.h"
+
+namespace media_router {
+
+static constexpr char kCastStreamingAppId[] = "0F5096E8";
+static constexpr char kCastStreamingAudioAppId[] = "85CDB22F";
+
+// Placeholder app ID advertised by the multizone leader in a receiver status
+// message.
+static constexpr char kMultizoneLeaderAppId[] = "MultizoneLeader";
+
+static constexpr base::TimeDelta kDefaultLaunchTimeout =
+ base::TimeDelta::FromSeconds(60);
+
+// Class for storing a bitwise OR of enum values.
+//
+// TODO(jrw): Make values of cast_channel::CastDeviceCapability consecutive and
+// store sets of values using a class like v8::base::EnumSet instead of this
+// monstrosity.
+template <typename E, typename T = std::underlying_type_t<E>>
+class BitwiseOr {
+ public:
+ constexpr BitwiseOr() : bits_(0) {}
+ constexpr BitwiseOr(std::initializer_list<E> values) : bits_(0) {
+ for (E e : values)
+ Add(e);
+ }
+ bool empty() const { return bits_ == 0; }
+ void Add(E value) { bits_ |= Mask(value); }
+ bool operator==(const BitwiseOr& other) const { return bits_ == other.bits_; }
+ bool operator!=(const BitwiseOr& other) const { return *this != other; }
+
+ private:
+ static T Mask(E value) {
+ const T result = static_cast<T>(value);
+ DCHECK(static_cast<E>(result) == value);
+ return result;
+ }
+ T bits_;
+};
+
+// Represents a Cast app and its capabilitity requirements.
+struct CastAppInfo {
+ explicit CastAppInfo(const std::string& app_id,
+ BitwiseOr<cast_channel::CastDeviceCapability> = {});
+ ~CastAppInfo();
+
+ CastAppInfo(const CastAppInfo& other);
+
+ std::string app_id;
+
+ // A bitset of capabilities required by the app.
+ BitwiseOr<cast_channel::CastDeviceCapability> required_capabilities;
+};
+
+// Auto-join policy determines when the SDK will automatically connect a sender
+// application to an existing session after API initialization.
+enum class AutoJoinPolicy {
+ // No automatic connection. This is the default when no policy is specified.
+ kPageScoped,
+
+ // Automatically connects when the session was started with the same app ID,
+ // in the same tab and page origin.
+ kTabAndOriginScoped,
+
+ // Automatically connects when the session was started with the same app ID
+ // and the same page origin (regardless of tab).
+ kOriginScoped,
+
+ kMaxValue = kOriginScoped,
+};
+
+// Default action policy determines when the SDK will automatically create a
+// session after initializing the API. This also controls the default action
+// for the tab in the Cast dialog.
+enum class DefaultActionPolicy {
+ // If the tab containing the app is being cast when the API initializes, the
+ // SDK stops tab casting and automatically launches the app. The Cast dialog
+ // prompts the user to cast the app.
+ kCreateSession,
+
+ // No automatic launch is done after initializing the API, even if the tab is
+ // being cast. The Cast dialog prompts the user to mirror the tab (mirror,
+ // not cast, despite the name).
+ kCastThisTab,
+
+ kMaxValue = kCastThisTab,
+};
+
+// Tests whether a sender specified by (origin1, tab_id1) is allowed by |policy|
+// to join (origin2, tab_id2).
+bool IsAutoJoinAllowed(AutoJoinPolicy policy,
+ const url::Origin& origin1,
+ int tab_id1,
+ const url::Origin& origin2,
+ int tab_id2);
+
+// Represents a MediaSource parsed into structured, Cast specific data. The
+// following MediaSources can be parsed into CastMediaSource:
+// - Cast Presentation URLs
+// - HTTP(S) Presentation URLs
+// - Desktop / tab mirroring URNs
+class CastMediaSource {
+ public:
+ // Returns the parsed form of |source|, or nullptr if it cannot be parsed.
+ static std::unique_ptr<CastMediaSource> FromMediaSource(
+ const MediaSource& source);
+ static std::unique_ptr<CastMediaSource> FromMediaSourceId(
+ const MediaSource::Id& source);
+
+ static std::unique_ptr<CastMediaSource> FromAppId(const std::string& app_id);
+
+ CastMediaSource(const MediaSource::Id& source_id,
+ const std::vector<CastAppInfo>& app_infos,
+ AutoJoinPolicy auto_join_policy = AutoJoinPolicy::kPageScoped,
+ DefaultActionPolicy default_action_policy =
+ DefaultActionPolicy::kCreateSession);
+ CastMediaSource(const CastMediaSource& other);
+ ~CastMediaSource();
+
+ // Returns |true| if |app_infos| contain |app_id|.
+ bool ContainsApp(const std::string& app_id) const;
+ bool ContainsAnyAppFrom(const std::vector<std::string>& app_ids) const;
+
+ // Returns a list of App IDs in this CastMediaSource.
+ std::vector<std::string> GetAppIds() const;
+
+ const MediaSource::Id& source_id() const { return source_id_; }
+ const std::vector<CastAppInfo>& app_infos() const { return app_infos_; }
+ const std::string& client_id() const { return client_id_; }
+ void set_client_id(const std::string& client_id) { client_id_ = client_id; }
+ base::TimeDelta launch_timeout() const { return launch_timeout_; }
+ void set_launch_timeout(base::TimeDelta launch_timeout) {
+ launch_timeout_ = launch_timeout;
+ }
+ const base::Optional<cast_channel::BroadcastRequest>& broadcast_request()
+ const {
+ return broadcast_request_;
+ }
+ void set_broadcast_request(const cast_channel::BroadcastRequest& request) {
+ broadcast_request_ = request;
+ }
+ AutoJoinPolicy auto_join_policy() const { return auto_join_policy_; }
+ DefaultActionPolicy default_action_policy() const {
+ return default_action_policy_;
+ }
+
+ private:
+ MediaSource::Id source_id_;
+ std::vector<CastAppInfo> app_infos_;
+ AutoJoinPolicy auto_join_policy_;
+ DefaultActionPolicy default_action_policy_;
+ base::TimeDelta launch_timeout_ = kDefaultLaunchTimeout;
+ // Empty if not set.
+ std::string client_id_;
+ base::Optional<cast_channel::BroadcastRequest> broadcast_request_;
+};
+
+} // namespace media_router
+
+#endif // CHROME_COMMON_MEDIA_ROUTER_PROVIDERS_CAST_CAST_MEDIA_SOURCE_H_
diff --git a/chromium/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc b/chromium/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc
new file mode 100644
index 00000000000..7073e8e2dc7
--- /dev/null
+++ b/chromium/chrome/common/media_router/providers/cast/cast_media_source_unittest.cc
@@ -0,0 +1,153 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/media_router/providers/cast/cast_media_source.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using cast_channel::CastDeviceCapability;
+
+namespace media_router {
+
+TEST(CastMediaSourceTest, FromCastURLWithDefaults) {
+ MediaSource::Id source_id("cast:ABCDEFAB");
+ std::unique_ptr<CastMediaSource> source =
+ CastMediaSource::FromMediaSourceId(source_id);
+ ASSERT_TRUE(source);
+ EXPECT_EQ(source_id, source->source_id());
+ ASSERT_EQ(1u, source->app_infos().size());
+ const CastAppInfo& app_info = source->app_infos()[0];
+ EXPECT_EQ("ABCDEFAB", app_info.app_id);
+ EXPECT_TRUE(app_info.required_capabilities.empty());
+ const auto& broadcast_request = source->broadcast_request();
+ EXPECT_FALSE(broadcast_request);
+ EXPECT_EQ("", source->client_id());
+ EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout());
+ EXPECT_EQ(AutoJoinPolicy::kPageScoped, source->auto_join_policy());
+ EXPECT_EQ(DefaultActionPolicy::kCreateSession,
+ source->default_action_policy());
+}
+
+TEST(CastMediaSourceTest, FromCastURL) {
+ MediaSource::Id source_id(
+ "cast:ABCDEFAB?capabilities=video_out,audio_out"
+ "&broadcastNamespace=namespace"
+ "&broadcastMessage=message%25"
+ "&clientId=12345"
+ "&launchTimeout=30000"
+ "&autoJoinPolicy=tab_and_origin_scoped"
+ "&defaultActionPolicy=cast_this_tab");
+ std::unique_ptr<CastMediaSource> source =
+ CastMediaSource::FromMediaSourceId(source_id);
+ ASSERT_TRUE(source);
+ EXPECT_EQ(source_id, source->source_id());
+ ASSERT_EQ(1u, source->app_infos().size());
+ const CastAppInfo& app_info = source->app_infos()[0];
+ EXPECT_EQ("ABCDEFAB", app_info.app_id);
+ EXPECT_EQ((BitwiseOr<CastDeviceCapability>{CastDeviceCapability::VIDEO_OUT,
+ CastDeviceCapability::AUDIO_OUT}),
+ app_info.required_capabilities);
+ const auto& broadcast_request = source->broadcast_request();
+ ASSERT_TRUE(broadcast_request);
+ EXPECT_EQ("namespace", broadcast_request->broadcast_namespace);
+ EXPECT_EQ("message%", broadcast_request->message);
+ EXPECT_EQ("12345", source->client_id());
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(30000), source->launch_timeout());
+ EXPECT_EQ(AutoJoinPolicy::kTabAndOriginScoped, source->auto_join_policy());
+ EXPECT_EQ(DefaultActionPolicy::kCastThisTab, source->default_action_policy());
+}
+
+TEST(CastMediaSourceTest, FromLegacyCastURL) {
+ MediaSource::Id source_id(
+ "https://google.com/cast"
+ "#__castAppId__=ABCDEFAB(video_out,audio_out)"
+ "/__castAppId__=otherAppId"
+ "/__castBroadcastNamespace__=namespace"
+ "/__castBroadcastMessage__=message%25"
+ "/__castClientId__=12345"
+ "/__castLaunchTimeout__=30000"
+ "/__castAutoJoinPolicy__=origin_scoped"
+ "/__castDefaultActionPolicy__=cast_this_tab");
+ std::unique_ptr<CastMediaSource> source =
+ CastMediaSource::FromMediaSourceId(source_id);
+ ASSERT_TRUE(source);
+ EXPECT_EQ(source_id, source->source_id());
+ ASSERT_EQ(2u, source->app_infos().size());
+ const CastAppInfo& app_info = source->app_infos()[0];
+ EXPECT_EQ("ABCDEFAB", app_info.app_id);
+ EXPECT_EQ((BitwiseOr<CastDeviceCapability>{CastDeviceCapability::VIDEO_OUT,
+ CastDeviceCapability::AUDIO_OUT}),
+ app_info.required_capabilities);
+ EXPECT_EQ("otherAppId", source->app_infos()[1].app_id);
+ const auto& broadcast_request = source->broadcast_request();
+ ASSERT_TRUE(broadcast_request);
+ EXPECT_EQ("namespace", broadcast_request->broadcast_namespace);
+ EXPECT_EQ("message%", broadcast_request->message);
+ EXPECT_EQ("12345", source->client_id());
+ EXPECT_EQ(base::TimeDelta::FromMilliseconds(30000), source->launch_timeout());
+ EXPECT_EQ(AutoJoinPolicy::kOriginScoped, source->auto_join_policy());
+ EXPECT_EQ(DefaultActionPolicy::kCastThisTab, source->default_action_policy());
+}
+
+TEST(CastMediaSourceTest, FromPresentationURL) {
+ MediaSource::Id source_id("https://google.com");
+ std::unique_ptr<CastMediaSource> source =
+ CastMediaSource::FromMediaSourceId(source_id);
+ ASSERT_TRUE(source);
+ EXPECT_EQ(source_id, source->source_id());
+ ASSERT_EQ(2u, source->app_infos().size());
+ EXPECT_EQ(kCastStreamingAppId, source->app_infos()[0].app_id);
+ EXPECT_EQ(kCastStreamingAudioAppId, source->app_infos()[1].app_id);
+ EXPECT_TRUE(source->client_id().empty());
+ EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout());
+ EXPECT_EQ(AutoJoinPolicy::kPageScoped, source->auto_join_policy());
+ EXPECT_EQ(DefaultActionPolicy::kCreateSession,
+ source->default_action_policy());
+}
+
+TEST(CastMediaSourceTest, FromMirroringURN) {
+ MediaSource::Id source_id("urn:x-org.chromium.media:source:tab:5");
+ std::unique_ptr<CastMediaSource> source =
+ CastMediaSource::FromMediaSourceId(source_id);
+ ASSERT_TRUE(source);
+ EXPECT_EQ(source_id, source->source_id());
+ ASSERT_EQ(2u, source->app_infos().size());
+ EXPECT_EQ(kCastStreamingAppId, source->app_infos()[0].app_id);
+ EXPECT_EQ(kCastStreamingAudioAppId, source->app_infos()[1].app_id);
+ EXPECT_TRUE(source->client_id().empty());
+ EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout());
+ EXPECT_EQ(AutoJoinPolicy::kPageScoped, source->auto_join_policy());
+ EXPECT_EQ(DefaultActionPolicy::kCreateSession,
+ source->default_action_policy());
+}
+
+TEST(CastMediaSourceTest, FromDesktopUrn) {
+ MediaSource::Id source_id("urn:x-org.chromium.media:source:desktop");
+ std::unique_ptr<CastMediaSource> source =
+ CastMediaSource::FromMediaSourceId(source_id);
+ ASSERT_TRUE(source);
+ EXPECT_EQ(source_id, source->source_id());
+ ASSERT_EQ(1u, source->app_infos().size());
+ EXPECT_EQ(kCastStreamingAppId, source->app_infos()[0].app_id);
+ EXPECT_TRUE(source->client_id().empty());
+ EXPECT_EQ(kDefaultLaunchTimeout, source->launch_timeout());
+ EXPECT_EQ(AutoJoinPolicy::kPageScoped, source->auto_join_policy());
+ EXPECT_EQ(DefaultActionPolicy::kCreateSession,
+ source->default_action_policy());
+}
+
+TEST(CastMediaSourceTest, FromInvalidSource) {
+ EXPECT_FALSE(CastMediaSource::FromMediaSourceId("invalid:source"));
+ EXPECT_FALSE(CastMediaSource::FromMediaSourceId("file:///foo.mp4"));
+ EXPECT_FALSE(CastMediaSource::FromMediaSourceId(""));
+ EXPECT_FALSE(CastMediaSource::FromMediaSourceId("cast:"));
+
+ // Missing app ID.
+ EXPECT_FALSE(CastMediaSource::FromMediaSourceId("cast:?param=foo"));
+ EXPECT_FALSE(CastMediaSource::FromMediaSourceId(
+ "https://google.com/cast#__castAppId__=/param=foo"));
+}
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/route_request_result.cc b/chromium/chrome/common/media_router/route_request_result.cc
new file mode 100644
index 00000000000..538bff4fdf2
--- /dev/null
+++ b/chromium/chrome/common/media_router/route_request_result.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 "chrome/common/media_router/route_request_result.h"
+
+#include "chrome/common/media_router/media_route.h"
+
+namespace media_router {
+
+// static
+std::unique_ptr<RouteRequestResult> RouteRequestResult::FromSuccess(
+ const MediaRoute& route,
+ const std::string& presentation_id) {
+ return std::make_unique<RouteRequestResult>(
+ std::make_unique<MediaRoute>(route), presentation_id, std::string(),
+ RouteRequestResult::OK);
+}
+
+// static
+std::unique_ptr<RouteRequestResult> RouteRequestResult::FromError(
+ const std::string& error,
+ ResultCode result_code) {
+ return std::make_unique<RouteRequestResult>(nullptr, std::string(), error,
+ result_code);
+}
+
+RouteRequestResult::RouteRequestResult(std::unique_ptr<MediaRoute> route,
+ const std::string& presentation_id,
+ const std::string& error,
+ ResultCode result_code)
+ : route_(std::move(route)),
+ presentation_id_(presentation_id),
+ error_(error),
+ result_code_(result_code) {
+ if (route_)
+ presentation_url_ = route_->media_source().url();
+}
+
+RouteRequestResult::~RouteRequestResult() = default;
+
+} // namespace media_router
diff --git a/chromium/chrome/common/media_router/route_request_result.h b/chromium/chrome/common/media_router/route_request_result.h
new file mode 100644
index 00000000000..8b6a251f1d2
--- /dev/null
+++ b/chromium/chrome/common/media_router/route_request_result.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 CHROME_COMMON_MEDIA_ROUTER_ROUTE_REQUEST_RESULT_H_
+#define CHROME_COMMON_MEDIA_ROUTER_ROUTE_REQUEST_RESULT_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "url/gurl.h"
+
+namespace media_router {
+
+class MediaRoute;
+
+// Holds the result of a successful or failed route request.
+// On success:
+// |route|: The route created or joined.
+// |presentation_id|:
+// The presentation ID of the route created or joined. In the case of
+// |CreateRoute()|, the ID is generated by MediaRouter and is guaranteed to
+// be unique.
+// |error|: Empty string.
+// |result_code|: RouteRequestResult::OK
+// On failure:
+// |route|: nullptr
+// |presentation_id|: Empty string.
+// |error|: Non-empty string describing the error.
+// |result_code|: A value from RouteRequestResult describing the error.
+class RouteRequestResult {
+ public:
+ // Keep in sync with:
+ // - RouteRequestResultCode in media_router.mojom
+ // - MediaRouteProviderResult enum in tools/metrics/histograms.xml
+ // - mr.RouteRequestResultCode in route_request_error.js
+ // - media_router_mojom_traits.h
+ enum ResultCode {
+ UNKNOWN_ERROR = 0,
+ OK = 1,
+ TIMED_OUT = 2,
+ ROUTE_NOT_FOUND = 3,
+ SINK_NOT_FOUND = 4,
+ INVALID_ORIGIN = 5,
+ INCOGNITO_MISMATCH = 6,
+ NO_SUPPORTED_PROVIDER = 7,
+ CANCELLED = 8,
+ ROUTE_ALREADY_EXISTS = 9,
+ // New values must be added here.
+
+ TOTAL_COUNT = 10 // The total number of values.
+ };
+
+ static std::unique_ptr<RouteRequestResult> FromSuccess(
+ const MediaRoute& route,
+ const std::string& presentation_id);
+ static std::unique_ptr<RouteRequestResult> FromError(const std::string& error,
+ ResultCode result_code);
+ RouteRequestResult(std::unique_ptr<MediaRoute> route,
+ const std::string& presentation_id,
+ const std::string& error,
+ ResultCode result_code);
+
+ ~RouteRequestResult();
+
+ // Note the caller does not own the returned MediaRoute. The caller must
+ // create a copy if they wish to use it after this object is destroyed.
+ const MediaRoute* route() const { return route_.get(); }
+ std::string presentation_id() const { return presentation_id_; }
+ GURL presentation_url() const { return presentation_url_; }
+ std::string error() const { return error_; }
+ ResultCode result_code() const { return result_code_; }
+
+ private:
+ std::unique_ptr<MediaRoute> route_;
+ std::string presentation_id_;
+ GURL presentation_url_;
+ std::string error_;
+ ResultCode result_code_;
+
+ DISALLOW_COPY_AND_ASSIGN(RouteRequestResult);
+};
+
+} // namespace media_router
+
+#endif // CHROME_COMMON_MEDIA_ROUTER_ROUTE_REQUEST_RESULT_H_
diff --git a/chromium/chrome/common/metrics_constants_util_win.cc b/chromium/chrome/common/metrics_constants_util_win.cc
new file mode 100644
index 00000000000..8c789ebbfb2
--- /dev/null
+++ b/chromium/chrome/common/metrics_constants_util_win.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 "chrome/common/metrics_constants_util_win.h"
+
+#include "chrome/install_static/install_util.h"
+
+namespace chrome {
+
+base::string16 GetBrowserExitCodesRegistryPath() {
+ return install_static::GetRegistryPath().append(L"\\BrowserExitCodes");
+}
+
+} // namespace chrome
diff --git a/chromium/chrome/common/metrics_constants_util_win.h b/chromium/chrome/common/metrics_constants_util_win.h
new file mode 100644
index 00000000000..349191360f0
--- /dev/null
+++ b/chromium/chrome/common/metrics_constants_util_win.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.
+
+// A handful of resource-like constants related to the Chrome application.
+
+#ifndef CHROME_COMMON_METRICS_CONSTANTS_UTIL_WIN_H_
+#define CHROME_COMMON_METRICS_CONSTANTS_UTIL_WIN_H_
+
+#include "base/strings/string16.h"
+
+namespace chrome {
+
+// Returns the registry path where exit code are stored for this product. This
+// is used by browser exit code metrics reporting.
+base::string16 GetBrowserExitCodesRegistryPath();
+
+} // namespace chrome
+
+#endif // CHROME_COMMON_METRICS_CONSTANTS_UTIL_WIN_H_
diff --git a/chromium/chrome/common/multi_process_lock.h b/chromium/chrome/common/multi_process_lock.h
new file mode 100644
index 00000000000..622c58fba3b
--- /dev/null
+++ b/chromium/chrome/common/multi_process_lock.h
@@ -0,0 +1,33 @@
+// 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 CHROME_COMMON_MULTI_PROCESS_LOCK_H_
+#define CHROME_COMMON_MULTI_PROCESS_LOCK_H_
+
+#include <sys/types.h>
+#include <memory>
+#include <string>
+
+// Platform abstraction for a lock that can be shared between processes.
+// The process that owns the lock will release it on exit even if
+// the exit is due to a crash. Locks are not recursive.
+class MultiProcessLock {
+ public:
+ // Factory method for creating a multi-process lock.
+ // |name| is the name of the lock. The name has special meaning on Windows
+ // where the prefix can determine the namespace of the lock.
+ // See http://msdn.microsoft.com/en-us/library/aa382954(v=VS.85).aspx for
+ // details.
+ static std::unique_ptr<MultiProcessLock> Create(const std::string& name);
+
+ virtual ~MultiProcessLock() { }
+
+ // Try to grab ownership of the lock.
+ virtual bool TryLock() = 0;
+
+ // Release ownership of the lock.
+ virtual void Unlock() = 0;
+};
+
+#endif // CHROME_COMMON_MULTI_PROCESS_LOCK_H_
diff --git a/chromium/chrome/common/multi_process_lock_linux.cc b/chromium/chrome/common/multi_process_lock_linux.cc
new file mode 100644
index 00000000000..b057bc72296
--- /dev/null
+++ b/chromium/chrome/common/multi_process_lock_linux.cc
@@ -0,0 +1,111 @@
+// 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 "chrome/common/multi_process_lock.h"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+
+class MultiProcessLockLinux : public MultiProcessLock {
+ public:
+ explicit MultiProcessLockLinux(const std::string& name)
+ : name_(name), fd_(-1) { }
+
+ ~MultiProcessLockLinux() override {
+ if (fd_ != -1) {
+ Unlock();
+ }
+ }
+
+ bool TryLock() override {
+ struct sockaddr_un address;
+
+ // +1 for terminator, +1 for 0 in position 0 that makes it an
+ // abstract named socket.
+ const size_t max_len = sizeof(address.sun_path) - 2;
+
+ if (fd_ != -1) {
+ DLOG(ERROR) << "MultiProcessLock is already locked - " << name_;
+ return true;
+ }
+
+ if (name_.length() > max_len) {
+ LOG(ERROR) << "Socket name too long (" << name_.length()
+ << " > " << max_len << ") - " << name_;
+ return false;
+ }
+
+ memset(&address, 0, sizeof(address));
+ int print_length = snprintf(&address.sun_path[1],
+ max_len + 1,
+ "%s", name_.c_str());
+
+ if (print_length < 0 ||
+ print_length > static_cast<int>(max_len)) {
+ PLOG(ERROR) << "Couldn't create sun_path - " << name_;
+ return false;
+ }
+
+ // Must set the first character of the path to something non-zero
+ // before we call SUN_LEN which depends on strcpy working.
+ address.sun_path[0] = '@';
+ size_t length = SUN_LEN(&address);
+
+ // Reset the first character of the path back to zero so that
+ // bind returns an abstract name socket.
+ address.sun_path[0] = 0;
+ address.sun_family = AF_LOCAL;
+
+ int socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (socket_fd < 0) {
+ PLOG(ERROR) << "Couldn't create socket - " << name_;
+ return false;
+ }
+
+ if (bind(socket_fd,
+ reinterpret_cast<sockaddr *>(&address),
+ length) == 0) {
+ fd_ = socket_fd;
+ return true;
+ } else {
+ DVLOG(1) << "Couldn't bind socket - "
+ << &(address.sun_path[1])
+ << " Length: " << length;
+ if (IGNORE_EINTR(close(socket_fd)) < 0) {
+ PLOG(ERROR) << "close";
+ }
+ return false;
+ }
+ }
+
+ void Unlock() override {
+ if (fd_ == -1) {
+ DLOG(ERROR) << "Over-unlocked MultiProcessLock - " << name_;
+ return;
+ }
+ if (IGNORE_EINTR(close(fd_)) < 0) {
+ DPLOG(ERROR) << "close";
+ }
+ fd_ = -1;
+ }
+
+ private:
+ std::string name_;
+ int fd_;
+ DISALLOW_COPY_AND_ASSIGN(MultiProcessLockLinux);
+};
+
+std::unique_ptr<MultiProcessLock> MultiProcessLock::Create(
+ const std::string& name) {
+ return std::make_unique<MultiProcessLockLinux>(name);
+}
diff --git a/chromium/chrome/common/multi_process_lock_mac.cc b/chromium/chrome/common/multi_process_lock_mac.cc
new file mode 100644
index 00000000000..3ec3e3236ca
--- /dev/null
+++ b/chromium/chrome/common/multi_process_lock_mac.cc
@@ -0,0 +1,59 @@
+// 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 "chrome/common/multi_process_lock.h"
+
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
+#include "base/strings/sys_string_conversions.h"
+
+#include <servers/bootstrap.h>
+
+class MultiProcessLockMac : public MultiProcessLock {
+ public:
+ explicit MultiProcessLockMac(const std::string& name) : name_(name) { }
+
+ ~MultiProcessLockMac() override {
+ if (port_ != NULL) {
+ Unlock();
+ }
+ }
+
+ bool TryLock() override {
+ if (port_ != NULL) {
+ DLOG(ERROR) << "MultiProcessLock is already locked - " << name_;
+ return true;
+ }
+
+ if (name_.length() >= BOOTSTRAP_MAX_NAME_LEN) {
+ LOG(ERROR) << "Socket name too long (" << name_.length()
+ << " >= " << BOOTSTRAP_MAX_NAME_LEN << ") - " << name_;
+ return false;
+ }
+
+ CFStringRef cf_name(base::SysUTF8ToCFStringRef(name_));
+ base::ScopedCFTypeRef<CFStringRef> scoped_cf_name(cf_name);
+ port_.reset(CFMessagePortCreateLocal(NULL, cf_name, NULL, NULL, NULL));
+ return port_ != NULL;
+ }
+
+ void Unlock() override {
+ if (port_ == NULL) {
+ DLOG(ERROR) << "Over-unlocked MultiProcessLock - " << name_;
+ return;
+ }
+ port_.reset();
+ }
+
+ private:
+ std::string name_;
+ base::ScopedCFTypeRef<CFMessagePortRef> port_;
+ DISALLOW_COPY_AND_ASSIGN(MultiProcessLockMac);
+};
+
+std::unique_ptr<MultiProcessLock> MultiProcessLock::Create(
+ const std::string& name) {
+ return std::make_unique<MultiProcessLockMac>(name);
+}
diff --git a/chromium/chrome/common/multi_process_lock_unittest.cc b/chromium/chrome/common/multi_process_lock_unittest.cc
new file mode 100644
index 00000000000..4d59c5ad471
--- /dev/null
+++ b/chromium/chrome/common/multi_process_lock_unittest.cc
@@ -0,0 +1,168 @@
+// 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 "chrome/common/multi_process_lock.h"
+
+#include <memory>
+
+#include "base/environment.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/process/kill.h"
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/scoped_environment_variable_override.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "testing/multiprocess_func_list.h"
+
+class MultiProcessLockTest : public base::MultiProcessTest {
+ public:
+ static const char kLockEnvironmentVarName[];
+
+ std::string GenerateLockName();
+ void ExpectLockIsLocked(const std::string &name);
+ void ExpectLockIsUnlocked(const std::string &name);
+};
+
+const char MultiProcessLockTest::kLockEnvironmentVarName[] =
+ "MULTI_PROCESS_TEST_LOCK_NAME";
+
+std::string MultiProcessLockTest::GenerateLockName() {
+ base::Time now = base::Time::NowFromSystemTime();
+ return base::StringPrintf("multi_process_test_lock %lf%lf",
+ now.ToDoubleT(), base::RandDouble());
+}
+
+void MultiProcessLockTest::ExpectLockIsLocked(const std::string &name) {
+ base::test::ScopedEnvironmentVariableOverride var(kLockEnvironmentVarName,
+ name);
+ EXPECT_FALSE(var.WasSet());
+
+ base::Process process = SpawnChild("MultiProcessLockTryFailMain");
+ ASSERT_TRUE(process.IsValid());
+ int exit_code = -1;
+ EXPECT_TRUE(process.WaitForExit(&exit_code));
+ EXPECT_EQ(0, exit_code);
+}
+
+void MultiProcessLockTest::ExpectLockIsUnlocked(
+ const std::string &name) {
+ base::test::ScopedEnvironmentVariableOverride var(kLockEnvironmentVarName,
+ name);
+ EXPECT_FALSE(var.WasSet());
+ base::Process process = SpawnChild("MultiProcessLockTrySucceedMain");
+ ASSERT_TRUE(process.IsValid());
+ int exit_code = -1;
+ EXPECT_TRUE(process.WaitForExit(&exit_code));
+ EXPECT_EQ(0, exit_code);
+}
+
+TEST_F(MultiProcessLockTest, BasicCreationTest) {
+ // Test basic creation/destruction with no lock taken
+ std::string name = GenerateLockName();
+ std::unique_ptr<MultiProcessLock> scoped = MultiProcessLock::Create(name);
+ ExpectLockIsUnlocked(name);
+ scoped.reset(NULL);
+}
+
+TEST_F(MultiProcessLockTest, LongNameTest) {
+ // Every platform has has it's own max path name size,
+ // so different checks are needed for them.
+ // POSIX: sizeof(address.sun_path) - 2
+ // Mac OS X: BOOTSTRAP_MAX_NAME_LEN
+ // Windows: MAX_PATH
+ LOG(INFO) << "Following error log due to long name is expected";
+#if defined(OS_MACOSX)
+ std::string name("This is a name that is longer than one hundred and "
+ "twenty-eight characters to make sure that we fail appropriately on "
+ "Mac OS X when we have a path that is too long for Mac OS X to handle");
+#elif defined(OS_POSIX)
+ std::string name("This is a name that is longer than one hundred and eight "
+ "characters to make sure that we fail appropriately on POSIX systems "
+ "when we have a path that is too long for the system to handle");
+#elif defined(OS_WIN)
+ std::string name("This is a name that is longer than two hundred and sixty "
+ "characters to make sure that we fail appropriately on Windows when we "
+ "have a path that is too long for Windows to handle "
+ "This limitation comes from the MAX_PATH definition which is obviously "
+ "defined to be a maximum of two hundred and sixty characters ");
+#endif
+ std::unique_ptr<MultiProcessLock> test_lock = MultiProcessLock::Create(name);
+ EXPECT_FALSE(test_lock->TryLock());
+}
+
+TEST_F(MultiProcessLockTest, SimpleLock) {
+ std::string name = GenerateLockName();
+ std::unique_ptr<MultiProcessLock> test_lock = MultiProcessLock::Create(name);
+ EXPECT_TRUE(test_lock->TryLock());
+ ExpectLockIsLocked(name);
+ test_lock->Unlock();
+ ExpectLockIsUnlocked(name);
+}
+
+TEST_F(MultiProcessLockTest, RecursiveLock) {
+ std::string name = GenerateLockName();
+ std::unique_ptr<MultiProcessLock> test_lock = MultiProcessLock::Create(name);
+ EXPECT_TRUE(test_lock->TryLock());
+ ExpectLockIsLocked(name);
+ LOG(INFO) << "Following error log "
+ << "'MultiProcessLock is already locked' is expected";
+ EXPECT_TRUE(test_lock->TryLock());
+ ExpectLockIsLocked(name);
+ test_lock->Unlock();
+ ExpectLockIsUnlocked(name);
+ LOG(INFO) << "Following error log "
+ << "'Over-unlocked MultiProcessLock' is expected";
+ test_lock->Unlock();
+ ExpectLockIsUnlocked(name);
+ test_lock.reset();
+}
+
+TEST_F(MultiProcessLockTest, LockScope) {
+ // Check to see that lock is released when it goes out of scope.
+ std::string name = GenerateLockName();
+ {
+ std::unique_ptr<MultiProcessLock> test_lock =
+ MultiProcessLock::Create(name);
+ EXPECT_TRUE(test_lock->TryLock());
+ ExpectLockIsLocked(name);
+ }
+ ExpectLockIsUnlocked(name);
+}
+
+MULTIPROCESS_TEST_MAIN(MultiProcessLockTryFailMain) {
+ std::string name;
+ std::unique_ptr<base::Environment> environment(base::Environment::Create());
+ EXPECT_TRUE(environment->GetVar(MultiProcessLockTest::kLockEnvironmentVarName,
+ &name));
+#if defined(OS_MACOSX)
+ // OS X sends out a log if a lock fails.
+ // Hopefully this will keep people from panicking about it when they
+ // are perusing the build logs.
+ LOG(INFO) << "Following error log "
+ << "\"CFMessagePort: bootstrap_register(): failed 1100 (0x44c) "
+ << "'Permission denied'\" is expected";
+#endif // defined(OS_MACOSX)
+ std::unique_ptr<MultiProcessLock> test_lock = MultiProcessLock::Create(name);
+
+ // Expect locking to fail because it is claimed by another process.
+ bool locked_successfully = test_lock->TryLock();
+ EXPECT_FALSE(locked_successfully);
+ return locked_successfully;
+}
+
+MULTIPROCESS_TEST_MAIN(MultiProcessLockTrySucceedMain) {
+ std::string name;
+ std::unique_ptr<base::Environment> environment(base::Environment::Create());
+ EXPECT_TRUE(environment->GetVar(MultiProcessLockTest::kLockEnvironmentVarName,
+ &name));
+ std::unique_ptr<MultiProcessLock> test_lock = MultiProcessLock::Create(name);
+
+ // Expect locking to succeed because it is not claimed yet.
+ bool locked_successfully = test_lock->TryLock();
+ EXPECT_TRUE(locked_successfully);
+ return !locked_successfully;
+}
diff --git a/chromium/chrome/common/multi_process_lock_win.cc b/chromium/chrome/common/multi_process_lock_win.cc
new file mode 100644
index 00000000000..d7819b7ebbe
--- /dev/null
+++ b/chromium/chrome/common/multi_process_lock_win.cc
@@ -0,0 +1,63 @@
+// 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 "chrome/common/multi_process_lock.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/scoped_handle.h"
+
+#include <windows.h>
+
+class MultiProcessLockWin : public MultiProcessLock {
+ public:
+ explicit MultiProcessLockWin(const std::string& name) : name_(name) { }
+
+ ~MultiProcessLockWin() override {
+ if (event_.Get() != NULL) {
+ Unlock();
+ }
+ }
+
+ bool TryLock() override {
+ if (event_.Get() != NULL) {
+ DLOG(ERROR) << "MultiProcessLock is already locked - " << name_;
+ return true;
+ }
+
+ if (name_.length() >= MAX_PATH) {
+ LOG(ERROR) << "Socket name too long (" << name_.length()
+ << " >= " << MAX_PATH << ") - " << name_;
+ return false;
+ }
+
+ base::string16 wname = base::UTF8ToUTF16(name_);
+ event_.Set(CreateEvent(NULL, FALSE, FALSE, wname.c_str()));
+ if (event_.Get() && GetLastError() != ERROR_ALREADY_EXISTS) {
+ return true;
+ } else {
+ event_.Set(NULL);
+ return false;
+ }
+ }
+
+ void Unlock() override {
+ if (event_.Get() == NULL) {
+ DLOG(ERROR) << "Over-unlocked MultiProcessLock - " << name_;
+ return;
+ }
+ event_.Set(NULL);
+ }
+
+ private:
+ std::string name_;
+ base::win::ScopedHandle event_;
+ DISALLOW_COPY_AND_ASSIGN(MultiProcessLockWin);
+};
+
+std::unique_ptr<MultiProcessLock> MultiProcessLock::Create(
+ const std::string& name) {
+ return std::make_unique<MultiProcessLockWin>(name);
+}
diff --git a/chromium/chrome/common/net/DEPS b/chromium/chrome/common/net/DEPS
new file mode 100644
index 00000000000..1b4d86377c7
--- /dev/null
+++ b/chromium/chrome/common/net/DEPS
@@ -0,0 +1,5 @@
+include_rules = [
+ # Other libraries.
+ "+chrome/third_party/mozilla_security_manager",
+ "+components/google/core/common",
+]
diff --git a/chromium/chrome/common/net/OWNERS b/chromium/chrome/common/net/OWNERS
new file mode 100644
index 00000000000..b77292902d2
--- /dev/null
+++ b/chromium/chrome/common/net/OWNERS
@@ -0,0 +1,4 @@
+file://net/OWNERS
+
+# COMPONENT: Internals>Network
+# TEAM: net-dev@chromium.org
diff --git a/chromium/chrome/common/net/net_resource_provider.cc b/chromium/chrome/common/net/net_resource_provider.cc
new file mode 100644
index 00000000000..1ee21324c6c
--- /dev/null
+++ b/chromium/chrome/common/net/net_resource_provider.cc
@@ -0,0 +1,64 @@
+// 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 "chrome/common/net/net_resource_provider.h"
+
+#include <string>
+
+#include "base/i18n/rtl.h"
+#include "base/no_destructor.h"
+#include "base/values.h"
+#include "chrome/grit/chromium_strings.h"
+#include "chrome/grit/generated_resources.h"
+#include "net/grit/net_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/layout.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/webui/jstemplate_builder.h"
+
+namespace {
+
+// The net module doesn't have access to this HTML or the strings that need to
+// be localized. The Chrome locale will never change while we're running, so
+// it's safe to have a static string that we always return a pointer into.
+struct LazyDirectoryListerCacher {
+ LazyDirectoryListerCacher() {
+ base::DictionaryValue value;
+ value.SetString("header",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_HEADER));
+ value.SetString("parentDirText",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_PARENT));
+ value.SetString("headerName",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_NAME));
+ value.SetString("headerSize",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_SIZE));
+ value.SetString("headerDateModified",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_DATE_MODIFIED));
+ value.SetString("language",
+ l10n_util::GetLanguage(base::i18n::GetConfiguredLocale()));
+ value.SetString("listingParsingErrorBoxText",
+ l10n_util::GetStringFUTF16(IDS_DIRECTORY_LISTING_PARSING_ERROR_BOX_TEXT,
+ l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)));
+ value.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
+ std::string str = webui::GetI18nTemplateHtml(
+ ui::ResourceBundle::GetSharedInstance().DecompressDataResource(
+ IDR_DIR_HEADER_HTML),
+ &value);
+
+ html_data = base::RefCountedString::TakeString(&str);
+ }
+
+ scoped_refptr<base::RefCountedMemory> html_data;
+};
+
+} // namespace
+
+scoped_refptr<base::RefCountedMemory> ChromeNetResourceProvider(int key) {
+ static base::NoDestructor<LazyDirectoryListerCacher> lazy_dir_lister;
+
+ if (IDR_DIR_HEADER_HTML == key)
+ return lazy_dir_lister->html_data;
+
+ return ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(key);
+}
diff --git a/chromium/chrome/common/net/net_resource_provider.h b/chromium/chrome/common/net/net_resource_provider.h
new file mode 100644
index 00000000000..7a2d5453e13
--- /dev/null
+++ b/chromium/chrome/common/net/net_resource_provider.h
@@ -0,0 +1,13 @@
+// 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 CHROME_COMMON_NET_NET_RESOURCE_PROVIDER_H_
+#define CHROME_COMMON_NET_NET_RESOURCE_PROVIDER_H_
+
+#include "base/memory/ref_counted_memory.h"
+
+// This is called indirectly by the network layer to access resources.
+scoped_refptr<base::RefCountedMemory> ChromeNetResourceProvider(int key);
+
+#endif // CHROME_COMMON_NET_NET_RESOURCE_PROVIDER_H_
diff --git a/chromium/chrome/common/net/safe_search_util.cc b/chromium/chrome/common/net/safe_search_util.cc
new file mode 100644
index 00000000000..60fdaa97229
--- /dev/null
+++ b/chromium/chrome/common/net/safe_search_util.cc
@@ -0,0 +1,113 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/net/safe_search_util.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.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/google/core/common/google_util.h"
+#include "net/cookies/cookie_util.h"
+#include "net/http/http_request_headers.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Returns whether a URL parameter, |first_parameter| (e.g. foo=bar), has the
+// same key as the the |second_parameter| (e.g. foo=baz). Both parameters
+// must be in key=value form.
+bool HasSameParameterKey(base::StringPiece first_parameter,
+ base::StringPiece second_parameter) {
+ DCHECK(second_parameter.find("=") != std::string::npos);
+ // Prefix for "foo=bar" is "foo=".
+ base::StringPiece parameter_prefix =
+ second_parameter.substr(0, second_parameter.find("=") + 1);
+ return base::StartsWith(first_parameter, parameter_prefix,
+ base::CompareCase::INSENSITIVE_ASCII);
+}
+
+// Examines the query string containing parameters and adds the necessary ones
+// so that SafeSearch is active. |query| is the string to examine and the
+// return value is the |query| string modified such that SafeSearch is active.
+std::string AddSafeSearchParameters(const std::string& query) {
+ std::vector<base::StringPiece> new_parameters;
+ std::string safe_parameter = safe_search_util::kSafeSearchSafeParameter;
+ std::string ssui_parameter = safe_search_util::kSafeSearchSsuiParameter;
+
+ for (const base::StringPiece& param : base::SplitStringPiece(
+ query, "&", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+ if (!HasSameParameterKey(param, safe_parameter) &&
+ !HasSameParameterKey(param, ssui_parameter)) {
+ new_parameters.push_back(param);
+ }
+ }
+
+ new_parameters.push_back(safe_parameter);
+ new_parameters.push_back(ssui_parameter);
+ return base::JoinString(new_parameters, "&");
+}
+
+} // namespace
+
+namespace safe_search_util {
+
+const char kSafeSearchSafeParameter[] = "safe=active";
+const char kSafeSearchSsuiParameter[] = "ssui=on";
+const char kYouTubeRestrictHeaderName[] = "YouTube-Restrict";
+const char kYouTubeRestrictHeaderValueModerate[] = "Moderate";
+const char kYouTubeRestrictHeaderValueStrict[] = "Strict";
+const char kGoogleAppsAllowedDomains[] = "X-GoogApps-Allowed-Domains";
+
+// If |request| is a request to Google Web Search the function
+// enforces that the SafeSearch query parameters are set to active.
+// Sets the query part of |new_url| with the new value of the parameters.
+void ForceGoogleSafeSearch(const GURL& url, GURL* new_url) {
+ if (!google_util::IsGoogleSearchUrl(url) &&
+ !google_util::IsGoogleHomePageUrl(url))
+ return;
+
+ std::string query = url.query();
+ std::string new_query = AddSafeSearchParameters(query);
+ if (query == new_query)
+ return;
+
+ GURL::Replacements replacements;
+ replacements.SetQueryStr(new_query);
+ *new_url = url.ReplaceComponents(replacements);
+}
+
+void ForceYouTubeRestrict(const GURL& url,
+ net::HttpRequestHeaders* headers,
+ YouTubeRestrictMode mode) {
+ if (!google_util::IsYoutubeDomainUrl(
+ url, google_util::ALLOW_SUBDOMAIN,
+ google_util::DISALLOW_NON_STANDARD_PORTS))
+ return;
+
+ switch (mode) {
+ case YOUTUBE_RESTRICT_OFF:
+ case YOUTUBE_RESTRICT_COUNT:
+ NOTREACHED();
+ break;
+
+ case YOUTUBE_RESTRICT_MODERATE:
+ headers->SetHeader(kYouTubeRestrictHeaderName,
+ kYouTubeRestrictHeaderValueModerate);
+ break;
+
+ case YOUTUBE_RESTRICT_STRICT:
+ headers->SetHeader(kYouTubeRestrictHeaderName,
+ kYouTubeRestrictHeaderValueStrict);
+ break;
+ }
+}
+
+} // namespace safe_search_util
diff --git a/chromium/chrome/common/net/safe_search_util.h b/chromium/chrome/common/net/safe_search_util.h
new file mode 100644
index 00000000000..f52b08274f9
--- /dev/null
+++ b/chromium/chrome/common/net/safe_search_util.h
@@ -0,0 +1,55 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_NET_SAFE_SEARCH_UTIL_H_
+#define CHROME_COMMON_NET_SAFE_SEARCH_UTIL_H_
+
+class GURL;
+
+namespace net {
+class HttpRequestHeaders;
+}
+
+namespace safe_search_util {
+
+// Parameters that get appended to force SafeSearch.
+extern const char kSafeSearchSafeParameter[];
+extern const char kSafeSearchSsuiParameter[];
+
+// Headers set for restricted YouTube.
+extern const char kYouTubeRestrictHeaderName[];
+extern const char kYouTubeRestrictHeaderValueModerate[];
+extern const char kYouTubeRestrictHeaderValueStrict[];
+
+// Header set when restricting allowed domains for apps.
+extern const char kGoogleAppsAllowedDomains[];
+
+// Values for YouTube Restricted Mode.
+// VALUES MUST COINCIDE WITH ForceYouTubeRestrict POLICY.
+enum YouTubeRestrictMode {
+ YOUTUBE_RESTRICT_OFF = 0, // Do not restrict YouTube content. YouTube
+ // might still restrict content based on its
+ // user settings.
+ YOUTUBE_RESTRICT_MODERATE = 1, // Enforce at least a moderately strict
+ // content filter for YouTube.
+ YOUTUBE_RESTRICT_STRICT = 2, // Enforce a strict content filter for YouTube.
+ YOUTUBE_RESTRICT_COUNT = 3 // Enum counter
+};
+
+// If |url| is a url to Google Web Search, enforces that the SafeSearch
+// query parameters are set to active. Sets |new_url| to a copy of the request
+// url in which the query part contains the new values of the parameters.
+void ForceGoogleSafeSearch(const GURL& url, GURL* new_url);
+
+// Does nothing if |url| is not a url to YouTube. Otherwise, if |mode|
+// is not |YOUTUBE_RESTRICT_OFF|, enforces a minimum YouTube Restrict mode
+// by setting YouTube Restrict header. Setting |YOUTUBE_RESTRICT_OFF| is not
+// supported and will do nothing in production.
+void ForceYouTubeRestrict(const GURL& url,
+ net::HttpRequestHeaders* headers,
+ YouTubeRestrictMode mode);
+
+} // namespace safe_search_util
+
+#endif // CHROME_COMMON_NET_SAFE_SEARCH_UTIL_H_
diff --git a/chromium/chrome/common/net/safe_search_util_unittest.cc b/chromium/chrome/common/net/safe_search_util_unittest.cc
new file mode 100644
index 00000000000..0dcf9466710
--- /dev/null
+++ b/chromium/chrome/common/net/safe_search_util_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/net/safe_search_util.h"
+
+#include "base/strings/string_piece.h"
+#include "chrome/common/url_constants.h"
+#include "net/http/http_request_headers.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+// Does a request using the |url_string| URL and verifies that the expected
+// string is equal to the query part (between ? and #) of the final url of
+// that request.
+void CheckAddedParameters(const std::string& url_string,
+ const std::string& expected_query_parameters) {
+ // Show the URL in the trace so we know where we failed.
+ SCOPED_TRACE(url_string);
+
+ GURL result(url_string);
+ safe_search_util::ForceGoogleSafeSearch(GURL(url_string), &result);
+
+ EXPECT_EQ(expected_query_parameters, result.query());
+}
+
+TEST(SafeSearchUtilTest, AddGoogleSafeSearchParams) {
+ const std::string kSafeParameter = safe_search_util::kSafeSearchSafeParameter;
+ const std::string kSsuiParameter = safe_search_util::kSafeSearchSsuiParameter;
+ const std::string kBothParameters = kSafeParameter + "&" + kSsuiParameter;
+
+ // Test the home page.
+ CheckAddedParameters("http://google.com/", kBothParameters);
+
+ // Test the search home page.
+ CheckAddedParameters("http://google.com/webhp", kBothParameters);
+
+ // Test different valid search pages with parameters.
+ CheckAddedParameters("http://google.com/search?q=google",
+ "q=google&" + kBothParameters);
+
+ CheckAddedParameters("http://google.com/?q=google",
+ "q=google&" + kBothParameters);
+
+ CheckAddedParameters("http://google.com/webhp?q=google",
+ "q=google&" + kBothParameters);
+
+ // Test the valid pages with safe set to off.
+ CheckAddedParameters("http://google.com/search?q=google&safe=off",
+ "q=google&" + kBothParameters);
+
+ CheckAddedParameters("http://google.com/?q=google&safe=off",
+ "q=google&" + kBothParameters);
+
+ CheckAddedParameters("http://google.com/webhp?q=google&safe=off",
+ "q=google&" + kBothParameters);
+
+ CheckAddedParameters("http://google.com/webhp?q=google&%73afe=off",
+ "q=google&%73afe=off&" + kBothParameters);
+
+ // Test the home page, different TLDs.
+ CheckAddedParameters("http://google.de/", kBothParameters);
+ CheckAddedParameters("http://google.ro/", kBothParameters);
+ CheckAddedParameters("http://google.nl/", kBothParameters);
+
+ // Test the search home page, different TLD.
+ CheckAddedParameters("http://google.de/webhp", kBothParameters);
+
+ // Test the search page with parameters, different TLD.
+ CheckAddedParameters("http://google.de/search?q=google",
+ "q=google&" + kBothParameters);
+
+ // Test the home page with parameters, different TLD.
+ CheckAddedParameters("http://google.de/?q=google",
+ "q=google&" + kBothParameters);
+
+ // Test the search page with the parameters set.
+ CheckAddedParameters("http://google.de/?q=google&" + kBothParameters,
+ "q=google&" + kBothParameters);
+
+ // Test some possibly tricky combinations.
+ CheckAddedParameters(
+ "http://google.com/?q=goog&" + kSafeParameter + "&ssui=one",
+ "q=goog&" + kBothParameters);
+
+ CheckAddedParameters(
+ "http://google.de/?q=goog&unsafe=active&" + kSsuiParameter,
+ "q=goog&unsafe=active&" + kBothParameters);
+
+ CheckAddedParameters("http://google.de/?q=goog&safe=off&ssui=off",
+ "q=goog&" + kBothParameters);
+
+ CheckAddedParameters("http://google.de/?q=&tbs=rimg:",
+ "q=&tbs=rimg:&" + kBothParameters);
+
+ // Test various combinations where we should not add anything.
+ CheckAddedParameters(
+ "http://google.com/?q=goog&" + kSsuiParameter + "&" + kSafeParameter,
+ "q=goog&" + kBothParameters);
+
+ CheckAddedParameters(
+ "http://google.com/?" + kSsuiParameter + "&q=goog&" + kSafeParameter,
+ "q=goog&" + kBothParameters);
+
+ CheckAddedParameters(
+ "http://google.com/?" + kSsuiParameter + "&" + kSafeParameter + "&q=goog",
+ "q=goog&" + kBothParameters);
+
+ // Test that another website is not affected, without parameters.
+ CheckAddedParameters("http://google.com/finance", std::string());
+
+ // Test that another website is not affected, with parameters.
+ CheckAddedParameters("http://google.com/finance?q=goog", "q=goog");
+
+ // Test with percent-encoded data (%26 is &)
+ CheckAddedParameters("http://google.com/?q=%26%26%26&" + kSsuiParameter +
+ "&" + kSafeParameter + "&param=%26%26%26",
+ "q=%26%26%26&param=%26%26%26&" + kBothParameters);
+}
+
+TEST(SafeSearchUtilTest, SetYoutubeHeader) {
+ net::HttpRequestHeaders headers;
+ safe_search_util::ForceYouTubeRestrict(
+ GURL("http://www.youtube.com"), &headers,
+ safe_search_util::YOUTUBE_RESTRICT_MODERATE);
+ std::string value;
+ EXPECT_TRUE(headers.GetHeader("Youtube-Restrict", &value));
+ EXPECT_EQ("Moderate", value);
+}
+
+TEST(SafeSearchUtilTest, OverrideYoutubeHeader) {
+ net::HttpRequestHeaders headers;
+ headers.SetHeader("Youtube-Restrict", "Off");
+ safe_search_util::ForceYouTubeRestrict(
+ GURL("http://www.youtube.com"), &headers,
+ safe_search_util::YOUTUBE_RESTRICT_MODERATE);
+ std::string value;
+ EXPECT_TRUE(headers.GetHeader("Youtube-Restrict", &value));
+ EXPECT_EQ("Moderate", value);
+}
+
+TEST(SafeSearchUtilTest, DoesntTouchNonYoutubeURL) {
+ net::HttpRequestHeaders headers;
+ headers.SetHeader("Youtube-Restrict", "Off");
+ safe_search_util::ForceYouTubeRestrict(
+ GURL("http://www.notyoutube.com"), &headers,
+ safe_search_util::YOUTUBE_RESTRICT_MODERATE);
+ std::string value;
+ EXPECT_TRUE(headers.GetHeader("Youtube-Restrict", &value));
+ EXPECT_EQ("Off", value);
+}
+
+} // namespace
diff --git a/chromium/chrome/common/net/x509_certificate_model_nss.cc b/chromium/chrome/common/net/x509_certificate_model_nss.cc
new file mode 100644
index 00000000000..5932c3a0f17
--- /dev/null
+++ b/chromium/chrome/common/net/x509_certificate_model_nss.cc
@@ -0,0 +1,365 @@
+// 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 "chrome/common/net/x509_certificate_model_nss.h"
+
+#include <cert.h>
+#include <cms.h>
+#include <hasht.h>
+#include <keyhi.h> // SECKEY_DestroyPrivateKey
+#include <keythi.h> // SECKEYPrivateKey
+#include <pk11pub.h> // PK11_FindKeyByAnyCert
+#include <seccomon.h> // SECItem
+#include <sechash.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <unicode/uidna.h>
+
+#include <algorithm>
+#include <memory>
+
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/grit/generated_resources.h"
+#include "chrome/third_party/mozilla_security_manager/nsNSSCertHelper.h"
+#include "chrome/third_party/mozilla_security_manager/nsNSSCertificate.h"
+#include "chrome/third_party/mozilla_security_manager/nsUsageArrayHelper.h"
+#include "components/url_formatter/url_formatter.h"
+#include "crypto/nss_util.h"
+#include "crypto/scoped_nss_types.h"
+#include "net/cert/x509_util_nss.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace psm = mozilla_security_manager;
+
+namespace {
+
+// Convert a char* return value from NSS into a std::string and free the NSS
+// memory. If the arg is NULL, an empty string will be returned instead.
+std::string Stringize(char* nss_text, const std::string& alternative_text) {
+ if (!nss_text)
+ return alternative_text;
+
+ std::string s = nss_text;
+ PORT_Free(nss_text);
+ return s;
+}
+
+// Hash a certificate using the given algorithm, return the result as a
+// colon-seperated hex string. The len specified is the number of bytes
+// required for storing the raw fingerprint.
+// (It's a bit redundant that the caller needs to specify len in addition to the
+// algorithm, but given the limited uses, not worth fixing.)
+std::string HashCert(CERTCertificate* cert, HASH_HashType algorithm, int len) {
+ unsigned char fingerprint[HASH_LENGTH_MAX];
+
+ DCHECK(NULL != cert->derCert.data);
+ DCHECK_NE(0U, cert->derCert.len);
+ DCHECK_LE(len, HASH_LENGTH_MAX);
+ memset(fingerprint, 0, len);
+ SECStatus rv = HASH_HashBuf(algorithm, fingerprint, cert->derCert.data,
+ cert->derCert.len);
+ DCHECK_EQ(rv, SECSuccess);
+ return x509_certificate_model::ProcessRawBytes(fingerprint, len);
+}
+
+std::string ProcessSecAlgorithmInternal(SECAlgorithmID* algorithm_id) {
+ return psm::GetOIDText(&algorithm_id->algorithm);
+}
+
+std::string ProcessExtension(
+ const std::string& critical_label,
+ const std::string& non_critical_label,
+ CERTCertExtension* extension) {
+ std::string criticality =
+ extension->critical.data && extension->critical.data[0] ?
+ critical_label : non_critical_label;
+ return criticality + "\n" + psm::ProcessExtensionData(extension);
+}
+
+std::string GetNickname(CERTCertificate* cert_handle) {
+ std::string name;
+ if (cert_handle->nickname) {
+ name = cert_handle->nickname;
+ // Hack copied from mozilla: Cut off text before first :, which seems to
+ // just be the token name.
+ size_t colon_pos = name.find(':');
+ if (colon_pos != std::string::npos)
+ name = name.substr(colon_pos + 1);
+ }
+ return name;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// NSS certificate export functions.
+
+struct NSSCMSMessageDeleter {
+ inline void operator()(NSSCMSMessage* x) const {
+ NSS_CMSMessage_Destroy(x);
+ }
+};
+typedef std::unique_ptr<NSSCMSMessage, NSSCMSMessageDeleter>
+ ScopedNSSCMSMessage;
+
+struct FreeNSSCMSSignedData {
+ inline void operator()(NSSCMSSignedData* x) const {
+ NSS_CMSSignedData_Destroy(x);
+ }
+};
+typedef std::unique_ptr<NSSCMSSignedData, FreeNSSCMSSignedData>
+ ScopedNSSCMSSignedData;
+
+} // namespace
+
+namespace x509_certificate_model {
+
+using std::string;
+
+string GetCertNameOrNickname(CERTCertificate* cert_handle) {
+ string name = ProcessIDN(
+ Stringize(CERT_GetCommonName(&cert_handle->subject), std::string()));
+ if (!name.empty())
+ return name;
+ return GetNickname(cert_handle);
+}
+
+string GetVersion(CERTCertificate* cert_handle) {
+ // If the version field is omitted from the certificate, the default
+ // value is v1(0).
+ unsigned long version = 0;
+ if (cert_handle->version.len == 0 ||
+ SEC_ASN1DecodeInteger(&cert_handle->version, &version) == SECSuccess) {
+ return base::NumberToString(base::strict_cast<uint64_t>(version + 1));
+ }
+ return std::string();
+}
+
+net::CertType GetType(CERTCertificate* cert_handle) {
+ return psm::GetCertType(cert_handle);
+}
+
+void GetUsageStrings(CERTCertificate* cert_handle,
+ std::vector<string>* usages) {
+ psm::GetCertUsageStrings(cert_handle, usages);
+}
+
+string GetSerialNumberHexified(CERTCertificate* cert_handle,
+ const string& alternative_text) {
+ return Stringize(CERT_Hexify(&cert_handle->serialNumber, true),
+ alternative_text);
+}
+
+string GetIssuerCommonName(CERTCertificate* cert_handle,
+ const string& alternative_text) {
+ return Stringize(CERT_GetCommonName(&cert_handle->issuer), alternative_text);
+}
+
+string GetIssuerOrgName(CERTCertificate* cert_handle,
+ const string& alternative_text) {
+ return Stringize(CERT_GetOrgName(&cert_handle->issuer), alternative_text);
+}
+
+string GetIssuerOrgUnitName(CERTCertificate* cert_handle,
+ const string& alternative_text) {
+ return Stringize(CERT_GetOrgUnitName(&cert_handle->issuer), alternative_text);
+}
+
+string GetSubjectOrgName(CERTCertificate* cert_handle,
+ const string& alternative_text) {
+ return Stringize(CERT_GetOrgName(&cert_handle->subject), alternative_text);
+}
+
+string GetSubjectOrgUnitName(CERTCertificate* cert_handle,
+ const string& alternative_text) {
+ return Stringize(CERT_GetOrgUnitName(&cert_handle->subject),
+ alternative_text);
+}
+
+string GetSubjectCommonName(CERTCertificate* cert_handle,
+ const string& alternative_text) {
+ return Stringize(CERT_GetCommonName(&cert_handle->subject), alternative_text);
+}
+
+bool GetTimes(CERTCertificate* cert_handle,
+ base::Time* issued,
+ base::Time* expires) {
+ return net::x509_util::GetValidityTimes(cert_handle, issued, expires);
+}
+
+string GetTitle(CERTCertificate* cert_handle) {
+ return psm::GetCertTitle(cert_handle);
+}
+
+string GetIssuerName(CERTCertificate* cert_handle) {
+ return psm::ProcessName(&cert_handle->issuer);
+}
+
+string GetSubjectName(CERTCertificate* cert_handle) {
+ return psm::ProcessName(&cert_handle->subject);
+}
+
+std::string GetIssuerDisplayName(CERTCertificate* cert_handle) {
+ return net::x509_util::GetCERTNameDisplayName(&cert_handle->issuer);
+}
+
+std::string GetSubjectDisplayName(CERTCertificate* cert_handle) {
+ return net::x509_util::GetCERTNameDisplayName(&cert_handle->subject);
+}
+
+void GetExtensions(const string& critical_label,
+ const string& non_critical_label,
+ CERTCertificate* cert_handle,
+ Extensions* extensions) {
+ if (cert_handle->extensions) {
+ for (size_t i = 0; cert_handle->extensions[i] != NULL; ++i) {
+ Extension extension;
+ extension.name = psm::GetOIDText(&cert_handle->extensions[i]->id);
+ extension.value = ProcessExtension(
+ critical_label, non_critical_label, cert_handle->extensions[i]);
+ extensions->push_back(extension);
+ }
+ }
+}
+
+string HashCertSHA256(CERTCertificate* cert_handle) {
+ return HashCert(cert_handle, HASH_AlgSHA256, SHA256_LENGTH);
+}
+
+string HashCertSHA1(CERTCertificate* cert_handle) {
+ return HashCert(cert_handle, HASH_AlgSHA1, SHA1_LENGTH);
+}
+
+string GetCMSString(const net::ScopedCERTCertificateList& cert_chain,
+ size_t start,
+ size_t end) {
+ crypto::ScopedPLArenaPool arena(PORT_NewArena(1024));
+ DCHECK(arena.get());
+
+ ScopedNSSCMSMessage message(NSS_CMSMessage_Create(arena.get()));
+ DCHECK(message.get());
+
+ // First, create SignedData with the certificate only (no chain).
+ ScopedNSSCMSSignedData signed_data(NSS_CMSSignedData_CreateCertsOnly(
+ message.get(), cert_chain[start].get(), PR_FALSE));
+ if (!signed_data.get()) {
+ DLOG(ERROR) << "NSS_CMSSignedData_Create failed";
+ return std::string();
+ }
+ // Add the rest of the chain (if any).
+ for (size_t i = start + 1; i < end; ++i) {
+ if (NSS_CMSSignedData_AddCertificate(signed_data.get(),
+ cert_chain[i].get()) != SECSuccess) {
+ DLOG(ERROR) << "NSS_CMSSignedData_AddCertificate failed on " << i;
+ return std::string();
+ }
+ }
+
+ NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(message.get());
+ if (NSS_CMSContentInfo_SetContent_SignedData(
+ message.get(), cinfo, signed_data.get()) == SECSuccess) {
+ ignore_result(signed_data.release());
+ } else {
+ DLOG(ERROR) << "NSS_CMSMessage_GetContentInfo failed";
+ return std::string();
+ }
+
+ SECItem cert_p7 = { siBuffer, NULL, 0 };
+ NSSCMSEncoderContext *ecx = NSS_CMSEncoder_Start(message.get(), NULL, NULL,
+ &cert_p7, arena.get(), NULL,
+ NULL, NULL, NULL, NULL,
+ NULL);
+ if (!ecx) {
+ DLOG(ERROR) << "NSS_CMSEncoder_Start failed";
+ return std::string();
+ }
+
+ if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
+ DLOG(ERROR) << "NSS_CMSEncoder_Finish failed";
+ return std::string();
+ }
+
+ return string(reinterpret_cast<const char*>(cert_p7.data), cert_p7.len);
+}
+
+string ProcessSecAlgorithmSignature(CERTCertificate* cert_handle) {
+ return ProcessSecAlgorithmInternal(&cert_handle->signature);
+}
+
+string ProcessSecAlgorithmSubjectPublicKey(CERTCertificate* cert_handle) {
+ return ProcessSecAlgorithmInternal(
+ &cert_handle->subjectPublicKeyInfo.algorithm);
+}
+
+string ProcessSecAlgorithmSignatureWrap(CERTCertificate* cert_handle) {
+ return ProcessSecAlgorithmInternal(
+ &cert_handle->signatureWrap.signatureAlgorithm);
+}
+
+string ProcessSubjectPublicKeyInfo(CERTCertificate* cert_handle) {
+ return psm::ProcessSubjectPublicKeyInfo(&cert_handle->subjectPublicKeyInfo);
+}
+
+string ProcessRawBitsSignatureWrap(CERTCertificate* cert_handle) {
+ return ProcessRawBits(cert_handle->signatureWrap.signature.data,
+ cert_handle->signatureWrap.signature.len);
+}
+
+std::string ProcessIDN(const std::string& input) {
+ // Convert the ASCII input to a string16 for ICU.
+ base::string16 input16;
+ input16.reserve(input.length());
+ input16.insert(input16.end(), input.begin(), input.end());
+
+ base::string16 output16 = url_formatter::IDNToUnicode(input);
+ if (input16 == output16)
+ return input; // Input did not contain any encoded data.
+
+ // Input contained encoded data, return formatted string showing original and
+ // decoded forms.
+ return l10n_util::GetStringFUTF8(IDS_CERT_INFO_IDN_VALUE_FORMAT, input16,
+ output16);
+}
+
+std::string ProcessRawBytesWithSeparators(const unsigned char* data,
+ size_t data_length,
+ char hex_separator,
+ char line_separator) {
+ static const char kHexChars[] = "0123456789ABCDEF";
+
+ // Each input byte creates two output hex characters + a space or newline,
+ // except for the last byte.
+ std::string ret;
+ size_t kMin = 0U;
+
+ if (!data_length)
+ return std::string();
+
+ ret.reserve(std::max(kMin, data_length * 3 - 1));
+
+ for (size_t i = 0; i < data_length; ++i) {
+ unsigned char b = data[i];
+ ret.push_back(kHexChars[(b >> 4) & 0xf]);
+ ret.push_back(kHexChars[b & 0xf]);
+ if (i + 1 < data_length) {
+ if ((i + 1) % 16 == 0)
+ ret.push_back(line_separator);
+ else
+ ret.push_back(hex_separator);
+ }
+ }
+ return ret;
+}
+
+std::string ProcessRawBytes(const unsigned char* data, size_t data_length) {
+ return ProcessRawBytesWithSeparators(data, data_length, ' ', '\n');
+}
+
+std::string ProcessRawBits(const unsigned char* data, size_t data_length) {
+ return ProcessRawBytes(data, (data_length + 7) / 8);
+}
+
+} // namespace x509_certificate_model
diff --git a/chromium/chrome/common/net/x509_certificate_model_nss.h b/chromium/chrome/common/net/x509_certificate_model_nss.h
new file mode 100644
index 00000000000..c3a5c24e739
--- /dev/null
+++ b/chromium/chrome/common/net/x509_certificate_model_nss.h
@@ -0,0 +1,117 @@
+// 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 CHROME_COMMON_NET_X509_CERTIFICATE_MODEL_NSS_H_
+#define CHROME_COMMON_NET_X509_CERTIFICATE_MODEL_NSS_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "net/cert/cert_type.h"
+#include "net/cert/scoped_nss_types.h"
+
+typedef struct CERTCertificateStr CERTCertificate;
+
+namespace base {
+class Time;
+}
+
+// This namespace defines a set of functions to be used in UI-related bits of
+// X509 certificates.
+namespace x509_certificate_model {
+
+std::string GetCertNameOrNickname(CERTCertificate* cert_handle);
+
+std::string GetVersion(CERTCertificate* cert_handle);
+
+net::CertType GetType(CERTCertificate* cert_handle);
+
+void GetUsageStrings(CERTCertificate* cert_handle,
+ std::vector<std::string>* usages);
+
+std::string GetSerialNumberHexified(CERTCertificate* cert_handle,
+ const std::string& alternative_text);
+
+std::string GetIssuerCommonName(CERTCertificate* cert_handle,
+ const std::string& alternative_text);
+
+std::string GetIssuerOrgName(CERTCertificate* cert_handle,
+ const std::string& alternative_text);
+
+std::string GetIssuerOrgUnitName(CERTCertificate* cert_handle,
+ const std::string& alternative_text);
+
+std::string GetSubjectOrgName(CERTCertificate* cert_handle,
+ const std::string& alternative_text);
+
+std::string GetSubjectOrgUnitName(CERTCertificate* cert_handle,
+ const std::string& alternative_text);
+
+std::string GetSubjectCommonName(CERTCertificate* cert_handle,
+ const std::string& alternative_text);
+
+std::string GetIssuerDisplayName(CERTCertificate* cert_handle);
+std::string GetSubjectDisplayName(CERTCertificate* cert_handle);
+
+bool GetTimes(CERTCertificate* cert_handle,
+ base::Time* issued,
+ base::Time* expires);
+
+std::string GetTitle(CERTCertificate* cert_handle);
+std::string GetIssuerName(CERTCertificate* cert_handle);
+std::string GetSubjectName(CERTCertificate* cert_handle);
+
+struct Extension {
+ std::string name;
+ std::string value;
+};
+
+typedef std::vector<Extension> Extensions;
+
+void GetExtensions(const std::string& critical_label,
+ const std::string& non_critical_label,
+ CERTCertificate* cert_handle,
+ Extensions* extensions);
+
+// Hash a certificate using the given algorithm, return the result as a
+// colon-seperated hex string.
+std::string HashCertSHA256(CERTCertificate* cert_handle);
+std::string HashCertSHA1(CERTCertificate* cert_handle);
+
+std::string GetCMSString(const net::ScopedCERTCertificateList& cert_chain,
+ size_t start,
+ size_t end);
+
+std::string ProcessSecAlgorithmSignature(CERTCertificate* cert_handle);
+std::string ProcessSecAlgorithmSubjectPublicKey(CERTCertificate* cert_handle);
+std::string ProcessSecAlgorithmSignatureWrap(CERTCertificate* cert_handle);
+
+std::string ProcessSubjectPublicKeyInfo(CERTCertificate* cert_handle);
+
+std::string ProcessRawBitsSignatureWrap(CERTCertificate* cert_handle);
+
+// For host values, if they contain IDN Punycode-encoded A-labels, this will
+// return a string suitable for display that contains both the original and the
+// decoded U-label form. Otherwise, the string will be returned as is.
+std::string ProcessIDN(const std::string& input);
+
+// Format a buffer as |hex_separator| separated string, with 16 bytes on each
+// line separated using |line_separator|.
+std::string ProcessRawBytesWithSeparators(const unsigned char* data,
+ size_t data_length,
+ char hex_separator,
+ char line_separator);
+
+// Format a buffer as a space separated string, with 16 bytes on each line.
+std::string ProcessRawBytes(const unsigned char* data, size_t data_length);
+
+// Format a buffer as a space separated string, with 16 bytes on each line.
+// |data_length| is the length in bits.
+std::string ProcessRawBits(const unsigned char* data, size_t data_length);
+
+} // namespace x509_certificate_model
+
+#endif // CHROME_COMMON_NET_X509_CERTIFICATE_MODEL_NSS_H_
diff --git a/chromium/chrome/common/net/x509_certificate_model_nss_unittest.cc b/chromium/chrome/common/net/x509_certificate_model_nss_unittest.cc
new file mode 100644
index 00000000000..3bc0cc84cb2
--- /dev/null
+++ b/chromium/chrome/common/net/x509_certificate_model_nss_unittest.cc
@@ -0,0 +1,403 @@
+// 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 "chrome/common/net/x509_certificate_model_nss.h"
+
+#include <stddef.h>
+
+#include "base/files/file_path.h"
+#include "crypto/scoped_test_nss_db.h"
+#include "net/cert/nss_cert_database.h"
+#include "net/cert/scoped_nss_types.h"
+#include "net/cert/x509_util_nss.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(X509CertificateModelTest, GetCertNameOrNicknameAndGetTitle) {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "root_ca_cert.pem"));
+ ASSERT_TRUE(cert.get());
+ EXPECT_EQ("Test Root CA",
+ x509_certificate_model::GetCertNameOrNickname(cert.get()));
+
+ net::ScopedCERTCertificate punycode_cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "punycodetest.pem"));
+ ASSERT_TRUE(punycode_cert.get());
+ EXPECT_EQ("xn--wgv71a119e.com (日本語.com)",
+ x509_certificate_model::GetCertNameOrNickname(punycode_cert.get()));
+
+ net::ScopedCERTCertificate no_cn_cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "no_subject_common_name_cert.pem"));
+ ASSERT_TRUE(no_cn_cert.get());
+ // Temp cert has no nickname.
+ EXPECT_EQ("",
+ x509_certificate_model::GetCertNameOrNickname(no_cn_cert.get()));
+
+ EXPECT_EQ("xn--wgv71a119e.com",
+ x509_certificate_model::GetTitle(punycode_cert.get()));
+
+ EXPECT_EQ("E=wtc@google.com",
+ x509_certificate_model::GetTitle(no_cn_cert.get()));
+
+ net::ScopedCERTCertificate no_cn_cert2(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "ct-test-embedded-cert.pem"));
+ ASSERT_TRUE(no_cn_cert2.get());
+ EXPECT_EQ("L=Erw Wen,ST=Wales,O=Certificate Transparency,C=GB",
+ x509_certificate_model::GetTitle(no_cn_cert2.get()));
+}
+
+TEST(X509CertificateModelTest, GetExtensions) {
+ {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "root_ca_cert.pem"));
+ ASSERT_TRUE(cert.get());
+
+ x509_certificate_model::Extensions extensions;
+ x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
+ &extensions);
+ ASSERT_EQ(3U, extensions.size());
+
+ EXPECT_EQ("Certificate Basic Constraints", extensions[0].name);
+ EXPECT_EQ(
+ "critical\nIs a Certification Authority\n"
+ "Maximum number of intermediate CAs: unlimited",
+ extensions[0].value);
+
+ EXPECT_EQ("Certificate Subject Key ID", extensions[1].name);
+ EXPECT_EQ(
+ "notcrit\nKey ID: 9B 26 0B 8A 98 A9 BB 1D B9 1F 1C E3 1A 40 33 ED\n8E "
+ "17 88 AB",
+ extensions[1].value);
+
+ EXPECT_EQ("Certificate Key Usage", extensions[2].name);
+ EXPECT_EQ("critical\nCertificate Signer\nCRL Signer", extensions[2].value);
+ }
+
+ {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "subjectAltName_sanity_check.pem"));
+ ASSERT_TRUE(cert.get());
+
+ x509_certificate_model::Extensions extensions;
+ x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
+ &extensions);
+ ASSERT_EQ(2U, extensions.size());
+ EXPECT_EQ("Certificate Subject Alternative Name", extensions[1].name);
+ EXPECT_EQ(
+ "notcrit\nIP Address: 127.0.0.2\nIP Address: fe80::1\nDNS Name: "
+ "test.example\nEmail Address: test@test.example\nOID.1.2.3.4: 0C 09 69 "
+ "67 6E 6F 72 65 20 6D 65\nX.500 Name: CN = 127.0.0.3\n\n",
+ extensions[1].value);
+ }
+
+ {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "foaf.me.chromium-test-cert.der"));
+ ASSERT_TRUE(cert.get());
+
+ x509_certificate_model::Extensions extensions;
+ x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
+ &extensions);
+ ASSERT_EQ(5U, extensions.size());
+ EXPECT_EQ("Netscape Certificate Comment", extensions[1].name);
+ EXPECT_EQ("notcrit\nOpenSSL Generated Certificate", extensions[1].value);
+ }
+
+ {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "2029_globalsign_com_cert.pem"));
+ ASSERT_TRUE(cert.get());
+
+ x509_certificate_model::Extensions extensions;
+ x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
+ &extensions);
+ ASSERT_EQ(9U, extensions.size());
+
+ EXPECT_EQ("Certificate Subject Key ID", extensions[0].name);
+ EXPECT_EQ(
+ "notcrit\nKey ID: 59 BC D9 69 F7 B0 65 BB C8 34 C5 D2 C2 EF 17 78\nA6 "
+ "47 1E 8B",
+ extensions[0].value);
+
+ EXPECT_EQ("Certification Authority Key ID", extensions[1].name);
+ EXPECT_EQ(
+ "notcrit\nKey ID: 8A FC 14 1B 3D A3 59 67 A5 3B E1 73 92 A6 62 91\n7F "
+ "E4 78 30\n",
+ extensions[1].value);
+
+ EXPECT_EQ("Authority Information Access", extensions[2].name);
+ EXPECT_EQ(
+ "notcrit\nCA Issuers: "
+ "URI: http://secure.globalsign.net/cacert/SHA256extendval1.crt\n",
+ extensions[2].value);
+
+ EXPECT_EQ("CRL Distribution Points", extensions[3].name);
+ EXPECT_EQ("notcrit\nURI: http://crl.globalsign.net/SHA256ExtendVal1.crl\n",
+ extensions[3].value);
+
+ EXPECT_EQ("Certificate Basic Constraints", extensions[4].name);
+ EXPECT_EQ("notcrit\nIs not a Certification Authority\n",
+ extensions[4].value);
+
+ EXPECT_EQ("Certificate Key Usage", extensions[5].name);
+ EXPECT_EQ(
+ "critical\nSigning\nNon-repudiation\nKey Encipherment\n"
+ "Data Encipherment",
+ extensions[5].value);
+
+ EXPECT_EQ("Extended Key Usage", extensions[6].name);
+ EXPECT_EQ(
+ "notcrit\nTLS WWW Server Authentication (OID.1.3.6.1.5.5.7.3.1)\n"
+ "TLS WWW Client Authentication (OID.1.3.6.1.5.5.7.3.2)\n",
+ extensions[6].value);
+
+ EXPECT_EQ("Certificate Policies", extensions[7].name);
+ EXPECT_EQ(
+ "notcrit\nOID.1.3.6.1.4.1.4146.1.1:\n"
+ " Certification Practice Statement Pointer:"
+ " http://www.globalsign.net/repository/\n",
+ extensions[7].value);
+
+ EXPECT_EQ("Netscape Certificate Type", extensions[8].name);
+ EXPECT_EQ("notcrit\nSSL Client Certificate\nSSL Server Certificate",
+ extensions[8].value);
+ }
+
+ {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "diginotar_public_ca_2025.pem"));
+ ASSERT_TRUE(cert.get());
+
+ x509_certificate_model::Extensions extensions;
+ x509_certificate_model::GetExtensions("critical", "notcrit", cert.get(),
+ &extensions);
+ ASSERT_EQ(7U, extensions.size());
+
+ EXPECT_EQ("Authority Information Access", extensions[0].name);
+ EXPECT_EQ(
+ "notcrit\nOCSP Responder: "
+ "URI: http://validation.diginotar.nl\n",
+ extensions[0].value);
+
+ EXPECT_EQ("Certificate Basic Constraints", extensions[2].name);
+ EXPECT_EQ(
+ "critical\nIs a Certification Authority\n"
+ "Maximum number of intermediate CAs: 0",
+ extensions[2].value);
+ EXPECT_EQ("Certificate Policies", extensions[3].name);
+ EXPECT_EQ(
+ "notcrit\nOID.2.16.528.1.1001.1.1.1.1.5.2.6.4:\n"
+ " Certification Practice Statement Pointer:"
+ " http://www.diginotar.nl/cps\n"
+ " User Notice:\n"
+ " Conditions, as mentioned on our website (www.diginotar.nl), are "
+ "applicable to all our products and services.\n",
+ extensions[3].value);
+ }
+}
+
+TEST(X509CertificateModelTest, GetTypeCA) {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "root_ca_cert.pem"));
+ ASSERT_TRUE(cert.get());
+
+ EXPECT_EQ(net::CA_CERT, x509_certificate_model::GetType(cert.get()));
+
+ crypto::ScopedTestNSSDB test_nssdb;
+ net::NSSCertDatabase db(crypto::ScopedPK11Slot(PK11_ReferenceSlot(
+ test_nssdb.slot())) /* public slot */,
+ crypto::ScopedPK11Slot(PK11_ReferenceSlot(
+ test_nssdb.slot())) /* private slot */);
+
+ // Test that explicitly distrusted CA certs are still returned as CA_CERT
+ // type. See http://crbug.com/96654.
+ EXPECT_TRUE(db.SetCertTrust(cert.get(), net::CA_CERT,
+ net::NSSCertDatabase::DISTRUSTED_SSL));
+
+ EXPECT_EQ(net::CA_CERT, x509_certificate_model::GetType(cert.get()));
+}
+
+TEST(X509CertificateModelTest, GetTypeServer) {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "google.single.der"));
+ ASSERT_TRUE(cert.get());
+
+ // Test mozilla_security_manager::GetCertType with server certs and default
+ // trust. Currently this doesn't work.
+ // TODO(mattm): make mozilla_security_manager::GetCertType smarter so we can
+ // tell server certs even if they have no trust bits set.
+ EXPECT_EQ(net::OTHER_CERT, x509_certificate_model::GetType(cert.get()));
+
+ crypto::ScopedTestNSSDB test_nssdb;
+ net::NSSCertDatabase db(crypto::ScopedPK11Slot(PK11_ReferenceSlot(
+ test_nssdb.slot())) /* public slot */,
+ crypto::ScopedPK11Slot(PK11_ReferenceSlot(
+ test_nssdb.slot())) /* private slot */);
+
+ // Test GetCertType with server certs and explicit trust.
+ EXPECT_TRUE(db.SetCertTrust(cert.get(), net::SERVER_CERT,
+ net::NSSCertDatabase::TRUSTED_SSL));
+
+ EXPECT_EQ(net::SERVER_CERT, x509_certificate_model::GetType(cert.get()));
+
+ // Test GetCertType with server certs and explicit distrust.
+ EXPECT_TRUE(db.SetCertTrust(cert.get(), net::SERVER_CERT,
+ net::NSSCertDatabase::DISTRUSTED_SSL));
+
+ EXPECT_EQ(net::SERVER_CERT, x509_certificate_model::GetType(cert.get()));
+}
+
+// An X.509 v1 certificate with the version field omitted should get
+// the default value v1.
+TEST(X509CertificateModelTest, GetVersionOmitted) {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "ndn.ca.crt"));
+ ASSERT_TRUE(cert.get());
+
+ EXPECT_EQ("1", x509_certificate_model::GetVersion(cert.get()));
+}
+
+TEST(X509CertificateModelTest, GetCMSString) {
+ net::ScopedCERTCertificateList certs = CreateCERTCertificateListFromFile(
+ net::GetTestCertsDirectory(), "multi-root-chain1.pem",
+ net::X509Certificate::FORMAT_AUTO);
+
+ {
+ // Write the full chain.
+ std::string pkcs7_string =
+ x509_certificate_model::GetCMSString(certs, 0, certs.size());
+
+ ASSERT_FALSE(pkcs7_string.empty());
+
+ net::ScopedCERTCertificateList decoded_certs =
+ net::x509_util::CreateCERTCertificateListFromBytes(
+ pkcs7_string.data(), pkcs7_string.size(),
+ net::X509Certificate::FORMAT_PKCS7);
+
+ ASSERT_EQ(certs.size(), decoded_certs.size());
+
+ // NSS sorts the certs before writing the file.
+ EXPECT_TRUE(net::x509_util::IsSameCertificate(certs[0].get(),
+ decoded_certs.back().get()));
+ for (size_t i = 1; i < certs.size(); ++i)
+ EXPECT_TRUE(net::x509_util::IsSameCertificate(
+ certs[i].get(), decoded_certs[i - 1].get()));
+ }
+
+ {
+ // Write only the first cert.
+ std::string pkcs7_string =
+ x509_certificate_model::GetCMSString(certs, 0, 1);
+
+ net::ScopedCERTCertificateList decoded_certs =
+ net::x509_util::CreateCERTCertificateListFromBytes(
+ pkcs7_string.data(), pkcs7_string.size(),
+ net::X509Certificate::FORMAT_PKCS7);
+
+ ASSERT_EQ(1U, decoded_certs.size());
+ EXPECT_TRUE(net::x509_util::IsSameCertificate(certs[0].get(),
+ decoded_certs[0].get()));
+ }
+}
+
+TEST(X509CertificateModelTest, ProcessSecAlgorithms) {
+ {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "root_ca_cert.pem"));
+ ASSERT_TRUE(cert.get());
+
+ EXPECT_EQ("PKCS #1 SHA-256 With RSA Encryption",
+ x509_certificate_model::ProcessSecAlgorithmSignature(cert.get()));
+ EXPECT_EQ(
+ "PKCS #1 SHA-256 With RSA Encryption",
+ x509_certificate_model::ProcessSecAlgorithmSignatureWrap(cert.get()));
+ EXPECT_EQ("PKCS #1 RSA Encryption",
+ x509_certificate_model::ProcessSecAlgorithmSubjectPublicKey(
+ cert.get()));
+ }
+ {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "weak_digest_md5_root.pem"));
+ ASSERT_TRUE(cert.get());
+
+ EXPECT_EQ("PKCS #1 MD5 With RSA Encryption",
+ x509_certificate_model::ProcessSecAlgorithmSignature(cert.get()));
+ EXPECT_EQ(
+ "PKCS #1 MD5 With RSA Encryption",
+ x509_certificate_model::ProcessSecAlgorithmSignatureWrap(cert.get()));
+ EXPECT_EQ("PKCS #1 RSA Encryption",
+ x509_certificate_model::ProcessSecAlgorithmSubjectPublicKey(
+ cert.get()));
+ }
+}
+
+TEST(X509CertificateModelTest, ProcessSubjectPublicKeyInfo) {
+ {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "root_ca_cert.pem"));
+ ASSERT_TRUE(cert.get());
+
+ EXPECT_EQ(
+ "Modulus (2048 bits):\n"
+ " C6 81 1F 92 73 B6 58 85 D9 8D AC B7 20 FD C7 BF\n"
+ "40 B2 EA FA E5 0B 52 01 8F 9A C1 EB 7A 80 C1 F3\n"
+ "89 A4 3E D5 1B 61 CC B5 CF 80 B1 1A DB BB 25 E0\n"
+ "18 BF 92 69 26 50 CD E7 3F FF 0D 3C B4 1F 14 12\n"
+ "AB 67 37 DE 07 03 6C 12 74 82 36 AC C3 D4 D3 64\n"
+ "9F 91 ED 5B F6 A9 7A A4 9C 98 E8 65 6C 94 E1 CB\n"
+ "55 73 AE F8 1D 50 B0 78 E5 74 FF B1 37 2C CB 19\n"
+ "3D A4 8C E7 76 4E 86 5C 3F DF B3 ED 45 23 4F 54\n"
+ "9B 33 C6 89 5E 13 1D DD 7D 59 A5 07 34 28 86 27\n"
+ "1F FA 9E 53 4F 2A B6 42 AD 37 12 62 F5 72 36 B6\n"
+ "02 12 40 44 FE C7 9E 95 89 43 51 5E B4 6E C7 67\n"
+ "80 58 43 BE CC 07 28 BD 59 FF 1C 4C 8D 90 42 F4\n"
+ "CF FD 54 00 4F 48 72 2B E1 67 3C 84 17 68 95 BF\n"
+ "CA 07 7B DF 86 9D 56 E3 32 E3 70 87 B7 F8 3A F7\n"
+ "E3 6E 65 14 7C BB 76 B7 17 F1 42 8C 6F 2A 34 64\n"
+ "10 35 14 8C 85 F6 57 BF F3 5C 55 9D AD 03 10 F3\n"
+ "\n"
+ " Public Exponent (24 bits):\n"
+ " 01 00 01",
+ x509_certificate_model::ProcessSubjectPublicKeyInfo(cert.get()));
+ }
+ {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "prime256v1-ecdsa-intermediate.pem"));
+ ASSERT_TRUE(cert.get());
+
+ EXPECT_EQ(
+ "04 D5 C1 4A 32 95 95 C5 88 FA 01 FA C5 9E DC E2\n"
+ "99 62 EB 13 E5 35 42 B3 7A FC 46 C0 FA 29 12 C8\n"
+ "2D EA 30 0F D2 9A 47 97 2C 7E 89 E6 EF 49 55 06\n"
+ "C9 37 C7 99 56 16 B2 2B C9 7C 69 8E 10 7A DD 1F\n"
+ "42",
+ x509_certificate_model::ProcessSubjectPublicKeyInfo(cert.get()));
+ }
+}
+
+TEST(X509CertificateModelTest, ProcessRawBitsSignatureWrap) {
+ net::ScopedCERTCertificate cert(net::ImportCERTCertificateFromFile(
+ net::GetTestCertsDirectory(), "root_ca_cert.pem"));
+ ASSERT_TRUE(cert.get());
+
+ EXPECT_EQ(
+ "5B 53 FF 6D D5 0A 43 A5 0F D4 7D C6 5D 88 E3 98\n"
+ "9D 67 EB 32 82 B3 0F F5 C1 78 F8 05 4A BF BC 21\n"
+ "05 EE 21 08 2C B2 15 A1 B8 B2 F6 A3 15 61 E4 C1\n"
+ "AD 84 A4 A7 40 0C 87 09 5F 2B 1B F9 4D 6C 92 7D\n"
+ "CB 7E 2B B0 01 0A ED 40 E5 4E AF 1A F1 0D EC 1D\n"
+ "9E 96 C7 D4 61 64 39 23 FA 5F 29 C4 2A 3A B8 ED\n"
+ "8A 72 50 6A AC 45 04 76 09 A8 3D 57 D7 F0 4B AE\n"
+ "46 B4 83 C1 14 50 2A 19 59 53 B2 4D AE FC 2F 40\n"
+ "49 C8 AD 4D 9D C8 22 8D 8C 01 DB 31 33 5A F4 BC\n"
+ "4C 9B ED D7 E3 43 D9 E8 1D 53 8B 30 D8 81 9E 72\n"
+ "AB 9E CE B8 F5 83 93 F2 72 DB DE CD B0 52 9A 45\n"
+ "4D CF E7 21 D8 CE 16 64 8F 42 AF C1 87 A8 F9 D5\n"
+ "E2 03 DD BA 6B 1B 7C 7D A0 38 33 61 39 B4 DD 5C\n"
+ "69 17 79 02 3A EC 1D 6F 5E BB 13 FB A6 82 5D 07\n"
+ "20 FC 86 FE 6E 8B AC E1 C2 18 A2 FE 3F 95 66 D3\n"
+ "69 8A 00 06 2C 56 37 34 B9 B6 31 DE 0F F6 44 39",
+ x509_certificate_model::ProcessRawBitsSignatureWrap(cert.get()));
+}
diff --git a/chromium/chrome/common/origin_trials/OWNERS b/chromium/chrome/common/origin_trials/OWNERS
new file mode 100644
index 00000000000..de0e62d14ac
--- /dev/null
+++ b/chromium/chrome/common/origin_trials/OWNERS
@@ -0,0 +1,3 @@
+file://third_party/blink/common/origin_trials/OWNERS
+# COMPONENT: Internals>OriginTrials
+# TEAM: experimentation-dev@chromium.org
diff --git a/chromium/chrome/common/origin_trials/chrome_origin_trial_policy.cc b/chromium/chrome/common/origin_trials/chrome_origin_trial_policy.cc
new file mode 100644
index 00000000000..deacef0b0db
--- /dev/null
+++ b/chromium/chrome/common/origin_trials/chrome_origin_trial_policy.cc
@@ -0,0 +1,117 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/origin_trials/chrome_origin_trial_policy.h"
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/stl_util.h"
+#include "base/strings/string_split.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/origin_util.h"
+
+// This is the default public key used for validating signatures.
+// TODO(iclelland): Provide a mechanism to allow for multiple signing keys.
+// https://crbug.com/584737
+static const uint8_t kDefaultPublicKey[] = {
+ 0x7c, 0xc4, 0xb8, 0x9a, 0x93, 0xba, 0x6e, 0xe2, 0xd0, 0xfd, 0x03,
+ 0x1d, 0xfb, 0x32, 0x66, 0xc7, 0x3b, 0x72, 0xfd, 0x54, 0x3a, 0x07,
+ 0x51, 0x14, 0x66, 0xaa, 0x02, 0x53, 0x4e, 0x33, 0xa1, 0x15,
+};
+
+ChromeOriginTrialPolicy::ChromeOriginTrialPolicy()
+ : public_key_(std::string(reinterpret_cast<const char*>(kDefaultPublicKey),
+ base::size(kDefaultPublicKey))) {
+ // Set the public key and disabled feature list for the origin trial key
+ // manager, based on the command line flags which were passed to this process.
+ // If the flags are not present, or are incorrectly formatted, the defaults
+ // will remain active.
+ if (base::CommandLine::InitializedForCurrentProcess()) {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kOriginTrialPublicKey)) {
+ SetPublicKeyFromASCIIString(
+ command_line->GetSwitchValueASCII(switches::kOriginTrialPublicKey));
+ }
+ if (command_line->HasSwitch(switches::kOriginTrialDisabledFeatures)) {
+ SetDisabledFeatures(command_line->GetSwitchValueASCII(
+ switches::kOriginTrialDisabledFeatures));
+ }
+ if (command_line->HasSwitch(switches::kOriginTrialDisabledTokens)) {
+ SetDisabledTokens(command_line->GetSwitchValueASCII(
+ switches::kOriginTrialDisabledTokens));
+ }
+ }
+}
+
+ChromeOriginTrialPolicy::~ChromeOriginTrialPolicy() {}
+
+bool ChromeOriginTrialPolicy::IsOriginTrialsSupported() const {
+ return true;
+}
+
+base::StringPiece ChromeOriginTrialPolicy::GetPublicKey() const {
+ return base::StringPiece(public_key_);
+}
+
+bool ChromeOriginTrialPolicy::IsFeatureDisabled(
+ base::StringPiece feature) const {
+ return disabled_features_.count(feature.as_string()) > 0;
+}
+
+bool ChromeOriginTrialPolicy::IsTokenDisabled(
+ base::StringPiece token_signature) const {
+ return disabled_tokens_.count(token_signature.as_string()) > 0;
+}
+
+bool ChromeOriginTrialPolicy::IsOriginSecure(const GURL& url) const {
+ return content::IsOriginSecure(url);
+}
+
+bool ChromeOriginTrialPolicy::SetPublicKeyFromASCIIString(
+ const std::string& ascii_public_key) {
+ // Base64-decode the incoming string. Set the key if it is correctly formatted
+ std::string new_public_key;
+ if (!base::Base64Decode(ascii_public_key, &new_public_key))
+ return false;
+ if (new_public_key.size() != 32)
+ return false;
+ public_key_.swap(new_public_key);
+ return true;
+}
+
+bool ChromeOriginTrialPolicy::SetDisabledFeatures(
+ const std::string& disabled_feature_list) {
+ std::set<std::string> new_disabled_features;
+ const std::vector<std::string> features =
+ base::SplitString(disabled_feature_list, "|", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+ for (const std::string& feature : features)
+ new_disabled_features.insert(feature);
+ disabled_features_.swap(new_disabled_features);
+ return true;
+}
+
+bool ChromeOriginTrialPolicy::SetDisabledTokens(
+ const std::string& disabled_token_list) {
+ std::set<std::string> new_disabled_tokens;
+ const std::vector<std::string> tokens =
+ base::SplitString(disabled_token_list, "|", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+ for (const std::string& ascii_token : tokens) {
+ std::string token_signature;
+ if (!base::Base64Decode(ascii_token, &token_signature))
+ continue;
+ if (token_signature.size() != 64)
+ continue;
+ new_disabled_tokens.insert(token_signature);
+ }
+ disabled_tokens_.swap(new_disabled_tokens);
+ return true;
+}
diff --git a/chromium/chrome/common/origin_trials/chrome_origin_trial_policy.h b/chromium/chrome/common/origin_trials/chrome_origin_trial_policy.h
new file mode 100644
index 00000000000..ebb892ee667
--- /dev/null
+++ b/chromium/chrome/common/origin_trials/chrome_origin_trial_policy.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 CHROME_COMMON_ORIGIN_TRIALS_CHROME_ORIGIN_TRIAL_POLICY_H_
+#define CHROME_COMMON_ORIGIN_TRIALS_CHROME_ORIGIN_TRIAL_POLICY_H_
+
+#include <set>
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "third_party/blink/public/common/origin_trials/origin_trial_policy.h"
+
+// This class is instantiated on the main/ui thread, but its methods can be
+// accessed from any thread.
+class ChromeOriginTrialPolicy : public blink::OriginTrialPolicy {
+ public:
+ ChromeOriginTrialPolicy();
+ ~ChromeOriginTrialPolicy() override;
+
+ // blink::OriginTrialPolicy interface
+ bool IsOriginTrialsSupported() const override;
+ base::StringPiece GetPublicKey() const override;
+ bool IsFeatureDisabled(base::StringPiece feature) const override;
+ bool IsTokenDisabled(base::StringPiece token_signature) const override;
+ bool IsOriginSecure(const GURL& url) const override;
+
+ bool SetPublicKeyFromASCIIString(const std::string& ascii_public_key);
+ bool SetDisabledFeatures(const std::string& disabled_feature_list);
+ bool SetDisabledTokens(const std::string& disabled_token_list);
+
+ private:
+ std::string public_key_;
+ std::set<std::string> disabled_features_;
+ std::set<std::string> disabled_tokens_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeOriginTrialPolicy);
+};
+
+#endif // CHROME_COMMON_ORIGIN_TRIALS_CHROME_ORIGIN_TRIAL_POLICY_H_
diff --git a/chromium/chrome/common/origin_trials/chrome_origin_trial_policy_unittest.cc b/chromium/chrome/common/origin_trials/chrome_origin_trial_policy_unittest.cc
new file mode 100644
index 00000000000..831c8b6d086
--- /dev/null
+++ b/chromium/chrome/common/origin_trials/chrome_origin_trial_policy_unittest.cc
@@ -0,0 +1,262 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/origin_trials/chrome_origin_trial_policy.h"
+
+#include <memory>
+
+#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "chrome/common/chrome_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+const uint8_t kTestPublicKey[] = {
+ 0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2,
+ 0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f,
+ 0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0,
+};
+
+// Base64 encoding of the above sample public key
+const char kTestPublicKeyString[] =
+ "dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNA=";
+const char kBadEncodingPublicKeyString[] = "Not even base64!";
+// Base64-encoded, 31 bytes long
+const char kTooShortPublicKeyString[] =
+ "dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BN==";
+// Base64-encoded, 33 bytes long
+const char kTooLongPublicKeyString[] =
+ "dRCs+TocuKkocNKa0AtZ4awrt9XKH2SQCI6o4FY6BNAA";
+
+const char kOneDisabledFeature[] = "A";
+const char kTwoDisabledFeatures[] = "A|B";
+const char kThreeDisabledFeatures[] = "A|B|C";
+const char kSpacesInDisabledFeatures[] = "A|B C";
+
+// Various tokens, each provide the command (in tools/origin_trials) used for
+// generation.
+// generate_token.py example.com A --expire-timestamp=2000000000
+const uint8_t kToken1Signature[] = {
+ 0x43, 0xdd, 0xd3, 0x2b, 0x12, 0x09, 0x59, 0x52, 0x17, 0xf3, 0x60,
+ 0x44, 0xab, 0xae, 0x18, 0xcd, 0xcd, 0x20, 0xf4, 0x0f, 0x37, 0x8c,
+ 0x04, 0x98, 0x8b, 0x8e, 0xf5, 0x7f, 0x56, 0xe3, 0x22, 0xa8, 0xe5,
+ 0x02, 0x08, 0xfc, 0x2b, 0xd8, 0x6e, 0x91, 0x1f, 0x8f, 0xf1, 0xec,
+ 0x61, 0xbc, 0x0d, 0xb2, 0x96, 0xcf, 0xc3, 0xf0, 0xc2, 0xc3, 0x23,
+ 0xe9, 0x34, 0x4f, 0x55, 0x62, 0x46, 0xcb, 0x57, 0x0b};
+const char kToken1SignatureEncoded[] =
+ "Q93TKxIJWVIX82BEq64Yzc0g9A83jASYi471f1bjIqjlAgj8K9hukR+P8exhvA2yls/"
+ "D8MLDI+k0T1ViRstXCw==";
+// generate_token.py example.com A --expire-timestamp=2500000000
+const uint8_t kToken2Signature[] = {
+ 0xcd, 0x7f, 0x73, 0xb4, 0x49, 0xf5, 0xff, 0xef, 0xf3, 0x71, 0x4e,
+ 0x3d, 0xbd, 0x07, 0xcb, 0x94, 0xd7, 0x25, 0x6f, 0x48, 0x14, 0x2f,
+ 0xb6, 0x9a, 0xc1, 0x33, 0xf6, 0x8f, 0x8f, 0x72, 0xab, 0xd8, 0xeb,
+ 0x52, 0x5a, 0x20, 0x49, 0xad, 0xf0, 0x84, 0x49, 0x22, 0x64, 0x65,
+ 0x25, 0xa2, 0xb4, 0xc8, 0x5d, 0xc3, 0xa4, 0x24, 0xaf, 0xac, 0xcd,
+ 0x48, 0x22, 0xa4, 0x21, 0x1f, 0x2b, 0xf0, 0xb1, 0x02};
+const char kToken2SignatureEncoded[] =
+ "zX9ztEn1/+/"
+ "zcU49vQfLlNclb0gUL7aawTP2j49yq9jrUlogSa3whEkiZGUlorTIXcOkJK+szUgipCEfK/"
+ "CxAg==";
+// generate_token.py example.com B --expire-timestamp=2000000000
+const uint8_t kToken3Signature[] = {
+ 0x33, 0x49, 0x37, 0x0e, 0x92, 0xbc, 0xf8, 0xf6, 0x71, 0xa9, 0x7a,
+ 0x46, 0xd5, 0x35, 0x6d, 0x30, 0xd6, 0x89, 0xe3, 0xa4, 0x5b, 0x0b,
+ 0xae, 0x6c, 0x77, 0x47, 0xe9, 0x5a, 0x20, 0x14, 0x0d, 0x6f, 0xde,
+ 0xb4, 0x20, 0xe6, 0xce, 0x3a, 0xf1, 0xcb, 0x92, 0xf9, 0xaf, 0xb2,
+ 0x89, 0x19, 0xce, 0x35, 0xcc, 0x63, 0x5f, 0x59, 0xd9, 0xef, 0x8f,
+ 0xf9, 0xa1, 0x92, 0xda, 0x8b, 0xda, 0xfd, 0xf1, 0x08};
+const char kToken3SignatureEncoded[] =
+ "M0k3DpK8+PZxqXpG1TVtMNaJ46RbC65sd0fpWiAUDW/etCDmzjrxy5L5r7KJGc41zGNfWdnvj/"
+ "mhktqL2v3xCA==";
+const char kTokenSeparator[] = "|";
+
+class ChromeOriginTrialPolicyTest : public testing::Test {
+ protected:
+ ChromeOriginTrialPolicyTest()
+ : token1_signature_(
+ std::string(reinterpret_cast<const char*>(kToken1Signature),
+ base::size(kToken1Signature))),
+ token2_signature_(
+ std::string(reinterpret_cast<const char*>(kToken2Signature),
+ base::size(kToken2Signature))),
+ token3_signature_(
+ std::string(reinterpret_cast<const char*>(kToken3Signature),
+ base::size(kToken3Signature))),
+ two_disabled_tokens_(
+ base::JoinString({kToken1SignatureEncoded, kToken2SignatureEncoded},
+ kTokenSeparator)),
+ three_disabled_tokens_(
+ base::JoinString({kToken1SignatureEncoded, kToken2SignatureEncoded,
+ kToken3SignatureEncoded},
+ kTokenSeparator)),
+ manager_(base::WrapUnique(new ChromeOriginTrialPolicy())),
+ default_key_(manager_->GetPublicKey().as_string()),
+ test_key_(std::string(reinterpret_cast<const char*>(kTestPublicKey),
+ base::size(kTestPublicKey))) {}
+
+ ChromeOriginTrialPolicy* manager() { return manager_.get(); }
+ base::StringPiece default_key() { return default_key_; }
+ base::StringPiece test_key() { return test_key_; }
+ std::string token1_signature_;
+ std::string token2_signature_;
+ std::string token3_signature_;
+ std::string two_disabled_tokens_;
+ std::string three_disabled_tokens_;
+
+ private:
+ std::unique_ptr<ChromeOriginTrialPolicy> manager_;
+ std::string default_key_;
+ std::string test_key_;
+};
+
+TEST_F(ChromeOriginTrialPolicyTest, DefaultConstructor) {
+ // We don't specify here what the key should be, but make sure that it is
+ // returned, is valid, and is consistent.
+ base::StringPiece key = manager()->GetPublicKey();
+ EXPECT_EQ(32UL, key.size());
+ EXPECT_EQ(default_key(), key);
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, DefaultKeyIsConsistent) {
+ ChromeOriginTrialPolicy manager2;
+ EXPECT_EQ(manager()->GetPublicKey(), manager2.GetPublicKey());
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, OverridePublicKey) {
+ EXPECT_TRUE(manager()->SetPublicKeyFromASCIIString(kTestPublicKeyString));
+ EXPECT_NE(default_key(), manager()->GetPublicKey());
+ EXPECT_EQ(test_key(), manager()->GetPublicKey());
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, OverrideKeyNotBase64) {
+ EXPECT_FALSE(
+ manager()->SetPublicKeyFromASCIIString(kBadEncodingPublicKeyString));
+ EXPECT_EQ(default_key(), manager()->GetPublicKey());
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, OverrideKeyTooShort) {
+ EXPECT_FALSE(
+ manager()->SetPublicKeyFromASCIIString(kTooShortPublicKeyString));
+ EXPECT_EQ(default_key(), manager()->GetPublicKey());
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, OverrideKeyTooLong) {
+ EXPECT_FALSE(manager()->SetPublicKeyFromASCIIString(kTooLongPublicKeyString));
+ EXPECT_EQ(default_key(), manager()->GetPublicKey());
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, NoDisabledFeatures) {
+ EXPECT_FALSE(manager()->IsFeatureDisabled("A"));
+ EXPECT_FALSE(manager()->IsFeatureDisabled("B"));
+ EXPECT_FALSE(manager()->IsFeatureDisabled("C"));
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, DisableOneFeature) {
+ EXPECT_TRUE(manager()->SetDisabledFeatures(kOneDisabledFeature));
+ EXPECT_TRUE(manager()->IsFeatureDisabled("A"));
+ EXPECT_FALSE(manager()->IsFeatureDisabled("B"));
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, DisableTwoFeatures) {
+ EXPECT_TRUE(manager()->SetDisabledFeatures(kTwoDisabledFeatures));
+ EXPECT_TRUE(manager()->IsFeatureDisabled("A"));
+ EXPECT_TRUE(manager()->IsFeatureDisabled("B"));
+ EXPECT_FALSE(manager()->IsFeatureDisabled("C"));
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, DisableThreeFeatures) {
+ EXPECT_TRUE(manager()->SetDisabledFeatures(kThreeDisabledFeatures));
+ EXPECT_TRUE(manager()->IsFeatureDisabled("A"));
+ EXPECT_TRUE(manager()->IsFeatureDisabled("B"));
+ EXPECT_TRUE(manager()->IsFeatureDisabled("C"));
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, DisableFeatureWithSpace) {
+ EXPECT_TRUE(manager()->SetDisabledFeatures(kSpacesInDisabledFeatures));
+ EXPECT_TRUE(manager()->IsFeatureDisabled("A"));
+ EXPECT_TRUE(manager()->IsFeatureDisabled("B C"));
+ EXPECT_FALSE(manager()->IsFeatureDisabled("B"));
+ EXPECT_FALSE(manager()->IsFeatureDisabled("C"));
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, NoDisabledTokens) {
+ EXPECT_FALSE(manager()->IsTokenDisabled(token1_signature_));
+ EXPECT_FALSE(manager()->IsTokenDisabled(token2_signature_));
+ EXPECT_FALSE(manager()->IsTokenDisabled(token3_signature_));
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, DisableOneToken) {
+ EXPECT_TRUE(manager()->SetDisabledTokens(kToken1SignatureEncoded));
+ EXPECT_TRUE(manager()->IsTokenDisabled(token1_signature_));
+ EXPECT_FALSE(manager()->IsTokenDisabled(token2_signature_));
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, DisableTwoTokens) {
+ EXPECT_TRUE(manager()->SetDisabledTokens(two_disabled_tokens_));
+ EXPECT_TRUE(manager()->IsTokenDisabled(token1_signature_));
+ EXPECT_TRUE(manager()->IsTokenDisabled(token2_signature_));
+ EXPECT_FALSE(manager()->IsTokenDisabled(token3_signature_));
+}
+
+TEST_F(ChromeOriginTrialPolicyTest, DisableThreeTokens) {
+ EXPECT_TRUE(manager()->SetDisabledTokens(three_disabled_tokens_));
+ EXPECT_TRUE(manager()->IsTokenDisabled(token1_signature_));
+ EXPECT_TRUE(manager()->IsTokenDisabled(token2_signature_));
+ EXPECT_TRUE(manager()->IsTokenDisabled(token3_signature_));
+}
+
+// Tests for initialization from command line
+class ChromeOriginTrialPolicyInitializationTest
+ : public ChromeOriginTrialPolicyTest {
+ protected:
+ ChromeOriginTrialPolicyInitializationTest() {}
+
+ ChromeOriginTrialPolicy* initialized_manager() {
+ return initialized_manager_.get();
+ }
+
+ void SetUp() override {
+ ChromeOriginTrialPolicyTest::SetUp();
+
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ ASSERT_FALSE(command_line->HasSwitch(switches::kOriginTrialPublicKey));
+ ASSERT_FALSE(
+ command_line->HasSwitch(switches::kOriginTrialDisabledFeatures));
+ ASSERT_FALSE(command_line->HasSwitch(switches::kOriginTrialDisabledTokens));
+
+ // Setup command line with various updated values
+ // New public key
+ command_line->AppendSwitchASCII(switches::kOriginTrialPublicKey,
+ kTestPublicKeyString);
+ // One disabled feature
+ command_line->AppendSwitchASCII(switches::kOriginTrialDisabledFeatures,
+ kOneDisabledFeature);
+ // One disabled token
+ command_line->AppendSwitchASCII(switches::kOriginTrialDisabledTokens,
+ kToken1SignatureEncoded);
+
+ initialized_manager_ = base::WrapUnique(new ChromeOriginTrialPolicy());
+ }
+
+ private:
+ std::unique_ptr<ChromeOriginTrialPolicy> initialized_manager_;
+};
+
+TEST_F(ChromeOriginTrialPolicyInitializationTest, PublicKeyInitialized) {
+ EXPECT_NE(default_key(), initialized_manager()->GetPublicKey());
+ EXPECT_EQ(test_key(), initialized_manager()->GetPublicKey());
+}
+
+TEST_F(ChromeOriginTrialPolicyInitializationTest, DisabledFeaturesInitialized) {
+ EXPECT_TRUE(initialized_manager()->IsFeatureDisabled("A"));
+ EXPECT_FALSE(initialized_manager()->IsFeatureDisabled("B"));
+}
+
+TEST_F(ChromeOriginTrialPolicyInitializationTest, DisabledTokensInitialized) {
+ EXPECT_TRUE(initialized_manager()->IsTokenDisabled(token1_signature_));
+ EXPECT_FALSE(initialized_manager()->IsTokenDisabled(token2_signature_));
+}
diff --git a/chromium/chrome/common/pdf_util.cc b/chromium/chrome/common/pdf_util.cc
new file mode 100644
index 00000000000..cda76216d46
--- /dev/null
+++ b/chromium/chrome/common/pdf_util.cc
@@ -0,0 +1,33 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/pdf_util.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "chrome/grit/renderer_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/webui/jstemplate_builder.h"
+#include "ui/base/webui/web_ui_util.h"
+#include "url/gurl.h"
+
+void ReportPDFLoadStatus(PDFLoadStatus status) {
+ UMA_HISTOGRAM_ENUMERATION("PDF.LoadStatus", status,
+ PDFLoadStatus::kPdfLoadStatusCount);
+}
+
+std::string GetPDFPlaceholderHTML(const GURL& pdf_url) {
+ std::string template_html = ui::ResourceBundle::GetSharedInstance()
+ .GetRawDataResource(IDR_PDF_PLUGIN_HTML)
+ .as_string();
+ webui::AppendWebUiCssTextDefaults(&template_html);
+
+ base::DictionaryValue values;
+ values.SetString("fileName", pdf_url.ExtractFileName());
+ values.SetString("open", l10n_util::GetStringUTF8(IDS_ACCNAME_OPEN));
+ values.SetString("pdfUrl", pdf_url.spec());
+
+ return webui::GetI18nTemplateHtml(template_html, &values);
+}
diff --git a/chromium/chrome/common/pdf_util.h b/chromium/chrome/common/pdf_util.h
new file mode 100644
index 00000000000..2eed9090acf
--- /dev/null
+++ b/chromium/chrome/common/pdf_util.h
@@ -0,0 +1,31 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_PDF_UTIL_H_
+#define CHROME_COMMON_PDF_UTIL_H_
+
+#include <string>
+
+class GURL;
+
+// Must be kept in sync with PDFLoadStatus enum in histograms.xml.
+// This enum should be treated as append-only.
+enum class PDFLoadStatus {
+ kLoadedFullPagePdfWithPdfium = 0,
+ kLoadedEmbeddedPdfWithPdfium = 1,
+ kShowedDisabledPluginPlaceholderForEmbeddedPdf = 2,
+ kTriggeredNoGestureDriveByDownload = 3,
+ kLoadedIframePdfWithNoPdfViewer = 4,
+ kViewPdfClickedInPdfPluginPlaceholder = 5,
+ kPdfLoadStatusCount
+};
+
+void ReportPDFLoadStatus(PDFLoadStatus status);
+
+// Returns the HTML contents of the placeholder.
+std::string GetPDFPlaceholderHTML(const GURL& pdf_url);
+
+constexpr char kPDFMimeType[] = "application/pdf";
+
+#endif // CHROME_COMMON_PDF_UTIL_H_
diff --git a/chromium/chrome/common/pepper_flash.cc b/chromium/chrome/common/pepper_flash.cc
new file mode 100644
index 00000000000..2cdac4a8914
--- /dev/null
+++ b/chromium/chrome/common/pepper_flash.cc
@@ -0,0 +1,155 @@
+// 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 "chrome/common/pepper_flash.h"
+
+#include <stddef.h>
+
+#include "base/strings/string_split.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "build/build_config.h"
+#include "chrome/common/ppapi_utils.h"
+#include "ppapi/c/private/ppb_pdf.h"
+#include "ppapi/shared_impl/ppapi_permissions.h"
+
+#if defined(OS_WIN)
+#include "base/win/registry.h"
+#endif
+
+const int32_t kPepperFlashPermissions =
+ ppapi::PERMISSION_DEFAULT | ppapi::PERMISSION_DEV |
+ ppapi::PERMISSION_PRIVATE | ppapi::PERMISSION_BYPASS_USER_GESTURE |
+ ppapi::PERMISSION_FLASH;
+
+namespace {
+
+// File name of the Pepper Flash component manifest on different platforms.
+const char kPepperFlashManifestName[] = "Flapper";
+
+// Name of the Pepper Flash OS in the component manifest.
+const char kPepperFlashOperatingSystem[] =
+#if defined(OS_MACOSX)
+ "mac";
+#elif defined(OS_WIN)
+ "win";
+#elif defined(OS_CHROMEOS)
+ "chromeos";
+#else // OS_LINUX,
+ "linux";
+#endif
+
+// Name of the Pepper Flash architecture in the component manifest.
+const char kPepperFlashArch[] =
+#if defined(ARCH_CPU_X86)
+ "ia32";
+#elif defined(ARCH_CPU_X86_64)
+ "x64";
+#elif defined(ARCH_CPU_ARMEL)
+ "arm";
+#else
+ "???";
+#endif
+
+// Returns true if the Pepper |interface_name| is implemented by this browser.
+// It does not check if the interface is proxied.
+bool SupportsPepperInterface(const char* interface_name) {
+ if (IsSupportedPepperInterface(interface_name))
+ return true;
+ // The PDF interface is invisible to SupportsInterface() on the browser
+ // process because it is provided using PpapiInterfaceFactoryManager. We need
+ // to check for that as well.
+ // TODO(cpu): make this more sane.
+ return (strcmp(interface_name, PPB_PDF_INTERFACE) == 0);
+}
+
+// Returns true if this browser implements one of the interfaces given in
+// |interface_string|, which is a '|'-separated string of interface names.
+bool CheckPepperFlashInterfaceString(const std::string& interface_string) {
+ for (const std::string& name : base::SplitString(
+ interface_string, "|",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
+ if (SupportsPepperInterface(name.c_str()))
+ return true;
+ }
+ return false;
+}
+
+// Returns true if this browser implements all the interfaces that Flash
+// specifies in its component installer manifest.
+bool CheckPepperFlashInterfaces(const base::DictionaryValue& manifest) {
+ const base::ListValue* interface_list = NULL;
+
+ // We don't *require* an interface list, apparently.
+ if (!manifest.GetList("x-ppapi-required-interfaces", &interface_list))
+ return true;
+
+ for (size_t i = 0; i < interface_list->GetSize(); i++) {
+ std::string interface_string;
+ if (!interface_list->GetString(i, &interface_string))
+ return false;
+ if (!CheckPepperFlashInterfaceString(interface_string))
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace
+
+bool CheckPepperFlashManifest(const base::DictionaryValue& manifest,
+ base::Version* version_out) {
+ std::string name;
+ manifest.GetStringASCII("name", &name);
+ if (name != kPepperFlashManifestName)
+ return false;
+
+ std::string proposed_version;
+ manifest.GetStringASCII("version", &proposed_version);
+ base::Version version(proposed_version);
+ if (!version.IsValid())
+ return false;
+
+ if (!CheckPepperFlashInterfaces(manifest))
+ return false;
+
+ std::string os;
+ manifest.GetStringASCII("x-ppapi-os", &os);
+ if (os != kPepperFlashOperatingSystem)
+ return false;
+
+ std::string arch;
+ manifest.GetStringASCII("x-ppapi-arch", &arch);
+ if (arch != kPepperFlashArch) {
+#if defined(OS_MACOSX)
+ // On Mac OS X the arch is 'x64' for component updated Flash but 'mac' for
+ // system Flash, so accept both variations.
+ if (arch != kPepperFlashOperatingSystem)
+ return false;
+#else
+ return false;
+#endif
+ }
+
+ *version_out = version;
+ return true;
+}
+
+bool IsSystemFlashScriptDebuggerPresent() {
+#if defined(OS_WIN)
+ const wchar_t kFlashRegistryRoot[] =
+ L"SOFTWARE\\Macromedia\\FlashPlayerPepper";
+ const wchar_t kIsDebuggerValueName[] = L"isScriptDebugger";
+
+ base::win::RegKey path_key(HKEY_LOCAL_MACHINE, kFlashRegistryRoot, KEY_READ);
+ DWORD debug_value;
+ if (path_key.ReadValueDW(kIsDebuggerValueName, &debug_value) != ERROR_SUCCESS)
+ return false;
+
+ return (debug_value == 1);
+#else
+ // TODO(wfh): implement this on OS X and Linux. crbug.com/497996.
+ return false;
+#endif
+}
diff --git a/chromium/chrome/common/pepper_flash.h b/chromium/chrome/common/pepper_flash.h
new file mode 100644
index 00000000000..e404dac24ad
--- /dev/null
+++ b/chromium/chrome/common/pepper_flash.h
@@ -0,0 +1,25 @@
+// 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 CHROME_COMMON_PEPPER_FLASH_H_
+#define CHROME_COMMON_PEPPER_FLASH_H_
+
+#include <stdint.h>
+
+#include "base/values.h"
+#include "base/version.h"
+
+// Permission bits for Pepper Flash.
+extern const int32_t kPepperFlashPermissions;
+
+// Returns true if this browser is compatible with the given Pepper Flash
+// manifest, with the version specified in the manifest in |version_out|.
+bool CheckPepperFlashManifest(const base::DictionaryValue& manifest,
+ base::Version* version_out);
+
+// Returns true if the version of Flash installed on the system is the Flash
+// Script debugger.
+bool IsSystemFlashScriptDebuggerPresent();
+
+#endif // CHROME_COMMON_PEPPER_FLASH_H_
diff --git a/chromium/chrome/common/pepper_permission_util.cc b/chromium/chrome/common/pepper_permission_util.cc
new file mode 100644
index 00000000000..c448d4653f4
--- /dev/null
+++ b/chromium/chrome/common/pepper_permission_util.cc
@@ -0,0 +1,101 @@
+// 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 "chrome/common/pepper_permission_util.h"
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/hash/sha1.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_tokenizer.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_set.h"
+#include "extensions/common/manifest_handlers/shared_module_info.h"
+
+using extensions::Extension;
+using extensions::Manifest;
+using extensions::SharedModuleInfo;
+
+namespace {
+
+std::string HashHost(const std::string& host) {
+ const std::string id_hash = base::SHA1HashString(host);
+ DCHECK_EQ(id_hash.length(), base::kSHA1Length);
+ return base::HexEncode(id_hash.c_str(), id_hash.length());
+}
+
+bool HostIsInSet(const std::string& host, const std::set<std::string>& set) {
+ return set.count(host) > 0 || set.count(HashHost(host)) > 0;
+}
+
+} // namespace
+
+bool IsExtensionOrSharedModuleWhitelisted(
+ const GURL& url,
+ const extensions::ExtensionSet* extension_set,
+ const std::set<std::string>& whitelist) {
+ if (!url.is_valid() || !url.SchemeIs(extensions::kExtensionScheme))
+ return false;
+
+ const std::string host = url.host();
+ if (HostIsInSet(host, whitelist))
+ return true;
+
+ // Check the modules that are imported by this extension to see if any of them
+ // is whitelisted.
+ const Extension* extension = extension_set ? extension_set->GetByID(host)
+ : NULL;
+ if (!extension)
+ return false;
+
+ typedef std::vector<SharedModuleInfo::ImportInfo> ImportInfoVector;
+ const ImportInfoVector& imports = SharedModuleInfo::GetImports(extension);
+ for (auto it = imports.begin(); it != imports.end(); ++it) {
+ const Extension* imported_extension =
+ extension_set->GetByID(it->extension_id);
+ if (imported_extension &&
+ SharedModuleInfo::IsSharedModule(imported_extension) &&
+ HostIsInSet(it->extension_id, whitelist)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool IsHostAllowedByCommandLine(const GURL& url,
+ const extensions::ExtensionSet* extension_set,
+ const char* command_line_switch) {
+ if (!url.is_valid())
+ return false;
+
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ const std::string allowed_list =
+ command_line.GetSwitchValueASCII(command_line_switch);
+ if (allowed_list.empty())
+ return false;
+
+ const std::string host = url.host();
+ if (allowed_list == "*") {
+ // For now, we only allow packaged and platform apps in this wildcard.
+ if (!extension_set || !url.SchemeIs(extensions::kExtensionScheme))
+ return false;
+
+ const Extension* extension = extension_set->GetByID(host);
+ return extension &&
+ (extension->GetType() == Manifest::TYPE_LEGACY_PACKAGED_APP ||
+ extension->GetType() == Manifest::TYPE_PLATFORM_APP);
+ }
+
+ base::StringTokenizer t(allowed_list, ",");
+ while (t.GetNext()) {
+ if (t.token() == host)
+ return true;
+ }
+
+ return false;
+}
diff --git a/chromium/chrome/common/pepper_permission_util.h b/chromium/chrome/common/pepper_permission_util.h
new file mode 100644
index 00000000000..b2793e80c35
--- /dev/null
+++ b/chromium/chrome/common/pepper_permission_util.h
@@ -0,0 +1,37 @@
+// 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 CHROME_COMMON_PEPPER_PERMISSION_UTIL_H_
+#define CHROME_COMMON_PEPPER_PERMISSION_UTIL_H_
+
+#include <set>
+#include <string>
+
+class GURL;
+
+namespace extensions {
+class ExtensionSet;
+}
+
+// Returns true if the extension (or an imported module if any) is whitelisted.
+// Module imports are at most one level deep (ie, a module that exports cannot
+// import another extension). The extension is identified by the host of |url|
+// (if it is a chrome-extension URL). |extension_set| is the list of installed
+// and enabled extensions for a given profile. |whitelist| is a set of
+// (possibly hashed) extension IDs to check against.
+bool IsExtensionOrSharedModuleWhitelisted(
+ const GURL& url,
+ const extensions::ExtensionSet* extension_set,
+ const std::set<std::string>& whitelist);
+
+// Checks whether the host of |url| is allowed by |command_line_switch|.
+//
+// If the value of |command_line_switch| is:
+// (1) '*': returns true for any packaged or platform apps;
+// (2) a list of host names separated by ',': returns true if |host| is in the
+// list. (NOTE: In this case, |url| doesn't have to belong to an extension.)
+bool IsHostAllowedByCommandLine(const GURL& url,
+ const extensions::ExtensionSet* extension_set,
+ const char* command_line_switch);
+#endif // CHROME_COMMON_PEPPER_PERMISSION_UTIL_H_
diff --git a/chromium/chrome/common/pepper_permission_util_unittest.cc b/chromium/chrome/common/pepper_permission_util_unittest.cc
new file mode 100644
index 00000000000..35f2c484b60
--- /dev/null
+++ b/chromium/chrome/common/pepper_permission_util_unittest.cc
@@ -0,0 +1,144 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/pepper_permission_util.h"
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+
+#include "components/crx_file/id_util.h"
+#include "components/version_info/version_info.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/extension_set.h"
+#include "extensions/common/features/feature_channel.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace {
+
+// Return an extension with |id| which imports a module with the given
+// |import_id|.
+scoped_refptr<const Extension> CreateExtensionImportingModule(
+ const std::string& import_id,
+ const std::string& id) {
+ std::unique_ptr<base::DictionaryValue> manifest =
+ DictionaryBuilder()
+ .Set("name", "Has Dependent Modules")
+ .Set("version", "1.0")
+ .Set("manifest_version", 2)
+ .Set("import",
+ ListBuilder()
+ .Append(DictionaryBuilder().Set("id", import_id).Build())
+ .Build())
+ .Build();
+
+ return ExtensionBuilder()
+ .SetManifest(std::move(manifest))
+ .AddFlags(Extension::FROM_WEBSTORE)
+ .SetID(id)
+ .Build();
+}
+
+} // namespace
+
+TEST(PepperPermissionUtilTest, ExtensionWhitelisting) {
+ ScopedCurrentChannel current_channel(version_info::Channel::UNKNOWN);
+ ExtensionSet extensions;
+ std::string whitelisted_id =
+ crx_file::id_util::GenerateId("whitelisted_extension");
+ std::unique_ptr<base::DictionaryValue> manifest =
+ DictionaryBuilder()
+ .Set("name", "Whitelisted Extension")
+ .Set("version", "1.0")
+ .Set("manifest_version", 2)
+ .Build();
+ scoped_refptr<const Extension> ext = ExtensionBuilder()
+ .SetManifest(std::move(manifest))
+ .SetID(whitelisted_id)
+ .Build();
+ extensions.Insert(ext);
+ std::set<std::string> whitelist;
+ std::string url = std::string("chrome-extension://") + whitelisted_id +
+ std::string("/manifest.nmf");
+ std::string bad_scheme_url =
+ std::string("http://") + whitelisted_id + std::string("/manifest.nmf");
+ std::string bad_host_url = std::string("chrome-extension://") +
+ crx_file::id_util::GenerateId("bad_host");
+ std::string("/manifest.nmf");
+
+ EXPECT_FALSE(
+ IsExtensionOrSharedModuleWhitelisted(GURL(url), &extensions, whitelist));
+ whitelist.insert(whitelisted_id);
+ EXPECT_TRUE(
+ IsExtensionOrSharedModuleWhitelisted(GURL(url), &extensions, whitelist));
+ EXPECT_FALSE(IsExtensionOrSharedModuleWhitelisted(
+ GURL(bad_scheme_url), &extensions, whitelist));
+ EXPECT_FALSE(IsExtensionOrSharedModuleWhitelisted(
+ GURL(bad_host_url), &extensions, whitelist));
+}
+
+TEST(PepperPermissionUtilTest, SharedModuleWhitelisting) {
+ ScopedCurrentChannel current_channel(version_info::Channel::UNKNOWN);
+ ExtensionSet extensions;
+ std::string whitelisted_id = crx_file::id_util::GenerateId("extension_id");
+ std::string bad_id = crx_file::id_util::GenerateId("bad_id");
+
+ std::unique_ptr<base::DictionaryValue> shared_module_manifest =
+ DictionaryBuilder()
+ .Set("name", "Whitelisted Shared Module")
+ .Set("version", "1.0")
+ .Set("manifest_version", 2)
+ .Set("export",
+ DictionaryBuilder()
+ .Set("resources", ListBuilder().Append("*").Build())
+ // Add the extension to the whitelist. This
+ // restricts import to |whitelisted_id| only.
+ .Set("whitelist",
+ ListBuilder().Append(whitelisted_id).Build())
+ .Build())
+ .Build();
+ scoped_refptr<const Extension> shared_module =
+ ExtensionBuilder().SetManifest(std::move(shared_module_manifest)).Build();
+
+ scoped_refptr<const Extension> ext =
+ CreateExtensionImportingModule(shared_module->id(), whitelisted_id);
+ std::string extension_url =
+ std::string("chrome-extension://") + ext->id() + std::string("/foo.html");
+
+ std::set<std::string> whitelist;
+ // Important: whitelist *only* the shared module.
+ whitelist.insert(shared_module->id());
+
+ extensions.Insert(ext);
+ // This should fail because shared_module is not in the set of extensions.
+ EXPECT_FALSE(IsExtensionOrSharedModuleWhitelisted(
+ GURL(extension_url), &extensions, whitelist));
+ extensions.Insert(shared_module);
+ EXPECT_TRUE(IsExtensionOrSharedModuleWhitelisted(
+ GURL(extension_url), &extensions, whitelist));
+ scoped_refptr<const Extension> not_in_sm_whitelist =
+ CreateExtensionImportingModule(shared_module->id(), bad_id);
+ std::string not_in_sm_whitelist_url = std::string("chrome-extension://") +
+ not_in_sm_whitelist->id() +
+ std::string("/foo.html");
+
+ extensions.Insert(not_in_sm_whitelist);
+ // This should succeed, even though |not_in_sm_whitelist| is not whitelisted
+ // to use shared_module, because the pepper permission utility does not care
+ // about that whitelist. It is possible to install against the whitelist as
+ // an unpacked extension.
+ EXPECT_TRUE(IsExtensionOrSharedModuleWhitelisted(
+ GURL(not_in_sm_whitelist_url), &extensions, whitelist));
+
+ // Note that the whitelist should be empty after this call, so tests checking
+ // for failure to import will fail because of this.
+ whitelist.erase(shared_module->id());
+ EXPECT_FALSE(IsExtensionOrSharedModuleWhitelisted(
+ GURL(extension_url), &extensions, whitelist));
+}
+
+} // namespace extensions
diff --git a/chromium/chrome/common/performance_manager/OWNERS b/chromium/chrome/common/performance_manager/OWNERS
new file mode 100644
index 00000000000..0a5168e1964
--- /dev/null
+++ b/chromium/chrome/common/performance_manager/OWNERS
@@ -0,0 +1 @@
+file://chrome/browser/performance_manager/OWNERS
diff --git a/chromium/chrome/common/performance_manager/mojom/OWNERS b/chromium/chrome/common/performance_manager/mojom/OWNERS
new file mode 100644
index 00000000000..08850f42120
--- /dev/null
+++ b/chromium/chrome/common/performance_manager/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/chrome/common/plugin_utils.cc b/chromium/chrome/common/plugin_utils.cc
new file mode 100644
index 00000000000..9c143751282
--- /dev/null
+++ b/chromium/chrome/common/plugin_utils.cc
@@ -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.
+
+#include "chrome/common/plugin_utils.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/webplugininfo.h"
+
+bool ShouldUseJavaScriptSettingForPlugin(const content::WebPluginInfo& plugin) {
+ if (plugin.name == base::ASCIIToUTF16(content::kFlashPluginName))
+ return false;
+
+ // Since all the UI surfaces for Plugin content settings display "Flash",
+ // treat all other plugins as JavaScript. These include all of:
+ // - Internally registered plugins such as:
+ // - NaCl
+ // - Widevine
+ // - PDF
+ // - Custom plugins loaded from the command line
+ return true;
+}
diff --git a/chromium/chrome/common/plugin_utils.h b/chromium/chrome/common/plugin_utils.h
new file mode 100644
index 00000000000..4cc9f7a3048
--- /dev/null
+++ b/chromium/chrome/common/plugin_utils.h
@@ -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.
+
+#ifndef CHROME_COMMON_PLUGIN_UTILS_H_
+#define CHROME_COMMON_PLUGIN_UTILS_H_
+
+namespace content {
+struct WebPluginInfo;
+}
+
+// Returns true if |plugin| should use the JavaScript Content Settings.
+bool ShouldUseJavaScriptSettingForPlugin(const content::WebPluginInfo& plugin);
+
+#endif // CHROME_COMMON_PLUGIN_UTILS_H_
diff --git a/chromium/chrome/common/ppapi_utils.cc b/chromium/chrome/common/ppapi_utils.cc
new file mode 100644
index 00000000000..acfb297b9fd
--- /dev/null
+++ b/chromium/chrome/common/ppapi_utils.cc
@@ -0,0 +1,130 @@
+// 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 "chrome/common/ppapi_utils.h"
+
+#include <cstring>
+
+#include "build/build_config.h"
+#include "ppapi/c/dev/ppb_audio_input_dev.h"
+#include "ppapi/c/dev/ppb_audio_output_dev.h"
+#include "ppapi/c/dev/ppb_buffer_dev.h"
+#include "ppapi/c/dev/ppb_char_set_dev.h"
+#include "ppapi/c/dev/ppb_crypto_dev.h"
+#include "ppapi/c/dev/ppb_cursor_control_dev.h"
+#include "ppapi/c/dev/ppb_device_ref_dev.h"
+#include "ppapi/c/dev/ppb_file_chooser_dev.h"
+#include "ppapi/c/dev/ppb_gles_chromium_texture_mapping_dev.h"
+#include "ppapi/c/dev/ppb_ime_input_event_dev.h"
+#include "ppapi/c/dev/ppb_memory_dev.h"
+#include "ppapi/c/dev/ppb_opengles2ext_dev.h"
+#include "ppapi/c/dev/ppb_printing_dev.h"
+#include "ppapi/c/dev/ppb_text_input_dev.h"
+#include "ppapi/c/dev/ppb_trace_event_dev.h"
+#include "ppapi/c/dev/ppb_truetype_font_dev.h"
+#include "ppapi/c/dev/ppb_url_util_dev.h"
+#include "ppapi/c/dev/ppb_var_deprecated.h"
+#include "ppapi/c/dev/ppb_video_capture_dev.h"
+#include "ppapi/c/dev/ppb_video_decoder_dev.h"
+#include "ppapi/c/dev/ppb_view_dev.h"
+#include "ppapi/c/ppb_audio.h"
+#include "ppapi/c/ppb_audio_buffer.h"
+#include "ppapi/c/ppb_audio_config.h"
+#include "ppapi/c/ppb_audio_encoder.h"
+#include "ppapi/c/ppb_console.h"
+#include "ppapi/c/ppb_core.h"
+#include "ppapi/c/ppb_file_io.h"
+#include "ppapi/c/ppb_file_ref.h"
+#include "ppapi/c/ppb_file_system.h"
+#include "ppapi/c/ppb_fullscreen.h"
+#include "ppapi/c/ppb_gamepad.h"
+#include "ppapi/c/ppb_graphics_2d.h"
+#include "ppapi/c/ppb_graphics_3d.h"
+#include "ppapi/c/ppb_host_resolver.h"
+#include "ppapi/c/ppb_image_data.h"
+#include "ppapi/c/ppb_input_event.h"
+#include "ppapi/c/ppb_instance.h"
+#include "ppapi/c/ppb_media_stream_audio_track.h"
+#include "ppapi/c/ppb_media_stream_video_track.h"
+#include "ppapi/c/ppb_messaging.h"
+#include "ppapi/c/ppb_mouse_cursor.h"
+#include "ppapi/c/ppb_mouse_lock.h"
+#include "ppapi/c/ppb_net_address.h"
+#include "ppapi/c/ppb_network_list.h"
+#include "ppapi/c/ppb_network_monitor.h"
+#include "ppapi/c/ppb_network_proxy.h"
+#include "ppapi/c/ppb_opengles2.h"
+#include "ppapi/c/ppb_tcp_socket.h"
+#include "ppapi/c/ppb_text_input_controller.h"
+#include "ppapi/c/ppb_udp_socket.h"
+#include "ppapi/c/ppb_url_loader.h"
+#include "ppapi/c/ppb_url_request_info.h"
+#include "ppapi/c/ppb_url_response_info.h"
+#include "ppapi/c/ppb_var.h"
+#include "ppapi/c/ppb_var_array.h"
+#include "ppapi/c/ppb_var_array_buffer.h"
+#include "ppapi/c/ppb_var_dictionary.h"
+#include "ppapi/c/ppb_video_decoder.h"
+#include "ppapi/c/ppb_video_encoder.h"
+#include "ppapi/c/ppb_video_frame.h"
+#include "ppapi/c/ppb_view.h"
+#include "ppapi/c/ppb_vpn_provider.h"
+#include "ppapi/c/ppb_websocket.h"
+#include "ppapi/c/private/ppb_camera_capabilities_private.h"
+#include "ppapi/c/private/ppb_camera_device_private.h"
+#include "ppapi/c/private/ppb_ext_crx_file_system_private.h"
+#include "ppapi/c/private/ppb_file_io_private.h"
+#include "ppapi/c/private/ppb_file_ref_private.h"
+#include "ppapi/c/private/ppb_find_private.h"
+#include "ppapi/c/private/ppb_flash.h"
+#include "ppapi/c/private/ppb_flash_clipboard.h"
+#include "ppapi/c/private/ppb_flash_drm.h"
+#include "ppapi/c/private/ppb_flash_file.h"
+#include "ppapi/c/private/ppb_flash_font_file.h"
+#include "ppapi/c/private/ppb_flash_fullscreen.h"
+#include "ppapi/c/private/ppb_flash_menu.h"
+#include "ppapi/c/private/ppb_flash_message_loop.h"
+#include "ppapi/c/private/ppb_flash_print.h"
+#include "ppapi/c/private/ppb_host_resolver_private.h"
+#include "ppapi/c/private/ppb_isolated_file_system_private.h"
+#include "ppapi/c/private/ppb_pdf.h"
+#include "ppapi/c/private/ppb_proxy_private.h"
+#include "ppapi/c/private/ppb_tcp_server_socket_private.h"
+#include "ppapi/c/private/ppb_tcp_socket_private.h"
+#include "ppapi/c/private/ppb_testing_private.h"
+#include "ppapi/c/private/ppb_udp_socket_private.h"
+#include "ppapi/c/private/ppb_uma_private.h"
+#include "ppapi/c/private/ppb_x509_certificate_private.h"
+#include "ppapi/c/trusted/ppb_broker_trusted.h"
+#include "ppapi/c/trusted/ppb_browser_font_trusted.h"
+#include "ppapi/c/trusted/ppb_char_set_trusted.h"
+#include "ppapi/c/trusted/ppb_file_chooser_trusted.h"
+#include "ppapi/c/trusted/ppb_url_loader_trusted.h"
+#include "ppapi/thunk/thunk.h"
+
+bool IsSupportedPepperInterface(const char* name) {
+// TODO(brettw) put these in a hash map for better performance.
+#define PROXIED_IFACE(iface_str, iface_struct) \
+ if (strcmp(name, iface_str) == 0) \
+ return true;
+
+#include "ppapi/thunk/interfaces_ppb_private.h"
+#include "ppapi/thunk/interfaces_ppb_private_flash.h"
+#include "ppapi/thunk/interfaces_ppb_private_no_permissions.h"
+#include "ppapi/thunk/interfaces_ppb_private_pdf.h"
+#include "ppapi/thunk/interfaces_ppb_public_dev.h"
+#include "ppapi/thunk/interfaces_ppb_public_dev_channel.h"
+#include "ppapi/thunk/interfaces_ppb_public_socket.h"
+#include "ppapi/thunk/interfaces_ppb_public_stable.h"
+
+#undef PROXIED_IFACE
+
+#define LEGACY_IFACE(iface_str, dummy) \
+ if (strcmp(name, iface_str) == 0) \
+ return true;
+
+#include "ppapi/thunk/interfaces_legacy.h"
+
+#undef LEGACY_IFACE
+ return false;
+}
diff --git a/chromium/chrome/common/ppapi_utils.h b/chromium/chrome/common/ppapi_utils.h
new file mode 100644
index 00000000000..7e286273489
--- /dev/null
+++ b/chromium/chrome/common/ppapi_utils.h
@@ -0,0 +1,12 @@
+// 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 CHROME_COMMON_PPAPI_UTILS_H_
+#define CHROME_COMMON_PPAPI_UTILS_H_
+
+// Returns true if the interface name passed in is supported by the
+// browser.
+bool IsSupportedPepperInterface(const char* name);
+
+#endif // CHROME_COMMON_PPAPI_UTILS_H_
diff --git a/chromium/chrome/common/pref_font_script_names-inl.h b/chromium/chrome/common/pref_font_script_names-inl.h
new file mode 100644
index 00000000000..8c5532f30b5
--- /dev/null
+++ b/chromium/chrome/common/pref_font_script_names-inl.h
@@ -0,0 +1,163 @@
+// 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, hence no include guard.
+// This file defines all font scripts in a manner that can be re-used to
+// generate the various data tables required in RO memory, and it can not
+// contain any header guards. Callers need to
+// #define EXPAND_SCRIPT_FONTS to their needs and call ALL_FONT_SCRIPTS.
+
+#define ALL_FONT_SCRIPTS(x) \
+ EXPAND_SCRIPT_FONT(x, "Afak") \
+ EXPAND_SCRIPT_FONT(x, "Arab") \
+ EXPAND_SCRIPT_FONT(x, "Armi") \
+ EXPAND_SCRIPT_FONT(x, "Armn") \
+ EXPAND_SCRIPT_FONT(x, "Avst") \
+ EXPAND_SCRIPT_FONT(x, "Bali") \
+ EXPAND_SCRIPT_FONT(x, "Bamu") \
+ EXPAND_SCRIPT_FONT(x, "Bass") \
+ EXPAND_SCRIPT_FONT(x, "Batk") \
+ EXPAND_SCRIPT_FONT(x, "Beng") \
+ EXPAND_SCRIPT_FONT(x, "Blis") \
+ EXPAND_SCRIPT_FONT(x, "Bopo") \
+ EXPAND_SCRIPT_FONT(x, "Brah") \
+ EXPAND_SCRIPT_FONT(x, "Brai") \
+ EXPAND_SCRIPT_FONT(x, "Bugi") \
+ EXPAND_SCRIPT_FONT(x, "Buhd") \
+ EXPAND_SCRIPT_FONT(x, "Cakm") \
+ EXPAND_SCRIPT_FONT(x, "Cans") \
+ EXPAND_SCRIPT_FONT(x, "Cari") \
+ EXPAND_SCRIPT_FONT(x, "Cham") \
+ EXPAND_SCRIPT_FONT(x, "Cher") \
+ EXPAND_SCRIPT_FONT(x, "Cirt") \
+ EXPAND_SCRIPT_FONT(x, "Copt") \
+ EXPAND_SCRIPT_FONT(x, "Cprt") \
+ EXPAND_SCRIPT_FONT(x, "Cyrl") \
+ EXPAND_SCRIPT_FONT(x, "Cyrs") \
+ EXPAND_SCRIPT_FONT(x, "Deva") \
+ EXPAND_SCRIPT_FONT(x, "Dsrt") \
+ EXPAND_SCRIPT_FONT(x, "Dupl") \
+ EXPAND_SCRIPT_FONT(x, "Egyd") \
+ EXPAND_SCRIPT_FONT(x, "Egyh") \
+ EXPAND_SCRIPT_FONT(x, "Egyp") \
+ EXPAND_SCRIPT_FONT(x, "Elba") \
+ EXPAND_SCRIPT_FONT(x, "Ethi") \
+ EXPAND_SCRIPT_FONT(x, "Geor") \
+ EXPAND_SCRIPT_FONT(x, "Geok") \
+ EXPAND_SCRIPT_FONT(x, "Glag") \
+ EXPAND_SCRIPT_FONT(x, "Goth") \
+ EXPAND_SCRIPT_FONT(x, "Gran") \
+ EXPAND_SCRIPT_FONT(x, "Grek") \
+ EXPAND_SCRIPT_FONT(x, "Gujr") \
+ EXPAND_SCRIPT_FONT(x, "Guru") \
+ EXPAND_SCRIPT_FONT(x, "Hang") \
+ EXPAND_SCRIPT_FONT(x, "Hani") \
+ EXPAND_SCRIPT_FONT(x, "Hano") \
+ EXPAND_SCRIPT_FONT(x, "Hans") \
+ EXPAND_SCRIPT_FONT(x, "Hant") \
+ EXPAND_SCRIPT_FONT(x, "Hebr") \
+ EXPAND_SCRIPT_FONT(x, "Hluw") \
+ EXPAND_SCRIPT_FONT(x, "Hmng") \
+ EXPAND_SCRIPT_FONT(x, "Hung") \
+ EXPAND_SCRIPT_FONT(x, "Inds") \
+ EXPAND_SCRIPT_FONT(x, "Ital") \
+ EXPAND_SCRIPT_FONT(x, "Java") \
+ EXPAND_SCRIPT_FONT(x, "Jpan") \
+ EXPAND_SCRIPT_FONT(x, "Jurc") \
+ EXPAND_SCRIPT_FONT(x, "Kali") \
+ EXPAND_SCRIPT_FONT(x, "Khar") \
+ EXPAND_SCRIPT_FONT(x, "Khmr") \
+ EXPAND_SCRIPT_FONT(x, "Khoj") \
+ EXPAND_SCRIPT_FONT(x, "Knda") \
+ EXPAND_SCRIPT_FONT(x, "Kpel") \
+ EXPAND_SCRIPT_FONT(x, "Kthi") \
+ EXPAND_SCRIPT_FONT(x, "Lana") \
+ EXPAND_SCRIPT_FONT(x, "Laoo") \
+ EXPAND_SCRIPT_FONT(x, "Latf") \
+ EXPAND_SCRIPT_FONT(x, "Latg") \
+ EXPAND_SCRIPT_FONT(x, "Latn") \
+ EXPAND_SCRIPT_FONT(x, "Lepc") \
+ EXPAND_SCRIPT_FONT(x, "Limb") \
+ EXPAND_SCRIPT_FONT(x, "Lina") \
+ EXPAND_SCRIPT_FONT(x, "Linb") \
+ EXPAND_SCRIPT_FONT(x, "Lisu") \
+ EXPAND_SCRIPT_FONT(x, "Loma") \
+ EXPAND_SCRIPT_FONT(x, "Lyci") \
+ EXPAND_SCRIPT_FONT(x, "Lydi") \
+ EXPAND_SCRIPT_FONT(x, "Mand") \
+ EXPAND_SCRIPT_FONT(x, "Mani") \
+ EXPAND_SCRIPT_FONT(x, "Maya") \
+ EXPAND_SCRIPT_FONT(x, "Mend") \
+ EXPAND_SCRIPT_FONT(x, "Merc") \
+ EXPAND_SCRIPT_FONT(x, "Mero") \
+ EXPAND_SCRIPT_FONT(x, "Mlym") \
+ EXPAND_SCRIPT_FONT(x, "Moon") \
+ EXPAND_SCRIPT_FONT(x, "Mong") \
+ EXPAND_SCRIPT_FONT(x, "Mroo") \
+ EXPAND_SCRIPT_FONT(x, "Mtei") \
+ EXPAND_SCRIPT_FONT(x, "Mymr") \
+ EXPAND_SCRIPT_FONT(x, "Narb") \
+ EXPAND_SCRIPT_FONT(x, "Nbat") \
+ EXPAND_SCRIPT_FONT(x, "Nkgb") \
+ EXPAND_SCRIPT_FONT(x, "Nkoo") \
+ EXPAND_SCRIPT_FONT(x, "Nshu") \
+ EXPAND_SCRIPT_FONT(x, "Ogam") \
+ EXPAND_SCRIPT_FONT(x, "Olck") \
+ EXPAND_SCRIPT_FONT(x, "Orkh") \
+ EXPAND_SCRIPT_FONT(x, "Orya") \
+ EXPAND_SCRIPT_FONT(x, "Osma") \
+ EXPAND_SCRIPT_FONT(x, "Palm") \
+ EXPAND_SCRIPT_FONT(x, "Perm") \
+ EXPAND_SCRIPT_FONT(x, "Phag") \
+ EXPAND_SCRIPT_FONT(x, "Phli") \
+ EXPAND_SCRIPT_FONT(x, "Phlp") \
+ EXPAND_SCRIPT_FONT(x, "Phlv") \
+ EXPAND_SCRIPT_FONT(x, "Phnx") \
+ EXPAND_SCRIPT_FONT(x, "Plrd") \
+ EXPAND_SCRIPT_FONT(x, "Prti") \
+ EXPAND_SCRIPT_FONT(x, "Rjng") \
+ EXPAND_SCRIPT_FONT(x, "Roro") \
+ EXPAND_SCRIPT_FONT(x, "Runr") \
+ EXPAND_SCRIPT_FONT(x, "Samr") \
+ EXPAND_SCRIPT_FONT(x, "Sara") \
+ EXPAND_SCRIPT_FONT(x, "Sarb") \
+ EXPAND_SCRIPT_FONT(x, "Saur") \
+ EXPAND_SCRIPT_FONT(x, "Sgnw") \
+ EXPAND_SCRIPT_FONT(x, "Shaw") \
+ EXPAND_SCRIPT_FONT(x, "Shrd") \
+ EXPAND_SCRIPT_FONT(x, "Sind") \
+ EXPAND_SCRIPT_FONT(x, "Sinh") \
+ EXPAND_SCRIPT_FONT(x, "Sora") \
+ EXPAND_SCRIPT_FONT(x, "Sund") \
+ EXPAND_SCRIPT_FONT(x, "Sylo") \
+ EXPAND_SCRIPT_FONT(x, "Syrc") \
+ EXPAND_SCRIPT_FONT(x, "Syre") \
+ EXPAND_SCRIPT_FONT(x, "Syrj") \
+ EXPAND_SCRIPT_FONT(x, "Syrn") \
+ EXPAND_SCRIPT_FONT(x, "Tagb") \
+ EXPAND_SCRIPT_FONT(x, "Takr") \
+ EXPAND_SCRIPT_FONT(x, "Tale") \
+ EXPAND_SCRIPT_FONT(x, "Talu") \
+ EXPAND_SCRIPT_FONT(x, "Taml") \
+ EXPAND_SCRIPT_FONT(x, "Tang") \
+ EXPAND_SCRIPT_FONT(x, "Tavt") \
+ EXPAND_SCRIPT_FONT(x, "Telu") \
+ EXPAND_SCRIPT_FONT(x, "Teng") \
+ EXPAND_SCRIPT_FONT(x, "Tfng") \
+ EXPAND_SCRIPT_FONT(x, "Tglg") \
+ EXPAND_SCRIPT_FONT(x, "Thaa") \
+ EXPAND_SCRIPT_FONT(x, "Thai") \
+ EXPAND_SCRIPT_FONT(x, "Tibt") \
+ EXPAND_SCRIPT_FONT(x, "Tirh") \
+ EXPAND_SCRIPT_FONT(x, "Ugar") \
+ EXPAND_SCRIPT_FONT(x, "Vaii") \
+ EXPAND_SCRIPT_FONT(x, "Visp") \
+ EXPAND_SCRIPT_FONT(x, "Wara") \
+ EXPAND_SCRIPT_FONT(x, "Wole") \
+ EXPAND_SCRIPT_FONT(x, "Xpeo") \
+ EXPAND_SCRIPT_FONT(x, "Xsux") \
+ EXPAND_SCRIPT_FONT(x, "Yiii") \
+ EXPAND_SCRIPT_FONT(x, "Zmth") \
+ EXPAND_SCRIPT_FONT(x, "Zsym") \
+ EXPAND_SCRIPT_FONT(x, "Zyyy")
diff --git a/chromium/chrome/common/pref_font_webkit_names.h b/chromium/chrome/common/pref_font_webkit_names.h
new file mode 100644
index 00000000000..a9827622caa
--- /dev/null
+++ b/chromium/chrome/common/pref_font_webkit_names.h
@@ -0,0 +1,19 @@
+// 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 CHROME_COMMON_PREF_FONT_WEBKIT_NAMES_H__
+#define CHROME_COMMON_PREF_FONT_WEBKIT_NAMES_H__
+
+// This file defines the font pref names that are used in conjunction with
+// pref_font_script_names-inl.h.
+
+#define WEBKIT_WEBPREFS_FONTS_CURSIVE "webkit.webprefs.fonts.cursive"
+#define WEBKIT_WEBPREFS_FONTS_FANTASY "webkit.webprefs.fonts.fantasy"
+#define WEBKIT_WEBPREFS_FONTS_FIXED "webkit.webprefs.fonts.fixed"
+#define WEBKIT_WEBPREFS_FONTS_PICTOGRAPH "webkit.webprefs.fonts.pictograph"
+#define WEBKIT_WEBPREFS_FONTS_SANSERIF "webkit.webprefs.fonts.sansserif"
+#define WEBKIT_WEBPREFS_FONTS_SERIF "webkit.webprefs.fonts.serif"
+#define WEBKIT_WEBPREFS_FONTS_STANDARD "webkit.webprefs.fonts.standard"
+
+#endif // CHROME_COMMON_PREF_FONT_WEBKIT_NAMES_H__
diff --git a/chromium/chrome/common/pref_names.cc b/chromium/chrome/common/pref_names.cc
index 04eb256d186..86cfea5d7cd 100644
--- a/chromium/chrome/common/pref_names.cc
+++ b/chromium/chrome/common/pref_names.cc
@@ -4,12 +4,1150 @@
#include "chrome/common/pref_names.h"
+#include "base/stl_util.h"
+#include "build/branding_buildflags.h"
+#include "build/build_config.h"
+#include "chrome/common/buildflags.h"
+#include "chrome/common/pref_font_webkit_names.h"
+#include "extensions/buildflags/buildflags.h"
+#include "media/media_buildflags.h"
+#include "ppapi/buildflags/buildflags.h"
+
namespace prefs {
-const char kAcceptLanguages[] = "intl.accept_languages";
-// Integer that holds the value of the next persistent notification ID to be
-// used.
-const char kNotificationNextPersistentId[] = "persistent_notifications.next_id";
+// *************** PROFILE PREFS ***************
+// These are attached to the user profile
+
+// A bool pref that indicates whether interventions for abusive experiences
+// should be enforced.
+const char kAbusiveExperienceInterventionEnforce[] =
+ "abusive_experience_intervention_enforce";
+
+// A bool pref that keeps whether the child status for this profile was already
+// successfully checked via ChildAccountService.
+const char kChildAccountStatusKnown[] = "child_account_status_known";
+
+// A string property indicating whether default apps should be installed
+// in this profile. Use the value "install" to enable defaults apps, or
+// "noinstall" to disable them. This property is usually set in the
+// master_preferences and copied into the profile preferences on first run.
+// Defaults apps are installed only when creating a new profile.
+const char kDefaultApps[] = "default_apps";
+
+// Disable SafeBrowsing checks for files coming from trusted URLs when false.
+const char kSafeBrowsingForTrustedSourcesEnabled[] =
+ "safebrowsing_for_trusted_sources_enabled";
+
+// Disables screenshot accelerators and extension APIs.
+// This setting resides both in profile prefs and local state. Accelerator
+// handling code reads local state, while extension APIs use profile pref.
+const char kDisableScreenshots[] = "disable_screenshots";
+
+// Prevents certain types of downloads based on integer value, which corresponds
+// to DownloadPrefs::DownloadRestriction.
+// 0 - No special restrictions (default)
+// 1 - Block dangerous downloads
+// 2 - Block potentially dangerous downloads
+// 3 - Block all downloads
+// 4 - Block malicious downloads
+const char kDownloadRestrictions[] = "download_restrictions";
+
+// If set to true profiles are created in ephemeral mode and do not store their
+// data in the profile folder on disk but only in memory.
+const char kForceEphemeralProfiles[] = "profile.ephemeral_mode";
+
+// A boolean specifying whether the New Tab page is the home page or not.
+const char kHomePageIsNewTabPage[] = "homepage_is_newtabpage";
+
+// This is the URL of the page to load when opening new tabs.
+const char kHomePage[] = "homepage";
+
+// Stores information about the important sites dialog, including the time and
+// frequency it has been ignored.
+const char kImportantSitesDialogHistory[] = "important_sites_dialog";
+
+#if defined(OS_WIN)
+// This is a timestamp of the last time this profile was reset by a third party
+// tool. On Windows, a third party tool may set a registry value that will be
+// compared to this value and if different will result in a profile reset
+// prompt. See triggered_profile_resetter.h for more information.
+const char kLastProfileResetTimestamp[] = "profile.last_reset_timestamp";
+
+// A boolean indicating if settings should be reset for this profile once a
+// run of the Chrome Cleanup Tool has completed.
+const char kChromeCleanerResetPending[] = "chrome_cleaner.reset_pending";
+#endif
+
+// The URL to open the new tab page to. Only set by Group Policy.
+const char kNewTabPageLocationOverride[] = "newtab_page_location_override";
+
+// An integer that keeps track of the profile icon version. This allows us to
+// determine the state of the profile icon for icon format changes.
+const char kProfileIconVersion[] = "profile.icon_version";
+
+// Used to determine if the last session exited cleanly. Set to false when
+// first opened, and to true when closing. On startup if the value is false,
+// it means the profile didn't exit cleanly.
+// DEPRECATED: this is replaced by kSessionExitType and exists for backwards
+// compatibility.
+const char kSessionExitedCleanly[] = "profile.exited_cleanly";
+
+// A string pref whose values is one of the values defined by
+// |ProfileImpl::kPrefExitTypeXXX|. Set to |kPrefExitTypeCrashed| on startup and
+// one of |kPrefExitTypeNormal| or |kPrefExitTypeSessionEnded| during
+// shutdown. Used to determine the exit type the last time the profile was open.
+const char kSessionExitType[] = "profile.exit_type";
+
+// Stores the total amount of observed active session time for the user while
+// in-product help is active. Observed time is active session time in seconds.
+const char kObservedSessionTime[] = "profile.observed_session_time";
+
+// Stores counts and timestamps of SSL certificate errors that have occurred.
+// When the same error recurs within some period of time, a message is added to
+// the SSL interstitial.
+const char kRecurrentSSLInterstitial[] = "profile.ssl_recurrent_interstitial";
+
+// The last time that the site engagement service recorded an engagement event
+// for this profile for any URL. Recorded only during shutdown. Used to prevent
+// the service from decaying engagement when a user does not use Chrome at all
+// for an extended period of time.
+const char kSiteEngagementLastUpdateTime[] = "profile.last_engagement_time";
+
+// An integer pref. Holds one of several values:
+// 0: unused, previously indicated to open the homepage on startup
+// 1: restore the last session.
+// 2: this was used to indicate a specific session should be restored. It is
+// no longer used, but saved to avoid conflict with old preferences.
+// 3: unused, previously indicated the user wants to restore a saved session.
+// 4: restore the URLs defined in kURLsToRestoreOnStartup.
+// 5: open the New Tab Page on startup.
+const char kRestoreOnStartup[] = "session.restore_on_startup";
+
+// The URLs to restore on startup or when the home button is pressed. The URLs
+// are only restored on startup if kRestoreOnStartup is 4.
+const char kURLsToRestoreOnStartup[] = "session.startup_urls";
+
+// Boolean that is true when user feedback to Google is allowed.
+const char kUserFeedbackAllowed[] = "feedback_allowed";
+
+// Stores the email address associated with the google account of the custodian
+// of the supervised user, set when the supervised user is created.
+const char kSupervisedUserCustodianEmail[] = "profile.managed.custodian_email";
+
+// Stores the display name associated with the google account of the custodian
+// of the supervised user, updated (if possible) each time the supervised user
+// starts a session.
+const char kSupervisedUserCustodianName[] = "profile.managed.custodian_name";
+
+// Stores the obfuscated gaia id associated with the google account of the
+// custodian of the supervised user, updated (if possible) each time the
+// supervised user starts a session.
+const char kSupervisedUserCustodianObfuscatedGaiaId[] =
+ "profile.managed.custodian_obfuscated_gaia_id";
+
+// Stores the URL of the profile image associated with the google account of the
+// custodian of the supervised user.
+const char kSupervisedUserCustodianProfileImageURL[] =
+ "profile.managed.custodian_profile_image_url";
+
+// Stores the URL of the profile associated with the google account of the
+// custodian of the supervised user.
+const char kSupervisedUserCustodianProfileURL[] =
+ "profile.managed.custodian_profile_url";
+
+// Maps host names to whether the host is manually allowed or blocked.
+const char kSupervisedUserManualHosts[] = "profile.managed.manual_hosts";
+
+// Maps URLs to whether the URL is manually allowed or blocked.
+const char kSupervisedUserManualURLs[] = "profile.managed.manual_urls";
+
+// Maps extension ids to the approved version of this extension for a
+// supervised user. Missing extensions are not approved.
+const char kSupervisedUserApprovedExtensions[] =
+ "profile.managed.approved_extensions";
+
+// Stores whether the SafeSites filter is enabled.
+const char kSupervisedUserSafeSites[] = "profile.managed.safe_sites";
+
+// Stores the email address associated with the google account of the secondary
+// custodian of the supervised user, set when the supervised user is created.
+const char kSupervisedUserSecondCustodianEmail[] =
+ "profile.managed.second_custodian_email";
+
+// Stores the display name associated with the google account of the secondary
+// custodian of the supervised user, updated (if possible) each time the
+// supervised user starts a session.
+const char kSupervisedUserSecondCustodianName[] =
+ "profile.managed.second_custodian_name";
+
+// Stores the obfuscated gaia id associated with the google account of the
+// secondary custodian of the supervised user, updated (if possible) each time
+// the supervised user starts a session.
+const char kSupervisedUserSecondCustodianObfuscatedGaiaId[] =
+ "profile.managed.second_custodian_obfuscated_gaia_id";
+
+// Stores the URL of the profile image associated with the google account of the
+// secondary custodian of the supervised user.
+const char kSupervisedUserSecondCustodianProfileImageURL[] =
+ "profile.managed.second_custodian_profile_image_url";
+
+// Stores the URL of the profile associated with the google account of the
+// secondary custodian of the supervised user.
+const char kSupervisedUserSecondCustodianProfileURL[] =
+ "profile.managed.second_custodian_profile_url";
+
+// Stores settings that can be modified both by a supervised user and their
+// manager. See SupervisedUserSharedSettingsService for a description of
+// the format.
+const char kSupervisedUserSharedSettings[] = "profile.managed.shared_settings";
+
+// A dictionary storing whitelists for a supervised user. The key is the CRX ID
+// of the whitelist, the value a dictionary containing whitelist properties
+// (currently the name).
+const char kSupervisedUserWhitelists[] = "profile.managed.whitelists";
+
+#if BUILDFLAG(ENABLE_RLZ)
+// Integer. RLZ ping delay in seconds.
+const char kRlzPingDelaySeconds[] = "rlz_ping_delay";
+#endif // BUILDFLAG(ENABLE_RLZ)
+
+#if defined(OS_CHROMEOS)
+// Locale preference of device' owner. ChromeOS device appears in this locale
+// after startup/wakeup/signout.
+const char kOwnerLocale[] = "intl.owner_locale";
+// Locale accepted by user. Non-syncable.
+// Used to determine whether we need to show Locale Change notification.
+const char kApplicationLocaleAccepted[] = "intl.app_locale_accepted";
+// Non-syncable item.
+// It is used in two distinct ways.
+// (1) Used for two-step initialization of locale in ChromeOS
+// because synchronization of kApplicationLocale is not instant.
+// (2) Used to detect locale change. Locale change is detected by
+// LocaleChangeGuard in case values of kApplicationLocaleBackup and
+// kApplicationLocale are both non-empty and differ.
+// Following is a table showing how state of those prefs may change upon
+// common real-life use cases:
+// AppLocale Backup Accepted
+// Initial login - A -
+// Sync B A -
+// Accept (B) B B B
+// -----------------------------------------------------------
+// Initial login - A -
+// No sync and second login A A -
+// Change options B B -
+// -----------------------------------------------------------
+// Initial login - A -
+// Sync A A -
+// Locale changed on login screen A C -
+// Accept (A) A A A
+// -----------------------------------------------------------
+// Initial login - A -
+// Sync B A -
+// Revert A A -
+const char kApplicationLocaleBackup[] = "intl.app_locale_backup";
+
+// List of locales the UI is allowed to be displayed in by policy. The list is
+// empty if no restriction is being enforced.
+const char kAllowedLanguages[] = "intl.allowed_languages";
+#endif
+
+// The default character encoding to assume for a web page in the
+// absence of MIME charset specification
+const char kDefaultCharset[] = "intl.charset_default";
+
+// If these change, the corresponding enums in the extension API
+// experimental.fontSettings.json must also change.
+const char* const kWebKitScriptsForFontFamilyMaps[] = {
+#define EXPAND_SCRIPT_FONT(x, script_name) script_name ,
+#include "chrome/common/pref_font_script_names-inl.h"
+ALL_FONT_SCRIPTS("unused param")
+#undef EXPAND_SCRIPT_FONT
+};
+
+const size_t kWebKitScriptsForFontFamilyMapsLength =
+ base::size(kWebKitScriptsForFontFamilyMaps);
+
+// Strings for WebKit font family preferences. If these change, the pref prefix
+// in pref_names_util.cc and the pref format in font_settings_api.cc must also
+// change.
+const char kWebKitStandardFontFamilyMap[] =
+ WEBKIT_WEBPREFS_FONTS_STANDARD;
+const char kWebKitFixedFontFamilyMap[] =
+ WEBKIT_WEBPREFS_FONTS_FIXED;
+const char kWebKitSerifFontFamilyMap[] =
+ WEBKIT_WEBPREFS_FONTS_SERIF;
+const char kWebKitSansSerifFontFamilyMap[] =
+ WEBKIT_WEBPREFS_FONTS_SANSERIF;
+const char kWebKitCursiveFontFamilyMap[] =
+ WEBKIT_WEBPREFS_FONTS_CURSIVE;
+const char kWebKitFantasyFontFamilyMap[] =
+ WEBKIT_WEBPREFS_FONTS_FANTASY;
+const char kWebKitPictographFontFamilyMap[] =
+ WEBKIT_WEBPREFS_FONTS_PICTOGRAPH;
+const char kWebKitStandardFontFamilyArabic[] =
+ "webkit.webprefs.fonts.standard.Arab";
+#if defined(OS_WIN)
+const char kWebKitFixedFontFamilyArabic[] =
+ "webkit.webprefs.fonts.fixed.Arab";
+#endif
+const char kWebKitSerifFontFamilyArabic[] =
+ "webkit.webprefs.fonts.serif.Arab";
+const char kWebKitSansSerifFontFamilyArabic[] =
+ "webkit.webprefs.fonts.sansserif.Arab";
+#if defined(OS_WIN)
+const char kWebKitStandardFontFamilyCyrillic[] =
+ "webkit.webprefs.fonts.standard.Cyrl";
+const char kWebKitFixedFontFamilyCyrillic[] =
+ "webkit.webprefs.fonts.fixed.Cyrl";
+const char kWebKitSerifFontFamilyCyrillic[] =
+ "webkit.webprefs.fonts.serif.Cyrl";
+const char kWebKitSansSerifFontFamilyCyrillic[] =
+ "webkit.webprefs.fonts.sansserif.Cyrl";
+const char kWebKitStandardFontFamilyGreek[] =
+ "webkit.webprefs.fonts.standard.Grek";
+const char kWebKitFixedFontFamilyGreek[] =
+ "webkit.webprefs.fonts.fixed.Grek";
+const char kWebKitSerifFontFamilyGreek[] =
+ "webkit.webprefs.fonts.serif.Grek";
+const char kWebKitSansSerifFontFamilyGreek[] =
+ "webkit.webprefs.fonts.sansserif.Grek";
+#endif
+const char kWebKitStandardFontFamilyJapanese[] =
+ "webkit.webprefs.fonts.standard.Jpan";
+const char kWebKitFixedFontFamilyJapanese[] =
+ "webkit.webprefs.fonts.fixed.Jpan";
+const char kWebKitSerifFontFamilyJapanese[] =
+ "webkit.webprefs.fonts.serif.Jpan";
+const char kWebKitSansSerifFontFamilyJapanese[] =
+ "webkit.webprefs.fonts.sansserif.Jpan";
+const char kWebKitStandardFontFamilyKorean[] =
+ "webkit.webprefs.fonts.standard.Hang";
+const char kWebKitFixedFontFamilyKorean[] =
+ "webkit.webprefs.fonts.fixed.Hang";
+const char kWebKitSerifFontFamilyKorean[] =
+ "webkit.webprefs.fonts.serif.Hang";
+const char kWebKitSansSerifFontFamilyKorean[] =
+ "webkit.webprefs.fonts.sansserif.Hang";
+#if defined(OS_WIN)
+const char kWebKitCursiveFontFamilyKorean[] =
+ "webkit.webprefs.fonts.cursive.Hang";
+#endif
+const char kWebKitStandardFontFamilySimplifiedHan[] =
+ "webkit.webprefs.fonts.standard.Hans";
+const char kWebKitFixedFontFamilySimplifiedHan[] =
+ "webkit.webprefs.fonts.fixed.Hans";
+const char kWebKitSerifFontFamilySimplifiedHan[] =
+ "webkit.webprefs.fonts.serif.Hans";
+const char kWebKitSansSerifFontFamilySimplifiedHan[] =
+ "webkit.webprefs.fonts.sansserif.Hans";
+const char kWebKitStandardFontFamilyTraditionalHan[] =
+ "webkit.webprefs.fonts.standard.Hant";
+const char kWebKitFixedFontFamilyTraditionalHan[] =
+ "webkit.webprefs.fonts.fixed.Hant";
+const char kWebKitSerifFontFamilyTraditionalHan[] =
+ "webkit.webprefs.fonts.serif.Hant";
+const char kWebKitSansSerifFontFamilyTraditionalHan[] =
+ "webkit.webprefs.fonts.sansserif.Hant";
+#if defined(OS_WIN) || defined(OS_MACOSX)
+const char kWebKitCursiveFontFamilySimplifiedHan[] =
+ "webkit.webprefs.fonts.cursive.Hans";
+const char kWebKitCursiveFontFamilyTraditionalHan[] =
+ "webkit.webprefs.fonts.cursive.Hant";
+#endif
+
+// WebKit preferences.
+const char kWebKitWebSecurityEnabled[] = "webkit.webprefs.web_security_enabled";
+const char kWebKitDomPasteEnabled[] = "webkit.webprefs.dom_paste_enabled";
+const char kWebKitTextAreasAreResizable[] =
+ "webkit.webprefs.text_areas_are_resizable";
+const char kWebKitJavascriptCanAccessClipboard[] =
+ "webkit.webprefs.javascript_can_access_clipboard";
+const char kWebkitTabsToLinks[] = "webkit.webprefs.tabs_to_links";
+const char kWebKitAllowRunningInsecureContent[] =
+ "webkit.webprefs.allow_running_insecure_content";
+#if defined(OS_ANDROID)
+const char kWebKitFontScaleFactor[] = "webkit.webprefs.font_scale_factor";
+const char kWebKitForceEnableZoom[] = "webkit.webprefs.force_enable_zoom";
+const char kWebKitPasswordEchoEnabled[] =
+ "webkit.webprefs.password_echo_enabled";
+#endif
+const char kWebKitForceDarkModeEnabled[] =
+ "webkit.webprefs.force_dark_mode_enabled";
+
+const char kWebKitCommonScript[] = "Zyyy";
+const char kWebKitStandardFontFamily[] = "webkit.webprefs.fonts.standard.Zyyy";
+const char kWebKitFixedFontFamily[] = "webkit.webprefs.fonts.fixed.Zyyy";
+const char kWebKitSerifFontFamily[] = "webkit.webprefs.fonts.serif.Zyyy";
+const char kWebKitSansSerifFontFamily[] =
+ "webkit.webprefs.fonts.sansserif.Zyyy";
+const char kWebKitCursiveFontFamily[] = "webkit.webprefs.fonts.cursive.Zyyy";
+const char kWebKitFantasyFontFamily[] = "webkit.webprefs.fonts.fantasy.Zyyy";
+const char kWebKitPictographFontFamily[] =
+ "webkit.webprefs.fonts.pictograph.Zyyy";
+const char kWebKitDefaultFontSize[] = "webkit.webprefs.default_font_size";
+const char kWebKitDefaultFixedFontSize[] =
+ "webkit.webprefs.default_fixed_font_size";
+const char kWebKitMinimumFontSize[] = "webkit.webprefs.minimum_font_size";
+const char kWebKitMinimumLogicalFontSize[] =
+ "webkit.webprefs.minimum_logical_font_size";
+const char kWebKitJavascriptEnabled[] = "webkit.webprefs.javascript_enabled";
+const char kWebKitLoadsImagesAutomatically[] =
+ "webkit.webprefs.loads_images_automatically";
+const char kWebKitPluginsEnabled[] = "webkit.webprefs.plugins_enabled";
+
+// Boolean that is true when the SSL interstitial should allow users to
+// proceed anyway. Otherwise, proceeding is not possible.
+const char kSSLErrorOverrideAllowed[] = "ssl.error_override_allowed";
+
+// Enum that specifies whether Incognito mode is:
+// 0 - Enabled. Default behaviour. Default mode is available on demand.
+// 1 - Disabled. Used cannot browse pages in Incognito mode.
+// 2 - Forced. All pages/sessions are forced into Incognito.
+const char kIncognitoModeAvailability[] = "incognito.mode_availability";
+
+// Boolean that is true when Suggest support is enabled.
+const char kSearchSuggestEnabled[] = "search.suggest_enabled";
+
+#if defined(OS_ANDROID)
+// String indicating the Contextual Search enabled state.
+// "false" - opt-out (disabled)
+// "" (empty string) - undecided
+// "true" - opt-in (enabled)
+const char kContextualSearchEnabled[] = "search.contextual_search_enabled";
+const char kContextualSearchDisabledValue[] = "false";
+const char kContextualSearchEnabledValue[] = "true";
+#endif // defined(OS_ANDROID)
+
+#if defined(OS_MACOSX)
+// Boolean that indicates whether the browser should put up a confirmation
+// window when the user is attempting to quit. Only on Mac.
+const char kConfirmToQuitEnabled[] = "browser.confirm_to_quit";
+
+// Boolean that indicates whether the browser should show the toolbar when it's
+// in fullscreen. Mac only.
+const char kShowFullscreenToolbar[] = "browser.show_fullscreen_toolbar";
+
+// Boolean that indicates whether the browser should allow Javascript injection
+// via Apple Events. Mac only.
+const char kAllowJavascriptAppleEvents[] =
+ "browser.allow_javascript_apple_events";
+
+#endif
+
+// Boolean which specifies whether we should ask the user if we should download
+// a file (true) or just download it automatically.
+const char kPromptForDownload[] = "download.prompt_for_download";
+
+// A boolean pref set to true if we're using Link Doctor error pages.
+const char kAlternateErrorPagesEnabled[] = "alternate_error_pages.enabled";
+
+// Controls if the QUIC protocol is allowed.
+const char kQuicAllowed[] = "net.quic_allowed";
+
+// Prefs for persisting network qualities.
+const char kNetworkQualities[] = "net.network_qualities";
+
+// Pref storing the user's network easter egg game high score.
+const char kNetworkEasterEggHighScore[] = "net.easter_egg_high_score";
+
+#if defined(OS_ANDROID)
+// Last time that a check for cloud policy management was done. This time is
+// recorded on Android so that retries aren't attempted on every startup.
+// Instead the cloud policy registration is retried at least 1 or 3 days later.
+const char kLastPolicyCheckTime[] = "policy.last_policy_check_time";
+#endif
+
+// A preference of enum chrome_browser_net::NetworkPredictionOptions shows
+// if prediction of network actions is allowed, depending on network type.
+// Actions include DNS prefetching, TCP and SSL preconnection, prerendering
+// of web pages, and resource prefetching.
+// TODO(bnc): Implement this preference as per crbug.com/334602.
+const char kNetworkPredictionOptions[] = "net.network_prediction_options";
+
+// An integer representing the state of the default apps installation process.
+// This value is persisted in the profile's user preferences because the process
+// is async, and the user may have stopped chrome in the middle. The next time
+// the profile is opened, the process will continue from where it left off.
+//
+// See possible values in external_provider_impl.cc.
+const char kDefaultAppsInstallState[] = "default_apps_install_state";
+
+// A boolean pref set to true if the Chrome Web Store icons should be hidden
+// from the New Tab Page and app launcher.
+const char kHideWebStoreIcon[] = "hide_web_store_icon";
+
+#if defined(OS_CHROMEOS)
+// An integer preference to store the number of times the Chrome OS Account
+// Manager migration flow ran successfully.
+const char kAccountManagerNumTimesMigrationRanSuccessfully[] =
+ "account_manager.num_times_migration_ran_successfully";
+
+// An integer preference to store the number of times the Chrome OS Account
+// Manager welcome screen has been shown.
+const char kAccountManagerNumTimesWelcomeScreenShown[] =
+ "account_manager.num_times_welcome_screen_shown";
+
+// A boolean pref set to true if touchpad tap-to-click is enabled.
+const char kTapToClickEnabled[] = "settings.touchpad.enable_tap_to_click";
+
+// A boolean pref set to true if touchpad three-finger-click is enabled.
+const char kEnableTouchpadThreeFingerClick[] =
+ "settings.touchpad.enable_three_finger_click";
+
+// A boolean pref set to true if touchpad natural scrolling is enabled.
+const char kNaturalScroll[] = "settings.touchpad.natural_scroll";
+
+// A boolean pref set to true if primary mouse button is the left button.
+const char kPrimaryMouseButtonRight[] = "settings.mouse.primary_right";
+
+// A boolean pref set to true if turning the mouse wheel toward the user should
+// result in scrolling up instead of the more common scrolling down.
+const char kMouseReverseScroll[] = "settings.mouse.reverse_scroll";
+
+// A boolean pref set to true if mouse acceleration is enabled. When disabled
+// only simple linear scaling is applied based on sensitivity.
+const char kMouseAcceleration[] = "settings.mouse.acceleration";
+
+// A boolean pref set to true if touchpad acceleration is enabled. When
+// disabled only simple linear scaling is applied based on sensitivity.
+const char kTouchpadAcceleration[] = "settings.touchpad.acceleration";
+
+// A integer pref for the touchpad sensitivity.
+const char kMouseSensitivity[] = "settings.mouse.sensitivity2";
+
+// A integer pref for the touchpad sensitivity.
+const char kTouchpadSensitivity[] = "settings.touchpad.sensitivity2";
+
+// A boolean pref set to true if time should be displayed in 24-hour clock.
+const char kUse24HourClock[] = "settings.clock.use_24hour_clock";
+
+// A string pref containing Timezone ID for this user.
+const char kUserTimezone[] = "settings.timezone";
+
+// This setting disables manual timezone selection and starts periodic timezone
+// refresh.
+// Deprecated. Replaced with kResolveTimezoneByGeolocationMethod.
+// TODO(alemate): https://crbug.com/783367 Remove outdated prefs.
+const char kResolveTimezoneByGeolocation[] =
+ "settings.resolve_timezone_by_geolocation";
+
+// This setting controls what information is sent to the server to get
+// device location to resolve time zone in user session. Values must
+// match TimeZoneResolverManager::TimeZoneResolveMethod enum.
+const char kResolveTimezoneByGeolocationMethod[] =
+ "settings.resolve_timezone_by_geolocation_method";
+
+// This setting is true when kResolveTimezoneByGeolocation value
+// has been migrated to kResolveTimezoneByGeolocationMethod.
+const char kResolveTimezoneByGeolocationMigratedToMethod[] =
+ "settings.resolve_timezone_by_geolocation_migrated_to_method";
+
+// A string pref set to the current input method.
+const char kLanguageCurrentInputMethod[] =
+ "settings.language.current_input_method";
+
+// A string pref set to the previous input method.
+const char kLanguagePreviousInputMethod[] =
+ "settings.language.previous_input_method";
+
+// A list pref set to the allowed input methods (see policy
+// "AllowedInputMethods").
+const char kLanguageAllowedInputMethods[] =
+ "settings.language.allowed_input_methods";
+
+// A string pref (comma-separated list) set to the preloaded (active) input
+// method IDs (ex. "pinyin,mozc").
+const char kLanguagePreloadEngines[] = "settings.language.preload_engines";
+const char kLanguagePreloadEnginesSyncable[] =
+ "settings.language.preload_engines_syncable";
+
+// A string pref (comma-separated list) set to the extension and ARC IMEs to be
+// enabled.
+const char kLanguageEnabledImes[] = "settings.language.enabled_extension_imes";
+const char kLanguageEnabledImesSyncable[] =
+ "settings.language.enabled_extension_imes_syncable";
+
+// A boolean pref set to true if the IME menu is activated.
+const char kLanguageImeMenuActivated[] = "settings.language.ime_menu_activated";
+
+// A dictionary of input method IDs and their settings. Each value is itself a
+// dictionary of key / value string pairs, with each pair representing a setting
+// and its value.
+const char kLanguageInputMethodSpecificSettings[] =
+ "settings.language.input_method_specific_settings";
+
+// A boolean pref to indicate whether we still need to add the globally synced
+// input methods. False after the initial post-OOBE sync.
+const char kLanguageShouldMergeInputMethods[] =
+ "settings.language.merge_input_methods";
+
+// A boolean pref that causes top-row keys to be interpreted as function keys
+// instead of as media keys.
+const char kLanguageSendFunctionKeys[] =
+ "settings.language.send_function_keys";
+
+// A boolean pref which determines whether key repeat is enabled.
+const char kLanguageXkbAutoRepeatEnabled[] =
+ "settings.language.xkb_auto_repeat_enabled_r2";
+// A integer pref which determines key repeat delay (in ms).
+const char kLanguageXkbAutoRepeatDelay[] =
+ "settings.language.xkb_auto_repeat_delay_r2";
+// A integer pref which determines key repeat interval (in ms).
+const char kLanguageXkbAutoRepeatInterval[] =
+ "settings.language.xkb_auto_repeat_interval_r2";
+// "_r2" suffixes were added to the three prefs above when we changed the
+// preferences to not be user-configurable or sync with the cloud. The prefs are
+// now user-configurable and syncable again, but we don't want to overwrite the
+// current values with the old synced values, so we continue to use this suffix.
+
+// A boolean pref which turns on Advanced Filesystem
+// (USB support, SD card, etc).
+const char kLabsAdvancedFilesystemEnabled[] =
+ "settings.labs.advanced_filesystem";
+
+// A boolean pref which turns on the mediaplayer.
+const char kLabsMediaplayerEnabled[] = "settings.labs.mediaplayer";
+
+// A boolean pref of whether to show mobile data first-use warning notification.
+// Note: 3g in the name is for legacy reasons. The pref was added while only 3G
+// mobile data was supported.
+const char kShowMobileDataNotification[] =
+ "settings.internet.mobile.show_3g_promo_notification";
+
+// An integer pref counting times Data Saver prompt has been shown.
+const char kDataSaverPromptsShown[] =
+ "settings.internet.mobile.datasaver_prompts_shown";
+
+// A string pref that contains version where "What's new" promo was shown.
+const char kChromeOSReleaseNotesVersion[] = "settings.release_notes.version";
+
+// A string pref that contains either a Chrome app ID (see
+// extensions::ExtensionId) or an Android package name (using Java package
+// naming conventions) of the preferred note-taking app. An empty value
+// indicates that the user hasn't selected an app yet.
+const char kNoteTakingAppId[] = "settings.note_taking_app_id";
+
+// A boolean pref indicating whether preferred note-taking app (see
+// |kNoteTakingAppId|) is allowed to handle note taking actions on the lock
+// screen.
+const char kNoteTakingAppEnabledOnLockScreen[] =
+ "settings.note_taking_app_enabled_on_lock_screen";
+
+// List of note taking aps that can be enabled to run on the lock screen.
+// The intended usage is to whitelist the set of apps that the user can enable
+// to run on lock screen, not to actually enable the apps to run on lock screen.
+const char kNoteTakingAppsLockScreenWhitelist[] =
+ "settings.note_taking_apps_lock_screen_whitelist";
+
+// Dictionary pref that maps lock screen app ID to a boolean indicating whether
+// the toast dialog has been show and dismissed as the app was being launched
+// on the lock screen.
+const char kNoteTakingAppsLockScreenToastShown[] =
+ "settings.note_taking_apps_lock_screen_toast_shown";
+
+// Whether the preferred note taking app should be requested to restore the last
+// note created on lock screen when launched on lock screen.
+const char kRestoreLastLockScreenNote[] =
+ "settings.restore_last_lock_screen_note";
+
+// A boolean pref indicating whether user activity has been observed in the
+// current session already. The pref is used to restore information about user
+// activity after browser crashes.
+const char kSessionUserActivitySeen[] = "session.user_activity_seen";
+
+// A preference to keep track of the session start time. If the session length
+// limit is configured to start running after initial user activity has been
+// observed, the pref is set after the first user activity in a session.
+// Otherwise, it is set immediately after session start. The pref is used to
+// restore the session start time after browser crashes. The time is expressed
+// as the serialization obtained from base::TimeTicks::ToInternalValue().
+const char kSessionStartTime[] = "session.start_time";
+
+// Holds the maximum session time in milliseconds. If this pref is set, the
+// user is logged out when the maximum session time is reached. The user is
+// informed about the remaining time by a countdown timer shown in the ash
+// system tray.
+const char kSessionLengthLimit[] = "session.length_limit";
+
+// Whether the session length limit should start running only after the first
+// user activity has been observed in a session.
+const char kSessionWaitForInitialUserActivity[] =
+ "session.wait_for_initial_user_activity";
+
+// A preference of the last user session type. It is used with the
+// kLastSessionLength pref below to store the last user session info
+// on shutdown so that it could be reported on the next run.
+const char kLastSessionType[] = "session.last_session_type";
+
+// A preference of the last user session length.
+const char kLastSessionLength[] = "session.last_session_length";
+
+// The URL from which the Terms of Service can be downloaded. The value is only
+// honored for public accounts.
+const char kTermsOfServiceURL[] = "terms_of_service.url";
+
+// Indicates whether the remote attestation is enabled for the user.
+const char kAttestationEnabled[] = "attestation.enabled";
+// The list of extensions allowed to use the platformKeysPrivate API for
+// remote attestation.
+const char kAttestationExtensionWhitelist[] = "attestation.extension_whitelist";
+
+// A boolean pref recording whether user has dismissed the multiprofile
+// itroduction dialog show.
+const char kMultiProfileNeverShowIntro[] =
+ "settings.multi_profile_never_show_intro";
+
+// A boolean pref recording whether user has dismissed the multiprofile
+// teleport warning dialog show.
+const char kMultiProfileWarningShowDismissed[] =
+ "settings.multi_profile_warning_show_dismissed";
+
+// A string pref that holds string enum values of how the user should behave
+// in a multiprofile session. See ChromeOsMultiProfileUserBehavior policy
+// for more details of the valid values.
+const char kMultiProfileUserBehavior[] = "settings.multiprofile_user_behavior";
+
+// A boolean preference indicating whether user has seen first-run tutorial
+// already.
+const char kFirstRunTutorialShown[] = "settings.first_run_tutorial_shown";
+
+// Indicates the amount of time for which a user authenticated via SAML can use
+// offline authentication against a cached password before being forced to go
+// through online authentication against GAIA again. The time is expressed in
+// seconds. A value of -1 indicates no limit, allowing the user to use offline
+// authentication indefinitely. The limit is in effect only if GAIA redirected
+// the user to a SAML IdP during the last online authentication.
+const char kSAMLOfflineSigninTimeLimit[] = "saml.offline_signin_time_limit";
+
+// A preference to keep track of the last time the user authenticated against
+// GAIA using SAML. The preference is updated whenever the user authenticates
+// against GAIA: If GAIA redirects to a SAML IdP, the preference is set to the
+// current time. If GAIA performs the authentication itself, the preference is
+// cleared. The time is expressed as the serialization obtained from
+// base::Time::ToInternalValue().
+const char kSAMLLastGAIASignInTime[] = "saml.last_gaia_sign_in_time";
+
+// The total number of seconds that the machine has spent sitting on the
+// OOBE screen.
+const char kTimeOnOobe[] = "settings.time_on_oobe";
+
+// List of mounted file systems via the File System Provider API. Used to
+// restore them after a reboot.
+const char kFileSystemProviderMounted[] = "file_system_provider.mounted";
+
+// A boolean pref set to true if the virtual keyboard should be enabled.
+const char kTouchVirtualKeyboardEnabled[] = "ui.touch_virtual_keyboard_enabled";
+
+// A boolean pref that controls whether the dark connect feature is enabled.
+// The dark connect feature allows a Chrome OS device to periodically wake
+// from suspend in a low-power state to maintain WiFi connectivity.
+const char kWakeOnWifiDarkConnect[] =
+ "settings.internet.wake_on_wifi_darkconnect";
+
+// This is the policy CaptivePortalAuthenticationIgnoresProxy that allows to
+// open captive portal authentication pages in a separate window under
+// a temporary incognito profile ("signin profile" is used for this purpose),
+// which allows to bypass the user's proxy for captive portal authentication.
+const char kCaptivePortalAuthenticationIgnoresProxy[] =
+ "proxy.captive_portal_ignores_proxy";
+
+// This boolean controls whether the first window shown on first run should be
+// unconditionally maximized, overriding the heuristic that normally chooses the
+// window size.
+const char kForceMaximizeOnFirstRun[] = "ui.force_maximize_on_first_run";
+
+// A dictionary pref mapping public keys that identify platform keys to its
+// properties like whether it's meant for corporate usage.
+const char kPlatformKeys[] = "platform_keys";
+
+// A boolean pref. If set to true, the Unified Desktop feature is made
+// available and turned on by default, which allows applications to span
+// multiple screens. Users may turn the feature off and on in the settings
+// while this is set to true.
+const char kUnifiedDesktopEnabledByDefault[] =
+ "settings.display.unified_desktop_enabled_by_default";
+
+// An int64 pref. This is a timestamp of the most recent time the profile took
+// or dismissed HaTS (happiness-tracking) survey.
+const char kHatsLastInteractionTimestamp[] = "hats_last_interaction_timestamp";
+
+// An int64 pref. This is the timestamp that indicates the end of the most
+// recent survey cycle.
+const char kHatsSurveyCycleEndTimestamp[] = "hats_survey_cycle_end_timestamp";
+
+// A boolean pref. Indicates if the device is selected for HaTS in the current
+// survey cycle.
+const char kHatsDeviceIsSelected[] = "hats_device_is_selected";
+
+// A boolean pref. Indicates if we've already shown a notification to inform the
+// current user about the quick unlock feature.
+const char kPinUnlockFeatureNotificationShown[] =
+ "pin_unlock_feature_notification_shown";
+// A boolean pref. Indicates if we've already shown a notification to inform the
+// current user about the fingerprint unlock feature.
+const char kFingerprintUnlockFeatureNotificationShown[] =
+ "fingerprint_unlock_feature_notification_shown";
+
+// The hash for the pin quick unlock mechanism.
+const char kQuickUnlockPinSecret[] = "quick_unlock.pin.secret";
+
+// An integer pref. Indicates the number of fingerprint records registered.
+const char kQuickUnlockFingerprintRecord[] = "quick_unlock.fingerprint.record";
+
+// Deprecated (crbug/998983) in favor of kEndOfLifeDate.
+// An integer pref. Holds one of several values:
+// 0: Supported. Device is in supported state.
+// 1: Security Only. Device is in Security-Only update (after initial 5 years).
+// 2: EOL. Device is End of Life(No more updates expected).
+// This value needs to be consistent with EndOfLifeStatus enum.
+const char kEolStatus[] = "eol_status";
+
+// A Time pref. Holds the last used Eol Date and is compared to the latest Eol
+// Date received to make changes to Eol notifications accordingly.
+const char kEndOfLifeDate[] = "eol_date";
+
+// Boolean pref indicating that the first warning End Of Life month and year
+// notification was dismissed by the user.
+const char kFirstEolWarningDismissed[] = "first_eol_warning_dismissed";
+
+// Boolean pref indicating that the second warning End Of Life month and year
+// notification was dismissed by the user.
+const char kSecondEolWarningDismissed[] = "second_eol_warning_dismissed";
+
+// Boolean pref indicating that the End Of Life final update notification was
+// dismissed by the user.
+const char kEolNotificationDismissed[] = "eol_notification_dismissed";
+
+// A list of allowed quick unlock modes. A quick unlock mode can only be used if
+// its type is on this list, or if type all (all quick unlock modes enabled) is
+// on this list.
+const char kQuickUnlockModeWhitelist[] = "quick_unlock_mode_whitelist";
+// Enum that specifies how often a user has to enter their password to continue
+// using quick unlock. These values are the same as the ones in
+// chromeos::QuickUnlockPasswordConfirmationFrequency.
+// 0 - six hours. Users will have to enter their password every six hours.
+// 1 - twelve hours. Users will have to enter their password every twelve hours.
+// 2 - day. Users will have to enter their password every day.
+// 3 - week. Users will have to enter their password every week.
+const char kQuickUnlockTimeout[] = "quick_unlock_timeout";
+// Integer prefs indicating the minimum and maximum lengths of the lock screen
+// pin.
+const char kPinUnlockMinimumLength[] = "pin_unlock_minimum_length";
+const char kPinUnlockMaximumLength[] = "pin_unlock_maximum_length";
+// Boolean pref indicating whether users are allowed to set easy pins.
+const char kPinUnlockWeakPinsAllowed[] = "pin_unlock_weak_pins_allowed";
+
+// Boolean pref indicating whether this device supports BLE advertising.
+const char kInstantTetheringBleAdvertisingSupported[] =
+ "tether.ble_advertising_supported";
+
+// Boolean pref indicating whether someone can cast to the device.
+const char kCastReceiverEnabled[] = "cast_receiver.enabled";
+
+// String pref indicating what is the minimum version of Chrome required to
+// allow user sign in. If the string is empty or blank no restrictions will
+// be applied. See base::Version for exact string format.
+const char kMinimumAllowedChromeVersion[] = "minimum_req.version";
+
+// Boolean preference that triggers chrome://settings/androidApps/details to be
+// opened on user session start.
+const char kShowArcSettingsOnSessionStart[] =
+ "start_arc_settings_on_session_start";
+
+// Boolean preference that triggers chrome://settings/syncSetup to be opened
+// on user session start.
+const char kShowSyncSettingsOnSessionStart[] =
+ "start_sync_settings_on_session_start";
+
+// Dictionary preference that maps language to default voice name preferences
+// for the users's text-to-speech settings. For example, this might map
+// 'en-US' to 'Chrome OS US English'.
+const char kTextToSpeechLangToVoiceName[] = "settings.tts.lang_to_voice_name";
+
+// Double preference that controls the default text-to-speech voice rate,
+// where 1.0 is an unchanged rate, and for example, 0.5 is half as fast,
+// and 2.0 is twice as fast.
+const char kTextToSpeechRate[] = "settings.tts.speech_rate";
+
+// Double preference that controls the default text-to-speech voice pitch,
+// where 1.0 is unchanged, and for example 0.5 is lower, and 2.0 is
+// higher-pitched.
+const char kTextToSpeechPitch[] = "settings.tts.speech_pitch";
+
+// Double preference that controls the default text-to-speech voice volume
+// relative to the system volume, where lower than 1.0 is quieter than the
+// system volume, and higher than 1.0 is louder.
+const char kTextToSpeechVolume[] = "settings.tts.speech_volume";
+
+// A dictionary containing the latest Time Limits override authorized by parent
+// access code.
+const char kTimeLimitLocalOverride[] = "screen_time.local_override";
+
+// A dictionary preference holding the usage time limit definitions for a user.
+const char kUsageTimeLimit[] = "screen_time.limit";
+
+// Last state of the screen time limit.
+const char kScreenTimeLastState[] = "screen_time.last_state";
+
+// Boolean controlling whether showing Sync Consent during sign-in is enabled.
+// Controlled by policy.
+const char kEnableSyncConsent[] = "sync_consent.enabled";
+
+// Boolean pref indicating whether a user is allowed to use the Network File
+// Shares for Chrome OS feature.
+const char kNetworkFileSharesAllowed[] = "network_file_shares.allowed";
+
+// Boolean pref indicating whether the currently running public session runs in
+// the old standard "public session" mode (false), or in the new "managed
+// session" mode which has lifted restrictions (true).
+const char kManagedSessionEnabled[] = "managed_session.enabled";
+
+// Boolean pref indicating whether the user has previously dismissed the
+// one-time notification indicating the need for a cleanup powerwash after TPM
+// firmware update that didn't flush the TPM SRK.
+const char kTPMFirmwareUpdateCleanupDismissed[] =
+ "tpm_firmware_update.cleanup_dismissed";
+
+// Int64 pref indicating the time in microseconds since Windows epoch
+// (1601-01-01 00:00:00 UTC) when the notification informing the user about a
+// planned TPM update that will clear all user data was shown. If the
+// notification was not yet shown the pref holds the value Time::Min().
+const char kTPMUpdatePlannedNotificationShownTime[] =
+ "tpm_auto_update.planned_notification_shown_time";
+
+// Boolean pref indicating whether the notification informing the user that an
+// auto-update that will clear all the user data at next reboot was shown.
+const char kTPMUpdateOnNextRebootNotificationShown[] =
+ "tpm_auto_update.update_on_reboot_notification_shown";
+
+// Boolean pref indicating whether the NetBios Name Query Request Protocol is
+// used for discovering shares on the user's network by the Network File
+// Shares for Chrome OS feature.
+const char kNetBiosShareDiscoveryEnabled[] =
+ "network_file_shares.netbios_discovery.enabled";
+
+// Amount of screen time that a child user has used in the current day.
+const char kChildScreenTimeMilliseconds[] = "child_screen_time";
+
+// Last time the kChildScreenTimeMilliseconds was saved.
+const char kLastChildScreenTimeSaved[] = "last_child_screen_time_saved";
+
+// Last time that the kChildScreenTime pref was reset.
+const char kLastChildScreenTimeReset[] = "last_child_screen_time_reset";
+
+// Last patch on which release notes were shown.
+const char kReleaseNotesLastShownMilestone[] =
+ "last_release_notes_shown_milestone";
+
+// Amount of times the release notes suggestion chip should be
+// shown before it disappears.
+const char kReleaseNotesSuggestionChipTimesLeftToShow[] =
+ "times_left_to_show_release_notes_suggestion_chip";
+
+// Boolean pref indicating whether the NTLM authentication protocol should be
+// enabled when mounting an SMB share with a user credential by the Network File
+// Shares for Chrome OS feature.
+const char kNTLMShareAuthenticationEnabled[] =
+ "network_file_shares.ntlm_share_authentication.enabled";
+
+// Dictionary pref containing configuration used to verify Parent Access Code.
+// Controlled by ParentAccessCodeConfig policy.
+const char kParentAccessCodeConfig[] = "child_user.parent_access_code.config";
+
+// List of preconfigured network file shares.
+const char kNetworkFileSharesPreconfiguredShares[] =
+ "network_file_shares.preconfigured_shares";
+
+// URL path string of the most recently used SMB NetworkFileShare path.
+const char kMostRecentlyUsedNetworkFileShareURL[] =
+ "network_file_shares.most_recently_used_url";
+
+// A string pref storing the path of device wallpaper image file.
+const char kDeviceWallpaperImageFilePath[] =
+ "policy.device_wallpaper_image_file_path";
+
+// Boolean whether Kerberos daemon supports remembering passwords.
+// Tied to KerberosRememberPasswordEnabled policy.
+const char kKerberosRememberPasswordEnabled[] =
+ "kerberos.remember_password_enabled";
+// Boolean whether users may add new Kerberos accounts.
+// Tied to KerberosAddAccountsAllowed policy.
+const char kKerberosAddAccountsAllowed[] = "kerberos.add_accounts_allowed";
+// Dictionary specifying a pre-set list of Kerberos accounts.
+// Tied to KerberosAccounts policy.
+const char kKerberosAccounts[] = "kerberos.accounts";
+// Used by KerberosCredentialsManager to remember which account is currently
+// active (empty if none) and to determine whether to wake up the Kerberos
+// daemon on session startup.
+const char kKerberosActivePrincipalName[] = "kerberos.active_principal_name";
+
+// A boolean pref for enabling/disabling App reinstall recommendations in Zero
+// State Launcher by policy.
+const char kAppReinstallRecommendationEnabled[] =
+ "zero_state_app_install_recommendation.enabled";
+
+// A boolean pref that when set to true, prevents the browser window from
+// launching at the start of the session.
+const char kStartupBrowserWindowLaunchSuppressed[] =
+ "startup_browser_window_launch_suppressed";
+
+// A string pref stored in local state. Set and read by extensions using the
+// chrome.login API.
+const char kLoginExtensionApiDataForNextLoginAttempt[] =
+ "extensions_api.login.data_for_next_login_attempt";
+
+// String containing last RSU lookup key uploaded. Empty until first upload.
+const char kLastRsuDeviceIdUploaded[] = "rsu.last_rsu_device_id_uploaded";
+
+// Boolean that determines whether to show a banner in OS Settings that links
+// to Browser settings.
+const char kSettingsShowBrowserBanner[] = "settings.cros.show_browser_banner";
+
+// Boolean user profile pref that determines whether to show a banner in browser
+// settings that links to OS settings.
+const char kSettingsShowOSBanner[] = "settings.cros.show_os_banner";
+
+// A JSON pref for controlling which USB devices are whitelisted for certain
+// urls to be used via the WebUSB API on the login screen.
+const char kDeviceLoginScreenWebUsbAllowDevicesForUrls[] =
+ "device_login_screen_webusb_allow_devices_for_urls";
+#endif // defined(OS_CHROMEOS)
+
+// A boolean pref set to true if a Home button to open the Home pages should be
+// visible on the toolbar.
+const char kShowHomeButton[] = "browser.show_home_button";
+
+// Boolean pref to define the default setting for "block offensive words".
+// The old key value is kept to avoid unnecessary migration code.
+const char kSpeechRecognitionFilterProfanities[] =
+ "browser.speechinput_censor_results";
+
+// Boolean controlling whether deleting browsing and download history is
+// permitted.
+const char kAllowDeletingBrowserHistory[] = "history.deleting_enabled";
+
+#if !defined(OS_ANDROID)
+// Whether the "Click here to clear your browsing data" tooltip promo has been
+// shown on the History page.
+const char kHistoryMenuPromoShown[] = "history.menu_promo_shown";
+#endif
+
+// Boolean controlling whether SafeSearch is mandatory for Google Web Searches.
+const char kForceGoogleSafeSearch[] = "settings.force_google_safesearch";
+
+// Integer controlling whether Restrict Mode (moderate/strict) is mandatory on
+// YouTube. See |safe_search_util::YouTubeRestrictMode| for possible values.
+const char kForceYouTubeRestrict[] = "settings.force_youtube_restrict";
+
+// Comma separated list of domain names (e.g. "google.com,school.edu").
+// When this pref is set, the user will be able to access Google Apps
+// only using an account that belongs to one of the domains from this pref.
+const char kAllowedDomainsForApps[] = "settings.allowed_domains_for_apps";
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// Linux specific preference on whether we should match the system theme.
+const char kUsesSystemTheme[] = "extensions.theme.use_system";
+#endif
+const char kCurrentThemePackFilename[] = "extensions.theme.pack";
+const char kCurrentThemeID[] = "extensions.theme.id";
+const char kAutogeneratedThemeColor[] = "autogenerated.theme.color";
+
+// Boolean pref which persists whether the extensions_ui is in developer mode
+// (showing developer packing tools and extensions details)
+const char kExtensionsUIDeveloperMode[] = "extensions.ui.developer_mode";
+
+// Dictionary pref that tracks which command belongs to which
+// extension + named command pair.
+const char kExtensionCommands[] = "extensions.commands";
+
+// Pref containing the directory for internal plugins as written to the plugins
+// list (below).
+const char kPluginsLastInternalDirectory[] = "plugins.last_internal_directory";
+
+// List pref containing information (dictionaries) on plugins.
+const char kPluginsPluginsList[] = "plugins.plugins_list";
+
+// List pref containing names of plugins that are disabled by policy.
+const char kPluginsDisabledPlugins[] = "plugins.plugins_disabled";
+
+// List pref containing exceptions to the list of plugins disabled by policy.
+const char kPluginsDisabledPluginsExceptions[] =
+ "plugins.plugins_disabled_exceptions";
+
+// List pref containing names of plugins that are enabled by policy.
+const char kPluginsEnabledPlugins[] = "plugins.plugins_enabled";
+
+// Whether Chrome should use its internal PDF viewer or not.
+const char kPluginsAlwaysOpenPdfExternally[] =
+ "plugins.always_open_pdf_externally";
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+// Whether about:plugins is shown in the details mode or not.
+const char kPluginsShowDetails[] = "plugins.show_details";
+#endif
+
+// Boolean that indicates whether outdated plugins are allowed or not.
+const char kPluginsAllowOutdated[] = "plugins.allow_outdated";
+
+// Boolean that indicates whether all Flash content (including cross-origin and
+// small content) is allowed to run when it is explicitly allowed via content
+// settings.
+const char kRunAllFlashInAllowMode[] = "plugins.run_all_flash_in_allow_mode";
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+// Dictionary holding plugins metadata.
+const char kPluginsMetadata[] = "plugins.metadata";
+
+// Last update time of plugins resource cache.
+const char kPluginsResourceCacheUpdate[] = "plugins.resource_cache_update";
+#endif
+
+// Last time the flash deprecation message was dismissed. Used to ensure a
+// cooldown period passes before the deprecation message is displayed again.
+const char kPluginsDeprecationInfobarLastShown[] =
+ "plugins.deprecation_infobar_last_shown";
+
+// Int64 containing the internal value of the time at which the default browser
+// infobar was last dismissed by the user.
+const char kDefaultBrowserLastDeclined[] =
+ "browser.default_browser_infobar_last_declined";
+// Boolean that indicates whether the kDefaultBrowserLastDeclined preference
+// should be reset on start-up.
+const char kResetCheckDefaultBrowser[] =
+ "browser.should_reset_check_default_browser";
+
+// Policy setting whether default browser check should be disabled and default
+// browser registration should take place.
+const char kDefaultBrowserSettingEnabled[] =
+ "browser.default_browser_setting_enabled";
+
+// String indicating the size of the captions text as a percentage.
+const char kAccessibilityCaptionsTextSize[] =
+ "accessibility.captions.text_size";
+
+// String indicating the font of the captions text.
+const char kAccessibilityCaptionsTextFont[] =
+ "accessibility.captions.text_font";
+
+// Comma-separated string indicating the RGB values of the captions text color.
+const char kAccessibilityCaptionsTextColor[] =
+ "accessibility.captions.text_color";
+
+// Integer indicating the opacity of the captions text from 0 - 100.
+const char kAccessibilityCaptionsTextOpacity[] =
+ "accessibility.captions.text_opacity";
+
+// Comma-separated string indicating the RGB values of the background color.
+const char kAccessibilityCaptionsBackgroundColor[] =
+ "accessibility.captions.background_color";
+
+// CSS string indicating the shadow of the captions text.
+const char kAccessibilityCaptionsTextShadow[] =
+ "accessibility.captions.text_shadow";
+
+// Integer indicating the opacity of the captions text background from 0 - 100.
+const char kAccessibilityCaptionsBackgroundOpacity[] =
+ "accessibility.captions.background_opacity";
// Boolean that indicates whether chrome://accessibility should show the
// internal accessibility tree.
@@ -25,4 +1163,1673 @@ const char kAccessibilityImageLabelsEnabled[] =
const char kAccessibilityImageLabelsOptInAccepted[] =
"settings.a11y.enable_accessibility_image_labels_opt_in_accepted";
+#if defined(OS_MACOSX)
+// Boolean that indicates whether the application should show the info bar
+// asking the user to set up automatic updates when Keystone promotion is
+// required.
+const char kShowUpdatePromotionInfoBar[] =
+ "browser.show_update_promotion_info_bar";
+#endif
+
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// Boolean that is false if we should show window manager decorations. If
+// true, we draw a custom chrome frame (thicker title bar and blue border).
+const char kUseCustomChromeFrame[] = "browser.custom_chrome_frame";
+#endif
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+// Which plugins have been whitelisted manually by the user.
+const char kContentSettingsPluginWhitelist[] =
+ "profile.content_settings.plugin_whitelist";
+#endif
+
+#if !defined(OS_ANDROID)
+// Double that indicates the default zoom level.
+const char kPartitionDefaultZoomLevel[] = "partition.default_zoom_level";
+
+// Dictionary that maps hostnames to zoom levels. Hosts not in this pref will
+// be displayed at the default zoom level.
+const char kPartitionPerHostZoomLevels[] = "partition.per_host_zoom_levels";
+
+const char kPinnedTabs[] = "pinned_tabs";
+#endif // !defined(OS_ANDROID)
+
+// Preference to disable 3D APIs (WebGL, Pepper 3D).
+const char kDisable3DAPIs[] = "disable_3d_apis";
+
+const char kEnableDeprecatedWebPlatformFeatures[] =
+ "enable_deprecated_web_platform_features";
+
+// Whether to enable hyperlink auditing ("<a ping>").
+const char kEnableHyperlinkAuditing[] = "enable_a_ping";
+
+// Whether to enable sending referrers.
+const char kEnableReferrers[] = "enable_referrers";
+
+// Whether to send the DNT header.
+const char kEnableDoNotTrack[] = "enable_do_not_track";
+
+// Whether to allow the use of Encrypted Media Extensions (EME), except for the
+// use of Clear Key key sytems, which is always allowed as required by the spec.
+// TODO(crbug.com/784675): This pref was used as a WebPreference which is why
+// the string is prefixed with "webkit.webprefs". Now this is used in
+// blink::mojom::RendererPreferences and we should migrate the pref to use a new
+// non-webkit-prefixed string.
+const char kEnableEncryptedMedia[] = "webkit.webprefs.encrypted_media_enabled";
+
+// Boolean that specifies whether to import the form data for autofill from the
+// default browser on first run.
+const char kImportAutofillFormData[] = "import_autofill_form_data";
+
+// Boolean that specifies whether to import bookmarks from the default browser
+// on first run.
+const char kImportBookmarks[] = "import_bookmarks";
+
+// Boolean that specifies whether to import the browsing history from the
+// default browser on first run.
+const char kImportHistory[] = "import_history";
+
+// Boolean that specifies whether to import the homepage from the default
+// browser on first run.
+const char kImportHomepage[] = "import_home_page";
+
+// Boolean that specifies whether to import the saved passwords from the default
+// browser on first run.
+const char kImportSavedPasswords[] = "import_saved_passwords";
+
+// Boolean that specifies whether to import the search engine from the default
+// browser on first run.
+const char kImportSearchEngine[] = "import_search_engine";
+
+// Prefs used to remember selections in the "Import data" dialog on the settings
+// page (chrome://settings/importData).
+const char kImportDialogAutofillFormData[] = "import_dialog_autofill_form_data";
+const char kImportDialogBookmarks[] = "import_dialog_bookmarks";
+const char kImportDialogHistory[] = "import_dialog_history";
+const char kImportDialogSavedPasswords[] = "import_dialog_saved_passwords";
+const char kImportDialogSearchEngine[] = "import_dialog_search_engine";
+
+// Profile avatar and name
+const char kProfileAvatarIndex[] = "profile.avatar_index";
+const char kProfileName[] = "profile.name";
+// Whether a profile is using a default avatar name (eg. Pickles or Person 1)
+// because it was randomly assigned at profile creation time.
+const char kProfileUsingDefaultName[] = "profile.using_default_name";
+// Whether a profile is using an avatar without having explicitely chosen it
+// (i.e. was assigned by default by legacy profile creation).
+const char kProfileUsingDefaultAvatar[] = "profile.using_default_avatar";
+const char kProfileUsingGAIAAvatar[] = "profile.using_gaia_avatar";
+
+// The supervised user ID.
+const char kSupervisedUserId[] = "profile.managed_user_id";
+
+// 64-bit integer serialization of the base::Time when the user's GAIA info
+// was last updated.
+const char kProfileGAIAInfoUpdateTime[] = "profile.gaia_info_update_time";
+
+// The URL from which the GAIA profile picture was downloaded. This is cached to
+// prevent the same picture from being downloaded multiple times.
+const char kProfileGAIAInfoPictureURL[] = "profile.gaia_info_picture_url";
+
+// Integer that specifies the number of times that we have shown the upgrade
+// tutorial card in the avatar menu bubble.
+const char kProfileAvatarTutorialShown[] =
+ "profile.avatar_bubble_tutorial_shown";
+
+// Indicates if we've already shown a notification that high contrast
+// mode is on, recommending high-contrast extensions and themes.
+const char kInvertNotificationShown[] = "invert_notification_version_2_shown";
+
+// Boolean controlling whether printing is enabled.
+const char kPrintingEnabled[] = "printing.enabled";
+
+// Boolean controlling whether print preview is disabled.
+const char kPrintPreviewDisabled[] = "printing.print_preview_disabled";
+
+// A pref holding the value of the policy used to control default destination
+// selection in the Print Preview. See DefaultPrinterSelection policy.
+const char kPrintPreviewDefaultDestinationSelectionRules[] =
+ "printing.default_destination_selection_rules";
+
+// The default value for the 'Headers and footers' checkbox, in Print Preview.
+// Takes priority over kPrintPreviewStickySettings if set.
+const char kPrintHeaderFooter[] = "printing.print_header_footer";
+
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+// A pref that sets the default destination in Print Preview to always be the
+// OS default printer instead of the most recently used destination.
+const char kPrintPreviewUseSystemDefaultPrinter[] =
+ "printing.use_system_default_printer";
+#endif // !OS_CHROMEOS && !OS_ANDROID
+
+#if defined(OS_CHROMEOS)
+// List of print servers ids that are allowed. List of strings.
+const char kExternalPrintServersWhitelist[] =
+ "native_printing.external_print_servers_whitelist";
+
+// List of printers configured by policy.
+const char kRecommendedNativePrinters[] =
+ "native_printing.recommended_printers";
+
+// Enum designating the type of restrictions bulk printers are using.
+const char kRecommendedNativePrintersAccessMode[] =
+ "native_printing.recommended_printers_access_mode";
+
+// List of printer ids which are explicitly disallowed. List of strings.
+const char kRecommendedNativePrintersBlacklist[] =
+ "native_printing.recommended_printers_blacklist";
+
+// List of printer ids that are allowed. List of strings.
+const char kRecommendedNativePrintersWhitelist[] =
+ "native_printing.recommended_printers_whitelist";
+
+// A Boolean flag which represents whether or not users are allowed to configure
+// and use their own native printers.
+const char kUserNativePrintersAllowed[] =
+ "native_printing.user_native_printers_allowed";
+
+// A pref holding the list of allowed printing color mode as a bitmask composed
+// of |printing::ColorModeRestriction| values. 0 is no restriction.
+const char kPrintingAllowedColorModes[] = "printing.allowed_color_modes";
+
+// A pref holding the list of allowed printing duplex mode as a bitmask composed
+// of |printing::DuplexModeRestriction| values. 0 is no restriction.
+const char kPrintingAllowedDuplexModes[] = "printing.allowed_duplex_modes";
+
+// A pref holding the allowed PIN printing modes.
+const char kPrintingAllowedPinModes[] = "printing.allowed_pin_modes";
+
+// A pref holding the allowed background graphics printing modes.
+const char kPrintingAllowedBackgroundGraphicsModes[] =
+ "printing.allowed_background_graphics_modes";
+
+// A pref holding the list of allowed printing duplex mode.
+// Empty list is no restriction.
+const char kPrintingAllowedPageSizes[] = "printing.allowed_page_sizes";
+
+// A pref holding the default color mode.
+const char kPrintingColorDefault[] = "printing.color_default";
+
+// A pref holding the default duplex mode.
+const char kPrintingDuplexDefault[] = "printing.duplex_default";
+
+// A pref holding the default PIN mode.
+const char kPrintingPinDefault[] = "printing.pin_default";
+
+// A pref holding the default background graphics mode.
+const char kPrintingBackgroundGraphicsDefault[] =
+ "printing.background_graphics_default";
+
+// A pref holding the default page size.
+const char kPrintingSizeDefault[] = "printing.size_default";
+
+// Boolean flag which represents whether username and filename should be sent
+// to print server.
+const char kPrintingSendUsernameAndFilenameEnabled[] =
+ "printing.send_username_and_filename_enabled";
+
+// Indicates how long print jobs metadata is stored on the device, in days.
+const char kPrintJobHistoryExpirationPeriod[] =
+ "printing.print_job_history_expiration_period";
+#endif // OS_CHROMEOS
+
+// An integer pref specifying the fallback behavior for sites outside of content
+// packs. One of:
+// 0: Allow (does nothing)
+// 1: Warn.
+// 2: Block.
+const char kDefaultSupervisedUserFilteringBehavior[] =
+ "profile.managed.default_filtering_behavior";
+
+// List pref containing the users supervised by this user.
+const char kSupervisedUsers[] = "profile.managed_users";
+
+// List pref containing the extension ids which are not allowed to send
+// notifications to the message center.
+const char kMessageCenterDisabledExtensionIds[] =
+ "message_center.disabled_extension_ids";
+
+// Boolean pref that determines whether the user can enter fullscreen mode.
+// Disabling fullscreen mode also makes kiosk mode unavailable on desktop
+// platforms.
+const char kFullscreenAllowed[] = "fullscreen.allowed";
+
+// Enable notifications for new devices on the local network that can be
+// registered to the user's account, e.g. Google Cloud Print printers.
+const char kLocalDiscoveryNotificationsEnabled[] =
+ "local_discovery.notifications_enabled";
+
+#if defined(OS_ANDROID)
+// Enable vibration for web notifications.
+const char kNotificationsVibrateEnabled[] = "notifications.vibrate_enabled";
+
+// Boolean pref indicating whether notification permissions were migrated to
+// notification channels (on Android O+ we use channels to store notification
+// permission, so any existing permissions must be migrated).
+const char kMigratedToSiteNotificationChannels[] =
+ "notifications.migrated_to_channels";
+
+// Boolean pref indicating whether blocked site notification channels underwent
+// a one-time reset yet for https://crbug.com/835232.
+// TODO(https://crbug.com/837614): Remove this after a few releases (M69?).
+const char kClearedBlockedSiteNotificationChannels[] =
+ "notifications.cleared_blocked_channels";
+
+// Usage stats reporting opt-in.
+const char kUsageStatsEnabled[] = "usage_stats_reporting.enabled";
+
+#endif // defined(OS_ANDROID)
+
+// Maps from app ids to origin + Service Worker registration ID.
+const char kPushMessagingAppIdentifierMap[] =
+ "gcm.push_messaging_application_id_map";
+
+// A string like "com.chrome.macosx" that should be used as the GCM category
+// when an app_id is sent as a subtype instead of as a category.
+const char kGCMProductCategoryForSubtypes[] =
+ "gcm.product_category_for_subtypes";
+
+// Whether a user is allowed to use Easy Unlock.
+const char kEasyUnlockAllowed[] = "easy_unlock.allowed";
+
+// Preference storing Easy Unlock pairing data.
+const char kEasyUnlockPairing[] = "easy_unlock.pairing";
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+// Used to indicate whether or not the toolbar redesign bubble has been shown
+// and acknowledged, and the last time the bubble was shown.
+const char kToolbarIconSurfacingBubbleAcknowledged[] =
+ "toolbar_icon_surfacing_bubble_acknowledged";
+const char kToolbarIconSurfacingBubbleLastShowTime[] =
+ "toolbar_icon_surfacing_bubble_show_time";
+#endif
+
+// Whether WebRTC should bind to individual NICs to explore all possible routing
+// options. Default is true. This has become obsoleted and replaced by
+// kWebRTCIPHandlingPolicy. TODO(guoweis): Remove this at M50.
+const char kWebRTCMultipleRoutesEnabled[] = "webrtc.multiple_routes_enabled";
+// Whether WebRTC should use non-proxied UDP. If false, WebRTC will not send UDP
+// unless it goes through a proxy (i.e RETURN when it's available). If no UDP
+// proxy is configured, it will not send UDP. If true, WebRTC will send UDP
+// regardless of whether or not a proxy is configured. TODO(guoweis): Remove
+// this at M50.
+const char kWebRTCNonProxiedUdpEnabled[] =
+ "webrtc.nonproxied_udp_enabled";
+// Define the IP handling policy override that WebRTC should follow. When not
+// set, it defaults to "default".
+const char kWebRTCIPHandlingPolicy[] = "webrtc.ip_handling_policy";
+// Define range of UDP ports allowed to be used by WebRTC PeerConnections.
+const char kWebRTCUDPPortRange[] = "webrtc.udp_port_range";
+// Whether WebRTC event log collection by Google domains is allowed.
+const char kWebRtcEventLogCollectionAllowed[] = "webrtc.event_logs_collection";
+// Holds URL patterns that specify URLs for which local IP addresses are exposed
+// in ICE candidates.
+const char kWebRtcLocalIpsAllowedUrls[] = "webrtc.local_ips_allowed_urls";
+
+#if !defined(OS_ANDROID)
+// Whether or not this profile has been shown the Welcome page.
+const char kHasSeenWelcomePage[] = "browser.has_seen_welcome_page";
+#endif
+
+#if defined(OS_WIN)
+// Put the user into an onboarding group that's decided when they go through
+// the first run onboarding experience. Only users in a group will have their
+// finch group pinged to keep track of them for the experiment.
+const char kNaviOnboardGroup[] = "browser.navi_onboard_group";
+#endif // defined(OS_WIN)
+
+// *************** LOCAL STATE ***************
+// These are attached to the machine/installation
+
+// Directory of the last profile used.
+const char kProfileLastUsed[] = "profile.last_used";
+
+// List of directories of the profiles last active.
+const char kProfilesLastActive[] = "profile.last_active_profiles";
+
+// Total number of profiles created for this Chrome build. Used to tag profile
+// directories.
+const char kProfilesNumCreated[] = "profile.profiles_created";
+
+// String containing the version of Chrome that the profile was created by.
+// If profile was created before this feature was added, this pref will default
+// to "1.0.0.0".
+const char kProfileCreatedByVersion[] = "profile.created_by_version";
+
+// A map of profile data directory to cached information. This cache can be
+// used to display information about profiles without actually having to load
+// them.
+const char kProfileInfoCache[] = "profile.info_cache";
+
+// A list of profile paths that should be deleted on shutdown. The deletion does
+// not happen if the browser crashes, so we remove the profile on next start.
+const char kProfilesDeleted[] = "profiles.profiles_deleted";
+
+// Deprecated preference for metric / crash reporting on Android. Use
+// kMetricsReportingEnabled instead.
+#if defined(OS_ANDROID)
+const char kCrashReportingEnabled[] =
+ "user_experience_metrics_crash.reporting_enabled";
+#endif // defined(OS_ANDROID)
+
+// This is the location of a list of dictionaries of plugin stability stats.
+const char kStabilityPluginStats[] =
+ "user_experience_metrics.stability.plugin_stats2";
+
+// On Chrome OS, total number of non-Chrome user process crashes
+// since the last report.
+const char kStabilityOtherUserCrashCount[] =
+ "user_experience_metrics.stability.other_user_crash_count";
+
+// On Chrome OS, total number of kernel crashes since the last report.
+const char kStabilityKernelCrashCount[] =
+ "user_experience_metrics.stability.kernel_crash_count";
+
+// On Chrome OS, total number of unclean system shutdowns since the
+// last report.
+const char kStabilitySystemUncleanShutdownCount[] =
+ "user_experience_metrics.stability.system_unclean_shutdowns";
+
+// The keys below are used for the dictionaries in the
+// kStabilityPluginStats list.
+const char kStabilityPluginName[] = "name";
+const char kStabilityPluginLaunches[] = "launches";
+const char kStabilityPluginInstances[] = "instances";
+const char kStabilityPluginCrashes[] = "crashes";
+const char kStabilityPluginLoadingErrors[] = "loading_errors";
+
+// String containing the version of Chrome for which Chrome will not prompt the
+// user about setting Chrome as the default browser.
+const char kBrowserSuppressDefaultBrowserPrompt[] =
+ "browser.suppress_default_browser_prompt_for_version";
+
+// A collection of position, size, and other data relating to the browser
+// window to restore on startup.
+const char kBrowserWindowPlacement[] = "browser.window_placement";
+
+// Browser window placement for popup windows.
+const char kBrowserWindowPlacementPopup[] = "browser.window_placement_popup";
+
+// A collection of position, size, and other data relating to the task
+// manager window to restore on startup.
+const char kTaskManagerWindowPlacement[] = "task_manager.window_placement";
+
+// The most recent stored column visibility of the task manager table to be
+// restored on startup.
+const char kTaskManagerColumnVisibility[] = "task_manager.column_visibility";
+
+// A boolean indicating if ending processes are enabled or disabled by policy.
+const char kTaskManagerEndProcessEnabled[] = "task_manager.end_process_enabled";
+
+// A collection of position, size, and other data relating to app windows to
+// restore on startup.
+const char kAppWindowPlacement[] = "browser.app_window_placement";
+
+// String which specifies where to download files to by default.
+const char kDownloadDefaultDirectory[] = "download.default_directory";
+
+// Boolean that records if the download directory was changed by an
+// upgrade a unsafe location to a safe location.
+const char kDownloadDirUpgraded[] = "download.directory_upgrade";
+
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
+const char kOpenPdfDownloadInSystemReader[] =
+ "download.open_pdf_in_system_reader";
+#endif
+
+#if defined(OS_ANDROID)
+// Int (as defined by DownloadPromptStatus) which specifies whether we should
+// ask the user where they want to download the file (only for Android).
+const char kPromptForDownloadAndroid[] = "download.prompt_for_download_android";
+
+// Boolean which specifies whether we should display the missing SD card error.
+// This is only applicable for Android.
+const char kShowMissingSdCardErrorAndroid[] =
+ "download.show_missing_sd_card_error_android";
+#endif
+
+// String which specifies where to save html files to by default.
+const char kSaveFileDefaultDirectory[] = "savefile.default_directory";
+
+// The type used to save the page. See the enum SavePackage::SavePackageType in
+// the chrome/browser/download/save_package.h for the possible values.
+const char kSaveFileType[] = "savefile.type";
+
+// String which specifies the last directory that was chosen for uploading
+// or opening a file.
+const char kSelectFileLastDirectory[] = "selectfile.last_directory";
+
+// Boolean that specifies if file selection dialogs are shown.
+const char kAllowFileSelectionDialogs[] = "select_file_dialogs.allowed";
+
+// Map of default tasks, associated by MIME type.
+const char kDefaultTasksByMimeType[] =
+ "filebrowser.tasks.default_by_mime_type";
+
+// Map of default tasks, associated by file suffix.
+const char kDefaultTasksBySuffix[] =
+ "filebrowser.tasks.default_by_suffix";
+
+// A flag to enable/disable the Shared Clipboard feature which enables users to
+// send text across devices.
+const char kSharedClipboardEnabled[] = "browser.shared_clipboard_enabled";
+
+#if BUILDFLAG(ENABLE_CLICK_TO_CALL)
+// A flag to enable/disable the Click to Call feature which enables users to
+// send phone numbers from desktop to Android phones.
+const char kClickToCallEnabled[] = "browser.click_to_call_enabled";
+#endif // BUILDFLAG(ENABLE_CLICK_TO_CALL)
+
+// Extensions which should be opened upon completion.
+const char kDownloadExtensionsToOpen[] = "download.extensions_to_open";
+
+// Dictionary of schemes used by the external protocol handler. If a scheme
+// is present with value |false|, the protocol may be launched without first
+// prompting the user.
+const char kExcludedSchemes[] = "protocol_handler.excluded_schemes";
+
+// String containing the last known intranet redirect URL, if any. See
+// intranet_redirect_detector.h for more information.
+const char kLastKnownIntranetRedirectOrigin[] = "browser.last_redirect_origin";
+
+// An enum value of how the browser was shut down (see browser_shutdown.h).
+const char kShutdownType[] = "shutdown.type";
+// Number of processes that were open when the user shut down.
+const char kShutdownNumProcesses[] = "shutdown.num_processes";
+// Number of processes that were shut down using the slow path.
+const char kShutdownNumProcessesSlow[] = "shutdown.num_processes_slow";
+
+// Whether to restart the current Chrome session automatically as the last thing
+// before shutting everything down.
+const char kRestartLastSessionOnShutdown[] = "restart.last.session.on.shutdown";
+
+#if !defined(OS_ANDROID)
+#if !defined(OS_CHROMEOS)
+// Pref name for the policy controlling presentation of full-tab promotional
+// and/or educational content.
+const char kPromotionalTabsEnabled[] = "browser.promotional_tabs_enabled";
+
+// Boolean that specifies whether or not to show security warnings for some
+// potentially bad command-line flags. True by default. Controlled by the
+// CommandLineFlagSecurityWarningsEnabled policy setting.
+const char kCommandLineFlagSecurityWarningsEnabled[] =
+ "browser.command_line_flag_security_warnings_enabled";
+#endif // !defined(OS_CHROMEOS)
+
+// Boolean that specifies whether or not showing the unsupported OS warning is
+// suppressed. False by default. Controlled by the SuppressUnsupportedOSWarning
+// policy setting.
+const char kSuppressUnsupportedOSWarning[] =
+ "browser.suppress_unsupported_os_warning";
+
+// Set before autorestarting Chrome, cleared on clean exit.
+const char kWasRestarted[] = "was.restarted";
+#endif // !defined(OS_ANDROID)
+
+// Whether Extensions are enabled.
+const char kDisableExtensions[] = "extensions.disabled";
+
+// Customized app page names that appear on the New Tab Page.
+const char kNtpAppPageNames[] = "ntp.app_page_names";
+
+// Keeps track of which sessions are collapsed in the Other Devices menu.
+const char kNtpCollapsedForeignSessions[] = "ntp.collapsed_foreign_sessions";
+
+#if defined(OS_ANDROID)
+// Keeps track of recently closed tabs collapsed state in the Other Devices
+// menu.
+const char kNtpCollapsedRecentlyClosedTabs[] =
+ "ntp.collapsed_recently_closed_tabs";
+
+// Keeps track of snapshot documents collapsed state in the Other Devices menu.
+const char kNtpCollapsedSnapshotDocument[] = "ntp.collapsed_snapshot_document";
+
+// Keeps track of sync promo collapsed state in the Other Devices menu.
+const char kNtpCollapsedSyncPromo[] = "ntp.collapsed_sync_promo";
+#else
+// Holds info for New Tab Page custom background
+const char kNtpCustomBackgroundDict[] = "ntp.custom_background_dict";
+const char kNtpCustomBackgroundLocalToDevice[] =
+ "ntp.custom_background_local_to_device";
+// List of promos that the user has dismissed while on the NTP.
+const char kNtpPromoBlocklist[] = "ntp.promo_blocklist";
+// Data associated with search suggestions that appear on the NTP.
+const char kNtpSearchSuggestionsBlocklist[] =
+ "ntp.search_suggestions_blocklist";
+const char kNtpSearchSuggestionsImpressions[] =
+ "ntp.search_suggestions_impressions";
+const char kNtpSearchSuggestionsOptOut[] = "ntp.search_suggestions_opt_out";
+// Tracks whether the user has chosen to hide the shortcuts tiles on the NTP.
+const char kNtpShortcutsVisible[] = "ntp.shortcust_visible";
+// Tracks whether the user has chosen to use custom links or most visited sites
+// for the shortcut tiles on the NTP.
+const char kNtpUseMostVisitedTiles[] = "ntp.use_most_visited_tiles";
+#endif // defined(OS_ANDROID)
+
+// Which page should be visible on the new tab page v4
+const char kNtpShownPage[] = "ntp.shown_page";
+
+// A private RSA key for ADB handshake.
+const char kDevToolsAdbKey[] = "devtools.adb_key";
+
+// Defines administrator-set availability of developer tools.
+const char kDevToolsAvailability[] = "devtools.availability";
+
+// Dictionary from background service to recording expiration time.
+const char kDevToolsBackgroundServicesExpirationDict[] =
+ "devtools.backgroundserviceexpiration";
+
+// Determines whether devtools should be discovering usb devices for
+// remote debugging at chrome://inspect.
+const char kDevToolsDiscoverUsbDevicesEnabled[] =
+ "devtools.discover_usb_devices";
+
+// Maps of files edited locally using DevTools.
+const char kDevToolsEditedFiles[] = "devtools.edited_files";
+
+// List of file system paths added in DevTools.
+const char kDevToolsFileSystemPaths[] = "devtools.file_system_paths";
+
+// A boolean specifying whether port forwarding should be enabled.
+const char kDevToolsPortForwardingEnabled[] =
+ "devtools.port_forwarding_enabled";
+
+// A boolean specifying whether default port forwarding configuration has been
+// set.
+const char kDevToolsPortForwardingDefaultSet[] =
+ "devtools.port_forwarding_default_set";
+
+// A dictionary of port->location pairs for port forwarding.
+const char kDevToolsPortForwardingConfig[] = "devtools.port_forwarding_config";
+
+// A boolean specifying whether or not Chrome will scan for available remote
+// debugging targets.
+const char kDevToolsDiscoverTCPTargetsEnabled[] =
+ "devtools.discover_tcp_targets";
+
+// A list of strings representing devtools target discovery servers.
+const char kDevToolsTCPDiscoveryConfig[] = "devtools.tcp_discovery_config";
+
+// A dictionary with generic DevTools settings.
+const char kDevToolsPreferences[] = "devtools.preferences";
+
+#if !defined(OS_ANDROID)
+// Tracks the number of times the dice signin promo has been shown in the user
+// menu.
+const char kDiceSigninUserMenuPromoCount[] = "sync_promo.user_menu_show_count";
+#endif
+
+// Create web application shortcut dialog preferences.
+const char kWebAppCreateOnDesktop[] = "browser.web_app.create_on_desktop";
+const char kWebAppCreateInAppsMenu[] = "browser.web_app.create_in_apps_menu";
+const char kWebAppCreateInQuickLaunchBar[] =
+ "browser.web_app.create_in_quick_launch_bar";
+
+// A list of dictionaries for force-installed Web Apps. Each dictionary contains
+// two strings: the URL of the Web App and "tab" or "window" for where the app
+// will be launched.
+const char kWebAppInstallForceList[] = "profile.web_app.install.forcelist";
+
+// Dictionary that maps web app ids to installation metrics used by UMA.
+const char kWebAppInstallMetrics[] = "web_app_install_metrics";
+
+// Dictionary that maps web app URLs to Chrome extension IDs.
+const char kWebAppsExtensionIDs[] = "web_apps.extension_ids";
+
+// A string representing the last version of Chrome that System Web Apps were
+// updated for.
+const char kSystemWebAppLastUpdateVersion[] =
+ "web_apps.system_web_app_last_update";
+
+// The default audio capture device used by the Media content setting.
+const char kDefaultAudioCaptureDevice[] = "media.default_audio_capture_device";
+
+// The default video capture device used by the Media content setting.
+const char kDefaultVideoCaptureDevice[] = "media.default_video_capture_Device";
+
+// The salt used for creating random MediaSource IDs.
+const char kMediaDeviceIdSalt[] = "media.device_id_salt";
+
+// The salt used for creating Storage IDs. The Storage ID is used by encrypted
+// media to bind persistent licenses to the device which is authorized to play
+// the content.
+const char kMediaStorageIdSalt[] = "media.storage_id_salt";
+
+// The last used printer and its settings.
+const char kPrintPreviewStickySettings[] =
+ "printing.print_preview_sticky_settings";
+
+// The list of BackgroundContents that should be loaded when the browser
+// launches.
+const char kRegisteredBackgroundContents[] = "background_contents.registered";
+
+// Integer that specifies the total memory usage, in mb, that chrome will
+// attempt to stay under. Can be specified via policy in addition to the default
+// memory pressure rules applied per platform.
+const char kTotalMemoryLimitMb[] = "total_memory_limit_mb";
+
+// String that lists supported HTTP authentication schemes.
+const char kAuthSchemes[] = "auth.schemes";
+
+// Boolean that specifies whether to disable CNAME lookups when generating
+// Kerberos SPN.
+const char kDisableAuthNegotiateCnameLookup[] =
+ "auth.disable_negotiate_cname_lookup";
+
+// Boolean that specifies whether to include the port in a generated Kerberos
+// SPN.
+const char kEnableAuthNegotiatePort[] = "auth.enable_negotiate_port";
+
+// Whitelist containing servers for which Integrated Authentication is enabled.
+const char kAuthServerWhitelist[] = "auth.server_whitelist";
+
+// Whitelist containing servers Chrome is allowed to do Kerberos delegation
+// with.
+const char kAuthNegotiateDelegateWhitelist[] =
+ "auth.negotiate_delegate_whitelist";
+
+// String that specifies the name of a custom GSSAPI library to load.
+const char kGSSAPILibraryName[] = "auth.gssapi_library_name";
+
+// String that specifies the Android account type to use for Negotiate
+// authentication.
+const char kAuthAndroidNegotiateAccountType[] =
+ "auth.android_negotiate_account_type";
+
+// Boolean that specifies whether to allow basic auth prompting on cross-
+// domain sub-content requests.
+const char kAllowCrossOriginAuthPrompt[] = "auth.allow_cross_origin_prompt";
+
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
+// Boolean that specifies whether OK-AS-DELEGATE flag from KDC is respected
+// along with kAuthNegotiateDelegateWhitelist.
+const char kAuthNegotiateDelegateByKdcPolicy[] =
+ "auth.negotiate_delegate_by_kdc_policy";
+#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
+
+#if defined(OS_POSIX)
+// Boolean that specifies whether NTLMv2 is enabled.
+const char kNtlmV2Enabled[] = "auth.ntlm_v2_enabled";
+#endif // defined(OS_POSIX)
+
+#if defined(OS_CHROMEOS)
+// Boolean whether Kerberos functionality is enabled.
+const char kKerberosEnabled[] = "kerberos.enabled";
+#endif
+
+// Boolean that specifies whether to enable revocation checking (best effort)
+// by default.
+const char kCertRevocationCheckingEnabled[] = "ssl.rev_checking.enabled";
+
+// Boolean that specifies whether to require a successful revocation check if
+// a certificate path ends in a locally-trusted (as opposed to publicly
+// trusted) trust anchor.
+const char kCertRevocationCheckingRequiredLocalAnchors[] =
+ "ssl.rev_checking.required_for_local_anchors";
+
+// String specifying the minimum TLS version to negotiate. Supported values
+// are "tls1", "tls1.1", "tls1.2", "tls1.3".
+const char kSSLVersionMin[] = "ssl.version_min";
+
+// String specifying the maximum TLS version to negotiate. Supported values
+// are "tls1.2", "tls1.3"
+const char kSSLVersionMax[] = "ssl.version_max";
+
+// String specifying the TLS ciphersuites to disable. Ciphersuites are
+// specified as a comma-separated list of 16-bit hexadecimal values, with
+// the values being the ciphersuites assigned by the IANA registry (e.g.
+// "0x0004,0x0005").
+const char kCipherSuiteBlacklist[] = "ssl.cipher_suites.blacklist";
+
+// List of strings specifying which hosts are allowed to have H2 connections
+// coalesced when client certs are also used. This follows rules similar to
+// the URLBlacklist format for hostnames: a pattern with a leading dot (e.g.
+// ".example.net") matches exactly the hostname following the dot (i.e. only
+// "example.net"), and a pattern with no leading dot (e.g. "example.com")
+// matches that hostname and all subdomains.
+const char kH2ClientCertCoalescingHosts[] =
+ "ssl.client_certs.h2_coalescing_hosts";
+
+// List of single-label hostnames that will skip the check to possibly upgrade
+// from http to https.
+const char kHSTSPolicyBypassList[] = "hsts.policy.upgrade_bypass_list";
+
+// If true, enables stronger TLS 1.3 downgrade protection for connections using
+// local trust anchors.
+const char kTLS13HardeningForLocalAnchorsEnabled[] =
+ "ssl.tls13_hardening_for_local_anchors";
+
+// Boolean that specifies whether the built-in asynchronous DNS client is used.
+const char kBuiltInDnsClientEnabled[] = "async_dns.enabled";
+
+// String specifying the secure DNS mode to use. Any string other than
+// "secure" or "automatic" will be mapped to the default "off" mode.
+const char kDnsOverHttpsMode[] = "dns_over_https.mode";
+// String containing a space-separated list of DNS over HTTPS templates to use
+// in secure mode or automatic mode. If no templates are specified in automatic
+// mode, we will attempt discovery of DoH servers associated with the configured
+// insecure resolvers.
+const char kDnsOverHttpsTemplates[] = "dns_over_https.templates";
+
+// A pref holding the value of the policy used to explicitly allow or deny
+// access to audio capture devices. When enabled or not set, the user is
+// prompted for device access. When disabled, access to audio capture devices
+// is not allowed and no prompt will be shown.
+// See also kAudioCaptureAllowedUrls.
+const char kAudioCaptureAllowed[] = "hardware.audio_capture_enabled";
+// Holds URL patterns that specify URLs that will be granted access to audio
+// capture devices without prompt.
+const char kAudioCaptureAllowedUrls[] = "hardware.audio_capture_allowed_urls";
+
+// A pref holding the value of the policy used to explicitly allow or deny
+// access to video capture devices. When enabled or not set, the user is
+// prompted for device access. When disabled, access to video capture devices
+// is not allowed and no prompt will be shown.
+const char kVideoCaptureAllowed[] = "hardware.video_capture_enabled";
+// Holds URL patterns that specify URLs that will be granted access to video
+// capture devices without prompt.
+const char kVideoCaptureAllowedUrls[] = "hardware.video_capture_allowed_urls";
+
+#if defined(OS_CHROMEOS)
+// An integer pref that holds enum value of current demo mode configuration.
+// Values are defined by DemoSession::DemoModeConfig enum.
+const char kDemoModeConfig[] = "demo_mode.config";
+
+// A string pref holding the value of the current country for demo sessions.
+const char kDemoModeCountry[] = "demo_mode.country";
+
+// A string pref holding the value of the default locale for demo sessions.
+const char kDemoModeDefaultLocale[] = "demo_mode.default_locale";
+
+// Dictionary for transient storage of settings that should go into device
+// settings storage before owner has been assigned.
+const char kDeviceSettingsCache[] = "signed_settings_cache";
+
+// The hardware keyboard layout of the device. This should look like
+// "xkb:us::eng".
+const char kHardwareKeyboardLayout[] = "intl.hardware_keyboard";
+
+// An integer pref which shows number of times carrier deal promo
+// notification has been shown to user.
+const char kCarrierDealPromoShown[] =
+ "settings.internet.mobile.carrier_deal_promo_shown";
+
+// A boolean pref of the auto-enrollment decision. Its value is only valid if
+// it's not the default value; otherwise, no auto-enrollment decision has been
+// made yet.
+const char kShouldAutoEnroll[] = "ShouldAutoEnroll";
+
+// An integer pref with the maximum number of bits used by the client in a
+// previous auto-enrollment request. If the client goes through an auto update
+// during OOBE and reboots into a version of the OS with a larger maximum
+// modulus, then it will retry auto-enrollment using the updated value.
+const char kAutoEnrollmentPowerLimit[] = "AutoEnrollmentPowerLimit";
+
+// The local state pref that stores device activity times before reporting
+// them to the policy server.
+const char kDeviceActivityTimes[] = "device_status.activity_times";
+
+// A pref that stores user activity times before reporting them to the policy
+// server.
+const char kUserActivityTimes[] = "consumer_device_status.activity_times";
+
+// A pref holding the value of the policy used to disable mounting of external
+// storage for the user.
+const char kExternalStorageDisabled[] = "hardware.external_storage_disabled";
+
+// A pref holding the value of the policy used to limit mounting of external
+// storage to read-only mode for the user.
+const char kExternalStorageReadOnly[] = "hardware.external_storage_read_only";
+
+// Copy of owner swap mouse buttons option to use on login screen.
+const char kOwnerPrimaryMouseButtonRight[] = "owner.mouse.primary_right";
+
+// Copy of owner tap-to-click option to use on login screen.
+const char kOwnerTapToClickEnabled[] = "owner.touchpad.enable_tap_to_click";
+
+// The length of device uptime after which an automatic reboot is scheduled,
+// expressed in seconds.
+const char kUptimeLimit[] = "automatic_reboot.uptime_limit";
+
+// Whether an automatic reboot should be scheduled when an update has been
+// applied and a reboot is required to complete the update process.
+const char kRebootAfterUpdate[] = "automatic_reboot.reboot_after_update";
+
+// An any-api scoped refresh token for enterprise-enrolled devices. Allows
+// for connection to Google APIs when the user isn't logged in. Currently used
+// for for getting a cloudprint scoped token to allow printing in Guest mode,
+// Public Accounts and kiosks.
+const char kDeviceRobotAnyApiRefreshToken[] =
+ "device_robot_refresh_token.any-api";
+
+// Device requisition for enterprise enrollment.
+const char kDeviceEnrollmentRequisition[] = "enrollment.device_requisition";
+
+// Sub organization for enterprise enrollment.
+const char kDeviceEnrollmentSubOrganization[] = "enrollment.sub_organization";
+
+// Whether to automatically start the enterprise enrollment step during OOBE.
+const char kDeviceEnrollmentAutoStart[] = "enrollment.auto_start";
+
+// Whether the user may exit enrollment.
+const char kDeviceEnrollmentCanExit[] = "enrollment.can_exit";
+
+// DM token fetched from the DM server during enrollment. Stored for Active
+// Directory devices only.
+const char kDeviceDMToken[] = "device_dm_token";
+
+// How many times HID detection OOBE dialog was shown.
+const char kTimesHIDDialogShown[] = "HIDDialog.shown_how_many_times";
+
+// Dictionary of per-user last input method (used at login screen). Note that
+// the pref name is UsersLRUInputMethods for compatibility with previous
+// versions.
+const char kUsersLastInputMethod[] = "UsersLRUInputMethod";
+
+// A dictionary pref of the echo offer check flag. It sets offer info when
+// an offer is checked.
+const char kEchoCheckedOffers[] = "EchoCheckedOffers";
+
+// Key name of a dictionary in local state to store cached multiprofle user
+// behavior policy value.
+const char kCachedMultiProfileUserBehavior[] = "CachedMultiProfileUserBehavior";
+
+// A string pref with initial locale set in VPD or manifest.
+const char kInitialLocale[] = "intl.initial_locale";
+
+// A boolean pref of the OOBE complete flag (first OOBE part before login).
+const char kOobeComplete[] = "OobeComplete";
+
+// The name of the screen that has to be shown if OOBE has been interrupted.
+const char kOobeScreenPending[] = "OobeScreenPending";
+
+
+// A boolean pref to indicate if the marketing opt-in screen in OOBE is finished
+// for the user.
+const char kOobeMarketingOptInScreenFinished[] =
+ "OobeMarketingOptInScreenFinished";
+
+// A boolean pref for whether the Goodies promotion webpage has been displayed,
+// or otherwise disqualified for auto-display, on this device.
+const char kCanShowOobeGoodiesPage[] = "CanShowOobeGoodiesPage";
+
+// A boolean pref of the device registered flag (second part after first login).
+const char kDeviceRegistered[] = "DeviceRegistered";
+
+// Boolean pref to signal corrupted enrollment to force the device through
+// enrollment recovery flow upon next boot.
+const char kEnrollmentRecoveryRequired[] = "EnrollmentRecoveryRequired";
+
+// List of usernames that used certificates pushed by policy before.
+// This is used to prevent these users from joining multiprofile sessions.
+const char kUsedPolicyCertificates[] = "policy.used_policy_certificates";
+
+// A dictionary containing server-provided device state pulled form the cloud
+// after recovery.
+const char kServerBackedDeviceState[] = "server_backed_device_state";
+
+// Customized wallpaper URL, which is already downloaded and scaled.
+// The URL from this preference must never be fetched. It is compared to the
+// URL from customization document to check if wallpaper URL has changed
+// since wallpaper was cached.
+const char kCustomizationDefaultWallpaperURL[] =
+ "customization.default_wallpaper_url";
+
+// System uptime, when last logout started.
+// This is saved to file and cleared after chrome process starts.
+const char kLogoutStartedLast[] = "chromeos.logout-started";
+
+
+// A boolean preference controlling Android status reporting.
+const char kReportArcStatusEnabled[] = "arc.status_reporting_enabled";
+
+// A string preference indicating the name of the OS level task scheduler
+// configuration to use.
+const char kSchedulerConfiguration[] = "chromeos.scheduler_configuration";
+
+// Dictionary indicating current network bandwidth throttling settings.
+// Contains a boolean (is throttling enabled) and two integers (upload rate
+// and download rate in kbits/s to throttle to)
+const char kNetworkThrottlingEnabled[] = "net.throttling_enabled";
+
+// Integer pref used by the metrics::DailyEvent owned by
+// chromeos::PowerMetricsReporter.
+const char kPowerMetricsDailySample[] = "power.metrics.daily_sample";
+
+// Integer prefs used to back event counts reported by
+// chromeos::PowerMetricsReporter.
+const char kPowerMetricsIdleScreenDimCount[] =
+ "power.metrics.idle_screen_dim_count";
+const char kPowerMetricsIdleScreenOffCount[] =
+ "power.metrics.idle_screen_off_count";
+const char kPowerMetricsIdleSuspendCount[] = "power.metrics.idle_suspend_count";
+const char kPowerMetricsLidClosedSuspendCount[] =
+ "power.metrics.lid_closed_suspend_count";
+
+// Key for list of users that should be reported.
+const char kReportingUsers[] = "reporting_users";
+
+// Whether to log events for Android app installs.
+const char kArcAppInstallEventLoggingEnabled[] =
+ "arc.app_install_event_logging_enabled";
+
+// Whether we received the remove users remote command, and hence should proceed
+// with removing the users while at the login screen.
+const char kRemoveUsersRemoteCommand[] = "remove_users_remote_command";
+
+// Whether camera-produced media files have been consolidated to one place.
+const char kCameraMediaConsolidated[] = "camera_media_consolidated";
+
+// Integer pref used by the metrics::DailyEvent owned by
+// chromeos::power::auto_screen_brightness::MetricsReporter.
+const char kAutoScreenBrightnessMetricsDailySample[] =
+ "auto_screen_brightness.metrics.daily_sample";
+
+// Integer prefs used to back event counts reported by
+// chromeos::power::auto_screen_brightness::MetricsReporter.
+const char kAutoScreenBrightnessMetricsAtlasUserAdjustmentCount[] =
+ "auto_screen_brightness.metrics.atlas_user_adjustment_count";
+const char kAutoScreenBrightnessMetricsEveUserAdjustmentCount[] =
+ "auto_screen_brightness.metrics.eve_user_adjustment_count";
+const char kAutoScreenBrightnessMetricsNocturneUserAdjustmentCount[] =
+ "auto_screen_brightness.metrics.nocturne_user_adjustment_count";
+const char kAutoScreenBrightnessMetricsNoAlsUserAdjustmentCount[] =
+ "auto_screen_brightness.metrics.no_als_user_adjustment_count";
+const char kAutoScreenBrightnessMetricsSupportedAlsUserAdjustmentCount[] =
+ "auto_screen_brightness.metrics.supported_als_user_adjustment_count";
+const char kAutoScreenBrightnessMetricsUnsupportedAlsUserAdjustmentCount[] =
+ "auto_screen_brightness.metrics.unsupported_als_user_adjustment_count";
+
+// Dictionary pref containing the configuration used to verify Parent Access
+// Code. The data is sent through the ParentAccessCodeConfig policy, which is
+// set for child users only, and kept on the known user storage.
+const char kKnownUserParentAccessCodeConfig[] =
+ "child_user.parent_access_code.config";
+
+// Enable chrome://password-change page for in-session change of SAML passwords.
+// Also enables SAML password expiry notifications, if we have that information.
+const char kSamlInSessionPasswordChangeEnabled[] =
+ "saml.in_session_password_change_enabled";
+// The number of days in advance to notify the user that their SAML password
+// will expire (works when kSamlInSessionPasswordChangeEnabled is true).
+const char kSamlPasswordExpirationAdvanceWarningDays[] =
+ "saml.password_expiration_advance_warning_days";
+
+#endif // defined(OS_CHROMEOS)
+
+// Whether there is a Flash version installed that supports clearing LSO data.
+const char kClearPluginLSODataEnabled[] = "browser.clear_lso_data_enabled";
+
+// Whether we should show Pepper Flash-specific settings.
+const char kPepperFlashSettingsEnabled[] =
+ "browser.pepper_flash_settings_enabled";
+
+// String which specifies where to store the disk cache.
+const char kDiskCacheDir[] = "browser.disk_cache_dir";
+// Pref name for the policy specifying the maximal cache size.
+const char kDiskCacheSize[] = "browser.disk_cache_size";
+
+// Specifies the release channel that the device should be locked to.
+// Possible values: "stable-channel", "beta-channel", "dev-channel", or an
+// empty string, in which case the value will be ignored.
+// TODO(dubroy): This preference may not be necessary once
+// http://crosbug.com/17015 is implemented and the update engine can just
+// fetch the correct value from the policy.
+const char kChromeOsReleaseChannel[] = "cros.system.releaseChannel";
+
+const char kPerformanceTracingEnabled[] =
+ "feedback.performance_tracing_enabled";
+
+// Boolean indicating whether tabstrip uses stacked layout (on touch devices).
+// Defaults to false.
+const char kTabStripStackedLayout[] = "tab-strip-stacked-layout";
+
+// Indicates that factory reset was requested from options page or reset screen.
+const char kFactoryResetRequested[] = "FactoryResetRequested";
+
+// Presence of this value indicates that a TPM firmware update has been
+// requested. The value indicates the requested update mode.
+const char kFactoryResetTPMFirmwareUpdateMode[] =
+ "FactoryResetTPMFirmwareUpdateMode";
+
+// Indicates that debugging features were requested from oobe screen.
+const char kDebuggingFeaturesRequested[] = "DebuggingFeaturesRequested";
+
+#if defined(OS_CHROMEOS)
+// This setting controls initial device timezone that is used before user
+// session started. It is controlled by device owner.
+const char kSigninScreenTimezone[] = "settings.signin_screen_timezone";
+
+// This setting starts periodic timezone refresh when not in user session.
+// (user session is controlled by user profile preference
+// kResolveTimezoneByGeolocation)
+//
+// Deprecated. Superseeded by kResolveDeviceTimezoneByGeolocationMethod.
+// TODO(alemate): https://crbug.com/783367 Remove outdated prefs.
+const char kResolveDeviceTimezoneByGeolocation[] =
+ "settings.resolve_device_timezone_by_geolocation";
+
+// This setting controls what information is sent to the server to get
+// device location to resolve time zone outside of user session. Values must
+// match TimeZoneResolverManager::TimeZoneResolveMethod enum.
+const char kResolveDeviceTimezoneByGeolocationMethod[] =
+ "settings.resolve_device_timezone_by_geolocation_method";
+
+// This is policy-controlled preference.
+// It has values defined in policy enum
+// SystemTimezoneAutomaticDetectionProto_AutomaticTimezoneDetectionType;
+const char kSystemTimezoneAutomaticDetectionPolicy[] =
+ "settings.resolve_device_timezone_by_geolocation_policy";
+#endif // defined(OS_CHROMEOS)
+
+// Pref name for the policy controlling whether to enable Media Router.
+const char kEnableMediaRouter[] = "media_router.enable_media_router";
+#if !defined(OS_ANDROID)
+// Pref name for the policy controlling whether to force the Cast icon to be
+// shown in the toolbar/overflow menu.
+const char kShowCastIconInToolbar[] = "media_router.show_cast_icon_in_toolbar";
+#endif // !defined(OS_ANDROID)
+
+#if !defined(OS_ANDROID)
+// Pref name for the policy controlling the way in which users are notified of
+// the need to relaunch the browser for a pending update.
+const char kRelaunchNotification[] = "browser.relaunch_notification";
+// Pref name for the policy controlling the time period over which users are
+// notified of the need to relaunch the browser for a pending update. Values
+// are in milliseconds.
+const char kRelaunchNotificationPeriod[] =
+ "browser.relaunch_notification_period";
+#endif // !defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+// Pref name for the policy controlling the time period between the first user
+// notification about need to relaunch and the end of the
+// RelaunchNotificationPeriod. Values are in milliseconds.
+const char kRelaunchHeadsUpPeriod[] = "browser.relaunch_heads_up_period";
+#endif // defined(OS_CHROMEOS)
+
+// *************** SERVICE PREFS ***************
+// These are attached to the service process.
+
+const char kCloudPrintRoot[] = "cloud_print";
+const char kCloudPrintProxyEnabled[] = "cloud_print.enabled";
+// The unique id for this instance of the cloud print proxy.
+const char kCloudPrintProxyId[] = "cloud_print.proxy_id";
+// The GAIA auth token for Cloud Print
+const char kCloudPrintAuthToken[] = "cloud_print.auth_token";
+// The email address of the account used to authenticate with the Cloud Print
+// server.
+const char kCloudPrintEmail[] = "cloud_print.email";
+// Settings specific to underlying print system.
+const char kCloudPrintPrintSystemSettings[] =
+ "cloud_print.print_system_settings";
+// A boolean indicating whether we should poll for print jobs when don't have
+// an XMPP connection (false by default).
+const char kCloudPrintEnableJobPoll[] = "cloud_print.enable_job_poll";
+const char kCloudPrintRobotRefreshToken[] = "cloud_print.robot_refresh_token";
+const char kCloudPrintRobotEmail[] = "cloud_print.robot_email";
+// A boolean indicating whether we should connect to cloud print new printers.
+const char kCloudPrintConnectNewPrinters[] =
+ "cloud_print.user_settings.connectNewPrinters";
+// A boolean indicating whether we should ping XMPP connection.
+const char kCloudPrintXmppPingEnabled[] = "cloud_print.xmpp_ping_enabled";
+// An int value indicating the average timeout between xmpp pings.
+const char kCloudPrintXmppPingTimeout[] = "cloud_print.xmpp_ping_timeout_sec";
+// Dictionary with settings stored by connector setup page.
+const char kCloudPrintUserSettings[] = "cloud_print.user_settings";
+// List of printers settings.
+const char kCloudPrintPrinters[] = "cloud_print.user_settings.printers";
+// A boolean indicating whether submitting jobs to Google Cloud Print is
+// blocked by policy.
+const char kCloudPrintSubmitEnabled[] = "cloud_print.submit_enabled";
+
+// Preference to store proxy settings.
+const char kMaxConnectionsPerProxy[] = "net.max_connections_per_proxy";
+
+#if defined(OS_MACOSX)
+// Set to true if the user removed our login item so we should not create a new
+// one when uninstalling background apps.
+const char kUserRemovedLoginItem[] = "background_mode.user_removed_login_item";
+
+// Set to true if Chrome already created a login item, so there's no need to
+// create another one.
+const char kChromeCreatedLoginItem[] =
+ "background_mode.chrome_created_login_item";
+
+// Set to true once we've initialized kChromeCreatedLoginItem for the first
+// time.
+const char kMigratedLoginItemPref[] =
+ "background_mode.migrated_login_item_pref";
+
+// A boolean that tracks whether to show a notification when trying to quit
+// while there are apps running.
+const char kNotifyWhenAppsKeepChromeAlive[] =
+ "apps.notify-when-apps-keep-chrome-alive";
+#endif
+
+// Set to true if background mode is enabled on this browser.
+const char kBackgroundModeEnabled[] = "background_mode.enabled";
+
+// Set to true if hardware acceleration mode is enabled on this browser.
+const char kHardwareAccelerationModeEnabled[] =
+ "hardware_acceleration_mode.enabled";
+
+// Hardware acceleration mode from previous browser launch.
+const char kHardwareAccelerationModePrevious[] =
+ "hardware_acceleration_mode_previous";
+
+// List of protocol handlers.
+const char kRegisteredProtocolHandlers[] =
+ "custom_handlers.registered_protocol_handlers";
+
+// List of protocol handlers the user has requested not to be asked about again.
+const char kIgnoredProtocolHandlers[] =
+ "custom_handlers.ignored_protocol_handlers";
+
+// List of protocol handlers registered by policy.
+const char kPolicyRegisteredProtocolHandlers[] =
+ "custom_handlers.policy.registered_protocol_handlers";
+
+// List of protocol handlers the policy has requested to be ignored.
+const char kPolicyIgnoredProtocolHandlers[] =
+ "custom_handlers.policy.ignored_protocol_handlers";
+
+// Whether user-specified handlers for protocols and content types can be
+// specified.
+const char kCustomHandlersEnabled[] = "custom_handlers.enabled";
+
+// Integer that specifies the policy refresh rate for device-policy in
+// milliseconds. Not all values are meaningful, so it is clamped to a sane range
+// by the cloud policy subsystem.
+const char kDevicePolicyRefreshRate[] = "policy.device_refresh_rate";
+
+#if !defined(OS_ANDROID)
+// A boolean where true means that the browser has previously attempted to
+// enable autoupdate and failed, so the next out-of-date browser start should
+// not prompt the user to enable autoupdate, it should offer to reinstall Chrome
+// instead.
+const char kAttemptedToEnableAutoupdate[] =
+ "browser.attempted_to_enable_autoupdate";
+
+// The next media gallery ID to assign.
+const char kMediaGalleriesUniqueId[] = "media_galleries.gallery_id";
+
+// A list of dictionaries, where each dictionary represents a known media
+// gallery.
+const char kMediaGalleriesRememberedGalleries[] =
+ "media_galleries.remembered_galleries";
+#endif // !defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+const char kPolicyPinnedLauncherApps[] = "policy_pinned_launcher_apps";
+// Keeps names of rolled default pin layouts for shelf in order not to apply
+// this twice. Names are separated by comma.
+const char kShelfDefaultPinLayoutRolls[] = "shelf_default_pin_layout_rolls";
+#endif // defined(OS_CHROMEOS)
+
+#if defined(OS_WIN)
+// Counts how many more times the 'profile on a network share' warning should be
+// shown to the user before the next silence period.
+const char kNetworkProfileWarningsLeft[] = "network_profile.warnings_left";
+// Tracks the time of the last shown warning. Used to reset
+// |network_profile.warnings_left| after a silence period.
+const char kNetworkProfileLastWarningTime[] =
+ "network_profile.last_warning_time";
+#endif
+
+#if defined(OS_CHROMEOS)
+// The RLZ brand code, if enabled.
+const char kRLZBrand[] = "rlz.brand";
+// Whether RLZ pings are disabled.
+const char kRLZDisabled[] = "rlz.disabled";
+#endif
+
+#if BUILDFLAG(ENABLE_APP_LIST)
+// Keeps local state of app list while sync service is not available.
+const char kAppListLocalState[] = "app_list.local_state";
+#endif
+
+// An integer that is incremented whenever changes are made to app shortcuts.
+// Increasing this causes all app shortcuts to be recreated.
+const char kAppShortcutsVersion[] = "apps.shortcuts_version";
+
+// A string pref for storing the salt used to compute the pepper device ID.
+const char kDRMSalt[] = "settings.privacy.drm_salt";
+// A boolean pref that enables the (private) pepper GetDeviceID() call and
+// enables the use of remote attestation for content protection.
+const char kEnableDRM[] = "settings.privacy.drm_enabled";
+
+// An integer per-profile pref that signals if the watchdog extension is
+// installed and active. We need to know if the watchdog extension active for
+// ActivityLog initialization before the extension system is initialized.
+const char kWatchdogExtensionActive[] =
+ "profile.extensions.activity_log.num_consumers_active";
+
+#if defined(OS_ANDROID)
+// A list of partner bookmark rename/remove mappings.
+// Each list item is a dictionary containing a "url", a "provider_title" and
+// "mapped_title" entries, detailing the bookmark target URL (if any), the title
+// given by the PartnerBookmarksProvider and either the user-visible renamed
+// title or an empty string if the bookmark node was removed.
+const char kPartnerBookmarkMappings[] = "partnerbookmarks.mappings";
+#endif // defined(OS_ANDROID)
+
+// Whether DNS Quick Check is disabled in proxy resolution.
+//
+// This is a performance optimization for WPAD (Web Proxy
+// Auto-Discovery) which places a 1 second timeout on resolving the
+// DNS for PAC script URLs.
+//
+// It is on by default, but can be disabled via the Policy option
+// "WPADQuickCheckEnbled". There is no other UI for changing this
+// preference.
+//
+// For instance, if the DNS resolution for 'wpad' takes longer than 1
+// second, auto-detection will give up and fallback to the next proxy
+// configuration (which could be manually configured proxy server
+// rules, or an implicit fallback to DIRECT connections).
+const char kQuickCheckEnabled[] = "proxy.quick_check_enabled";
+
+// Whether Guest Mode is enabled within the browser.
+const char kBrowserGuestModeEnabled[] = "profile.browser_guest_enabled";
+
+// Whether Guest Mode is enforced within the browser.
+const char kBrowserGuestModeEnforced[] = "profile.browser_guest_enforced";
+
+// Whether Adding a new Person is enabled within the user manager.
+const char kBrowserAddPersonEnabled[] = "profile.add_person_enabled";
+
+// Whether profile can be used before sign in.
+const char kForceBrowserSignin[] = "profile.force_browser_signin";
+
+// Boolean which indicates if the user is allowed to sign into Chrome on the
+// next startup.
+const char kSigninAllowedOnNextStartup[] = "signin.allowed_on_next_startup";
+
+// Device identifier used by CryptAuth stored in local state. This ID is
+// combined with a user ID before being registered with the CryptAuth server,
+// so it can't correlate users on the same device.
+// Note: This constant was previously specific to EasyUnlock, so the string
+// constant contains "easy_unlock".
+const char kCryptAuthDeviceId[] = "easy_unlock.device_id";
+
+// A dictionary that maps user id to hardlock state.
+const char kEasyUnlockHardlockState[] = "easy_unlock.hardlock_state";
+
+// A dictionary that maps user id to public part of RSA key pair used by
+// Easy Sign-in for the user.
+const char kEasyUnlockLocalStateTpmKeys[] = "easy_unlock.public_tpm_keys";
+
+// A dictionary in local state containing each user's Easy Unlock profile
+// preferences, so they can be accessed outside of the user's profile. The value
+// is a dictionary containing an entry for each user. Each user's entry mirrors
+// their profile's Easy Unlock preferences.
+const char kEasyUnlockLocalStateUserPrefs[] = "easy_unlock.user_prefs";
+
+// Boolean that indicates whether elevation is needed to recover Chrome upgrade.
+const char kRecoveryComponentNeedsElevation[] =
+ "recovery_component.needs_elevation";
+
+// A dictionary that maps from supervised user whitelist IDs to their properties
+// (name and a list of clients that registered the whitelist).
+const char kRegisteredSupervisedUserWhitelists[] =
+ "supervised_users.whitelists";
+
+#if !defined(OS_ANDROID)
+// Boolean that indicates whether Chrome enterprise cloud reporting is enabled
+// or not.
+const char kCloudReportingEnabled[] =
+ "enterprise_reporting.chrome_cloud_reporting";
+// Boolean that indicates whether Chrome enterprise extension request is enabled
+// or not.
+const char kCloudExtensionRequestEnabled[] =
+ "enterprise_reporting.extension_request.enabled";
+
+// A list of extension ids represents pending extension request. The ids are
+// stored once user sent the request until the request is canceled, approved or
+// denied.
+const char kCloudExtensionRequestIds[] =
+ "enterprise_reporting.extension_request.ids";
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+// Policy that indicates how to handle animated images.
+const char kAnimationPolicy[] = "settings.a11y.animation_policy";
+
+// A list of URLs (for U2F) or domains (for webauthn) that automatically permit
+// direct attestation of a Security Key.
+const char kSecurityKeyPermitAttestation[] = "securitykey.permit_attestation";
+#endif
+
+const char kBackgroundTracingLastUpload[] = "background_tracing.last_upload";
+
+const char kAllowDinosaurEasterEgg[] =
+ "allow_dinosaur_easter_egg";
+
+#if defined(OS_ANDROID)
+// Whether the update menu item was clicked. Used to facilitate logging whether
+// Chrome was updated after the menu item is clicked.
+const char kClickedUpdateMenuItem[] = "omaha.clicked_update_menu_item";
+// The latest version of Chrome available when the user clicked on the update
+// menu item.
+const char kLatestVersionWhenClickedUpdateMenuItem[] =
+ "omaha.latest_version_when_clicked_upate_menu_item";
+#endif
+
+// Whether or not the user has explicitly set the cloud services preference
+// through the first run flow.
+const char kMediaRouterCloudServicesPrefSet[] =
+ "media_router.cloudservices.prefset";
+// Whether or not the user has enabled cloud services with Media Router.
+const char kMediaRouterEnableCloudServices[] =
+ "media_router.cloudservices.enabled";
+// Whether or not the Media Router first run flow has been acknowledged by the
+// user.
+const char kMediaRouterFirstRunFlowAcknowledged[] =
+ "media_router.firstrunflow.acknowledged";
+// Whether or not the user has enabled Media Remoting. Defaults to true.
+const char kMediaRouterMediaRemotingEnabled[] =
+ "media_router.media_remoting.enabled";
+// A list of website origins on which the user has chosen to use tab mirroring.
+const char kMediaRouterTabMirroringSources[] =
+ "media_router.tab_mirroring_sources";
+
+// The base64-encoded representation of the public key to use to validate origin
+// trial token signatures.
+const char kOriginTrialPublicKey[] = "origin_trials.public_key";
+
+// A list of origin trial features to disable by policy.
+const char kOriginTrialDisabledFeatures[] = "origin_trials.disabled_features";
+
+// A list of origin trial tokens to disable by policy.
+const char kOriginTrialDisabledTokens[] = "origin_trials.disabled_tokens";
+
+// Policy that indicates the state of updates for the binary components.
+const char kComponentUpdatesEnabled[] =
+ "component_updates.component_updates_enabled";
+
+#if defined(OS_ANDROID)
+// The current level of backoff for showing the location settings dialog for the
+// default search engine.
+const char kLocationSettingsBackoffLevelDSE[] =
+ "location_settings_backoff_level_dse";
+
+// The current level of backoff for showing the location settings dialog for
+// sites other than the default search engine.
+const char kLocationSettingsBackoffLevelDefault[] =
+ "location_settings_backoff_level_default";
+
+// The next time the location settings dialog can be shown for the default
+// search engine.
+const char kLocationSettingsNextShowDSE[] = "location_settings_next_show_dse";
+
+// The next time the location settings dialog can be shown for sites other than
+// the default search engine.
+const char kLocationSettingsNextShowDefault[] =
+ "location_settings_next_show_default";
+
+// Whether the search geolocation disclosure has been dismissed by the user.
+const char kSearchGeolocationDisclosureDismissed[] =
+ "search_geolocation_disclosure.dismissed";
+
+// How many times the search geolocation disclosure has been shown.
+const char kSearchGeolocationDisclosureShownCount[] =
+ "search_geolocation_disclosure.shown_count";
+
+// When the disclosure was shown last.
+const char kSearchGeolocationDisclosureLastShowDate[] =
+ "search_geolocation_disclosure.last_show_date";
+
+// Whether the metrics for the state of geolocation pre-disclosure being shown
+// have been recorded.
+const char kSearchGeolocationPreDisclosureMetricsRecorded[] =
+ "search_geolocation_pre_disclosure_metrics_recorded";
+
+// Whether the metrics for the state of geolocation post-disclosure being shown
+// have been recorded.
+const char kSearchGeolocationPostDisclosureMetricsRecorded[] =
+ "search_geolocation_post_disclosure_metrics_recorded";
+#endif
+
+// A dictionary which stores whether location access is enabled for the current
+// default search engine. Deprecated for kDSEPermissionsSetting.
+const char kDSEGeolocationSettingDeprecated[] = "dse_geolocation_setting";
+
+// A dictionary which stores the geolocation and notifications content settings
+// for the default search engine before it became the default search engine so
+// that they can be restored if the DSE is ever changed.
+const char kDSEPermissionsSettings[] = "dse_permissions_settings";
+
+// A boolean indicating whether the DSE was previously disabled by enterprise
+// policy.
+const char kDSEWasDisabledByPolicy[] = "dse_was_disabled_by_policy";
+
+// A dictionary of manifest URLs of Web Share Targets to a dictionary containing
+// attributes of its share_target field found in its manifest. Each key in the
+// dictionary is the name of the attribute, and the value is the corresponding
+// value.
+const char kWebShareVisitedTargets[] = "profile.web_share.visited_targets";
+
+#if defined(OS_WIN)
+// Acts as a cache to remember incompatible applications through restarts. Used
+// for the Incompatible Applications Warning feature.
+const char kIncompatibleApplications[] = "incompatible_applications";
+
+// Contains the MD5 digest of the current module blacklist cache. Used to detect
+// external tampering.
+const char kModuleBlacklistCacheMD5Digest[] =
+ "module_blacklist_cache_md5_digest";
+
+// A boolean value, controlling whether third party software is allowed to
+// inject into Chrome's processes.
+const char kThirdPartyBlockingEnabled[] = "third_party_blocking_enabled";
+#endif // defined(OS_WIN)
+
+#if defined(OS_WIN)
+// A boolean value, controlling whether Chrome renderer processes have the CIG
+// mitigation enabled.
+const char kRendererCodeIntegrityEnabled[] = "renderer_code_integrity_enabled";
+#endif // defined(OS_WIN)
+
+// An integer that keeps track of prompt waves for the settings reset
+// prompt. Users will be prompted to reset settings at most once per prompt wave
+// for each setting that the prompt targets (default search, startup URLs and
+// homepage). The value is obtained via a feature parameter. When the stored
+// value is different from the feature parameter, a new prompt wave begins.
+const char kSettingsResetPromptPromptWave[] =
+ "settings_reset_prompt.prompt_wave";
+
+// Timestamp of the last time the settings reset prompt was shown during the
+// current prompt wave asking the user if they want to restore their search
+// engine.
+const char kSettingsResetPromptLastTriggeredForDefaultSearch[] =
+ "settings_reset_prompt.last_triggered_for_default_search";
+
+// Timestamp of the last time the settings reset prompt was shown during the
+// current prompt wave asking the user if they want to restore their startup
+// settings.
+const char kSettingsResetPromptLastTriggeredForStartupUrls[] =
+ "settings_reset_prompt.last_triggered_for_startup_urls";
+
+// Timestamp of the last time the settings reset prompt was shown during the
+// current prompt wave asking the user if they want to restore their homepage.
+const char kSettingsResetPromptLastTriggeredForHomepage[] =
+ "settings_reset_prompt.last_triggered_for_homepage";
+
+#if defined(OS_ANDROID)
+// Timestamp of the clipboard's last modified time, stored in base::Time's
+// internal format (int64) in local store. (I.e., this is not a per-profile
+// pref.)
+const char kClipboardLastModifiedTime[] = "ui.clipboard.last_modified_time";
+#endif
+
+#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+
+// The following set of Prefs is used by OfflineMetricsCollectorImpl to
+// backup the current Chrome usage tracking state and accumulated counters
+// of days with specific Chrome usage.
+
+// The boolean flags indicating whether the specific activity was observed
+// in Chrome during the day that started at |kOfflineUsageTrackingDay|. These
+// are used to track usage of Chrome is used while offline and how various
+// offline features affect that.
+const char kOfflineUsageStartObserved[] = "offline_pages.start_observed";
+const char kOfflineUsageOnlineObserved[] = "offline_pages.online_observed";
+const char kOfflineUsageOfflineObserved[] = "offline_pages.offline_observed";
+// Boolean flags indicating state of a prefetch subsystem during a day.
+const char kPrefetchUsageEnabledObserved[] =
+ "offline_pages.prefetch_enabled_observed";
+const char kPrefetchUsageFetchObserved[] =
+ "offline_pages.prefetch_fetch_observed";
+const char kPrefetchUsageOpenObserved[] =
+ "offline_pages.prefetch_open_observed";
+// A time corresponding to a midnight that starts the day for which
+// OfflineMetricsCollector tracks the Chrome usage. Once current time passes
+// 24hrs from this point, the further tracking is attributed to the next day.
+const char kOfflineUsageTrackingDay[] = "offline_pages.tracking_day";
+// Accumulated counters of days with specified Chrome usage. When there is
+// likely a network connection, these counters are reported via UMA and reset.
+const char kOfflineUsageUnusedCount[] = "offline_pages.unused_count";
+const char kOfflineUsageStartedCount[] = "offline_pages.started_count";
+const char kOfflineUsageOfflineCount[] = "offline_pages.offline_count";
+const char kOfflineUsageOnlineCount[] = "offline_pages.online_count";
+const char kOfflineUsageMixedCount[] = "offline_pages.mixed_count";
+// Accumulated counters of days with specified Prefetch usage. When there is
+// likely a network connection, these counters are reported via UMA and reset.
+const char kPrefetchUsageEnabledCount[] =
+ "offline_pages.prefetch_enabled_count";
+const char kPrefetchUsageFetchedCount[] =
+ "offline_pages.prefetch_fetched_count";
+const char kPrefetchUsageOpenedCount[] = "offline_pages.prefetch_opened_count";
+const char kPrefetchUsageMixedCount[] = "offline_pages.prefetch_mixed_count";
+
+#endif
+
+// Stores the Media Engagement Index schema version. If the stored value
+// is lower than the value in MediaEngagementService then the MEI data
+// will be wiped.
+const char kMediaEngagementSchemaVersion[] = "media.engagement.schema_version";
+
+// Maximum number of tabs that has been opened since the last time it has been
+// reported.
+const char kTabStatsTotalTabCountMax[] = "tab_stats.total_tab_count_max";
+
+// Maximum number of tabs that has been opened in a single window since the last
+// time it has been reported.
+const char kTabStatsMaxTabsPerWindow[] = "tab_stats.max_tabs_per_window";
+
+// Maximum number of windows that has been opened since the last time it has
+// been reported.
+const char kTabStatsWindowCountMax[] = "tab_stats.window_count_max";
+
+// Timestamp of the last time the tab stats daily metrics have been reported.
+const char kTabStatsDailySample[] = "tab_stats.last_daily_sample";
+
+// A list of origins (URLs) to treat as "secure origins" for debugging purposes.
+const char kUnsafelyTreatInsecureOriginAsSecure[] =
+ "unsafely_treat_insecure_origin_as_secure";
+
+// A list of origins (URLs) that specifies opting into --isolate-origins=...
+// (selective Site Isolation).
+const char kIsolateOrigins[] = "site_isolation.isolate_origins";
+
+// Boolean that specifies opting into --site-per-process (full Site Isolation).
+const char kSitePerProcess[] = "site_isolation.site_per_process";
+
+// A list of origins that were heuristically determined to need process
+// isolation. For example, an origin may be placed on this list in response to
+// the user typing a password on it.
+const char kUserTriggeredIsolatedOrigins[] =
+ "site_isolation.user_triggered_isolated_origins";
+
+// Boolean that specifies if the web driver flag is allowed to override policies
+// which prevent it from operating normally. (e.g. SitePerProcess.)
+const char kWebDriverOverridesIncompatiblePolicies[] =
+ "webdriver.override_incompatible_policy";
+
+#if !defined(OS_ANDROID)
+// Boolean that specifies whether media (audio/video) autoplay is allowed.
+const char kAutoplayAllowed[] = "media.autoplay_allowed";
+
+// Holds URL patterns that specify URLs that will be allowed to autoplay.
+const char kAutoplayWhitelist[] = "media.autoplay_whitelist";
+
+// Boolean that specifies whether autoplay blocking is enabled.
+const char kBlockAutoplayEnabled[] = "media.block_autoplay";
+#endif // !defined(OS_ANDROID)
+
+// Integer that holds the value of the next persistent notification ID to be
+// used.
+const char kNotificationNextPersistentId[] = "persistent_notifications.next_id";
+
+// Time that holds the value of the next notification trigger timestamp.
+const char kNotificationNextTriggerTime[] =
+ "persistent_notifications.next_trigger";
+
+// Preference for controlling whether tab freezing is enabled.
+const char kTabFreezingEnabled[] = "tab_freezing_enabled";
+
+// Boolean that enables the Enterprise Hardware Platform Extension API for
+// extensions installed by enterprise policy.
+const char kEnterpriseHardwarePlatformAPIEnabled[] =
+ "enterprise_hardware_platform_api.enabled";
+
+// Boolean that specifies whether Signed HTTP Exchange (SXG) loading is enabled.
+const char kSignedHTTPExchangeEnabled[] = "web_package.signed_exchange.enabled";
+
+// Boolean that allows a page to show popups during its unloading.
+// TODO(https://crbug.com/937569): Remove this in Chrome 82.
+const char kAllowPopupsDuringPageUnload[] = "allow_popups_during_page_unload";
+
+// Boolean that allows a page to perform synchronous XHR requests during page
+// dismissal.
+// TODO(https://crbug.com/1003101): Remove this in Chrome 82.
+const char kAllowSyncXHRInPageDismissal[] = "allow_sync_xhr_in_page_dismissal";
+
+#if defined(OS_CHROMEOS)
+// Enum that specifies client certificate management permissions for user. It
+// can have one of the following values.
+// 0: Users can manage all certificates.
+// 1: Users can manage user certificates, but not device certificates.
+// 2: Disallow users from managing certificates
+// Controlled by ClientCertificateManagementAllowed policy.
+const char kClientCertificateManagementAllowed[] =
+ "client_certificate_management_allowed";
+
+// Enum that specifies CA certificate management permissions for user. It
+// can have one of the following values.
+// 0: Users can manage all certificates.
+// 1: Users can manage user certificates, but not built-in certificates.
+// 2: Disallow users from managing certificates
+// Controlled by CACertificateManagementAllowed policy.
+const char kCACertificateManagementAllowed[] =
+ "ca_certificate_management_allowed";
+#endif
+
+#if BUILDFLAG(BUILTIN_CERT_VERIFIER_POLICY_SUPPORTED)
+// Boolean that specifies whether the built-in certificate verifier should be
+// used. If false, Chrome will use the platform certificate verifier. If not
+// set, Chrome will choose the certificate verifier based on experiments.
+const char kBuiltinCertificateVerifierEnabled[] =
+ "builtin_certificate_verifier_enabled";
+#endif
+
+const char kSharingVapidKey[] = "sharing.vapid_key";
+const char kSharingSyncedDevices[] = "sharing.synced_devices";
+const char kSharingFCMRegistration[] = "sharing.fcm_registration";
+const char kSharingLocalSharingInfo[] = "sharing.local_sharing_info";
+
+#if !defined(OS_ANDROID)
+// Dictionary that contains all of the Hats Survey Metadata.
+const char kHatsSurveyMetadata[] = "hats.survey_metadata";
+#endif // !defined(OS_ANDROID)
+
+// TODO(crbug.com/1000977, crbug.com/1000984): Remove this during M81:83.
+const char kCorsMitigationList[] = "cors.mitigation.list";
+// TODO(crbug.com/1001450): Remove this once we fully shipped OOR-CORS.
+const char kCorsLegacyModeEnabled[] = "cors.legacy_mode.enabled";
+
+const char kExternalProtocolDialogShowAlwaysOpenCheckbox[] =
+ "external_protocol_dialog.show_always_open_checkbox";
+
} // namespace prefs
diff --git a/chromium/chrome/common/pref_names.h b/chromium/chrome/common/pref_names.h
index 0c4d73c93ab..7ea87bfb8c2 100644
--- a/chromium/chrome/common/pref_names.h
+++ b/chromium/chrome/common/pref_names.h
@@ -7,12 +7,1007 @@
#ifndef CHROME_COMMON_PREF_NAMES_H_
#define CHROME_COMMON_PREF_NAMES_H_
+#include <stddef.h>
+
+#include "build/branding_buildflags.h"
+#include "build/build_config.h"
+#include "chrome/common/buildflags.h"
+#include "components/offline_pages/buildflags/buildflags.h"
+#include "extensions/buildflags/buildflags.h"
+#include "media/media_buildflags.h"
+#include "ppapi/buildflags/buildflags.h"
+#include "rlz/buildflags/buildflags.h"
+
namespace prefs {
-extern const char kAcceptLanguages[];
-extern const char kNotificationNextPersistentId[];
+
+// Profile prefs. Please add Local State prefs below instead.
+extern const char kAbusiveExperienceInterventionEnforce[];
+extern const char kChildAccountStatusKnown[];
+extern const char kDefaultApps[];
+extern const char kSafeBrowsingForTrustedSourcesEnabled[];
+extern const char kDisableScreenshots[];
+extern const char kDownloadRestrictions[];
+extern const char kForceEphemeralProfiles[];
+extern const char kHomePageIsNewTabPage[];
+extern const char kHomePage[];
+extern const char kImportantSitesDialogHistory[];
+#if defined(OS_WIN)
+extern const char kLastProfileResetTimestamp[];
+extern const char kChromeCleanerResetPending[];
+#endif
+extern const char kNewTabPageLocationOverride[];
+extern const char kProfileIconVersion[];
+extern const char kRestoreOnStartup[];
+extern const char kSessionExitedCleanly[];
+extern const char kSessionExitType[];
+extern const char kObservedSessionTime[];
+extern const char kRecurrentSSLInterstitial[];
+extern const char kSiteEngagementLastUpdateTime[];
+extern const char kSupervisedUserApprovedExtensions[];
+extern const char kSupervisedUserCustodianEmail[];
+extern const char kSupervisedUserCustodianName[];
+extern const char kSupervisedUserCustodianObfuscatedGaiaId[];
+extern const char kSupervisedUserCustodianProfileImageURL[];
+extern const char kSupervisedUserCustodianProfileURL[];
+extern const char kSupervisedUserManualHosts[];
+extern const char kSupervisedUserManualURLs[];
+extern const char kSupervisedUserSafeSites[];
+extern const char kSupervisedUserSecondCustodianEmail[];
+extern const char kSupervisedUserSecondCustodianName[];
+extern const char kSupervisedUserSecondCustodianObfuscatedGaiaId[];
+extern const char kSupervisedUserSecondCustodianProfileImageURL[];
+extern const char kSupervisedUserSecondCustodianProfileURL[];
+extern const char kSupervisedUserSharedSettings[];
+extern const char kSupervisedUserWhitelists[];
+extern const char kURLsToRestoreOnStartup[];
+extern const char kUserFeedbackAllowed[];
+
+#if BUILDFLAG(ENABLE_RLZ)
+extern const char kRlzPingDelaySeconds[];
+#endif // BUILDFLAG(ENABLE_RLZ)
+
+// For OS_CHROMEOS we maintain the kApplicationLocale property in both local
+// state and the user's profile. The global property determines the locale of
+// the login screen, while the user's profile determines their personal locale
+// preference.
+#if defined(OS_CHROMEOS)
+extern const char kApplicationLocaleBackup[];
+extern const char kApplicationLocaleAccepted[];
+extern const char kOwnerLocale[];
+extern const char kAllowedLanguages[];
+#endif
+
+extern const char kDefaultCharset[];
+extern const char kWebKitCommonScript[];
+extern const char kWebKitStandardFontFamily[];
+extern const char kWebKitFixedFontFamily[];
+extern const char kWebKitSerifFontFamily[];
+extern const char kWebKitSansSerifFontFamily[];
+extern const char kWebKitCursiveFontFamily[];
+extern const char kWebKitFantasyFontFamily[];
+extern const char kWebKitPictographFontFamily[];
+
+// ISO 15924 four-letter script codes that per-script font prefs are supported
+// for.
+extern const char* const kWebKitScriptsForFontFamilyMaps[];
+extern const size_t kWebKitScriptsForFontFamilyMapsLength;
+
+// Per-script font pref prefixes.
+extern const char kWebKitStandardFontFamilyMap[];
+extern const char kWebKitFixedFontFamilyMap[];
+extern const char kWebKitSerifFontFamilyMap[];
+extern const char kWebKitSansSerifFontFamilyMap[];
+extern const char kWebKitCursiveFontFamilyMap[];
+extern const char kWebKitFantasyFontFamilyMap[];
+extern const char kWebKitPictographFontFamilyMap[];
+
+// Per-script font prefs that have defaults, for easy reference when registering
+// the defaults.
+extern const char kWebKitStandardFontFamilyArabic[];
+#if defined(OS_WIN)
+extern const char kWebKitFixedFontFamilyArabic[];
+#endif
+extern const char kWebKitSerifFontFamilyArabic[];
+extern const char kWebKitSansSerifFontFamilyArabic[];
+#if defined(OS_WIN)
+extern const char kWebKitStandardFontFamilyCyrillic[];
+extern const char kWebKitFixedFontFamilyCyrillic[];
+extern const char kWebKitSerifFontFamilyCyrillic[];
+extern const char kWebKitSansSerifFontFamilyCyrillic[];
+extern const char kWebKitStandardFontFamilyGreek[];
+extern const char kWebKitFixedFontFamilyGreek[];
+extern const char kWebKitSerifFontFamilyGreek[];
+extern const char kWebKitSansSerifFontFamilyGreek[];
+#endif
+extern const char kWebKitStandardFontFamilyJapanese[];
+extern const char kWebKitFixedFontFamilyJapanese[];
+extern const char kWebKitSerifFontFamilyJapanese[];
+extern const char kWebKitSansSerifFontFamilyJapanese[];
+extern const char kWebKitStandardFontFamilyKorean[];
+extern const char kWebKitFixedFontFamilyKorean[];
+extern const char kWebKitSerifFontFamilyKorean[];
+extern const char kWebKitSansSerifFontFamilyKorean[];
+#if defined(OS_WIN)
+extern const char kWebKitCursiveFontFamilyKorean[];
+#endif
+extern const char kWebKitStandardFontFamilySimplifiedHan[];
+extern const char kWebKitFixedFontFamilySimplifiedHan[];
+extern const char kWebKitSerifFontFamilySimplifiedHan[];
+extern const char kWebKitSansSerifFontFamilySimplifiedHan[];
+extern const char kWebKitStandardFontFamilyTraditionalHan[];
+extern const char kWebKitFixedFontFamilyTraditionalHan[];
+extern const char kWebKitSerifFontFamilyTraditionalHan[];
+extern const char kWebKitSansSerifFontFamilyTraditionalHan[];
+#if defined(OS_WIN) || defined(OS_MACOSX)
+extern const char kWebKitCursiveFontFamilySimplifiedHan[];
+extern const char kWebKitCursiveFontFamilyTraditionalHan[];
+#endif
+
+extern const char kWebKitDefaultFontSize[];
+extern const char kWebKitDefaultFixedFontSize[];
+extern const char kWebKitMinimumFontSize[];
+extern const char kWebKitMinimumLogicalFontSize[];
+extern const char kWebKitJavascriptEnabled[];
+extern const char kWebKitWebSecurityEnabled[];
+extern const char kWebKitLoadsImagesAutomatically[];
+extern const char kWebKitPluginsEnabled[];
+extern const char kWebKitDomPasteEnabled[];
+extern const char kWebKitTextAreasAreResizable[];
+extern const char kWebKitJavascriptCanAccessClipboard[];
+extern const char kWebkitTabsToLinks[];
+extern const char kWebKitAllowRunningInsecureContent[];
+extern const char kWebKitForceDarkModeEnabled[];
+#if defined(OS_ANDROID)
+extern const char kWebKitFontScaleFactor[];
+extern const char kWebKitForceEnableZoom[];
+extern const char kWebKitPasswordEchoEnabled[];
+#endif
+extern const char kSSLErrorOverrideAllowed[];
+extern const char kIncognitoModeAvailability[];
+extern const char kSearchSuggestEnabled[];
+#if defined(OS_ANDROID)
+extern const char kContextualSearchEnabled[];
+extern const char kContextualSearchDisabledValue[];
+extern const char kContextualSearchEnabledValue[];
+#endif // defined(OS_ANDROID)
extern const char kShowInternalAccessibilityTree[];
extern const char kAccessibilityImageLabelsEnabled[];
extern const char kAccessibilityImageLabelsOptInAccepted[];
+extern const char kAccessibilityCaptionsTextSize[];
+extern const char kAccessibilityCaptionsTextFont[];
+extern const char kAccessibilityCaptionsTextColor[];
+extern const char kAccessibilityCaptionsTextOpacity[];
+extern const char kAccessibilityCaptionsBackgroundColor[];
+extern const char kAccessibilityCaptionsTextShadow[];
+extern const char kAccessibilityCaptionsBackgroundOpacity[];
+#if defined(OS_MACOSX)
+extern const char kConfirmToQuitEnabled[];
+extern const char kShowFullscreenToolbar[];
+extern const char kAllowJavascriptAppleEvents[];
+#endif
+extern const char kPromptForDownload[];
+extern const char kAlternateErrorPagesEnabled[];
+extern const char kQuicAllowed[];
+extern const char kNetworkQualities[];
+extern const char kNetworkEasterEggHighScore[];
+#if defined(OS_ANDROID)
+extern const char kLastPolicyCheckTime[];
+#endif
+extern const char kNetworkPredictionOptions[];
+extern const char kDefaultAppsInstallState[];
+extern const char kHideWebStoreIcon[];
+#if defined(OS_CHROMEOS)
+extern const char kAccountManagerNumTimesMigrationRanSuccessfully[];
+extern const char kAccountManagerNumTimesWelcomeScreenShown[];
+extern const char kTapToClickEnabled[];
+extern const char kEnableTouchpadThreeFingerClick[];
+extern const char kNaturalScroll[];
+extern const char kPrimaryMouseButtonRight[];
+extern const char kMouseReverseScroll[];
+extern const char kMouseAcceleration[];
+extern const char kTouchpadAcceleration[];
+extern const char kMouseSensitivity[];
+extern const char kTouchpadSensitivity[];
+extern const char kUse24HourClock[];
+extern const char kUserTimezone[];
+extern const char kResolveTimezoneByGeolocation[];
+extern const char kResolveTimezoneByGeolocationMethod[];
+extern const char kResolveTimezoneByGeolocationMigratedToMethod[];
+// TODO(yusukes): Change "kLanguageABC" to "kABC". The current form is too long
+// to remember and confusing. The prefs are actually for input methods and i18n
+// keyboards, not UI languages.
+extern const char kLanguageCurrentInputMethod[];
+extern const char kLanguagePreviousInputMethod[];
+extern const char kLanguageAllowedInputMethods[];
+extern const char kLanguagePreloadEngines[];
+extern const char kLanguagePreloadEnginesSyncable[];
+extern const char kLanguageEnabledImes[];
+extern const char kLanguageEnabledImesSyncable[];
+extern const char kLanguageImeMenuActivated[];
+extern const char kLanguageInputMethodSpecificSettings[];
+extern const char kLanguageShouldMergeInputMethods[];
+extern const char kLanguageSendFunctionKeys[];
+extern const char kLanguageXkbAutoRepeatEnabled[];
+extern const char kLanguageXkbAutoRepeatDelay[];
+extern const char kLanguageXkbAutoRepeatInterval[];
+
+extern const char kLabsAdvancedFilesystemEnabled[];
+extern const char kLabsMediaplayerEnabled[];
+extern const char kShowMobileDataNotification[];
+extern const char kDataSaverPromptsShown[];
+extern const char kChromeOSReleaseNotesVersion[];
+extern const char kNoteTakingAppId[];
+extern const char kNoteTakingAppEnabledOnLockScreen[];
+extern const char kNoteTakingAppsLockScreenWhitelist[];
+extern const char kNoteTakingAppsLockScreenToastShown[];
+extern const char kRestoreLastLockScreenNote[];
+extern const char kSessionUserActivitySeen[];
+extern const char kSessionStartTime[];
+extern const char kSessionLengthLimit[];
+extern const char kSessionWaitForInitialUserActivity[];
+extern const char kLastSessionType[];
+extern const char kLastSessionLength[];
+extern const char kTermsOfServiceURL[];
+extern const char kAttestationEnabled[];
+extern const char kAttestationExtensionWhitelist[];
+extern const char kMultiProfileNeverShowIntro[];
+extern const char kMultiProfileWarningShowDismissed[];
+extern const char kMultiProfileUserBehavior[];
+extern const char kFirstRunTutorialShown[];
+extern const char kSAMLOfflineSigninTimeLimit[];
+extern const char kSAMLLastGAIASignInTime[];
+extern const char kTimeOnOobe[];
+extern const char kFileSystemProviderMounted[];
+extern const char kTouchVirtualKeyboardEnabled[];
+extern const char kWakeOnWifiDarkConnect[];
+extern const char kCaptivePortalAuthenticationIgnoresProxy[];
+extern const char kForceMaximizeOnFirstRun[];
+extern const char kPlatformKeys[];
+extern const char kUnifiedDesktopEnabledByDefault[];
+extern const char kHatsLastInteractionTimestamp[];
+extern const char kHatsSurveyCycleEndTimestamp[];
+extern const char kHatsDeviceIsSelected[];
+extern const char kQuickUnlockPinSecret[];
+extern const char kQuickUnlockFingerprintRecord[];
+extern const char kEolStatus[];
+extern const char kEndOfLifeDate[];
+extern const char kEolNotificationDismissed[];
+extern const char kFirstEolWarningDismissed[];
+extern const char kSecondEolWarningDismissed[];
+extern const char kPinUnlockFeatureNotificationShown[];
+extern const char kFingerprintUnlockFeatureNotificationShown[];
+extern const char kQuickUnlockModeWhitelist[];
+extern const char kQuickUnlockTimeout[];
+extern const char kPinUnlockMinimumLength[];
+extern const char kPinUnlockMaximumLength[];
+extern const char kPinUnlockWeakPinsAllowed[];
+extern const char kInstantTetheringBleAdvertisingSupported[];
+extern const char kCastReceiverEnabled[];
+extern const char kMinimumAllowedChromeVersion[];
+extern const char kShowArcSettingsOnSessionStart[];
+extern const char kShowSyncSettingsOnSessionStart[];
+extern const char kTextToSpeechLangToVoiceName[];
+extern const char kTextToSpeechRate[];
+extern const char kTextToSpeechPitch[];
+extern const char kTextToSpeechVolume[];
+extern const char kTimeLimitLocalOverride[];
+extern const char kUsageTimeLimit[];
+extern const char kScreenTimeLastState[];
+extern const char kEnableSyncConsent[];
+extern const char kNetworkFileSharesAllowed[];
+extern const char kManagedSessionEnabled[];
+extern const char kTPMFirmwareUpdateCleanupDismissed[];
+extern const char kTPMUpdatePlannedNotificationShownTime[];
+extern const char kTPMUpdateOnNextRebootNotificationShown[];
+extern const char kNetBiosShareDiscoveryEnabled[];
+extern const char kChildScreenTimeMilliseconds[];
+extern const char kLastChildScreenTimeSaved[];
+extern const char kLastChildScreenTimeReset[];
+extern const char kReleaseNotesLastShownMilestone[];
+extern const char kReleaseNotesSuggestionChipTimesLeftToShow[];
+extern const char kNTLMShareAuthenticationEnabled[];
+extern const char kNetworkFileSharesPreconfiguredShares[];
+extern const char kMostRecentlyUsedNetworkFileShareURL[];
+extern const char kParentAccessCodeConfig[];
+extern const char kDeviceWallpaperImageFilePath[];
+extern const char kKerberosRememberPasswordEnabled[];
+extern const char kKerberosAddAccountsAllowed[];
+extern const char kKerberosAccounts[];
+extern const char kKerberosActivePrincipalName[];
+extern const char kAppReinstallRecommendationEnabled[];
+extern const char kStartupBrowserWindowLaunchSuppressed[];
+extern const char kLoginExtensionApiDataForNextLoginAttempt[];
+extern const char kSettingsShowBrowserBanner[];
+extern const char kSettingsShowOSBanner[];
+extern const char kDeviceLoginScreenWebUsbAllowDevicesForUrls[];
+#endif // defined(OS_CHROMEOS)
+extern const char kShowHomeButton[];
+extern const char kSpeechRecognitionFilterProfanities[];
+extern const char kAllowDeletingBrowserHistory[];
+#if !defined(OS_ANDROID)
+extern const char kHistoryMenuPromoShown[];
+#endif
+extern const char kForceGoogleSafeSearch[];
+extern const char kForceYouTubeRestrict[];
+extern const char kAllowedDomainsForApps[];
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+extern const char kUsesSystemTheme[];
+#endif
+extern const char kCurrentThemePackFilename[];
+extern const char kCurrentThemeID[];
+extern const char kAutogeneratedThemeColor[];
+extern const char kExtensionsUIDeveloperMode[];
+extern const char kExtensionsUIDismissedADTPromo[];
+extern const char kExtensionCommands[];
+extern const char kPluginsLastInternalDirectory[];
+extern const char kPluginsPluginsList[];
+extern const char kPluginsDisabledPlugins[];
+extern const char kPluginsDisabledPluginsExceptions[];
+extern const char kPluginsEnabledPlugins[];
+extern const char kPluginsAlwaysOpenPdfExternally[];
+#if BUILDFLAG(ENABLE_PLUGINS)
+extern const char kPluginsShowDetails[];
+#endif
+extern const char kPluginsAllowOutdated[];
+extern const char kRunAllFlashInAllowMode[];
+#if BUILDFLAG(ENABLE_PLUGINS)
+extern const char kPluginsMetadata[];
+extern const char kPluginsResourceCacheUpdate[];
+#endif
+extern const char kPluginsDeprecationInfobarLastShown[];
+extern const char kDefaultBrowserLastDeclined[];
+extern const char kResetCheckDefaultBrowser[];
+extern const char kDefaultBrowserSettingEnabled[];
+#if defined(OS_MACOSX)
+extern const char kShowUpdatePromotionInfoBar[];
+#endif
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+extern const char kUseCustomChromeFrame[];
+#endif
+#if BUILDFLAG(ENABLE_PLUGINS)
+extern const char kContentSettingsPluginWhitelist[];
+#endif
+#if !defined(OS_ANDROID)
+extern const char kPartitionDefaultZoomLevel[];
+extern const char kPartitionPerHostZoomLevels[];
+
+extern const char kPinnedTabs[];
+#endif // !defined(OS_ANDROID)
+
+extern const char kDisable3DAPIs[];
+extern const char kEnableDeprecatedWebPlatformFeatures[];
+extern const char kEnableHyperlinkAuditing[];
+extern const char kEnableReferrers[];
+extern const char kEnableDoNotTrack[];
+extern const char kEnableEncryptedMedia[];
+
+extern const char kImportAutofillFormData[];
+extern const char kImportBookmarks[];
+extern const char kImportHistory[];
+extern const char kImportHomepage[];
+extern const char kImportSavedPasswords[];
+extern const char kImportSearchEngine[];
+
+extern const char kImportDialogAutofillFormData[];
+extern const char kImportDialogBookmarks[];
+extern const char kImportDialogHistory[];
+extern const char kImportDialogSavedPasswords[];
+extern const char kImportDialogSearchEngine[];
+
+extern const char kProfileAvatarIndex[];
+extern const char kProfileUsingDefaultName[];
+extern const char kProfileName[];
+extern const char kProfileUsingDefaultAvatar[];
+extern const char kProfileUsingGAIAAvatar[];
+extern const char kSupervisedUserId[];
+
+extern const char kProfileGAIAInfoUpdateTime[];
+extern const char kProfileGAIAInfoPictureURL[];
+
+extern const char kProfileAvatarTutorialShown[];
+
+extern const char kInvertNotificationShown[];
+
+extern const char kPrintingEnabled[];
+extern const char kPrintPreviewDisabled[];
+extern const char kPrintPreviewDefaultDestinationSelectionRules[];
+extern const char kPrintHeaderFooter[];
+
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+extern const char kPrintPreviewUseSystemDefaultPrinter[];
+#endif
+
+#if defined(OS_CHROMEOS)
+extern const char kExternalPrintServersWhitelist[];
+extern const char kRecommendedNativePrinters[];
+extern const char kRecommendedNativePrintersAccessMode[];
+extern const char kRecommendedNativePrintersBlacklist[];
+extern const char kRecommendedNativePrintersWhitelist[];
+extern const char kUserNativePrintersAllowed[];
+
+extern const char kPrintingAllowedColorModes[];
+extern const char kPrintingAllowedDuplexModes[];
+extern const char kPrintingAllowedPinModes[];
+extern const char kPrintingAllowedBackgroundGraphicsModes[];
+extern const char kPrintingAllowedPageSizes[];
+extern const char kPrintingColorDefault[];
+extern const char kPrintingDuplexDefault[];
+extern const char kPrintingPinDefault[];
+extern const char kPrintingBackgroundGraphicsDefault[];
+extern const char kPrintingSizeDefault[];
+extern const char kPrintingSendUsernameAndFilenameEnabled[];
+extern const char kPrintJobHistoryExpirationPeriod[];
+#endif // OS_CHROMEOS
+
+extern const char kDefaultSupervisedUserFilteringBehavior[];
+
+extern const char kSupervisedUsers[];
+
+extern const char kMessageCenterDisabledExtensionIds[];
+
+extern const char kFullscreenAllowed[];
+
+extern const char kLocalDiscoveryNotificationsEnabled[];
+
+#if defined(OS_ANDROID)
+extern const char kNotificationsVibrateEnabled[];
+extern const char kMigratedToSiteNotificationChannels[];
+extern const char kClearedBlockedSiteNotificationChannels[];
+extern const char kUsageStatsEnabled[];
+#endif
+
+extern const char kPushMessagingAppIdentifierMap[];
+
+extern const char kGCMProductCategoryForSubtypes[];
+
+extern const char kEasyUnlockAllowed[];
+extern const char kEasyUnlockPairing[];
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+extern const char kToolbarIconSurfacingBubbleAcknowledged[];
+extern const char kToolbarIconSurfacingBubbleLastShowTime[];
+#endif
+
+extern const char kWebRTCMultipleRoutesEnabled[];
+extern const char kWebRTCNonProxiedUdpEnabled[];
+extern const char kWebRTCIPHandlingPolicy[];
+extern const char kWebRTCUDPPortRange[];
+extern const char kWebRtcEventLogCollectionAllowed[];
+extern const char kWebRtcLocalIpsAllowedUrls[];
+
+#if !defined(OS_ANDROID)
+extern const char kHasSeenWelcomePage[];
+#endif
+
+#if defined(OS_WIN)
+// Only used in branded builds.
+extern const char kNaviOnboardGroup[];
+#endif // defined(OS_WIN)
+
+// Deprecated preference for metric / crash reporting on Android. Use
+// kMetricsReportingEnabled instead.
+#if defined(OS_ANDROID)
+extern const char kCrashReportingEnabled[];
+#endif // defined(OS_ANDROID)
+
+extern const char kProfileLastUsed[];
+extern const char kProfilesLastActive[];
+extern const char kProfilesNumCreated[];
+extern const char kProfileInfoCache[];
+#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+extern const char kLegacyProfileNamesMigrated[];
+#endif // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+extern const char kProfileCreatedByVersion[];
+extern const char kProfilesDeleted[];
+
+extern const char kStabilityOtherUserCrashCount[];
+extern const char kStabilityKernelCrashCount[];
+extern const char kStabilitySystemUncleanShutdownCount[];
+
+extern const char kStabilityPluginStats[];
+extern const char kStabilityPluginName[];
+extern const char kStabilityPluginLaunches[];
+extern const char kStabilityPluginInstances[];
+extern const char kStabilityPluginCrashes[];
+extern const char kStabilityPluginLoadingErrors[];
+
+extern const char kBrowserSuppressDefaultBrowserPrompt[];
+
+extern const char kBrowserWindowPlacement[];
+extern const char kBrowserWindowPlacementPopup[];
+extern const char kTaskManagerWindowPlacement[];
+extern const char kTaskManagerColumnVisibility[];
+extern const char kTaskManagerEndProcessEnabled[];
+extern const char kAppWindowPlacement[];
+
+extern const char kDownloadDefaultDirectory[];
+extern const char kDownloadExtensionsToOpen[];
+extern const char kDownloadDirUpgraded[];
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX)
+extern const char kOpenPdfDownloadInSystemReader[];
+#endif
+#if defined(OS_ANDROID)
+extern const char kPromptForDownloadAndroid[];
+extern const char kShowMissingSdCardErrorAndroid[];
+#endif
+
+extern const char kSaveFileDefaultDirectory[];
+extern const char kSaveFileType[];
+
+extern const char kAllowFileSelectionDialogs[];
+extern const char kDefaultTasksByMimeType[];
+extern const char kDefaultTasksBySuffix[];
+
+extern const char kSharedClipboardEnabled[];
+
+#if BUILDFLAG(ENABLE_CLICK_TO_CALL)
+extern const char kClickToCallEnabled[];
+#endif // BUILDFLAG(ENABLE_CLICK_TO_CALL)
+
+extern const char kSelectFileLastDirectory[];
+
+extern const char kExcludedSchemes[];
+
+extern const char kLastKnownIntranetRedirectOrigin[];
+
+extern const char kShutdownType[];
+extern const char kShutdownNumProcesses[];
+extern const char kShutdownNumProcessesSlow[];
+
+extern const char kRestartLastSessionOnShutdown[];
+#if !defined(OS_ANDROID)
+#if !defined(OS_CHROMEOS)
+extern const char kPromotionalTabsEnabled[];
+extern const char kCommandLineFlagSecurityWarningsEnabled[];
+#endif
+extern const char kSuppressUnsupportedOSWarning[];
+extern const char kWasRestarted[];
+#endif // !defined(OS_ANDROID)
+
+extern const char kDisableExtensions[];
+
+extern const char kNtpAppPageNames[];
+extern const char kNtpCollapsedForeignSessions[];
+#if defined(OS_ANDROID)
+extern const char kNtpCollapsedRecentlyClosedTabs[];
+extern const char kNtpCollapsedSnapshotDocument[];
+extern const char kNtpCollapsedSyncPromo[];
+#else
+extern const char kNtpCustomBackgroundDict[];
+extern const char kNtpCustomBackgroundLocalToDevice[];
+extern const char kNtpPromoBlocklist[];
+extern const char kNtpSearchSuggestionsBlocklist[];
+extern const char kNtpSearchSuggestionsImpressions[];
+extern const char kNtpSearchSuggestionsOptOut[];
+extern const char kNtpShortcutsVisible[];
+extern const char kNtpUseMostVisitedTiles[];
+#endif // defined(OS_ANDROID)
+extern const char kNtpShownPage[];
+
+extern const char kDevToolsAdbKey[];
+extern const char kDevToolsAvailability[];
+extern const char kDevToolsBackgroundServicesExpirationDict[];
+extern const char kDevToolsDiscoverUsbDevicesEnabled[];
+extern const char kDevToolsEditedFiles[];
+extern const char kDevToolsFileSystemPaths[];
+extern const char kDevToolsPortForwardingEnabled[];
+extern const char kDevToolsPortForwardingDefaultSet[];
+extern const char kDevToolsPortForwardingConfig[];
+extern const char kDevToolsPreferences[];
+extern const char kDevToolsDiscoverTCPTargetsEnabled[];
+extern const char kDevToolsTCPDiscoveryConfig[];
+
+#if !defined(OS_ANDROID)
+extern const char kDiceSigninUserMenuPromoCount[];
+#endif
+
+extern const char kWebAppCreateOnDesktop[];
+extern const char kWebAppCreateInAppsMenu[];
+extern const char kWebAppCreateInQuickLaunchBar[];
+
+extern const char kWebAppInstallForceList[];
+extern const char kWebAppInstallMetrics[];
+
+extern const char kWebAppsExtensionIDs[];
+extern const char kSystemWebAppLastUpdateVersion[];
+
+extern const char kDefaultAudioCaptureDevice[];
+extern const char kDefaultVideoCaptureDevice[];
+extern const char kMediaDeviceIdSalt[];
+extern const char kMediaStorageIdSalt[];
+
+extern const char kPrintPreviewStickySettings[];
+extern const char kCloudPrintRoot[];
+extern const char kCloudPrintProxyEnabled[];
+extern const char kCloudPrintProxyId[];
+extern const char kCloudPrintAuthToken[];
+extern const char kCloudPrintEmail[];
+extern const char kCloudPrintPrintSystemSettings[];
+extern const char kCloudPrintEnableJobPoll[];
+extern const char kCloudPrintRobotRefreshToken[];
+extern const char kCloudPrintRobotEmail[];
+extern const char kCloudPrintConnectNewPrinters[];
+extern const char kCloudPrintXmppPingEnabled[];
+extern const char kCloudPrintXmppPingTimeout[];
+extern const char kCloudPrintPrinters[];
+extern const char kCloudPrintSubmitEnabled[];
+extern const char kCloudPrintUserSettings[];
+
+extern const char kMaxConnectionsPerProxy[];
+
+extern const char kAudioCaptureAllowed[];
+extern const char kAudioCaptureAllowedUrls[];
+extern const char kVideoCaptureAllowed[];
+extern const char kVideoCaptureAllowedUrls[];
+
+#if defined(OS_CHROMEOS)
+extern const char kDemoModeConfig[];
+extern const char kDemoModeCountry[];
+extern const char kDemoModeDefaultLocale[];
+extern const char kDeviceSettingsCache[];
+extern const char kHardwareKeyboardLayout[];
+extern const char kCarrierDealPromoShown[];
+extern const char kShouldAutoEnroll[];
+extern const char kAutoEnrollmentPowerLimit[];
+extern const char kDeviceActivityTimes[];
+extern const char kUserActivityTimes[];
+extern const char kExternalStorageDisabled[];
+extern const char kExternalStorageReadOnly[];
+extern const char kOwnerPrimaryMouseButtonRight[];
+extern const char kOwnerTapToClickEnabled[];
+extern const char kUptimeLimit[];
+extern const char kRebootAfterUpdate[];
+extern const char kDeviceRobotAnyApiRefreshToken[];
+extern const char kDeviceEnrollmentRequisition[];
+extern const char kDeviceEnrollmentSubOrganization[];
+extern const char kDeviceEnrollmentAutoStart[];
+extern const char kDeviceEnrollmentCanExit[];
+extern const char kDeviceDMToken[];
+extern const char kTimesHIDDialogShown[];
+extern const char kUsersLastInputMethod[];
+extern const char kEchoCheckedOffers[];
+extern const char kCachedMultiProfileUserBehavior[];
+extern const char kInitialLocale[];
+extern const char kOobeComplete[];
+extern const char kOobeScreenPending[];
+extern const char kOobeMarketingOptInScreenFinished[];
+extern const char kCanShowOobeGoodiesPage[];
+extern const char kDeviceRegistered[];
+extern const char kEnrollmentRecoveryRequired[];
+extern const char kUsedPolicyCertificates[];
+extern const char kServerBackedDeviceState[];
+extern const char kCustomizationDefaultWallpaperURL[];
+extern const char kLogoutStartedLast[];
+extern const char kConsumerManagementStage[];
+extern const char kReportArcStatusEnabled[];
+extern const char kSchedulerConfiguration[];
+extern const char kNetworkThrottlingEnabled[];
+extern const char kPowerMetricsDailySample[];
+extern const char kPowerMetricsIdleScreenDimCount[];
+extern const char kPowerMetricsIdleScreenOffCount[];
+extern const char kPowerMetricsIdleSuspendCount[];
+extern const char kPowerMetricsLidClosedSuspendCount[];
+extern const char kReportingUsers[];
+extern const char kArcAppInstallEventLoggingEnabled[];
+extern const char kRemoveUsersRemoteCommand[];
+extern const char kCameraMediaConsolidated[];
+extern const char kAutoScreenBrightnessMetricsDailySample[];
+extern const char kAutoScreenBrightnessMetricsAtlasUserAdjustmentCount[];
+extern const char kAutoScreenBrightnessMetricsEveUserAdjustmentCount[];
+extern const char kAutoScreenBrightnessMetricsNocturneUserAdjustmentCount[];
+extern const char kAutoScreenBrightnessMetricsNoAlsUserAdjustmentCount[];
+extern const char kAutoScreenBrightnessMetricsSupportedAlsUserAdjustmentCount[];
+extern const char
+ kAutoScreenBrightnessMetricsUnsupportedAlsUserAdjustmentCount[];
+extern const char kKnownUserParentAccessCodeConfig[];
+extern const char kSamlInSessionPasswordChangeEnabled[];
+extern const char kSamlPasswordExpirationAdvanceWarningDays[];
+extern const char kLastRsuDeviceIdUploaded[];
+#endif // defined(OS_CHROMEOS)
+
+extern const char kClearPluginLSODataEnabled[];
+extern const char kPepperFlashSettingsEnabled[];
+extern const char kDiskCacheDir[];
+extern const char kDiskCacheSize[];
+
+extern const char kChromeOsReleaseChannel[];
+
+extern const char kPerformanceTracingEnabled[];
+
+extern const char kTabStripStackedLayout[];
+
+extern const char kRegisteredBackgroundContents[];
+
+extern const char kTotalMemoryLimitMb[];
+
+extern const char kAuthSchemes[];
+extern const char kDisableAuthNegotiateCnameLookup[];
+extern const char kEnableAuthNegotiatePort[];
+extern const char kAuthServerWhitelist[];
+extern const char kAuthNegotiateDelegateWhitelist[];
+extern const char kGSSAPILibraryName[];
+extern const char kAuthAndroidNegotiateAccountType[];
+extern const char kAllowCrossOriginAuthPrompt[];
+
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
+extern const char kAuthNegotiateDelegateByKdcPolicy[];
+#endif // defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
+
+#if defined(OS_POSIX)
+extern const char kNtlmV2Enabled[];
+#endif // defined(OS_POSIX)
+
+#if defined(OS_CHROMEOS)
+extern const char kKerberosEnabled[];
+#endif
+
+extern const char kCertRevocationCheckingEnabled[];
+extern const char kCertRevocationCheckingRequiredLocalAnchors[];
+extern const char kSSLVersionMin[];
+extern const char kSSLVersionMax[];
+extern const char kCipherSuiteBlacklist[];
+extern const char kH2ClientCertCoalescingHosts[];
+extern const char kHSTSPolicyBypassList[];
+extern const char kTLS13HardeningForLocalAnchorsEnabled[];
+
+extern const char kBuiltInDnsClientEnabled[];
+extern const char kDnsOverHttpsMode[];
+extern const char kDnsOverHttpsTemplates[];
+
+extern const char kRegisteredProtocolHandlers[];
+extern const char kIgnoredProtocolHandlers[];
+extern const char kPolicyRegisteredProtocolHandlers[];
+extern const char kPolicyIgnoredProtocolHandlers[];
+extern const char kCustomHandlersEnabled[];
+
+#if defined(OS_MACOSX)
+extern const char kUserRemovedLoginItem[];
+extern const char kChromeCreatedLoginItem[];
+extern const char kMigratedLoginItemPref[];
+extern const char kNotifyWhenAppsKeepChromeAlive[];
+#endif
+
+extern const char kBackgroundModeEnabled[];
+extern const char kHardwareAccelerationModeEnabled[];
+extern const char kHardwareAccelerationModePrevious[];
+
+extern const char kDevicePolicyRefreshRate[];
+
+extern const char kFactoryResetRequested[];
+extern const char kFactoryResetTPMFirmwareUpdateMode[];
+extern const char kDebuggingFeaturesRequested[];
+
+#if defined(OS_CHROMEOS)
+extern const char kSigninScreenTimezone[];
+extern const char kResolveDeviceTimezoneByGeolocation[];
+extern const char kResolveDeviceTimezoneByGeolocationMethod[];
+extern const char kSystemTimezoneAutomaticDetectionPolicy[];
+#endif // defined(OS_CHROMEOS)
+
+extern const char kEnableMediaRouter[];
+#if !defined(OS_ANDROID)
+extern const char kShowCastIconInToolbar[];
+#endif // !defined(OS_ANDROID)
+
+#if !defined(OS_ANDROID)
+extern const char kRelaunchNotification[];
+extern const char kRelaunchNotificationPeriod[];
+#endif // !defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+extern const char kRelaunchHeadsUpPeriod[];
+#endif // defined(OS_CHROMEOS)
+
+#if !defined(OS_ANDROID)
+extern const char kAttemptedToEnableAutoupdate[];
+
+extern const char kMediaGalleriesUniqueId[];
+extern const char kMediaGalleriesRememberedGalleries[];
+#endif // !defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+extern const char kPolicyPinnedLauncherApps[];
+extern const char kShelfDefaultPinLayoutRolls[];
+#endif // defined(OS_CHROMEOS)
+
+#if defined(OS_WIN)
+extern const char kNetworkProfileWarningsLeft[];
+extern const char kNetworkProfileLastWarningTime[];
+#endif
+
+#if defined(OS_CHROMEOS)
+extern const char kRLZBrand[];
+extern const char kRLZDisabled[];
+#endif
+
+#if BUILDFLAG(ENABLE_APP_LIST)
+extern const char kAppListLocalState[];
+#endif // BUILDFLAG(ENABLE_APP_LIST)
+
+extern const char kAppShortcutsVersion[];
+
+extern const char kDRMSalt[];
+extern const char kEnableDRM[];
+
+extern const char kWatchdogExtensionActive[];
+
+#if defined(OS_ANDROID)
+extern const char kPartnerBookmarkMappings[];
+#endif // defined(OS_ANDROID)
+
+extern const char kQuickCheckEnabled[];
+extern const char kBrowserGuestModeEnabled[];
+extern const char kBrowserGuestModeEnforced[];
+extern const char kBrowserAddPersonEnabled[];
+extern const char kForceBrowserSignin[];
+extern const char kSigninAllowedOnNextStartup[];
+
+extern const char kCryptAuthDeviceId[];
+extern const char kEasyUnlockHardlockState[];
+extern const char kEasyUnlockLocalStateTpmKeys[];
+extern const char kEasyUnlockLocalStateUserPrefs[];
+
+extern const char kRecoveryComponentNeedsElevation[];
+
+extern const char kRegisteredSupervisedUserWhitelists[];
+
+#if !defined(OS_ANDROID)
+extern const char kCloudReportingEnabled[];
+extern const char kCloudExtensionRequestEnabled[];
+extern const char kCloudExtensionRequestIds[];
+#endif
+
+#if BUILDFLAG(ENABLE_BACKGROUND_MODE)
+extern const char kRestartInBackground[];
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+extern const char kAnimationPolicy[];
+extern const char kSecurityKeyPermitAttestation[];
+#endif
+
+extern const char kBackgroundTracingLastUpload[];
+
+extern const char kAllowDinosaurEasterEgg[];
+
+#if defined(OS_ANDROID)
+extern const char kClickedUpdateMenuItem[];
+extern const char kLatestVersionWhenClickedUpdateMenuItem[];
+#endif
+
+extern const char kMediaRouterCloudServicesPrefSet[];
+extern const char kMediaRouterEnableCloudServices[];
+extern const char kMediaRouterFirstRunFlowAcknowledged[];
+extern const char kMediaRouterMediaRemotingEnabled[];
+extern const char kMediaRouterTabMirroringSources[];
+
+extern const char kOriginTrialPublicKey[];
+extern const char kOriginTrialDisabledFeatures[];
+extern const char kOriginTrialDisabledTokens[];
+
+extern const char kComponentUpdatesEnabled[];
+
+#if defined(OS_ANDROID)
+extern const char kLocationSettingsBackoffLevelDSE[];
+extern const char kLocationSettingsBackoffLevelDefault[];
+extern const char kLocationSettingsNextShowDSE[];
+extern const char kLocationSettingsNextShowDefault[];
+
+extern const char kSearchGeolocationDisclosureDismissed[];
+extern const char kSearchGeolocationDisclosureShownCount[];
+extern const char kSearchGeolocationDisclosureLastShowDate[];
+extern const char kSearchGeolocationPreDisclosureMetricsRecorded[];
+extern const char kSearchGeolocationPostDisclosureMetricsRecorded[];
+#endif
+
+extern const char kDSEGeolocationSettingDeprecated[];
+
+extern const char kDSEPermissionsSettings[];
+extern const char kDSEWasDisabledByPolicy[];
+
+extern const char kWebShareVisitedTargets[];
+
+#if defined(OS_WIN)
+// Only used in branded builds.
+extern const char kIncompatibleApplications[];
+extern const char kModuleBlacklistCacheMD5Digest[];
+extern const char kThirdPartyBlockingEnabled[];
+#endif // defined(OS_WIN)
+
+// Windows mitigation policies.
+#if defined(OS_WIN)
+extern const char kRendererCodeIntegrityEnabled[];
+#endif // defined(OS_WIN)
+
+extern const char kSettingsResetPromptPromptWave[];
+extern const char kSettingsResetPromptLastTriggeredForDefaultSearch[];
+extern const char kSettingsResetPromptLastTriggeredForStartupUrls[];
+extern const char kSettingsResetPromptLastTriggeredForHomepage[];
+
+#if defined(OS_ANDROID)
+extern const char kClipboardLastModifiedTime[];
+#endif
+
+#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+extern const char kOfflineUsageStartObserved[];
+extern const char kOfflineUsageOnlineObserved[];
+extern const char kOfflineUsageOfflineObserved[];
+extern const char kPrefetchUsageEnabledObserved[];
+extern const char kPrefetchUsageFetchObserved[];
+extern const char kPrefetchUsageOpenObserved[];
+extern const char kOfflineUsageTrackingDay[];
+extern const char kOfflineUsageUnusedCount[];
+extern const char kOfflineUsageStartedCount[];
+extern const char kOfflineUsageOfflineCount[];
+extern const char kOfflineUsageOnlineCount[];
+extern const char kOfflineUsageMixedCount[];
+extern const char kPrefetchUsageEnabledCount[];
+extern const char kPrefetchUsageFetchedCount[];
+extern const char kPrefetchUsageOpenedCount[];
+extern const char kPrefetchUsageMixedCount[];
+#endif
+
+extern const char kMediaEngagementSchemaVersion[];
+
+// Preferences for recording metrics about tab and window usage.
+extern const char kTabStatsTotalTabCountMax[];
+extern const char kTabStatsMaxTabsPerWindow[];
+extern const char kTabStatsWindowCountMax[];
+extern const char kTabStatsDailySample[];
+
+extern const char kUnsafelyTreatInsecureOriginAsSecure[];
+
+extern const char kIsolateOrigins[];
+extern const char kSitePerProcess[];
+extern const char kUserTriggeredIsolatedOrigins[];
+extern const char kWebDriverOverridesIncompatiblePolicies[];
+
+#if !defined(OS_ANDROID)
+extern const char kAutoplayAllowed[];
+extern const char kAutoplayWhitelist[];
+extern const char kBlockAutoplayEnabled[];
+#endif
+
+extern const char kNotificationNextPersistentId[];
+extern const char kNotificationNextTriggerTime[];
+
+extern const char kTabFreezingEnabled[];
+
+extern const char kEnterpriseHardwarePlatformAPIEnabled[];
+
+extern const char kSignedHTTPExchangeEnabled[];
+
+extern const char kAllowPopupsDuringPageUnload[];
+
+extern const char kAllowSyncXHRInPageDismissal[];
+
+#if defined(OS_ANDROID)
+extern const char kUsageStatsEnabled[];
+#endif
+
+#if defined(OS_CHROMEOS)
+extern const char kClientCertificateManagementAllowed[];
+extern const char kCACertificateManagementAllowed[];
+#endif
+
+#if BUILDFLAG(BUILTIN_CERT_VERIFIER_POLICY_SUPPORTED)
+extern const char kBuiltinCertificateVerifierEnabled[];
+#endif
+
+extern const char kSharingVapidKey[];
+extern const char kSharingSyncedDevices[];
+extern const char kSharingFCMRegistration[];
+extern const char kSharingLocalSharingInfo[];
+
+#if !defined(OS_ANDROID)
+extern const char kHatsSurveyMetadata[];
+#endif // !defined(OS_ANDROID)
+
+extern const char kCorsMitigationList[];
+extern const char kCorsLegacyModeEnabled[];
+
+extern const char kExternalProtocolDialogShowAlwaysOpenCheckbox[];
+
} // namespace prefs
#endif // CHROME_COMMON_PREF_NAMES_H_
diff --git a/chromium/chrome/common/pref_names_util.cc b/chromium/chrome/common/pref_names_util.cc
new file mode 100644
index 00000000000..3ab666fb480
--- /dev/null
+++ b/chromium/chrome/common/pref_names_util.cc
@@ -0,0 +1,88 @@
+// 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 "chrome/common/pref_names_util.h"
+
+#include <stddef.h>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "ui/native_theme/native_theme.h"
+
+namespace {
+
+// Adds !important to all captions styles. They should always override any
+// styles added by the video author or by a user stylesheet. This is because in
+// Chrome, there is an option to turn off captions styles, so any time the
+// captions are on, the styles should take priority.
+std::string AddCSSImportant(std::string css_string) {
+ return css_string + " !important";
+}
+
+} // namespace
+
+namespace pref_names_util {
+
+const char kWebKitFontPrefPrefix[] = "webkit.webprefs.fonts.";
+
+bool ParseFontNamePrefPath(const std::string& pref_path,
+ std::string* generic_family,
+ std::string* script) {
+ if (!base::StartsWith(pref_path, kWebKitFontPrefPrefix,
+ base::CompareCase::SENSITIVE))
+ return false;
+
+ size_t start = strlen(kWebKitFontPrefPrefix);
+ size_t pos = pref_path.find('.', start);
+ if (pos == std::string::npos || pos + 1 == pref_path.length())
+ return false;
+ if (generic_family)
+ *generic_family = pref_path.substr(start, pos - start);
+ if (script)
+ *script = pref_path.substr(pos + 1);
+ return true;
+}
+
+base::Optional<ui::CaptionStyle> GetCaptionStyleFromPrefs(PrefService* prefs) {
+ if (!prefs) {
+ return base::nullopt;
+ }
+
+ ui::CaptionStyle style;
+
+ style.text_size =
+ AddCSSImportant(prefs->GetString(prefs::kAccessibilityCaptionsTextSize));
+ style.font_family =
+ AddCSSImportant(prefs->GetString(prefs::kAccessibilityCaptionsTextFont));
+ if (!prefs->GetString(prefs::kAccessibilityCaptionsTextColor).empty()) {
+ std::string text_color = base::StringPrintf(
+ "rgba(%s,%s)",
+ prefs->GetString(prefs::kAccessibilityCaptionsTextColor).c_str(),
+ base::NumberToString(
+ prefs->GetInteger(prefs::kAccessibilityCaptionsTextOpacity) / 100.0)
+ .c_str());
+ style.text_color = AddCSSImportant(text_color);
+ }
+
+ if (!prefs->GetString(prefs::kAccessibilityCaptionsBackgroundColor).empty()) {
+ std::string background_color = base::StringPrintf(
+ "rgba(%s,%s)",
+ prefs->GetString(prefs::kAccessibilityCaptionsBackgroundColor).c_str(),
+ base::NumberToString(
+ prefs->GetInteger(prefs::kAccessibilityCaptionsBackgroundOpacity) /
+ 100.0)
+ .c_str());
+ style.background_color = AddCSSImportant(background_color);
+ }
+
+ style.text_shadow = AddCSSImportant(
+ prefs->GetString(prefs::kAccessibilityCaptionsTextShadow));
+
+ return style;
+}
+
+} // namespace pref_names_util
diff --git a/chromium/chrome/common/pref_names_util.h b/chromium/chrome/common/pref_names_util.h
new file mode 100644
index 00000000000..b0c0177f4f6
--- /dev/null
+++ b/chromium/chrome/common/pref_names_util.h
@@ -0,0 +1,30 @@
+// 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 CHROME_COMMON_PREF_NAMES_UTIL_H_
+#define CHROME_COMMON_PREF_NAMES_UTIL_H_
+
+#include <string>
+
+#include "components/prefs/pref_service.h"
+#include "ui/native_theme/native_theme.h"
+
+namespace pref_names_util {
+
+// Prefs prefix for all font types. Ends in a period.
+extern const char kWebKitFontPrefPrefix[];
+
+// Extracts the generic family and script from font name pref path |pref_path|.
+// For example, if |pref_path| is "webkit.webprefs.fonts.serif.Hang", returns
+// true and sets |generic_family| to "serif" and |script| to "Hang".
+bool ParseFontNamePrefPath(const std::string& pref_path,
+ std::string* generic_family,
+ std::string* script);
+
+// Constructs the CaptionStyle struct from the caption-related preferences.
+base::Optional<ui::CaptionStyle> GetCaptionStyleFromPrefs(PrefService* prefs);
+
+} // namespace pref_names_util
+
+#endif // CHROME_COMMON_PREF_NAMES_UTIL_H_
diff --git a/chromium/chrome/common/pref_names_util_unittest.cc b/chromium/chrome/common/pref_names_util_unittest.cc
new file mode 100644
index 00000000000..9f215ea5808
--- /dev/null
+++ b/chromium/chrome/common/pref_names_util_unittest.cc
@@ -0,0 +1,52 @@
+// 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 "chrome/common/pref_names_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void ExpectNoParse(const std::string& path) {
+ EXPECT_FALSE(pref_names_util::ParseFontNamePrefPath(path, NULL, NULL));
+}
+
+void ExpectParse(const std::string& path,
+ const std::string& expected_generic_family,
+ const std::string& expected_script)
+{
+ std::string generic_family;
+ std::string script;
+
+ ASSERT_TRUE(pref_names_util::ParseFontNamePrefPath(path, &generic_family,
+ &script));
+ EXPECT_EQ(expected_generic_family, generic_family);
+ EXPECT_EQ(expected_script, script);
+}
+
+} // namespace
+
+TEST(PrefNamesUtilTest, Basic) {
+ ExpectNoParse(std::string());
+ ExpectNoParse(".");
+ ExpectNoParse(".....");
+ ExpectNoParse("webkit.webprefs.fonts.");
+ ExpectNoParse("webkit.webprefs.fonts..");
+ ExpectNoParse("webkit.webprefs.fontsfoobar.standard.Hrkt");
+ ExpectNoParse("foobar.webprefs.fonts.standard.Hrkt");
+ ExpectParse("webkit.webprefs.fonts.standard.Hrkt", "standard", "Hrkt");
+ ExpectParse("webkit.webprefs.fonts.standard.Hrkt.", "standard", "Hrkt.");
+ ExpectParse("webkit.webprefs.fonts.standard.Hrkt.Foobar", "standard",
+ "Hrkt.Foobar");
+
+ // We don't particularly care about the parsed family and script for these
+ // inputs, but just want to make sure it does something reasonable. Returning
+ // false may also be an option.
+ ExpectParse("webkit.webprefs.fonts...", std::string(), ".");
+ ExpectParse("webkit.webprefs.fonts....", std::string(), "..");
+
+ // Check that passing NULL output params is okay.
+ EXPECT_TRUE(pref_names_util::ParseFontNamePrefPath(
+ "webkit.webprefs.fonts.standard.Hrkt", NULL, NULL));
+}
diff --git a/chromium/chrome/common/prerender_messages.h b/chromium/chrome/common/prerender_messages.h
new file mode 100644
index 00000000000..ca7d57d1260
--- /dev/null
+++ b/chromium/chrome/common/prerender_messages.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 CHROME_COMMON_PRERENDER_MESSAGES_H_
+#define CHROME_COMMON_PRERENDER_MESSAGES_H_
+
+#include <stdint.h>
+
+#include "chrome/common/prerender_types.h"
+#include "content/public/common/referrer.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+#include "ui/gfx/geometry/size.h"
+#include "url/gurl.h"
+#include "url/ipc/url_param_traits.h"
+#include "url/origin.h"
+
+#define IPC_MESSAGE_START PrerenderMsgStart
+
+IPC_ENUM_TRAITS_MAX_VALUE(prerender::PrerenderMode,
+ prerender::PRERENDER_MODE_COUNT - 1)
+
+// PrerenderLinkManager Messages
+// These are messages sent from the renderer to the browser in
+// relation to <link rel=prerender> elements.
+
+IPC_STRUCT_BEGIN(PrerenderAttributes)
+ IPC_STRUCT_MEMBER(GURL, url)
+ IPC_STRUCT_MEMBER(uint32_t, rel_types)
+IPC_STRUCT_END()
+
+// Notifies of the insertion of a <link rel=prerender> element in the
+// document.
+IPC_MESSAGE_CONTROL(PrerenderHostMsg_AddLinkRelPrerender,
+ int /* prerender_id, assigned by WebPrerendererClient */,
+ PrerenderAttributes,
+ content::Referrer,
+ url::Origin /* initiator_origin */,
+ gfx::Size,
+ int /* render_view_route_id of launcher */)
+
+// Notifies on removal of a <link rel=prerender> element from the document.
+IPC_MESSAGE_CONTROL1(PrerenderHostMsg_CancelLinkRelPrerender,
+ int /* prerender_id, assigned by WebPrerendererClient */)
+
+// Notifies on unloading a <link rel=prerender> element from a frame.
+IPC_MESSAGE_CONTROL1(PrerenderHostMsg_AbandonLinkRelPrerender,
+ int /* prerender_id, assigned by WebPrerendererClient */)
+
+// Sent by the renderer process to notify that the resource prefetcher has
+// discovered all possible subresources and issued requests for them.
+IPC_MESSAGE_CONTROL0(PrerenderHostMsg_PrefetchFinished)
+
+// PrerenderDispatcher Messages
+// These are messages sent from the browser to the renderer in relation to
+// running prerenders.
+
+// Tells a renderer if it's currently being prerendered. Must only be set
+// before any navigation occurs, and only set to NO_PRERENDER at most once after
+// that.
+IPC_MESSAGE_ROUTED2(PrerenderMsg_SetIsPrerendering,
+ prerender::PrerenderMode,
+ std::string /* histogram_prefix */)
+
+#endif // CHROME_COMMON_PRERENDER_MESSAGES_H_
diff --git a/chromium/chrome/common/prerender_types.h b/chromium/chrome/common/prerender_types.h
new file mode 100644
index 00000000000..e6c98dc86e4
--- /dev/null
+++ b/chromium/chrome/common/prerender_types.h
@@ -0,0 +1,25 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_PRERENDER_TYPES_H_
+#define CHROME_COMMON_PRERENDER_TYPES_H_
+
+namespace prerender {
+
+enum PrerenderMode {
+ // Neither prefetch nor prerender.
+ NO_PRERENDER = 0,
+
+ // Only used in tests. Can be removed after http://crbug.com/898955 is fixed.
+ DEPRECATED_FULL_PRERENDER = 1,
+
+ // Prefetch some network resources to warm up the cache.
+ PREFETCH_ONLY = 2,
+
+ PRERENDER_MODE_COUNT = 3,
+};
+
+} // namespace prerender
+
+#endif // CHROME_COMMON_PRERENDER_TYPES_H_
diff --git a/chromium/chrome/common/prerender_url_loader_throttle.cc b/chromium/chrome/common/prerender_url_loader_throttle.cc
new file mode 100644
index 00000000000..70c8c8312f6
--- /dev/null
+++ b/chromium/chrome/common/prerender_url_loader_throttle.cc
@@ -0,0 +1,217 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/prerender_url_loader_throttle.h"
+
+#include "base/bind.h"
+#include "build/build_config.h"
+#include "chrome/common/prerender_util.h"
+#include "content/public/common/content_constants.h"
+#include "net/base/load_flags.h"
+#include "net/url_request/redirect_info.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/resource_response.h"
+
+namespace prerender {
+
+namespace {
+
+const char kPurposeHeaderName[] = "Purpose";
+const char kPurposeHeaderValue[] = "prefetch";
+
+void CancelPrerenderForUnsupportedMethod(
+ PrerenderURLLoaderThrottle::CancelerGetterCallback callback) {
+ chrome::mojom::PrerenderCanceler* canceler = std::move(callback).Run();
+ if (canceler)
+ canceler->CancelPrerenderForUnsupportedMethod();
+}
+
+void CancelPrerenderForUnsupportedScheme(
+ PrerenderURLLoaderThrottle::CancelerGetterCallback callback,
+ const GURL& url) {
+ chrome::mojom::PrerenderCanceler* canceler = std::move(callback).Run();
+ if (canceler)
+ canceler->CancelPrerenderForUnsupportedScheme(url);
+}
+
+void CancelPrerenderForSyncDeferredRedirect(
+ PrerenderURLLoaderThrottle::CancelerGetterCallback callback) {
+ chrome::mojom::PrerenderCanceler* canceler = std::move(callback).Run();
+ if (canceler)
+ canceler->CancelPrerenderForSyncDeferredRedirect();
+}
+
+// Returns true if the response has a "no-store" cache control header.
+bool IsNoStoreResponse(const network::ResourceResponseHead& response_head) {
+ return response_head.headers &&
+ response_head.headers->HasHeaderValue("cache-control", "no-store");
+}
+
+} // namespace
+
+PrerenderURLLoaderThrottle::PrerenderURLLoaderThrottle(
+ PrerenderMode mode,
+ const std::string& histogram_prefix,
+ CancelerGetterCallback canceler_getter,
+ scoped_refptr<base::SequencedTaskRunner> canceler_getter_task_runner)
+ : mode_(mode),
+ histogram_prefix_(histogram_prefix),
+ canceler_getter_(std::move(canceler_getter)),
+ canceler_getter_task_runner_(canceler_getter_task_runner) {
+}
+
+PrerenderURLLoaderThrottle::~PrerenderURLLoaderThrottle() {
+ if (destruction_closure_)
+ std::move(destruction_closure_).Run();
+}
+
+void PrerenderURLLoaderThrottle::PrerenderUsed() {
+ if (original_request_priority_)
+ delegate_->SetPriority(original_request_priority_.value());
+ if (deferred_)
+ delegate_->Resume();
+}
+
+void PrerenderURLLoaderThrottle::DetachFromCurrentSequence() {
+ // This method is only called for synchronous XHR from the main thread.
+ sync_xhr_ = true;
+}
+
+void PrerenderURLLoaderThrottle::WillStartRequest(
+ network::ResourceRequest* request,
+ bool* defer) {
+ if (mode_ == PREFETCH_ONLY) {
+ request->load_flags |= net::LOAD_PREFETCH;
+ request->cors_exempt_headers.SetHeader(kPurposeHeaderName,
+ kPurposeHeaderValue);
+ }
+
+ resource_type_ = static_cast<content::ResourceType>(request->resource_type);
+ // Abort any prerenders that spawn requests that use unsupported HTTP
+ // methods or schemes.
+ if (!IsValidHttpMethod(mode_, request->method)) {
+ // If this is a full prerender, cancel the prerender in response to
+ // invalid requests. For prefetches, cancel invalid requests but keep the
+ // prefetch going.
+ delegate_->CancelWithError(net::ERR_ABORTED);
+ if (mode_ == DEPRECATED_FULL_PRERENDER) {
+ canceler_getter_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(CancelPrerenderForUnsupportedMethod,
+ std::move(canceler_getter_)));
+ return;
+ }
+ }
+
+ if (request->resource_type !=
+ static_cast<int>(content::ResourceType::kMainFrame) &&
+ !DoesSubresourceURLHaveValidScheme(request->url)) {
+ // Destroying the prerender for unsupported scheme only for non-main
+ // resource to allow chrome://crash to actually crash in the
+ // *RendererCrash tests instead of being intercepted here. The
+ // unsupported scheme for the main resource is checked in
+ // WillRedirectRequest() and PrerenderContents::CheckURL(). See
+ // http://crbug.com/673771.
+ delegate_->CancelWithError(net::ERR_ABORTED);
+ canceler_getter_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(CancelPrerenderForUnsupportedScheme,
+ std::move(canceler_getter_), request->url));
+ return;
+ }
+
+#if defined(OS_ANDROID)
+ if (request->resource_type ==
+ static_cast<int>(content::ResourceType::kFavicon)) {
+ // Delay icon fetching until the contents are getting swapped in
+ // to conserve network usage in mobile devices.
+ *defer = true;
+ return;
+ }
+#else
+ // Priorities for prerendering requests are lowered, to avoid competing with
+ // other page loads, except on Android where this is less likely to be a
+ // problem. In some cases, this may negatively impact the performance of
+ // prerendering, see https://crbug.com/652746 for details.
+ // Requests with the IGNORE_LIMITS flag set (i.e., sync XHRs)
+ // should remain at MAXIMUM_PRIORITY.
+ if (request->load_flags & net::LOAD_IGNORE_LIMITS) {
+ DCHECK_EQ(request->priority, net::MAXIMUM_PRIORITY);
+ } else if (request->priority != net::IDLE) {
+ original_request_priority_ = request->priority;
+ request->priority = net::IDLE;
+ }
+#endif // OS_ANDROID
+
+ if (mode_ == PREFETCH_ONLY) {
+ detached_timer_.Start(FROM_HERE,
+ base::TimeDelta::FromMilliseconds(
+ content::kDefaultDetachableCancelDelayMs),
+ this, &PrerenderURLLoaderThrottle::OnTimedOut);
+ }
+}
+
+void PrerenderURLLoaderThrottle::WillRedirectRequest(
+ net::RedirectInfo* redirect_info,
+ const network::ResourceResponseHead& response_head,
+ bool* defer,
+ std::vector<std::string>* /* to_be_removed_headers */,
+ net::HttpRequestHeaders* /* modified_headers */) {
+ redirect_count_++;
+ if (mode_ == PREFETCH_ONLY) {
+ RecordPrefetchResponseReceived(
+ histogram_prefix_, content::IsResourceTypeFrame(resource_type_),
+ true /* is_redirect */, IsNoStoreResponse(response_head));
+ }
+
+ std::string follow_only_when_prerender_shown_header;
+ if (response_head.headers) {
+ response_head.headers->GetNormalizedHeader(
+ kFollowOnlyWhenPrerenderShown,
+ &follow_only_when_prerender_shown_header);
+ }
+ // Abort any prerenders with requests which redirect to invalid schemes.
+ if (!DoesURLHaveValidScheme(redirect_info->new_url)) {
+ delegate_->CancelWithError(net::ERR_ABORTED);
+ canceler_getter_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(CancelPrerenderForUnsupportedScheme,
+ std::move(canceler_getter_), redirect_info->new_url));
+ } else if (follow_only_when_prerender_shown_header == "1" &&
+ resource_type_ != content::ResourceType::kMainFrame) {
+ // Only defer redirects with the Follow-Only-When-Prerender-Shown
+ // header. Do not defer redirects on main frame loads.
+ if (sync_xhr_) {
+ // Cancel on deferred synchronous requests. Those will
+ // indefinitely hang up a renderer process.
+ canceler_getter_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(CancelPrerenderForSyncDeferredRedirect,
+ std::move(canceler_getter_)));
+ delegate_->CancelWithError(net::ERR_ABORTED);
+ } else {
+ // Defer the redirect until the prerender is used or canceled.
+ *defer = true;
+ deferred_ = true;
+ }
+ }
+}
+
+void PrerenderURLLoaderThrottle::WillProcessResponse(
+ const GURL& response_url,
+ network::ResourceResponseHead* response_head,
+ bool* defer) {
+ if (mode_ != PREFETCH_ONLY)
+ return;
+
+ bool is_main_resource = content::IsResourceTypeFrame(resource_type_);
+ RecordPrefetchResponseReceived(histogram_prefix_, is_main_resource,
+ true /* is_redirect */,
+ IsNoStoreResponse(*response_head));
+ RecordPrefetchRedirectCount(histogram_prefix_, is_main_resource,
+ redirect_count_);
+}
+
+void PrerenderURLLoaderThrottle::OnTimedOut() {
+ delegate_->CancelWithError(net::ERR_ABORTED);
+}
+
+} // namespace prerender
diff --git a/chromium/chrome/common/prerender_url_loader_throttle.h b/chromium/chrome/common/prerender_url_loader_throttle.h
new file mode 100644
index 00000000000..bf8d9a90a65
--- /dev/null
+++ b/chromium/chrome/common/prerender_url_loader_throttle.h
@@ -0,0 +1,83 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
+#define CHROME_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/sequenced_task_runner.h"
+#include "base/timer/timer.h"
+#include "chrome/common/prerender.mojom.h"
+#include "chrome/common/prerender_types.h"
+#include "content/public/common/resource_type.h"
+#include "net/base/request_priority.h"
+#include "third_party/blink/public/common/loader/url_loader_throttle.h"
+
+namespace prerender {
+
+class PrerenderURLLoaderThrottle
+ : public blink::URLLoaderThrottle,
+ public base::SupportsWeakPtr<PrerenderURLLoaderThrottle> {
+ public:
+ // If the throttle needs to cancel the prerender, it will run
+ // |canceler_getter| on |canceler_getter_task_runner| to do so.
+ using CancelerGetterCallback =
+ base::OnceCallback<chrome::mojom::PrerenderCanceler*()>;
+ PrerenderURLLoaderThrottle(
+ PrerenderMode mode,
+ const std::string& histogram_prefix,
+ CancelerGetterCallback canceler_getter,
+ scoped_refptr<base::SequencedTaskRunner> canceler_getter_task_runner);
+ ~PrerenderURLLoaderThrottle() override;
+
+ // Called when the prerender is used. This will unpaused requests and set the
+ // priorities to the original value.
+ void PrerenderUsed();
+
+ void set_destruction_closure(base::OnceClosure closure) {
+ destruction_closure_ = std::move(closure);
+ }
+
+ private:
+ // blink::URLLoaderThrottle implementation.
+ void DetachFromCurrentSequence() override;
+ void WillStartRequest(network::ResourceRequest* request,
+ bool* defer) override;
+ void WillRedirectRequest(net::RedirectInfo* redirect_info,
+ const network::ResourceResponseHead& response_head,
+ bool* defer,
+ std::vector<std::string>* to_be_removed_headers,
+ net::HttpRequestHeaders* modified_headers) override;
+ void WillProcessResponse(const GURL& response_url,
+ network::ResourceResponseHead* response_head,
+ bool* defer) override;
+
+ void OnTimedOut();
+
+ PrerenderMode mode_;
+ std::string histogram_prefix_;
+
+ bool deferred_ = false;
+ bool sync_xhr_ = false;
+ int redirect_count_ = 0;
+ content::ResourceType resource_type_;
+
+ CancelerGetterCallback canceler_getter_;
+ scoped_refptr<base::SequencedTaskRunner> canceler_getter_task_runner_;
+
+ // The throttle changes most request priorities to IDLE during prerendering.
+ // The priority is reset back to the original priority when prerendering is
+ // finished.
+ base::Optional<net::RequestPriority> original_request_priority_;
+
+ base::OnceClosure destruction_closure_;
+
+ base::OneShotTimer detached_timer_;
+};
+
+} // namespace prerender
+
+#endif // CHROME_COMMON_PRERENDER_URL_LOADER_THROTTLE_H_
diff --git a/chromium/chrome/common/prerender_util.cc b/chromium/chrome/common/prerender_util.cc
new file mode 100644
index 00000000000..70282cf5107
--- /dev/null
+++ b/chromium/chrome/common/prerender_util.cc
@@ -0,0 +1,112 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/prerender_util.h"
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "extensions/common/constants.h"
+#include "url/gurl.h"
+#include "url/url_constants.h"
+
+namespace prerender {
+
+namespace {
+
+// Valid HTTP methods for both prefetch and prerendering.
+const char* const kValidHttpMethods[] = {
+ "GET", "HEAD",
+};
+
+// Additional valid HTTP methods for prerendering.
+const char* const kValidHttpMethodsForPrerendering[] = {
+ "OPTIONS", "POST", "TRACE",
+};
+
+// This enum is used to define the buckets for the
+// "Prerender.NoStatePrefetchResourceCount" histogram family.
+// Hence, existing enumerated constants should never be deleted or reordered,
+// and new constants should only be appended at the end of the enumeration.
+enum NoStatePrefetchResponseType {
+ NO_STORE = 1 << 0,
+ REDIRECT = 1 << 1,
+ MAIN_RESOURCE = 1 << 2,
+ NO_STATE_PREFETCH_RESPONSE_TYPE_COUNT = 1 << 3
+};
+
+int GetResourceType(bool is_main_resource, bool is_redirect, bool is_no_store) {
+ return (is_no_store * NO_STORE) + (is_redirect * REDIRECT) +
+ (is_main_resource * MAIN_RESOURCE);
+}
+
+} // namespace
+
+const char kFollowOnlyWhenPrerenderShown[] = "follow-only-when-prerender-shown";
+
+bool DoesURLHaveValidScheme(const GURL& url) {
+ return (url.SchemeIsHTTPOrHTTPS() ||
+ url.SchemeIs(extensions::kExtensionScheme) ||
+ url.SchemeIs(url::kDataScheme));
+}
+
+bool DoesSubresourceURLHaveValidScheme(const GURL& url) {
+ return DoesURLHaveValidScheme(url) || url == url::kAboutBlankURL;
+}
+
+bool IsValidHttpMethod(PrerenderMode prerender_mode,
+ const std::string& method) {
+ DCHECK_NE(prerender_mode, NO_PRERENDER);
+ // |method| has been canonicalized to upper case at this point so we can just
+ // compare them.
+ DCHECK_EQ(method, base::ToUpperASCII(method));
+ for (auto* valid_method : kValidHttpMethods) {
+ if (method == valid_method)
+ return true;
+ }
+
+ if (prerender_mode == PREFETCH_ONLY)
+ return false;
+
+ for (auto* valid_method : kValidHttpMethodsForPrerendering) {
+ if (method == valid_method)
+ return true;
+ }
+
+ return false;
+}
+
+std::string ComposeHistogramName(const std::string& prefix_type,
+ const std::string& name) {
+ if (prefix_type.empty())
+ return std::string("Prerender.") + name;
+ return std::string("Prerender.") + prefix_type + std::string("_") + name;
+}
+
+void RecordPrefetchResponseReceived(const std::string& histogram_prefix,
+ bool is_main_resource,
+ bool is_redirect,
+ bool is_no_store) {
+ int sample = GetResourceType(is_main_resource, is_redirect, is_no_store);
+ std::string histogram_name =
+ ComposeHistogramName(histogram_prefix, "NoStatePrefetchResponseTypes");
+ base::UmaHistogramExactLinear(histogram_name, sample,
+ NO_STATE_PREFETCH_RESPONSE_TYPE_COUNT);
+}
+
+void RecordPrefetchRedirectCount(const std::string& histogram_prefix,
+ bool is_main_resource,
+ int redirect_count) {
+ const int kMaxRedirectCount = 10;
+ std::string histogram_base_name = base::StringPrintf(
+ "NoStatePrefetch%sResourceRedirects", is_main_resource ? "Main" : "Sub");
+ std::string histogram_name =
+ ComposeHistogramName(histogram_prefix, histogram_base_name);
+ base::UmaHistogramExactLinear(histogram_name, redirect_count,
+ kMaxRedirectCount);
+}
+
+} // namespace prerender
diff --git a/chromium/chrome/common/prerender_util.h b/chromium/chrome/common/prerender_util.h
new file mode 100644
index 00000000000..4fa1436ccb6
--- /dev/null
+++ b/chromium/chrome/common/prerender_util.h
@@ -0,0 +1,45 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_PRERENDER_UTIL_H_
+#define CHROME_COMMON_PRERENDER_UTIL_H_
+
+#include <string>
+
+#include "chrome/common/prerender_types.h"
+
+class GURL;
+
+namespace prerender {
+extern const char kFollowOnlyWhenPrerenderShown[];
+
+// Returns true iff the scheme of the URL given is valid for prerendering.
+bool DoesURLHaveValidScheme(const GURL& url);
+
+// Returns true iff the scheme of the subresource URL given is valid for
+// prerendering.
+bool DoesSubresourceURLHaveValidScheme(const GURL& url);
+
+// Returns true iff the method given is valid for prerendering.
+bool IsValidHttpMethod(PrerenderMode prerender_mode, const std::string& method);
+
+std::string ComposeHistogramName(const std::string& prefix_type,
+ const std::string& name);
+
+// Called when a NoStatePrefetch request has received a response (including
+// redirects). May be called several times per resource, in case of redirects.
+void RecordPrefetchResponseReceived(const std::string& histogram_prefix,
+ bool is_main_resource,
+ bool is_redirect,
+ bool is_no_store);
+
+// Called when a NoStatePrefetch resource has been loaded. This is called only
+// once per resource, when all redirects have been resolved.
+void RecordPrefetchRedirectCount(const std::string& histogram_prefix,
+ bool is_main_resource,
+ int redirect_count);
+
+} // namespace prerender
+
+#endif // CHROME_COMMON_PRERENDER_UTIL_H_
diff --git a/chromium/chrome/common/process_singleton_lock_posix.cc b/chromium/chrome/common/process_singleton_lock_posix.cc
new file mode 100644
index 00000000000..9e44b935e01
--- /dev/null
+++ b/chromium/chrome/common/process_singleton_lock_posix.cc
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/process_singleton_lock_posix.h"
+
+#include "base/files/file_util.h"
+#include "base/strings/string_number_conversions.h"
+
+const char kProcessSingletonLockDelimiter = '-';
+
+bool ParseProcessSingletonLock(const base::FilePath& path,
+ std::string* hostname,
+ int* pid) {
+ base::FilePath target;
+ if (!base::ReadSymbolicLink(path, &target)) {
+ // The only errno that should occur is ENOENT.
+ if (errno != 0 && errno != ENOENT)
+ PLOG(ERROR) << "readlink(" << path.value() << ") failed";
+ }
+
+ std::string real_path = target.value();
+ if (real_path.empty())
+ return false;
+
+ std::string::size_type pos = real_path.rfind(kProcessSingletonLockDelimiter);
+
+ // If the path is not a symbolic link, or doesn't contain what we expect,
+ // bail.
+ if (pos == std::string::npos) {
+ *hostname = "";
+ *pid = -1;
+ return true;
+ }
+
+ *hostname = real_path.substr(0, pos);
+
+ const std::string& pid_str = real_path.substr(pos + 1);
+ if (!base::StringToInt(pid_str, pid))
+ *pid = -1;
+
+ return true;
+}
diff --git a/chromium/chrome/common/process_singleton_lock_posix.h b/chromium/chrome/common/process_singleton_lock_posix.h
new file mode 100644
index 00000000000..58584d9950c
--- /dev/null
+++ b/chromium/chrome/common/process_singleton_lock_posix.h
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_PROCESS_SINGLETON_LOCK_POSIX_H_
+#define CHROME_COMMON_PROCESS_SINGLETON_LOCK_POSIX_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+
+// Extract the hostname and pid from the lock symlink. Returns true if the lock
+// existed. See ProcessSingleton for additional details.
+bool ParseProcessSingletonLock(const base::FilePath& path,
+ std::string* hostname,
+ int* pid);
+
+extern const char kProcessSingletonLockDelimiter;
+
+#endif // CHROME_COMMON_PROCESS_SINGLETON_LOCK_POSIX_H_
diff --git a/chromium/chrome/common/profiler/OWNERS b/chromium/chrome/common/profiler/OWNERS
new file mode 100644
index 00000000000..3ed2cd88c98
--- /dev/null
+++ b/chromium/chrome/common/profiler/OWNERS
@@ -0,0 +1,4 @@
+# COMPONENT: Internals>Metrics
+
+charliea@chromium.org
+wittman@chromium.org \ No newline at end of file
diff --git a/chromium/chrome/common/profiler/main_thread_stack_sampling_profiler.cc b/chromium/chrome/common/profiler/main_thread_stack_sampling_profiler.cc
new file mode 100644
index 00000000000..6f62d6a55cf
--- /dev/null
+++ b/chromium/chrome/common/profiler/main_thread_stack_sampling_profiler.cc
@@ -0,0 +1,44 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/profiler/main_thread_stack_sampling_profiler.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/threading/platform_thread.h"
+#include "chrome/common/thread_profiler.h"
+#include "components/metrics/call_stack_profile_metrics_provider.h"
+#include "content/public/common/content_switches.h"
+
+namespace {
+
+// Returns the profiler appropriate for the current process.
+std::unique_ptr<ThreadProfiler> CreateThreadProfiler() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+
+ // The browser process has an empty process type.
+ // TODO(wittman): Do this for other process types too.
+ if (!command_line->HasSwitch(switches::kProcessType)) {
+ ThreadProfiler::SetBrowserProcessReceiverCallback(base::BindRepeating(
+ &metrics::CallStackProfileMetricsProvider::ReceiveProfile));
+ return ThreadProfiler::CreateAndStartOnMainThread();
+ }
+
+ // No other processes are currently supported.
+ return nullptr;
+}
+
+} // namespace
+
+MainThreadStackSamplingProfiler::MainThreadStackSamplingProfiler() {
+ sampling_profiler_ = CreateThreadProfiler();
+}
+
+// Note that it's important for the |sampling_profiler_| destructor to run, as
+// it ensures program correctness on shutdown. Without it, the profiler thread's
+// destruction can race with the profiled thread's destruction, which results in
+// the sampling thread attempting to profile the sampled thread after the
+// sampled thread has already been shut down.
+MainThreadStackSamplingProfiler::~MainThreadStackSamplingProfiler() = default;
diff --git a/chromium/chrome/common/profiler/main_thread_stack_sampling_profiler.h b/chromium/chrome/common/profiler/main_thread_stack_sampling_profiler.h
new file mode 100644
index 00000000000..4e868ae5e72
--- /dev/null
+++ b/chromium/chrome/common/profiler/main_thread_stack_sampling_profiler.h
@@ -0,0 +1,35 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_PROFILER_MAIN_THREAD_STACK_SAMPLING_PROFILER_H_
+#define CHROME_COMMON_PROFILER_MAIN_THREAD_STACK_SAMPLING_PROFILER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/profiler/stack_sampling_profiler.h"
+
+class ThreadProfiler;
+
+// A wrapper class that begins profiling stack samples upon construction, and
+// ensures correct shutdown behavior on destruction. Should only be used on the
+// main thread of a process. Samples are collected for the thread of the current
+// process where this object is constructed, and only if profiling is enabled
+// for the thread. This data is used to understand startup performance behavior,
+// and the object should therefore be created as early during initialization as
+// possible.
+class MainThreadStackSamplingProfiler {
+ public:
+ MainThreadStackSamplingProfiler();
+ ~MainThreadStackSamplingProfiler();
+
+ private:
+ // A profiler that periodically samples stack traces. Used to understand
+ // thread and process startup behavior.
+ std::unique_ptr<ThreadProfiler> sampling_profiler_;
+
+ DISALLOW_COPY_AND_ASSIGN(MainThreadStackSamplingProfiler);
+};
+
+#endif // CHROME_COMMON_PROFILER_MAIN_THREAD_STACK_SAMPLING_PROFILER_H_
diff --git a/chromium/chrome/common/ref_counted_util.h b/chromium/chrome/common/ref_counted_util.h
new file mode 100644
index 00000000000..b8dd6e0680a
--- /dev/null
+++ b/chromium/chrome/common/ref_counted_util.h
@@ -0,0 +1,32 @@
+// 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 CHROME_COMMON_REF_COUNTED_UTIL_H__
+#define CHROME_COMMON_REF_COUNTED_UTIL_H__
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+
+// RefCountedVector is just a vector wrapped up with
+// RefCountedThreadSafe.
+template<class T>
+class RefCountedVector
+ : public base::RefCountedThreadSafe<RefCountedVector<T> > {
+ public:
+ RefCountedVector() {}
+ explicit RefCountedVector(const std::vector<T>& initializer)
+ : data(initializer) {}
+
+ std::vector<T> data;
+
+ private:
+ friend class base::RefCountedThreadSafe<RefCountedVector<T>>;
+ ~RefCountedVector() {}
+
+ DISALLOW_COPY_AND_ASSIGN(RefCountedVector<T>);
+};
+
+#endif // CHROME_COMMON_REF_COUNTED_UTIL_H__
diff --git a/chromium/chrome/common/render_messages.h b/chromium/chrome/common/render_messages.h
new file mode 100644
index 00000000000..97bb5f3e7af
--- /dev/null
+++ b/chromium/chrome/common/render_messages.h
@@ -0,0 +1,142 @@
+// 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 CHROME_COMMON_RENDER_MESSAGES_H_
+#define CHROME_COMMON_RENDER_MESSAGES_H_
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "chrome/common/buildflags.h"
+#include "chrome/common/web_application_info_provider_param_traits.h"
+#include "components/content_settings/core/common/content_settings.h"
+#include "components/content_settings/core/common/content_settings_pattern.h"
+#include "components/content_settings/core/common/content_settings_types.h"
+#include "components/offline_pages/buildflags/buildflags.h"
+#include "content/public/common/webplugininfo.h"
+#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_platform_file.h"
+#include "media/media_buildflags.h"
+#include "ppapi/buildflags/buildflags.h"
+#include "url/gurl.h"
+#include "url/ipc/url_param_traits.h"
+#include "url/origin.h"
+
+// Singly-included section for enums and custom IPC traits.
+#ifndef INTERNAL_CHROME_COMMON_RENDER_MESSAGES_H_
+#define INTERNAL_CHROME_COMMON_RENDER_MESSAGES_H_
+
+
+#endif // INTERNAL_CHROME_COMMON_RENDER_MESSAGES_H_
+
+#define IPC_MESSAGE_START ChromeMsgStart
+
+//-----------------------------------------------------------------------------
+// RenderView messages
+// These are messages sent from the browser to the renderer process.
+
+// Tells the render frame to load all blocked plugins with the given identifier.
+IPC_MESSAGE_ROUTED1(ChromeViewMsg_LoadBlockedPlugins,
+ std::string /* identifier */)
+
+// Tells the renderer whether or not a file system access has been allowed.
+IPC_MESSAGE_ROUTED2(ChromeViewMsg_RequestFileSystemAccessAsyncResponse,
+ int /* request_id */,
+ bool /* allowed */)
+
+// JavaScript related messages -----------------------------------------------
+
+#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
+// Message sent from the renderer to the browser to schedule to download the
+// page at a later time.
+IPC_MESSAGE_ROUTED0(ChromeViewHostMsg_DownloadPageLater)
+
+// Message sent from the renderer to the browser to indicate if download button
+// is being shown in error page.
+IPC_MESSAGE_ROUTED1(ChromeViewHostMsg_SetIsShowingDownloadButtonInErrorPage,
+ bool /* showing download button */)
+#endif
+
+//-----------------------------------------------------------------------------
+// Misc messages
+// 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_CONTROL4_1(ChromeViewHostMsg_AllowDatabase,
+ int /* render_frame_id */,
+ url::Origin /* origin */,
+ GURL /* site_for_cookies */,
+ url::Origin /* top frame_origin */,
+ bool /* allowed */)
+
+// Sent by the renderer process to check whether access to DOM Storage is
+// granted by content settings.
+IPC_SYNC_MESSAGE_CONTROL5_1(ChromeViewHostMsg_AllowDOMStorage,
+ int /* render_frame_id */,
+ url::Origin /* origin */,
+ GURL /* site_for_cookies */,
+ url::Origin /* top frame_origin */,
+ bool /* if true local storage, otherwise session */,
+ bool /* allowed */)
+
+// Sent by the renderer process to check whether access to FileSystem is
+// granted by content settings.
+IPC_SYNC_MESSAGE_CONTROL4_1(ChromeViewHostMsg_RequestFileSystemAccessSync,
+ int /* render_frame_id */,
+ url::Origin /* origin */,
+ GURL /* site_for_cookies */,
+ url::Origin /* top frame_origin */,
+ bool /* allowed */)
+
+// Sent by the renderer process to check whether access to FileSystem is
+// granted by content settings.
+IPC_MESSAGE_CONTROL5(ChromeViewHostMsg_RequestFileSystemAccessAsync,
+ int /* render_frame_id */,
+ int /* request_id */,
+ url::Origin /* origin */,
+ GURL /* site_for_cookies */,
+ url::Origin /* top frame_origin */)
+
+// Sent by the renderer process to check whether access to Indexed DB is
+// granted by content settings.
+IPC_SYNC_MESSAGE_CONTROL4_1(ChromeViewHostMsg_AllowIndexedDB,
+ int /* render_frame_id */,
+ url::Origin /* origin */,
+ GURL /* site_for_cookies */,
+ url::Origin /* top frame_origin */,
+ bool /* allowed */)
+
+// Sent by the renderer process to check whether access to CacheStorage is
+// granted by content settings.
+IPC_SYNC_MESSAGE_CONTROL4_1(ChromeViewHostMsg_AllowCacheStorage,
+ int /* render_frame_id */,
+ url::Origin /* origin */,
+ GURL /* site_for_cookies */,
+ url::Origin /* top frame_origin */,
+ bool /* allowed */)
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+// Sent by the renderer to check if crash reporting is enabled.
+IPC_SYNC_MESSAGE_CONTROL0_1(ChromeViewHostMsg_IsCrashReportingEnabled,
+ bool /* enabled */)
+#endif
+
+// Tells the browser to open a PDF file in a new tab. Used when no PDF Viewer is
+// available, and user clicks to view PDF.
+IPC_MESSAGE_ROUTED1(ChromeViewHostMsg_OpenPDF, GURL /* url */)
+
+#endif // CHROME_COMMON_RENDER_MESSAGES_H_
diff --git a/chromium/chrome/common/safe_browsing/DEPS b/chromium/chrome/common/safe_browsing/DEPS
new file mode 100644
index 00000000000..c191816456b
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ "+components/safe_browsing",
+ "+third_party/protobuf",
+ "+third_party/unrar",
+ "+third_party/zlib",
+]
diff --git a/chromium/chrome/common/safe_browsing/OWNERS b/chromium/chrome/common/safe_browsing/OWNERS
new file mode 100644
index 00000000000..1b014cbc05c
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/OWNERS
@@ -0,0 +1,23 @@
+drubery@chromium.org
+nparker@chromium.org
+vakh@chromium.org
+
+# This is for the common case of adding or renaming files. If you're doing
+# structural changes, use usual OWNERS rules.
+per-file BUILD.gn=*
+
+per-file *_messages*.h=set noparent
+per-file *_messages*.h=file://ipc/SECURITY_OWNERS
+
+# For security review of IPC-to-protobuf bridge.
+per-file *protobuf_message*.h=set noparent
+per-file *protobuf_message*.h=file://ipc/SECURITY_OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_param_traits*.*=set noparent
+per-file *_param_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
+
+# COMPONENT: Services>Safebrowsing
diff --git a/chromium/chrome/common/safe_browsing/archive_analyzer_results.cc b/chromium/chrome/common/safe_browsing/archive_analyzer_results.cc
new file mode 100644
index 00000000000..686b560aa0b
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/archive_analyzer_results.cc
@@ -0,0 +1,182 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file contains the archive file analysis implementation for download
+// protection, which runs in a sandboxed utility process.
+
+#include "chrome/common/safe_browsing/archive_analyzer_results.h"
+
+#include "base/files/file.h"
+#include "base/i18n/streaming_utf8_validator.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/stl_util.h"
+#include "build/build_config.h"
+#include "chrome/common/safe_browsing/archive_analyzer_results.h"
+#include "chrome/common/safe_browsing/binary_feature_extractor.h"
+#include "chrome/common/safe_browsing/download_type_util.h"
+#include "chrome/common/safe_browsing/file_type_policies.h"
+#include "crypto/secure_hash.h"
+#include "crypto/sha2.h"
+
+#if defined(OS_MACOSX)
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+#include "base/containers/span.h"
+#include "chrome/common/safe_browsing/disk_image_type_sniffer_mac.h"
+#include "chrome/common/safe_browsing/mach_o_image_reader_mac.h"
+#endif // OS_MACOSX
+
+namespace safe_browsing {
+
+namespace {
+
+void SetLengthAndDigestForContainedFile(
+ const base::FilePath& path,
+ base::File* temp_file,
+ int file_length,
+ ClientDownloadRequest::ArchivedBinary* archived_binary) {
+ std::string file_basename(path.BaseName().AsUTF8Unsafe());
+ if (base::StreamingUtf8Validator::Validate(file_basename))
+ archived_binary->set_file_basename(file_basename);
+ archived_binary->set_length(file_length);
+
+ std::unique_ptr<crypto::SecureHash> hasher =
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256);
+
+ const size_t kReadBufferSize = 4096;
+ char block[kReadBufferSize];
+
+ int bytes_read_previously = 0;
+ temp_file->Seek(base::File::Whence::FROM_BEGIN, 0);
+ while (true) {
+ int bytes_read_now = temp_file->ReadAtCurrentPos(block, kReadBufferSize);
+
+ if (bytes_read_previously + bytes_read_now > file_length)
+ bytes_read_now = file_length - bytes_read_previously;
+
+ if (bytes_read_now <= 0)
+ break;
+
+ hasher->Update(block, bytes_read_now);
+ bytes_read_previously += bytes_read_now;
+ }
+
+ uint8_t digest[crypto::kSHA256Length];
+ hasher->Finish(digest, base::size(digest));
+ archived_binary->mutable_digests()->set_sha256(digest, base::size(digest));
+}
+
+void AnalyzeContainedBinary(
+ const scoped_refptr<BinaryFeatureExtractor>& binary_feature_extractor,
+ base::File* temp_file,
+ ClientDownloadRequest::ArchivedBinary* archived_binary) {
+ if (!binary_feature_extractor->ExtractImageFeaturesFromFile(
+ temp_file->Duplicate(), BinaryFeatureExtractor::kDefaultOptions,
+ archived_binary->mutable_image_headers(),
+ archived_binary->mutable_signature()->mutable_signed_data())) {
+ archived_binary->clear_image_headers();
+ archived_binary->clear_signature();
+ } else if (!archived_binary->signature().signed_data_size()) {
+ // No SignedData blobs were extracted, so clear the
+ // signature field.
+ archived_binary->clear_signature();
+ }
+}
+
+} // namespace
+
+ArchiveAnalyzerResults::ArchiveAnalyzerResults()
+ : success(false),
+ has_executable(false),
+ has_archive(false),
+ file_count(0),
+ directory_count(0) {}
+
+ArchiveAnalyzerResults::ArchiveAnalyzerResults(
+ const ArchiveAnalyzerResults& other) = default;
+
+ArchiveAnalyzerResults::~ArchiveAnalyzerResults() {}
+
+void UpdateArchiveAnalyzerResultsWithFile(base::FilePath path,
+ base::File* file,
+ int file_length,
+ bool is_encrypted,
+ ArchiveAnalyzerResults* results) {
+ scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor(
+ new BinaryFeatureExtractor());
+ bool current_entry_is_executable;
+
+#if defined(OS_MACOSX)
+ uint32_t magic;
+ file->Read(0, reinterpret_cast<char*>(&magic), sizeof(uint32_t));
+
+ char dmg_header[DiskImageTypeSnifferMac::AppleDiskImageTrailerSize()];
+ file->Read(0, dmg_header,
+ DiskImageTypeSnifferMac::AppleDiskImageTrailerSize());
+
+ current_entry_is_executable =
+ FileTypePolicies::GetInstance()->IsCheckedBinaryFile(path) ||
+ MachOImageReader::IsMachOMagicValue(magic) ||
+ DiskImageTypeSnifferMac::IsAppleDiskImageTrailer(
+ base::span<const uint8_t>(
+ reinterpret_cast<const uint8_t*>(dmg_header),
+ DiskImageTypeSnifferMac::AppleDiskImageTrailerSize()));
+
+ // We can skip checking the trailer if we already know the file is executable.
+ if (!current_entry_is_executable) {
+ char trailer[DiskImageTypeSnifferMac::AppleDiskImageTrailerSize()];
+ file->Seek(base::File::Whence::FROM_END,
+ DiskImageTypeSnifferMac::AppleDiskImageTrailerSize());
+ file->ReadAtCurrentPos(
+ trailer, DiskImageTypeSnifferMac::AppleDiskImageTrailerSize());
+ current_entry_is_executable =
+ DiskImageTypeSnifferMac::IsAppleDiskImageTrailer(
+ base::span<const uint8_t>(
+ reinterpret_cast<const uint8_t*>(trailer),
+ DiskImageTypeSnifferMac::AppleDiskImageTrailerSize()));
+ }
+
+#else
+ current_entry_is_executable =
+ FileTypePolicies::GetInstance()->IsCheckedBinaryFile(path);
+#endif // OS_MACOSX
+
+ if (FileTypePolicies::GetInstance()->IsArchiveFile(path)) {
+ DVLOG(2) << "Downloaded a zipped archive: " << path.value();
+ results->has_archive = true;
+ results->archived_archive_filenames.push_back(path.BaseName());
+ ClientDownloadRequest::ArchivedBinary* archived_archive =
+ results->archived_binary.Add();
+ archived_archive->set_download_type(ClientDownloadRequest::ARCHIVE);
+ archived_archive->set_is_encrypted(is_encrypted);
+ SetLengthAndDigestForContainedFile(path, file, file_length,
+ archived_archive);
+ } else if (current_entry_is_executable) {
+#if defined(OS_MACOSX)
+ // This check prevents running analysis on .app files since they are
+ // really just directories and will cause binary feature extraction
+ // to fail.
+ if (path.Extension().compare(".app") == 0) {
+ DVLOG(2) << "Downloaded a zipped .app directory: " << path.value();
+ } else {
+#endif // OS_MACOSX
+ DVLOG(2) << "Downloaded a zipped executable: " << path.value();
+ results->has_executable = true;
+ ClientDownloadRequest::ArchivedBinary* archived_binary =
+ results->archived_binary.Add();
+ archived_binary->set_is_encrypted(is_encrypted);
+ archived_binary->set_download_type(
+ download_type_util::GetDownloadType(path));
+ SetLengthAndDigestForContainedFile(path, file, file_length,
+ archived_binary);
+ AnalyzeContainedBinary(binary_feature_extractor, file, archived_binary);
+#if defined(OS_MACOSX)
+ }
+#endif // OS_MACOSX
+ } else {
+ DVLOG(3) << "Ignoring non-binary file: " << path.value();
+ }
+}
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/archive_analyzer_results.h b/chromium/chrome/common/safe_browsing/archive_analyzer_results.h
new file mode 100644
index 00000000000..09c526dbd3f
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/archive_analyzer_results.h
@@ -0,0 +1,55 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file contains the archive analyzer analysis implementation for download
+// protection, which runs in a sandboxed utility process.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_ARCHIVE_ANALYZER_RESULTS_H_
+#define CHROME_COMMON_SAFE_BROWSING_ARCHIVE_ANALYZER_RESULTS_H_
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "build/build_config.h"
+#include "components/safe_browsing/proto/csd.pb.h"
+
+namespace base {
+class File;
+}
+
+namespace safe_browsing {
+
+struct ArchiveAnalyzerResults {
+ bool success;
+ bool has_executable;
+ bool has_archive;
+ google::protobuf::RepeatedPtrField<ClientDownloadRequest_ArchivedBinary>
+ archived_binary;
+ std::vector<base::FilePath> archived_archive_filenames;
+#if defined(OS_MACOSX)
+ std::vector<uint8_t> signature_blob;
+ google::protobuf::RepeatedPtrField<
+ ClientDownloadRequest_DetachedCodeSignature>
+ detached_code_signatures;
+#endif // OS_MACOSX
+ int file_count;
+ int directory_count;
+ ArchiveAnalyzerResults();
+ ArchiveAnalyzerResults(const ArchiveAnalyzerResults& other);
+ ~ArchiveAnalyzerResults();
+};
+
+// Updates |results| with the results of inspecting |file|, given that it will
+// be extracted to |path|. Due to complications with the utility process sandbox
+// (see https://crbug.com/944633), the file inspection is limited to the first
+// |file_length| bytes of |file|.
+void UpdateArchiveAnalyzerResultsWithFile(base::FilePath path,
+ base::File* file,
+ int file_length,
+ bool is_encrypted,
+ ArchiveAnalyzerResults* results);
+
+} // namespace safe_browsing
+
+#endif // CHROME_COMMON_SAFE_BROWSING_ARCHIVE_ANALYZER_RESULTS_H_
diff --git a/chromium/chrome/common/safe_browsing/binary_feature_extractor.cc b/chromium/chrome/common/safe_browsing/binary_feature_extractor.cc
new file mode 100644
index 00000000000..896768a6dcb
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/binary_feature_extractor.cc
@@ -0,0 +1,71 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/binary_feature_extractor.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/memory_mapped_file.h"
+#include "components/safe_browsing/proto/csd.pb.h"
+#include "crypto/secure_hash.h"
+#include "crypto/sha2.h"
+
+namespace safe_browsing {
+
+BinaryFeatureExtractor::BinaryFeatureExtractor() {}
+
+BinaryFeatureExtractor::~BinaryFeatureExtractor() {}
+
+bool BinaryFeatureExtractor::ExtractImageFeatures(
+ const base::FilePath& file_path,
+ ExtractHeadersOption options,
+ ClientDownloadRequest_ImageHeaders* image_headers,
+ google::protobuf::RepeatedPtrField<std::string>* signed_data) {
+ base::MemoryMappedFile mapped_file;
+ if (!mapped_file.Initialize(file_path))
+ return false;
+ return ExtractImageFeaturesFromData(mapped_file.data(), mapped_file.length(),
+ options, image_headers, signed_data);
+}
+
+bool BinaryFeatureExtractor::ExtractImageFeaturesFromFile(
+ base::File file,
+ ExtractHeadersOption options,
+ ClientDownloadRequest_ImageHeaders* image_headers,
+ google::protobuf::RepeatedPtrField<std::string>* signed_data) {
+ base::MemoryMappedFile mapped_file;
+ if (!mapped_file.Initialize(std::move(file)))
+ return false;
+ return ExtractImageFeaturesFromData(mapped_file.data(), mapped_file.length(),
+ options, image_headers, signed_data);
+}
+
+void BinaryFeatureExtractor::ExtractDigest(
+ const base::FilePath& file_path,
+ ClientDownloadRequest_Digests* digests) {
+ base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+ if (file.IsValid()) {
+ const int kBufferSize = 1 << 12;
+ std::unique_ptr<char[]> buf(new char[kBufferSize]);
+ std::unique_ptr<crypto::SecureHash> ctx(
+ crypto::SecureHash::Create(crypto::SecureHash::SHA256));
+ int len = 0;
+ while (true) {
+ len = file.ReadAtCurrentPos(buf.get(), kBufferSize);
+ if (len <= 0)
+ break;
+ ctx->Update(buf.get(), len);
+ }
+ if (!len) {
+ uint8_t hash[crypto::kSHA256Length];
+ ctx->Finish(hash, sizeof(hash));
+ digests->set_sha256(hash, sizeof(hash));
+ }
+ }
+}
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/binary_feature_extractor.h b/chromium/chrome/common/safe_browsing/binary_feature_extractor.h
new file mode 100644
index 00000000000..b0bf4bf4bf3
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/binary_feature_extractor.h
@@ -0,0 +1,87 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Utility functions to extract file features for malicious binary detection.
+// Each platform has its own implementation of this class.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_BINARY_FEATURE_EXTRACTOR_H_
+#define CHROME_COMMON_SAFE_BROWSING_BINARY_FEATURE_EXTRACTOR_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "third_party/protobuf/src/google/protobuf/repeated_field.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace safe_browsing {
+class ClientDownloadRequest_Digests;
+class ClientDownloadRequest_ImageHeaders;
+class ClientDownloadRequest_SignatureInfo;
+
+class BinaryFeatureExtractor
+ : public base::RefCountedThreadSafe<BinaryFeatureExtractor> {
+ public:
+ // The type and defined values for a bitfield that controls aspects of image
+ // header extraction.
+ typedef uint32_t ExtractHeadersOption;
+ static const ExtractHeadersOption kDefaultOptions = 0;
+ static const ExtractHeadersOption kOmitExports = 1U << 0;
+
+ BinaryFeatureExtractor();
+
+ // Fills in the DownloadRequest_SignatureInfo for the given file path.
+ // This method may be called on any thread.
+ virtual void CheckSignature(
+ const base::FilePath& file_path,
+ ClientDownloadRequest_SignatureInfo* signature_info);
+
+ // Populates |image_headers| with the PE image headers of |file_path| and, if
+ // non-null, |signed_data| with any PKCS#7 SignedData blobs found in the
+ // image's attribute certificate table. |options| is a bitfield controlling
+ // aspects of extraction. Returns true if |image_headers| is populated with
+ // any information.
+ virtual bool ExtractImageFeatures(
+ const base::FilePath& file_path,
+ ExtractHeadersOption options,
+ ClientDownloadRequest_ImageHeaders* image_headers,
+ google::protobuf::RepeatedPtrField<std::string>* signed_data);
+
+ // As above, but works with an already-opened file. BinaryFeatureExtractor
+ // takes ownership of |file| and closes it when done.
+ virtual bool ExtractImageFeaturesFromFile(
+ base::File file,
+ ExtractHeadersOption options,
+ ClientDownloadRequest_ImageHeaders* image_headers,
+ google::protobuf::RepeatedPtrField<std::string>* signed_data);
+
+ // As above, but works on a byte array containing image data. This does not
+ // take ownership of the data.
+ virtual bool ExtractImageFeaturesFromData(
+ const uint8_t* data, size_t data_size,
+ ExtractHeadersOption options,
+ ClientDownloadRequest_ImageHeaders* image_headers,
+ google::protobuf::RepeatedPtrField<std::string>* signed_data);
+
+ // Populates |digests.sha256| with the SHA256 digest of |file_path|.
+ virtual void ExtractDigest(const base::FilePath& file_path,
+ ClientDownloadRequest_Digests* digests);
+
+ protected:
+ friend class base::RefCountedThreadSafe<BinaryFeatureExtractor>;
+ virtual ~BinaryFeatureExtractor();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(BinaryFeatureExtractor);
+};
+} // namespace safe_browsing
+
+#endif // CHROME_COMMON_SAFE_BROWSING_BINARY_FEATURE_EXTRACTOR_H_
diff --git a/chromium/chrome/common/safe_browsing/binary_feature_extractor_fuzzer.cc b/chromium/chrome/common/safe_browsing/binary_feature_extractor_fuzzer.cc
new file mode 100644
index 00000000000..d69de8fac86
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/binary_feature_extractor_fuzzer.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/binary_feature_extractor.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "components/safe_browsing/proto/csd.pb.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ static safe_browsing::BinaryFeatureExtractor* extractor =
+ new safe_browsing::BinaryFeatureExtractor();
+
+ google::protobuf::RepeatedPtrField<std::string> signed_data;
+ safe_browsing::ClientDownloadRequest_ImageHeaders image_headers;
+ extractor->ExtractImageFeaturesFromData(
+ data, size, safe_browsing::BinaryFeatureExtractor::kDefaultOptions,
+ &image_headers, &signed_data);
+ return 0;
+}
diff --git a/chromium/chrome/common/safe_browsing/binary_feature_extractor_mac.cc b/chromium/chrome/common/safe_browsing/binary_feature_extractor_mac.cc
new file mode 100644
index 00000000000..9edb6482f4a
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/binary_feature_extractor_mac.cc
@@ -0,0 +1,68 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/binary_feature_extractor.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "chrome/common/safe_browsing/mach_o_image_reader_mac.h"
+#include "components/safe_browsing/proto/csd.pb.h"
+
+namespace safe_browsing {
+
+bool BinaryFeatureExtractor::ExtractImageFeaturesFromData(
+ const uint8_t* data, size_t data_size,
+ ExtractHeadersOption options,
+ ClientDownloadRequest_ImageHeaders* image_headers,
+ google::protobuf::RepeatedPtrField<std::string>* signed_data) {
+ MachOImageReader image_reader;
+ if (!image_reader.Initialize(data, data_size))
+ return false;
+
+ // If the image is fat, get all its MachO images. Otherwise, just scan
+ // the thin image.
+ std::vector<MachOImageReader*> images;
+ if (image_reader.IsFat())
+ images = image_reader.GetFatImages();
+ else
+ images.push_back(&image_reader);
+
+ for (auto* mach_o_reader : images) {
+ // Record the entire mach_header struct.
+ auto* mach_o_headers = image_headers->mutable_mach_o_headers()->Add();
+ if (mach_o_reader->Is64Bit()) {
+ const mach_header_64* header = mach_o_reader->GetMachHeader64();
+ mach_o_headers->set_mach_header(header, sizeof(*header));
+ } else {
+ const mach_header* header = mach_o_reader->GetMachHeader();
+ mach_o_headers->set_mach_header(header, sizeof(*header));
+ }
+
+ // Store the load commands for the Mach-O binary.
+ auto* proto_load_commands = mach_o_headers->mutable_load_commands();
+ const std::vector<MachOImageReader::LoadCommand>& load_commands =
+ mach_o_reader->GetLoadCommands();
+ for (const auto& load_command : load_commands) {
+ auto* proto_load_command = proto_load_commands->Add();
+ proto_load_command->set_command_id(load_command.cmd());
+ proto_load_command->set_command(&load_command.data[0],
+ load_command.data.size());
+ }
+
+ // Get the signature information.
+ if (signed_data) {
+ std::vector<uint8_t> code_signature;
+ if (mach_o_reader->GetCodeSignatureInfo(&code_signature)) {
+ signed_data->Add()->append(
+ reinterpret_cast<const char*>(&code_signature[0]),
+ code_signature.size());
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/binary_feature_extractor_mac_unittest.cc b/chromium/chrome/common/safe_browsing/binary_feature_extractor_mac_unittest.cc
new file mode 100644
index 00000000000..a1f44455be4
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/binary_feature_extractor_mac_unittest.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 "chrome/common/safe_browsing/binary_feature_extractor.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_paths.h"
+#include "components/safe_browsing/proto/csd.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+namespace {
+
+class BinaryFeatureExtractorMacTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_));
+ feature_extractor_ = new BinaryFeatureExtractor();
+ }
+
+ base::FilePath GetPath(const char* file_name) {
+ return test_data_.AppendASCII("safe_browsing")
+ .AppendASCII("mach_o")
+ .AppendASCII(file_name);
+ }
+
+ BinaryFeatureExtractor* feature_extractor() {
+ return feature_extractor_.get();
+ }
+
+ private:
+ base::FilePath test_data_;
+ scoped_refptr<BinaryFeatureExtractor> feature_extractor_;
+};
+
+TEST_F(BinaryFeatureExtractorMacTest, UnsignedMachOThin) {
+ ClientDownloadRequest_ImageHeaders image_headers;
+ google::protobuf::RepeatedPtrField<std::string> signed_data;
+
+ base::FilePath path = GetPath("lib32.dylib");
+ ASSERT_TRUE(feature_extractor()->ExtractImageFeatures(
+ path, 0, &image_headers, &signed_data));
+
+ EXPECT_EQ(1, image_headers.mach_o_headers().size());
+ EXPECT_EQ(0, signed_data.size());
+}
+
+TEST_F(BinaryFeatureExtractorMacTest, SignedMachOFat) {
+ ClientDownloadRequest_ImageHeaders image_headers;
+ google::protobuf::RepeatedPtrField<std::string> signed_data;
+
+ base::FilePath path = GetPath("signedexecutablefat");
+ ASSERT_TRUE(feature_extractor()->ExtractImageFeatures(
+ path, 0, &image_headers, &signed_data));
+
+ EXPECT_EQ(2, image_headers.mach_o_headers().size());
+ EXPECT_EQ(2, signed_data.size());
+}
+
+TEST_F(BinaryFeatureExtractorMacTest, NotMachO) {
+ ClientDownloadRequest_ImageHeaders image_headers;
+ google::protobuf::RepeatedPtrField<std::string> signed_data;
+
+ base::FilePath path = GetPath("src.c");
+ EXPECT_FALSE(feature_extractor()->ExtractImageFeatures(
+ path, 0, &image_headers, &signed_data));
+
+ EXPECT_EQ(0, image_headers.mach_o_headers().size());
+ EXPECT_EQ(0, signed_data.size());
+}
+
+} // namespace
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/binary_feature_extractor_posix.cc b/chromium/chrome/common/safe_browsing/binary_feature_extractor_posix.cc
new file mode 100644
index 00000000000..03bf9a1494f
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/binary_feature_extractor_posix.cc
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This is a stub for the code signing utilities on Mac and Linux.
+// It should eventually be replaced with a real implementation.
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "build/build_config.h"
+#include "chrome/common/safe_browsing/binary_feature_extractor.h"
+
+namespace safe_browsing {
+
+void BinaryFeatureExtractor::CheckSignature(
+ const base::FilePath& file_path,
+ ClientDownloadRequest_SignatureInfo* signature_info) {}
+
+#if !defined(OS_MACOSX)
+bool BinaryFeatureExtractor::ExtractImageFeaturesFromData(
+ const uint8_t* data, size_t data_size,
+ ExtractHeadersOption options,
+ ClientDownloadRequest_ImageHeaders* image_headers,
+ google::protobuf::RepeatedPtrField<std::string>* signed_data) {
+ return false;
+}
+#endif
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/binary_feature_extractor_unittest.cc b/chromium/chrome/common/safe_browsing/binary_feature_extractor_unittest.cc
new file mode 100644
index 00000000000..8cc98238565
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/binary_feature_extractor_unittest.cc
@@ -0,0 +1,106 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/binary_feature_extractor.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include <memory>
+
+#include "base/base_paths.h"
+#include "base/files/file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "components/safe_browsing/proto/csd.pb.h"
+#include "crypto/sha2.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+
+class BinaryFeatureExtractorTest : public testing::Test {
+ protected:
+ BinaryFeatureExtractorTest() : extractor_(new BinaryFeatureExtractor()) {}
+
+ void SetUp() override {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ path_ = temp_dir_.GetPath().Append(FILE_PATH_LITERAL("file.dll"));
+ }
+
+ // Writes |size| bytes from |data| to |path_|.
+ void WriteFileToHash(const char* data, int size) {
+ base::File file(path_, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+ ASSERT_TRUE(file.IsValid());
+ ASSERT_EQ(size, file.WriteAtCurrentPos(data, size));
+ }
+
+ // Verifies that |path_| hashes to |digest|.
+ void ExpectFileDigestEq(const uint8_t* digest) {
+ ClientDownloadRequest_Digests digests;
+ extractor_->ExtractDigest(path_, &digests);
+ EXPECT_TRUE(digests.has_sha256());
+ EXPECT_EQ(std::string(reinterpret_cast<const char*>(digest),
+ crypto::kSHA256Length),
+ digests.sha256());
+ }
+
+ static const int kBlockSize = 1 << 12;
+ scoped_refptr<BinaryFeatureExtractor> extractor_;
+ base::ScopedTempDir temp_dir_;
+
+ // The path to a file that may be hashed.
+ base::FilePath path_;
+};
+
+TEST_F(BinaryFeatureExtractorTest, ExtractDigestNoFile) {
+ base::FilePath no_file =
+ temp_dir_.GetPath().Append(FILE_PATH_LITERAL("does_not_exist.dll"));
+
+ ClientDownloadRequest_Digests digests;
+ extractor_->ExtractDigest(no_file, &digests);
+ EXPECT_FALSE(digests.has_sha256());
+}
+
+// Hash a file that is less than 1 4k block.
+TEST_F(BinaryFeatureExtractorTest, ExtractSmallDigest) {
+ static const uint8_t kDigest[] = {
+ 0x70, 0x27, 0x7b, 0xad, 0xfc, 0xb9, 0x97, 0x6b, 0x24, 0xf9, 0x80,
+ 0x22, 0x26, 0x2c, 0x31, 0xea, 0x8f, 0xb2, 0x1f, 0x54, 0x93, 0x6b,
+ 0x69, 0x8b, 0x5d, 0x54, 0xd4, 0xd4, 0x21, 0x0b, 0x98, 0xb7};
+
+ static const char kFileData[] = {"The mountains are robotic."};
+ static const int kDataLen = sizeof(kFileData) - 1;
+ WriteFileToHash(kFileData, kDataLen);
+ ExpectFileDigestEq(kDigest);
+}
+
+// Hash a file that is exactly 1 4k block.
+TEST_F(BinaryFeatureExtractorTest, ExtractOneBlockDigest) {
+ static const uint8_t kDigest[] = {
+ 0x4f, 0x93, 0x6e, 0xee, 0x89, 0x55, 0xa5, 0xe7, 0x46, 0xd0, 0x61,
+ 0x43, 0x54, 0x5f, 0x33, 0x7b, 0xdc, 0x30, 0x3a, 0x4b, 0x18, 0xb4,
+ 0x82, 0x20, 0xe3, 0x93, 0x4c, 0x65, 0xe0, 0xc1, 0xc0, 0x19};
+
+ const int kDataLen = kBlockSize;
+ std::unique_ptr<char[]> data(new char[kDataLen]);
+ memset(data.get(), 71, kDataLen);
+ WriteFileToHash(data.get(), kDataLen);
+ ExpectFileDigestEq(kDigest);
+}
+
+// Hash a file that is larger than 1 4k block.
+TEST_F(BinaryFeatureExtractorTest, ExtractBigBlockDigest) {
+ static const uint8_t kDigest[] = {
+ 0xda, 0xae, 0xa0, 0xd5, 0x3b, 0xce, 0x0b, 0x4e, 0x5f, 0x5d, 0x0b,
+ 0xc7, 0x6a, 0x69, 0x0e, 0xf1, 0x8b, 0x2d, 0x20, 0xcd, 0xf2, 0x6d,
+ 0x33, 0xa7, 0x70, 0xf3, 0x6b, 0x85, 0xbf, 0xce, 0x9d, 0x5c};
+
+ const int kDataLen = kBlockSize + 1;
+ std::unique_ptr<char[]> data(new char[kDataLen]);
+ memset(data.get(), 71, kDataLen);
+ WriteFileToHash(data.get(), kDataLen);
+ ExpectFileDigestEq(kDigest);
+}
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/binary_feature_extractor_win.cc b/chromium/chrome/common/safe_browsing/binary_feature_extractor_win.cc
new file mode 100644
index 00000000000..6178112370a
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/binary_feature_extractor_win.cc
@@ -0,0 +1,173 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/binary_feature_extractor.h"
+
+#include <windows.h>
+#include <softpub.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <wintrust.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/threading/scoped_thread_priority.h"
+#include "chrome/common/safe_browsing/pe_image_reader_win.h"
+#include "components/safe_browsing/proto/csd.pb.h"
+
+namespace safe_browsing {
+
+namespace {
+
+// An EnumCertificatesCallback that collects each SignedData blob.
+bool OnCertificateEntry(uint16_t revision,
+ uint16_t certificate_type,
+ const uint8_t* certificate_data,
+ size_t certificate_data_size,
+ void* context) {
+ google::protobuf::RepeatedPtrField<std::string>* signed_data =
+ reinterpret_cast<google::protobuf::RepeatedPtrField<std::string>*>(
+ context);
+
+ if (revision == WIN_CERT_REVISION_2_0 &&
+ certificate_type == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
+ signed_data->Add()->assign(certificate_data,
+ certificate_data + certificate_data_size);
+ }
+ return true;
+}
+
+} // namespace
+
+void BinaryFeatureExtractor::CheckSignature(
+ const base::FilePath& file_path,
+ ClientDownloadRequest_SignatureInfo* signature_info) {
+ // Mitigate the issues caused by loading DLLs on a background thread
+ // (http://crbug/973868).
+ base::ScopedThreadMayLoadLibraryOnBackgroundThread priority_boost(FROM_HERE);
+
+ DVLOG(2) << "Checking signature for " << file_path.value();
+
+ WINTRUST_FILE_INFO file_info = {0};
+ file_info.cbStruct = sizeof(file_info);
+ file_info.pcwszFilePath = file_path.value().c_str();
+ file_info.hFile = NULL;
+ file_info.pgKnownSubject = NULL;
+
+ WINTRUST_DATA wintrust_data = {0};
+ wintrust_data.cbStruct = sizeof(wintrust_data);
+ wintrust_data.pPolicyCallbackData = NULL;
+ wintrust_data.pSIPClientData = NULL;
+ wintrust_data.dwUIChoice = WTD_UI_NONE;
+ wintrust_data.fdwRevocationChecks = WTD_REVOKE_NONE;
+ wintrust_data.dwUnionChoice = WTD_CHOICE_FILE;
+ wintrust_data.pFile = &file_info;
+ wintrust_data.dwStateAction = WTD_STATEACTION_VERIFY;
+ wintrust_data.hWVTStateData = NULL;
+ wintrust_data.pwszURLReference = NULL;
+ // Disallow revocation checks over the network.
+ wintrust_data.dwProvFlags = WTD_CACHE_ONLY_URL_RETRIEVAL;
+ wintrust_data.dwUIContext = WTD_UICONTEXT_EXECUTE;
+
+ // The WINTRUST_ACTION_GENERIC_VERIFY_V2 policy verifies that the certificate
+ // chains up to a trusted root CA, and that it has appropriate permission to
+ // sign code.
+ GUID policy_guid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
+
+ LONG result = WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE),
+ &policy_guid,
+ &wintrust_data);
+
+ CRYPT_PROVIDER_DATA* prov_data = WTHelperProvDataFromStateData(
+ wintrust_data.hWVTStateData);
+ if (prov_data) {
+ if (prov_data->csSigners > 0) {
+ signature_info->set_trusted(result == ERROR_SUCCESS);
+ }
+ for (DWORD i = 0; i < prov_data->csSigners; ++i) {
+ const CERT_CHAIN_CONTEXT* cert_chain_context =
+ prov_data->pasSigners[i].pChainContext;
+ if (!cert_chain_context)
+ break;
+ for (DWORD j = 0; j < cert_chain_context->cChain; ++j) {
+ CERT_SIMPLE_CHAIN* simple_chain = cert_chain_context->rgpChain[j];
+ ClientDownloadRequest_CertificateChain* chain =
+ signature_info->add_certificate_chain();
+ if (!simple_chain)
+ break;
+ for (DWORD k = 0; k < simple_chain->cElement; ++k) {
+ CERT_CHAIN_ELEMENT* element = simple_chain->rgpElement[k];
+ chain->add_element()->set_certificate(
+ element->pCertContext->pbCertEncoded,
+ element->pCertContext->cbCertEncoded);
+ }
+ }
+ }
+
+ // Free the provider data.
+ wintrust_data.dwStateAction = WTD_STATEACTION_CLOSE;
+ WinVerifyTrust(static_cast<HWND>(INVALID_HANDLE_VALUE),
+ &policy_guid, &wintrust_data);
+ }
+}
+
+bool BinaryFeatureExtractor::ExtractImageFeaturesFromData(
+ const uint8_t* data, size_t data_size,
+ ExtractHeadersOption options,
+ ClientDownloadRequest_ImageHeaders* image_headers,
+ google::protobuf::RepeatedPtrField<std::string>* signed_data) {
+ PeImageReader pe_image;
+ if (!pe_image.Initialize(data, data_size))
+ return false;
+
+ // Copy the headers.
+ ClientDownloadRequest_PEImageHeaders* pe_headers =
+ image_headers->mutable_pe_headers();
+ pe_headers->set_dos_header(pe_image.GetDosHeader(), sizeof(IMAGE_DOS_HEADER));
+ pe_headers->set_file_header(pe_image.GetCoffFileHeader(),
+ sizeof(IMAGE_FILE_HEADER));
+ size_t optional_header_size = 0;
+ const uint8_t* optional_header_data =
+ pe_image.GetOptionalHeaderData(&optional_header_size);
+ if (pe_image.GetWordSize() == PeImageReader::WORD_SIZE_32) {
+ pe_headers->set_optional_headers32(optional_header_data,
+ optional_header_size);
+ } else {
+ pe_headers->set_optional_headers64(optional_header_data,
+ optional_header_size);
+ }
+ const size_t number_of_sections = pe_image.GetNumberOfSections();
+ for (size_t i = 0; i != number_of_sections; ++i) {
+ pe_headers->add_section_header(pe_image.GetSectionHeaderAt(i),
+ sizeof(IMAGE_SECTION_HEADER));
+ }
+ if (!(options & BinaryFeatureExtractor::kOmitExports)) {
+ size_t export_size = 0;
+ const uint8_t* export_section = pe_image.GetExportSection(&export_size);
+ if (export_section)
+ pe_headers->set_export_section_data(export_section, export_size);
+ }
+ size_t number_of_debug_entries = pe_image.GetNumberOfDebugEntries();
+ for (size_t i = 0; i != number_of_debug_entries; ++i) {
+ const uint8_t* raw_data = NULL;
+ size_t raw_data_size = 0;
+ const IMAGE_DEBUG_DIRECTORY* directory_entry =
+ pe_image.GetDebugEntry(i, &raw_data, &raw_data_size);
+ if (directory_entry) {
+ ClientDownloadRequest_PEImageHeaders_DebugData* debug_data =
+ pe_headers->add_debug_data();
+ debug_data->set_directory_entry(directory_entry,
+ sizeof(*directory_entry));
+ if (raw_data)
+ debug_data->set_raw_data(raw_data, raw_data_size);
+ }
+ }
+
+ if (signed_data)
+ pe_image.EnumCertificates(&OnCertificateEntry, signed_data);
+
+ return true;
+}
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/binary_feature_extractor_win_unittest.cc b/chromium/chrome/common/safe_browsing/binary_feature_extractor_win_unittest.cc
new file mode 100644
index 00000000000..619d63c9a43
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/binary_feature_extractor_win_unittest.cc
@@ -0,0 +1,210 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/binary_feature_extractor.h"
+
+#include <string>
+#include <vector>
+
+#include "base/base_paths.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_paths.h"
+#include "components/safe_browsing/proto/csd.pb.h"
+#include "net/cert/x509_cert_types.h"
+#include "net/cert/x509_certificate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+
+class BinaryFeatureExtractorWinTest : public testing::Test {
+ protected:
+ void SetUp() override {
+ base::FilePath source_path;
+ ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &source_path));
+ testdata_path_ = source_path
+ .AppendASCII("safe_browsing")
+ .AppendASCII("download_protection");
+
+ binary_feature_extractor_ = new BinaryFeatureExtractor();
+ }
+
+ // Given a certificate chain protobuf, parse it into X509Certificates.
+ void ParseCertificateChain(
+ const ClientDownloadRequest_CertificateChain& chain,
+ std::vector<scoped_refptr<net::X509Certificate> >* certs) {
+ for (int i = 0; i < chain.element_size(); ++i) {
+ scoped_refptr<net::X509Certificate> cert =
+ net::X509Certificate::CreateFromBytes(
+ chain.element(i).certificate().data(),
+ chain.element(i).certificate().size());
+ if (cert)
+ certs->push_back(cert);
+ }
+ }
+
+ base::FilePath testdata_path_;
+ scoped_refptr<BinaryFeatureExtractor> binary_feature_extractor_;
+};
+
+TEST_F(BinaryFeatureExtractorWinTest, UntrustedSignedBinary) {
+ // signed.exe is signed by an untrusted root CA.
+ ClientDownloadRequest_SignatureInfo signature_info;
+ binary_feature_extractor_->CheckSignature(
+ testdata_path_.Append(L"signed.exe"),
+ &signature_info);
+ ASSERT_EQ(1, signature_info.certificate_chain_size());
+ std::vector<scoped_refptr<net::X509Certificate> > certs;
+ ParseCertificateChain(signature_info.certificate_chain(0), &certs);
+ ASSERT_EQ(2u, certs.size());
+ EXPECT_EQ("Joe's-Software-Emporium", certs[0]->subject().common_name);
+ EXPECT_EQ("Root Agency", certs[1]->subject().common_name);
+
+ EXPECT_TRUE(signature_info.has_trusted());
+ EXPECT_FALSE(signature_info.trusted());
+}
+
+TEST_F(BinaryFeatureExtractorWinTest, TrustedBinary) {
+ // disable_outdated_build_detector.exe is dual signed using Google's signing
+ // certifiacte.
+ ClientDownloadRequest_SignatureInfo signature_info;
+ binary_feature_extractor_->CheckSignature(
+ testdata_path_.Append(L"disable_outdated_build_detector.exe"),
+ &signature_info);
+ ASSERT_EQ(1, signature_info.certificate_chain_size());
+ std::vector<scoped_refptr<net::X509Certificate> > certs;
+ ParseCertificateChain(signature_info.certificate_chain(0), &certs);
+ ASSERT_EQ(3u, certs.size());
+
+ EXPECT_EQ("Google Inc", certs[0]->subject().common_name);
+ EXPECT_EQ("VeriSign Class 3 Code Signing 2010 CA",
+ certs[1]->subject().common_name);
+ EXPECT_EQ("VeriSign Trust Network",
+ certs[2]->subject().organization_unit_names[0]);
+
+ EXPECT_TRUE(signature_info.trusted());
+}
+
+TEST_F(BinaryFeatureExtractorWinTest, UnsignedBinary) {
+ // unsigned.exe has no signature information.
+ ClientDownloadRequest_SignatureInfo signature_info;
+ binary_feature_extractor_->CheckSignature(
+ testdata_path_.Append(L"unsigned.exe"),
+ &signature_info);
+ EXPECT_EQ(0, signature_info.certificate_chain_size());
+ EXPECT_FALSE(signature_info.has_trusted());
+}
+
+TEST_F(BinaryFeatureExtractorWinTest, NonExistentBinary) {
+ // Test a file that doesn't exist.
+ ClientDownloadRequest_SignatureInfo signature_info;
+ binary_feature_extractor_->CheckSignature(
+ testdata_path_.Append(L"doesnotexist.exe"),
+ &signature_info);
+ EXPECT_EQ(0, signature_info.certificate_chain_size());
+ EXPECT_FALSE(signature_info.has_trusted());
+}
+
+TEST_F(BinaryFeatureExtractorWinTest, ExtractImageFeaturesNoFile) {
+ // Test extracting headers from a file that doesn't exist.
+ ClientDownloadRequest_ImageHeaders image_headers;
+ ASSERT_FALSE(binary_feature_extractor_->ExtractImageFeatures(
+ testdata_path_.AppendASCII("this_file_does_not_exist"),
+ BinaryFeatureExtractor::kDefaultOptions, &image_headers,
+ nullptr /* signed_data */));
+ EXPECT_FALSE(image_headers.has_pe_headers());
+}
+
+TEST_F(BinaryFeatureExtractorWinTest, ExtractImageFeaturesNonImage) {
+ // Test extracting headers from something that is not a PE image.
+ ClientDownloadRequest_ImageHeaders image_headers;
+ ASSERT_FALSE(binary_feature_extractor_->ExtractImageFeatures(
+ testdata_path_.AppendASCII("simple_exe.cc"),
+ BinaryFeatureExtractor::kDefaultOptions, &image_headers,
+ nullptr /* signed_data */));
+ EXPECT_FALSE(image_headers.has_pe_headers());
+}
+
+TEST_F(BinaryFeatureExtractorWinTest, ExtractImageFeatures) {
+ // Test extracting features from something that is a PE image.
+ ClientDownloadRequest_ImageHeaders image_headers;
+ google::protobuf::RepeatedPtrField<std::string> signed_data;
+ ASSERT_TRUE(binary_feature_extractor_->ExtractImageFeatures(
+ testdata_path_.AppendASCII("unsigned.exe"),
+ BinaryFeatureExtractor::kDefaultOptions, &image_headers, &signed_data));
+ EXPECT_TRUE(image_headers.has_pe_headers());
+ const ClientDownloadRequest_PEImageHeaders& pe_headers =
+ image_headers.pe_headers();
+ EXPECT_TRUE(pe_headers.has_dos_header());
+ EXPECT_TRUE(pe_headers.has_file_header());
+ EXPECT_TRUE(pe_headers.has_optional_headers32());
+ EXPECT_FALSE(pe_headers.has_optional_headers64());
+ EXPECT_NE(0, pe_headers.section_header_size());
+ EXPECT_FALSE(pe_headers.has_export_section_data());
+ EXPECT_EQ(0, pe_headers.debug_data_size());
+ EXPECT_EQ(0, signed_data.size());
+}
+
+TEST_F(BinaryFeatureExtractorWinTest, ExtractImageFeaturesWithDebugData) {
+ // Test extracting headers from something that is a PE image with debug data.
+ ClientDownloadRequest_ImageHeaders image_headers;
+ ASSERT_TRUE(binary_feature_extractor_->ExtractImageFeatures(
+ testdata_path_.DirName().AppendASCII("module_with_exports_x86.dll"),
+ BinaryFeatureExtractor::kDefaultOptions, &image_headers,
+ nullptr /* signed_data */));
+ EXPECT_TRUE(image_headers.has_pe_headers());
+ const ClientDownloadRequest_PEImageHeaders& pe_headers =
+ image_headers.pe_headers();
+ EXPECT_TRUE(pe_headers.has_dos_header());
+ EXPECT_TRUE(pe_headers.has_file_header());
+ EXPECT_TRUE(pe_headers.has_optional_headers32());
+ EXPECT_FALSE(pe_headers.has_optional_headers64());
+ EXPECT_NE(0, pe_headers.section_header_size());
+ EXPECT_TRUE(pe_headers.has_export_section_data());
+ EXPECT_EQ(1, pe_headers.debug_data_size());
+}
+
+TEST_F(BinaryFeatureExtractorWinTest, ExtractImageFeaturesWithoutExports) {
+ // Test extracting headers from something that is a PE image with debug data.
+ ClientDownloadRequest_ImageHeaders image_headers;
+ ASSERT_TRUE(binary_feature_extractor_->ExtractImageFeatures(
+ testdata_path_.DirName().AppendASCII("module_with_exports_x86.dll"),
+ BinaryFeatureExtractor::kOmitExports, &image_headers,
+ nullptr /* signed_data */));
+ EXPECT_TRUE(image_headers.has_pe_headers());
+ const ClientDownloadRequest_PEImageHeaders& pe_headers =
+ image_headers.pe_headers();
+ EXPECT_TRUE(pe_headers.has_dos_header());
+ EXPECT_TRUE(pe_headers.has_file_header());
+ EXPECT_TRUE(pe_headers.has_optional_headers32());
+ EXPECT_FALSE(pe_headers.has_optional_headers64());
+ EXPECT_NE(0, pe_headers.section_header_size());
+ EXPECT_FALSE(pe_headers.has_export_section_data());
+ EXPECT_EQ(1, pe_headers.debug_data_size());
+}
+
+TEST_F(BinaryFeatureExtractorWinTest, ExtractImageFeaturesUntrustedSigned) {
+ // Test extracting features from a signed PE image.
+ ClientDownloadRequest_ImageHeaders image_headers;
+ google::protobuf::RepeatedPtrField<std::string> signed_data;
+ ASSERT_TRUE(binary_feature_extractor_->ExtractImageFeatures(
+ testdata_path_.AppendASCII("signed.exe"),
+ BinaryFeatureExtractor::kDefaultOptions, &image_headers, &signed_data));
+ ASSERT_EQ(1, signed_data.size());
+ ASSERT_LT(0U, signed_data.Get(0).size());
+}
+
+TEST_F(BinaryFeatureExtractorWinTest, ExtractImageFeaturesTrustedSigned) {
+ // Test extracting features from a signed PE image from a trusted root.
+ ClientDownloadRequest_ImageHeaders image_headers;
+ google::protobuf::RepeatedPtrField<std::string> signed_data;
+ ASSERT_TRUE(binary_feature_extractor_->ExtractImageFeatures(
+ testdata_path_.AppendASCII("disable_outdated_build_detector.exe"),
+ BinaryFeatureExtractor::kDefaultOptions, &image_headers, &signed_data));
+ ASSERT_EQ(1, signed_data.size());
+ ASSERT_LT(0U, signed_data.Get(0).size());
+}
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/client_model.proto b/chromium/chrome/common/safe_browsing/client_model.proto
new file mode 100644
index 00000000000..8216682b2af
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/client_model.proto
@@ -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.
+//
+// This proto represents a machine learning model which is used to compute
+// the probability that a particular page visited by Chrome is phishing.
+//
+// Note: sine the machine learning model is trained on the server-side and then
+// downloaded onto the client it is important that this proto file stays in
+// sync with the server-side copy. Otherwise, the client may not be able to
+// parse the server generated model anymore. If you want to change this
+// protocol definition or you have questions regarding its format please contact
+// chrome-anti-phishing@googlegroups.com.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package safe_browsing;
+
+// This protocol buffer represents a machine learning model that is used in
+// client-side phishing detection (in Chrome). The client extracts a set
+// of features from every website the user visits. Extracted features map
+// feature names to floating point values (e.g., PageSecureLinksFreq -> 0.9).
+//
+// To compute the phishing score (i.e., the probability that the website is
+// phishing) a scorer will simply compute the sum of all rule scores for a
+// given set of extracted features. The score of a particular rule corresponds
+// to the product of all feature values that are part of the rule times the
+// rule weight. If a feature has no value (i.e., is not part of the extracted
+// features) its value will be set to zero. The overall score is computed
+// by summing up all the rule scores. This overall score is a logodds and can
+// be converted to a probability like this:
+// p = exp(logodds) / (exp(logodds) + 1).
+//
+// To make it harder for phishers to reverse engineer our machine learning model
+// all the features in the model are hashed with a sha256 hash function. The
+// feature extractors also hash the extracted features before scoring happens.
+message ClientSideModel {
+ // In order to save some space we store all the hashed strings in a
+ // single repeated field and then the rules as well as page terms
+ // and page words refer to an index in that repeated field. All
+ // hashes are sha256 hashes stored in binary format.
+ repeated bytes hashes = 1;
+
+ message Rule {
+ // List of indexes into hashes above which are basically hashed
+ // features that form the current rule.
+ repeated int32 feature = 1;
+
+ // The weight for this particular rule.
+ required float weight = 2;
+ }
+
+ // List of rules which make up the model
+ repeated Rule rule = 2;
+
+ // List of indexes that point to the hashed page terms that appear in
+ // the model. The hashes are computed over page terms that are encoded
+ // as lowercase UTF-8 strings.
+ repeated int32 page_term = 3;
+
+ // List of hashed page words. The page words correspond to all words that
+ // appear in page terms. If the term "one two" is in the list of page terms
+ // then "one" and "two" will be in the list of page words. For page words
+ // we don't use SHA256 because it is too expensive. We use MurmurHash3
+ // instead. See: http://code.google.com/p/smhasher.
+ repeated fixed32 page_word = 4;
+
+ // Page terms in page_term contain at most this many page words.
+ required int32 max_words_per_term = 5;
+
+ // Model version number. Every model that we train should have a different
+ // version number and it should always be larger than the previous model
+ // version.
+ optional int32 version = 6;
+
+ // List of known bad IP subnets.
+ message IPSubnet {
+ // The subnet prefix is a valid 16-byte IPv6 address (in network order) that
+ // is hashed using sha256.
+ required bytes prefix = 1;
+
+ // Network prefix size in bits. Default is an exact-host match.
+ optional int32 size = 2 [default = 128];
+ };
+ repeated IPSubnet bad_subnet = 7;
+
+ // Murmur hash seed that was used to hash the page words.
+ optional fixed32 murmur_hash_seed = 8;
+
+ // Maximum number of unique shingle hashes per page.
+ optional int32 max_shingles_per_page = 9 [default = 200];
+
+ // The number of words in a shingle.
+ optional int32 shingle_size = 10 [default = 4];
+}
diff --git a/chromium/chrome/common/safe_browsing/crx_info.proto b/chromium/chrome/common/safe_browsing/crx_info.proto
new file mode 100644
index 00000000000..78065fcc25a
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/crx_info.proto
@@ -0,0 +1,38 @@
+// 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";
+option optimize_for = LITE_RUNTIME;
+
+package extensions;
+
+// This is used to request more information on blacklisted CRX packages. The
+// client maintains a local cache of blacklisted ids, and makes requests to our
+// server to get more information, such as the blacklist type.
+message ClientCRXListInfoRequest {
+ // ID of the CRX package.
+ required string id = 1;
+
+ // Locale of the device, eg en, en_US.
+ optional string locale = 2;
+}
+
+message ClientCRXListInfoResponse {
+ enum Verdict {
+ NOT_IN_BLACKLIST = 0;
+ MALWARE = 1;
+ SECURITY_VULNERABILITY = 2;
+ CWS_POLICY_VIOLATION = 3;
+ POTENTIALLY_UNWANTED = 4;
+ }
+ // Although listed as optional, this is required.
+ optional Verdict verdict = 1 [default=NOT_IN_BLACKLIST];
+
+ message UserMessage {
+ // If present, will be appended to disable reason in the details page. We
+ // could use this to send a URL to a blogpost or help article.
+ optional string detail_message = 1;
+ }
+ optional UserMessage user_message = 2;
+}
diff --git a/chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac.cc b/chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac.cc
new file mode 100644
index 00000000000..e0b4e34f737
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac.cc
@@ -0,0 +1,64 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/disk_image_type_sniffer_mac.h"
+#include "base/threading/scoped_blocking_call.h"
+
+namespace safe_browsing {
+
+namespace {
+
+const uint8_t kKolySignature[4] = {'k', 'o', 'l', 'y'};
+constexpr size_t kSizeKolySignatureInBytes = sizeof(kKolySignature);
+const size_t kSizeKolyTrailerInBytes = 512;
+
+} // namespace
+
+DiskImageTypeSnifferMac::DiskImageTypeSnifferMac() {}
+
+// static
+bool DiskImageTypeSnifferMac::IsAppleDiskImage(const base::FilePath& dmg_file) {
+ // TODO(drubery): Macs accept DMGs with koly blocks at the beginning of the
+ // file. Investigate if this is a problem, and if so, update this function.
+ base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+ base::BlockingType::MAY_BLOCK);
+
+ base::File file(dmg_file, base::File::FLAG_OPEN | base::File::FLAG_READ);
+ if (!file.IsValid())
+ return false;
+
+ char data[kSizeKolySignatureInBytes];
+
+ if (file.Seek(base::File::FROM_END, -1 * kSizeKolyTrailerInBytes) == -1)
+ return false;
+
+ if (file.ReadAtCurrentPos(data, kSizeKolySignatureInBytes) !=
+ kSizeKolySignatureInBytes)
+ return false;
+
+ return IsAppleDiskImageTrailer(base::span<uint8_t>(
+ reinterpret_cast<uint8_t*>(data), kSizeKolySignatureInBytes));
+}
+
+// static
+bool DiskImageTypeSnifferMac::IsAppleDiskImageTrailer(
+ const base::span<const uint8_t>& trailer) {
+ if (trailer.size() < kSizeKolySignatureInBytes)
+ return false;
+
+ const base::span<const uint8_t> subspan =
+ trailer.last(kSizeKolySignatureInBytes);
+
+ return (memcmp(subspan.data(), kKolySignature, kSizeKolySignatureInBytes) ==
+ 0);
+}
+
+// static
+size_t DiskImageTypeSnifferMac::AppleDiskImageTrailerSize() {
+ return kSizeKolyTrailerInBytes;
+}
+
+DiskImageTypeSnifferMac::~DiskImageTypeSnifferMac() = default;
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac.h b/chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac.h
new file mode 100644
index 00000000000..8581b9980a3
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac.h
@@ -0,0 +1,43 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_DISK_IMAGE_TYPE_SNIFFER_MAC_H_
+#define CHROME_COMMON_SAFE_BROWSING_DISK_IMAGE_TYPE_SNIFFER_MAC_H_
+
+#include "base/containers/span.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+
+namespace safe_browsing {
+
+// This class is used to determine whether a given file is a Mac archive type,
+// regardless of file extension. It does so by determining whether the file has
+// the 'koly' signature typical of Mac archive files.
+class DiskImageTypeSnifferMac
+ : public base::RefCountedThreadSafe<DiskImageTypeSnifferMac> {
+ public:
+ DiskImageTypeSnifferMac();
+
+ // Reads trailer from file to see if it is a DMG type. Must be called on the
+ // FILE thread.
+ static bool IsAppleDiskImage(const base::FilePath& dmg_file);
+
+ // Returns true when the trailer is a valid trailer for a DMG type.
+ static bool IsAppleDiskImageTrailer(const base::span<const uint8_t>& trailer);
+
+ // Returns the size of a DMG trailer.
+ static size_t AppleDiskImageTrailerSize();
+
+ private:
+ friend class base::RefCountedThreadSafe<DiskImageTypeSnifferMac>;
+
+ ~DiskImageTypeSnifferMac();
+
+ DISALLOW_COPY_AND_ASSIGN(DiskImageTypeSnifferMac);
+};
+
+} // namespace safe_browsing
+
+#endif // CHROME_COMMON_SAFE_BROWSING_DISK_IMAGE_TYPE_SNIFFE_MAC_H_
diff --git a/chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac_unittest.cc b/chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac_unittest.cc
new file mode 100644
index 00000000000..6974174b3c8
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/disk_image_type_sniffer_mac_unittest.cc
@@ -0,0 +1,115 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/disk_image_type_sniffer_mac.h"
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "chrome/common/chrome_paths.h"
+#include "content/public/test/browser_task_environment.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+namespace {
+
+struct ArchiveTestCase {
+ // The disk image file to open.
+ const char* file_name;
+
+ // Expectation regarding the file being recognized as a DMG. As the UDIFParser
+ // class currently only supports certain UDIF features, this is used to
+ // properly test expectations.
+ bool expected_results;
+};
+
+std::ostream& operator<<(std::ostream& os, const ArchiveTestCase& test_case) {
+ os << test_case.file_name;
+ return os;
+}
+
+class DiskImageTypeSnifferMacTest
+ : public testing::TestWithParam<ArchiveTestCase> {
+ protected:
+ base::FilePath GetFilePath(const char* file_name) {
+ base::FilePath test_data;
+ EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data));
+ return test_data.AppendASCII("safe_browsing")
+ .AppendASCII("dmg")
+ .AppendASCII("data")
+ .AppendASCII(file_name);
+ }
+
+ private:
+ content::BrowserTaskEnvironment task_environment_;
+};
+
+TEST_P(DiskImageTypeSnifferMacTest, SniffDiskImage) {
+ const ArchiveTestCase& test_case = GetParam();
+ DVLOG(1) << "Test case: " << test_case;
+
+ base::FilePath path;
+ ASSERT_NO_FATAL_FAILURE(path = GetFilePath(test_case.file_name));
+
+ ASSERT_EQ(test_case.expected_results,
+ DiskImageTypeSnifferMac::IsAppleDiskImage(path));
+}
+
+const ArchiveTestCase cases[] = {
+ {"dmg_UDBZ_GPTSPUD.dmg", true},
+ {"dmg_UDBZ_NONE.dmg", true},
+ {"dmg_UDBZ_SPUD.dmg", true},
+ {"dmg_UDCO_GPTSPUD.dmg", true},
+ {"dmg_UDCO_NONE.dmg", true},
+ {"dmg_UDCO_SPUD.dmg", true},
+ {"dmg_UDRO_GPTSPUD.dmg", true},
+ {"dmg_UDRO_NONE.dmg", true},
+ {"dmg_UDRO_SPUD.dmg", true},
+ // UDRW not supported.
+ {"dmg_UDRW_GPTSPUD.dmg", false},
+ // UDRW not supported.
+ {"dmg_UDRW_NONE.dmg", false},
+ // UDRW not supported.
+ {"dmg_UDRW_SPUD.dmg", false},
+ // Sparse images not supported.
+ {"dmg_UDSP_GPTSPUD.sparseimage", false},
+ // UDRW not supported.
+ {"dmg_UDSP_NONE.sparseimage", false},
+ // Sparse images not supported.
+ {"dmg_UDSP_SPUD.sparseimage", false},
+ // CD/DVD format not supported.
+ {"dmg_UDTO_GPTSPUD.cdr", false},
+ // CD/DVD format not supported.
+ {"dmg_UDTO_NONE.cdr", false},
+ // CD/DVD format not supported.
+ {"dmg_UDTO_SPUD.cdr", false},
+ {"dmg_UDZO_GPTSPUD.dmg", true},
+ {"dmg_UDZO_SPUD.dmg", true},
+ {"dmg_UFBI_GPTSPUD.dmg", true},
+ {"dmg_UFBI_SPUD.dmg", true},
+ {"mach_o_in_dmg.dmg", true},
+ // Absence of 'koly' signature will cause parsing to fail - even if file has
+ // .dmg extension.
+ {"mach_o_in_dmg_no_koly_signature.dmg", false},
+ // Type sniffer should realize DMG type even without extension.
+ {"mach_o_in_dmg.txt", true}
+
+};
+
+INSTANTIATE_TEST_SUITE_P(DiskImageTypeSnifferMacTestInstantiation,
+ DiskImageTypeSnifferMacTest,
+ testing::ValuesIn(cases));
+
+TEST(DiskImageTypeSnifferMacTest, IsAppleDiskImageTrailerIsCorrect) {
+ uint8_t good_header[4] = {'k', 'o', 'l', 'y'};
+ EXPECT_TRUE(DiskImageTypeSnifferMac::IsAppleDiskImageTrailer(good_header));
+
+ uint8_t bad_header[6] = {'f', 'o', 'o', 'b', 'a', 'r'};
+ EXPECT_FALSE(DiskImageTypeSnifferMac::IsAppleDiskImageTrailer(bad_header));
+}
+
+} // namespace
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/download_file_types.proto b/chromium/chrome/common/safe_browsing/download_file_types.proto
new file mode 100644
index 00000000000..f9e2f3bb561
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/download_file_types.proto
@@ -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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package safe_browsing;
+
+// See //chrome/browser/resources/safe_browsing/README.md for guidelines
+// on how to set fields in this file.
+
+// Next id: 5
+message DownloadFileType {
+ optional string extension = 1; // required, except in default_file_type.
+ optional int64 uma_value = 2; // required
+ optional bool is_archive = 3 [default = false];
+
+ enum PingSetting {
+ SAMPLED_PING = 0;
+ NO_PING = 1;
+ FULL_PING = 2;
+ }
+ optional PingSetting ping_setting = 4; // required
+
+ enum DangerLevel {
+ NOT_DANGEROUS = 0;
+ ALLOW_ON_USER_GESTURE = 1;
+ DANGEROUS = 2;
+ }
+
+ enum AutoOpenHint {
+ DISALLOW_AUTO_OPEN = 0;
+ ALLOW_AUTO_OPEN = 1;
+ }
+
+ enum PlatformType {
+ PLATFORM_ANY = 0;
+ PLATFORM_ANDROID = 1;
+ PLATFORM_CHROME_OS = 2;
+ PLATFORM_LINUX = 3;
+ PLATFORM_MAC = 4;
+ PLATFORM_WINDOWS = 5;
+ }
+
+ // Next id: 5
+ message PlatformSettings {
+ optional PlatformType platform = 1 [default = PLATFORM_ANY];
+ optional DangerLevel danger_level = 2; // required
+ optional AutoOpenHint auto_open_hint = 3; // required
+ optional uint64 max_file_size_to_analyze = 4
+ [default = 18446744073709551615]; // (2^64)-1]
+ };
+
+ // Protos parsed by Chrome should have exactly one entry here.
+ repeated PlatformSettings platform_settings = 5;
+
+ // The type of file content inspection we should do, if any.
+ enum InspectionType {
+ NONE = 0;
+ ZIP = 1;
+ RAR = 2;
+ DMG = 3;
+ }
+ optional InspectionType inspection_type = 6;
+};
+
+// Next id: 6
+message DownloadFileTypeConfig {
+ // All required
+ optional uint32 version_id = 1;
+ optional float sampled_ping_probability = 2;
+ repeated DownloadFileType file_types = 3;
+ optional DownloadFileType default_file_type = 4;
+
+ // Limits on repeated fields in the ClientDownloadRequest (i.e. the
+ // download ping). Limits are per-ping.
+ optional uint64 max_archived_binaries_to_report = 5;
+}
diff --git a/chromium/chrome/common/safe_browsing/download_type_util.cc b/chromium/chrome/common/safe_browsing/download_type_util.cc
new file mode 100644
index 00000000000..a7967401240
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/download_type_util.cc
@@ -0,0 +1,101 @@
+// 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 "chrome/common/safe_browsing/download_type_util.h"
+
+#include <algorithm>
+
+#include "base/feature_list.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/string_util.h"
+#include "chrome/common/safe_browsing/file_type_policies.h"
+#include "components/safe_browsing/features.h"
+
+namespace safe_browsing {
+namespace download_type_util {
+
+ClientDownloadRequest::DownloadType GetDownloadType(
+ const base::FilePath& file) {
+ // TODO(nparker): Put all of this logic into the FileTypePolicies
+ // protobuf.
+ if (file.MatchesExtension(FILE_PATH_LITERAL(".apk")))
+ return ClientDownloadRequest::ANDROID_APK;
+ else if (file.MatchesExtension(FILE_PATH_LITERAL(".crx")))
+ return ClientDownloadRequest::CHROME_EXTENSION;
+ else if (file.MatchesExtension(FILE_PATH_LITERAL(".zip")))
+ // DownloadProtectionService doesn't send a ClientDownloadRequest for ZIP
+ // files unless they contain either executables or archives. The resulting
+ // DownloadType is either ZIPPED_EXECUTABLE or ZIPPED_ARCHIVE respectively.
+ // This function will return ZIPPED_EXECUTABLE for ZIP files as a
+ // placeholder. The correct DownloadType will be determined based on the
+ // result of analyzing the ZIP file.
+ return ClientDownloadRequest::ZIPPED_EXECUTABLE;
+ else if (file.MatchesExtension(FILE_PATH_LITERAL(".rar")))
+ // See the comment for .zip files.
+ return ClientDownloadRequest::RAR_COMPRESSED_EXECUTABLE;
+ else if (file.MatchesExtension(FILE_PATH_LITERAL(".dmg")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".img")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".iso")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".pkg")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".mpkg")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".smi")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".app")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".cdr")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".dmgpart")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".dvdr")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".dart")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".dc42")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".diskcopy42")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".imgpart")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".ndif")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".udif")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".toast")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".sparsebundle")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".sparseimage")))
+ return ClientDownloadRequest::MAC_EXECUTABLE;
+ else if (FileTypePolicies::GetInstance()->IsArchiveFile(file))
+ return ClientDownloadRequest::ARCHIVE;
+ else if (file.MatchesExtension(FILE_PATH_LITERAL(".pdf")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".doc")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".docx")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".docm")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".docb")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".dot")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".dotm")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".dotx")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xls")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xlsb")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xlt")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xlm")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xlsx")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xldm")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xltx")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xltm")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xlsb")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xla")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xlam")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xll")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xlw")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".ppt")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".pot")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".pps")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".pptx")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".pptm")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".potx")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".potm")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".ppam")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".ppsx")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".ppsm")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".sldx")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".xldm")) ||
+ file.MatchesExtension(FILE_PATH_LITERAL(".rtf")))
+ return ClientDownloadRequest::DOCUMENT;
+
+ return ClientDownloadRequest::WIN_EXECUTABLE;
+}
+
+} // namespace download_type_util
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/download_type_util.h b/chromium/chrome/common/safe_browsing/download_type_util.h
new file mode 100644
index 00000000000..87f17e4e479
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/download_type_util.h
@@ -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.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_DOWNLOAD_TYPE_UTIL_H_
+#define CHROME_COMMON_SAFE_BROWSING_DOWNLOAD_TYPE_UTIL_H_
+
+#include "base/files/file_path.h"
+#include "components/safe_browsing/proto/csd.pb.h"
+
+namespace safe_browsing {
+namespace download_type_util {
+
+// Returns the DownloadType of the file at |path|. This function is only valid
+// for paths that satisfy IsSupportedBinaryFile() above.
+ClientDownloadRequest::DownloadType GetDownloadType(const base::FilePath& file);
+
+} // namespace download_type_util
+} // namespace safe_browsing
+
+#endif // CHROME_COMMON_SAFE_BROWSING_DOWNLOAD_TYPE_UTIL_H_
diff --git a/chromium/chrome/common/safe_browsing/download_type_util_unittest.cc b/chromium/chrome/common/safe_browsing/download_type_util_unittest.cc
new file mode 100644
index 00000000000..9e507baca62
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/download_type_util_unittest.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/download_type_util.h"
+
+#include "base/feature_list.h"
+#include "base/files/file_path.h"
+#include "components/safe_browsing/features.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+namespace download_type_util {
+
+TEST(DownloadProtectionUtilTest, KnownValues) {
+ EXPECT_EQ(ClientDownloadRequest::WIN_EXECUTABLE,
+ GetDownloadType(base::FilePath(FILE_PATH_LITERAL("foo.exe"))));
+ EXPECT_EQ(ClientDownloadRequest::CHROME_EXTENSION,
+ GetDownloadType(base::FilePath(FILE_PATH_LITERAL("foo.crx"))));
+ EXPECT_EQ(ClientDownloadRequest::ZIPPED_EXECUTABLE,
+ GetDownloadType(base::FilePath(FILE_PATH_LITERAL("foo.zip"))));
+ EXPECT_EQ(ClientDownloadRequest::RAR_COMPRESSED_EXECUTABLE,
+ GetDownloadType(base::FilePath(FILE_PATH_LITERAL("foo.rar"))));
+ EXPECT_EQ(ClientDownloadRequest::MAC_EXECUTABLE,
+ GetDownloadType(base::FilePath(FILE_PATH_LITERAL("foo.pkg"))));
+ EXPECT_EQ(ClientDownloadRequest::ANDROID_APK,
+ GetDownloadType(base::FilePath(FILE_PATH_LITERAL("foo.apk"))));
+}
+
+} // namespace download_type_util
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/file_type_policies.cc b/chromium/chrome/common/safe_browsing/file_type_policies.cc
new file mode 100644
index 00000000000..b6f7939ff2d
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/file_type_policies.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 "chrome/common/safe_browsing/file_type_policies.h"
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/strings/string_util.h"
+#include "chrome/grit/browser_resources.h"
+#include "ui/base/resource/resource_bundle.h"
+
+namespace safe_browsing {
+
+using base::AutoLock;
+
+// Our Singleton needs to populate itself when first constructed.
+// This is left out of the constructor to make testing simpler.
+struct FileTypePoliciesSingletonTrait
+ : public base::DefaultSingletonTraits<FileTypePolicies> {
+ static FileTypePolicies* New() {
+ FileTypePolicies* instance = new FileTypePolicies();
+ instance->PopulateFromResourceBundle();
+ return instance;
+ }
+};
+
+// --- FileTypePolicies methods ---
+
+// static
+FileTypePolicies* FileTypePolicies::GetInstance() {
+ return base::Singleton<FileTypePolicies,
+ FileTypePoliciesSingletonTrait>::get();
+}
+
+FileTypePolicies::FileTypePolicies() {
+ // Setup a file-type policy to use if the ResourceBundle is unreadable.
+ // This should normally never be used.
+ last_resort_default_.set_uma_value(-1l);
+ last_resort_default_.set_ping_setting(DownloadFileType::NO_PING);
+ auto* settings = last_resort_default_.add_platform_settings();
+ settings->set_danger_level(DownloadFileType::ALLOW_ON_USER_GESTURE);
+ settings->set_auto_open_hint(DownloadFileType::DISALLOW_AUTO_OPEN);
+}
+
+FileTypePolicies::~FileTypePolicies() {
+ AutoLock lock(lock_); // DCHECK fail if the lock is held.
+}
+
+void FileTypePolicies::ReadResourceBundle(std::string* binary_pb) {
+ ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
+ bundle.GetRawDataResource(IDR_DOWNLOAD_FILE_TYPES_PB).CopyToString(binary_pb);
+}
+
+void FileTypePolicies::RecordUpdateMetrics(UpdateResult result,
+ const std::string& src_name) {
+ lock_.AssertAcquired();
+ // src_name should be "ResourceBundle" or "DynamicUpdate".
+ base::UmaHistogramSparse("SafeBrowsing.FileTypeUpdate." + src_name + "Result",
+ static_cast<unsigned int>(result));
+
+ if (result == UpdateResult::SUCCESS) {
+ base::UmaHistogramSparse(
+ "SafeBrowsing.FileTypeUpdate." + src_name + "Version",
+ config_->version_id());
+ base::UmaHistogramSparse(
+ "SafeBrowsing.FileTypeUpdate." + src_name + "TypeCount",
+ config_->file_types().size());
+ }
+}
+
+void FileTypePolicies::PopulateFromResourceBundle() {
+ AutoLock lock(lock_);
+ std::string binary_pb;
+ ReadResourceBundle(&binary_pb);
+ UpdateResult result = PopulateFromBinaryPb(binary_pb);
+ RecordUpdateMetrics(result, "ResourceBundle");
+}
+
+void FileTypePolicies::PopulateFromDynamicUpdate(const std::string& binary_pb) {
+ AutoLock lock(lock_);
+ UpdateResult result = PopulateFromBinaryPb(binary_pb);
+ RecordUpdateMetrics(result, "DynamicUpdate");
+}
+
+FileTypePolicies::UpdateResult FileTypePolicies::PopulateFromBinaryPb(
+ const std::string& binary_pb) {
+ lock_.AssertAcquired();
+
+ // Parse the proto and do some validation on it.
+ if (binary_pb.empty())
+ return UpdateResult::FAILED_EMPTY;
+
+ std::unique_ptr<DownloadFileTypeConfig> new_config(
+ new DownloadFileTypeConfig);
+ if (!new_config->ParseFromString(binary_pb))
+ return UpdateResult::FAILED_PROTO_PARSE;
+
+ // Need at least a default setting.
+ if (new_config->default_file_type().platform_settings().size() == 0)
+ return UpdateResult::FAILED_DEFAULT_SETTING_SET;
+
+ // Every file type should have exactly one setting, pre-filtered for this
+ // platform.
+ for (const auto& file_type : new_config->file_types()) {
+ if (file_type.platform_settings().size() != 1)
+ return UpdateResult::FAILED_WRONG_SETTINGS_COUNT;
+ }
+
+ // Compare against existing config, if we have one.
+ if (config_) {
+ // If versions are equal, we skip the update but it's not really
+ // a failure.
+ if (new_config->version_id() == config_->version_id())
+ return UpdateResult::SKIPPED_VERSION_CHECK_EQUAL;
+
+ // Check that version number increases
+ if (new_config->version_id() <= config_->version_id())
+ return UpdateResult::FAILED_VERSION_CHECK;
+
+ // Check that we haven't dropped more than 1/2 the list.
+ if (new_config->file_types().size() * 2 < config_->file_types().size())
+ return UpdateResult::FAILED_DELTA_CHECK;
+ }
+
+ // Looks good. Update our internal list.
+ SwapConfigLocked(new_config);
+
+ return UpdateResult::SUCCESS;
+}
+
+void FileTypePolicies::SwapConfig(
+ std::unique_ptr<DownloadFileTypeConfig>& new_config) {
+ AutoLock lock(lock_);
+ SwapConfigLocked(new_config);
+}
+
+void FileTypePolicies::SwapConfigLocked(
+ std::unique_ptr<DownloadFileTypeConfig>& new_config) {
+ lock_.AssertAcquired();
+ config_.swap(new_config);
+
+ // Build an index for faster lookup.
+ file_type_by_ext_.clear();
+ for (const DownloadFileType& file_type : config_->file_types()) {
+ // If there are dups, first one wins.
+ file_type_by_ext_.insert(std::make_pair(file_type.extension(), &file_type));
+ }
+}
+
+// static
+base::FilePath::StringType FileTypePolicies::GetFileExtension(
+ const base::FilePath& file) {
+ // Remove trailing space and period characters from the extension.
+ base::FilePath::StringType file_basename = file.BaseName().value();
+ base::FilePath::StringPieceType trimmed_filename = base::TrimString(
+ file_basename, FILE_PATH_LITERAL(". "), base::TRIM_TRAILING);
+ return base::FilePath(trimmed_filename).FinalExtension();
+}
+
+// static
+std::string FileTypePolicies::CanonicalizedExtension(
+ const base::FilePath& file) {
+ // The policy list is all ASCII, so a non-ASCII extension won't be in it.
+ const base::FilePath::StringType ext = GetFileExtension(file);
+ std::string ascii_ext =
+ base::ToLowerASCII(base::FilePath(ext).MaybeAsASCII());
+ if (ascii_ext[0] == '.')
+ ascii_ext.erase(0, 1);
+ return ascii_ext;
+}
+
+//
+// Accessors
+//
+
+float FileTypePolicies::SampledPingProbability() const {
+ AutoLock lock(lock_);
+ return config_ ? config_->sampled_ping_probability() : 0.0;
+}
+
+const DownloadFileType& FileTypePolicies::PolicyForExtension(
+ const std::string& ascii_ext) const {
+ lock_.AssertAcquired();
+ // This could happen if the ResourceBundle is corrupted.
+ if (!config_) {
+ DCHECK(false);
+ return last_resort_default_;
+ }
+ auto itr = file_type_by_ext_.find(ascii_ext);
+ if (itr != file_type_by_ext_.end())
+ return *itr->second;
+ else
+ return config_->default_file_type();
+}
+
+DownloadFileType FileTypePolicies::PolicyForFile(
+ const base::FilePath& file) const {
+ const std::string ext = CanonicalizedExtension(file);
+ AutoLock lock(lock_);
+ return PolicyForExtension(ext);
+}
+
+DownloadFileType::PlatformSettings FileTypePolicies::SettingsForFile(
+ const base::FilePath& file) const {
+ const std::string ext = CanonicalizedExtension(file);
+ AutoLock lock(lock_);
+ DCHECK_EQ(1, PolicyForExtension(ext).platform_settings().size());
+ return PolicyForExtension(ext).platform_settings(0);
+}
+
+int64_t FileTypePolicies::UmaValueForFile(const base::FilePath& file) const {
+ const std::string ext = CanonicalizedExtension(file);
+ AutoLock lock(lock_);
+ return PolicyForExtension(ext).uma_value();
+}
+
+bool FileTypePolicies::IsArchiveFile(const base::FilePath& file) const {
+ const std::string ext = CanonicalizedExtension(file);
+ AutoLock lock(lock_);
+ return PolicyForExtension(ext).is_archive();
+}
+
+// TODO(nparker): Add unit tests for these accessors.
+
+bool FileTypePolicies::IsAllowedToOpenAutomatically(
+ const base::FilePath& file) const {
+ const std::string ext = CanonicalizedExtension(file);
+ if (ext.empty())
+ return false;
+ AutoLock lock(lock_);
+ return PolicyForExtension(ext).platform_settings(0).auto_open_hint() ==
+ DownloadFileType::ALLOW_AUTO_OPEN;
+}
+
+DownloadFileType::PingSetting FileTypePolicies::PingSettingForFile(
+ const base::FilePath& file) const {
+ const std::string ext = CanonicalizedExtension(file);
+ AutoLock lock(lock_);
+ return PolicyForExtension(ext).ping_setting();
+}
+
+bool FileTypePolicies::IsCheckedBinaryFile(const base::FilePath& file) const {
+ return PingSettingForFile(file) == DownloadFileType::FULL_PING;
+}
+
+DownloadFileType::DangerLevel FileTypePolicies::GetFileDangerLevel(
+ const base::FilePath& file) const {
+ const std::string ext = CanonicalizedExtension(file);
+ AutoLock lock(lock_);
+ return PolicyForExtension(ext).platform_settings(0).danger_level();
+}
+
+uint64_t FileTypePolicies::GetMaxFileSizeToAnalyze(
+ const std::string& ascii_ext) const {
+ AutoLock lock(lock_);
+ return PolicyForExtension(ascii_ext)
+ .platform_settings(0)
+ .max_file_size_to_analyze();
+}
+
+uint64_t FileTypePolicies::GetMaxArchivedBinariesToReport() const {
+ AutoLock lock(lock_);
+ if (!config_ || !config_->has_max_archived_binaries_to_report()) {
+ // The resource bundle may be corrupted.
+ DCHECK(false);
+ return 10; // reasonable default
+ }
+ return config_->max_archived_binaries_to_report();
+}
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/file_type_policies.h b/chromium/chrome/common/safe_browsing/file_type_policies.h
new file mode 100644
index 00000000000..41b885071dd
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/file_type_policies.h
@@ -0,0 +1,156 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_FILE_TYPE_POLICIES_H_
+#define CHROME_COMMON_SAFE_BROWSING_FILE_TYPE_POLICIES_H_
+
+#include <map>
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/gtest_prod_util.h"
+#include "base/synchronization/lock.h"
+#include "chrome/common/safe_browsing/download_file_types.pb.h"
+
+namespace safe_browsing {
+
+struct FileTypePoliciesSingletonTrait;
+class FileTypePoliciesTestOverlay;
+
+// This holds a list of file types (aka file extensions) that we know about,
+// with policies related to how Safe Browsing and the download UI should treat
+// them.
+//
+// The data to populate it is read from a ResourceBundle and then also
+// fetched periodically from Google to get the most up-to-date policies.
+//
+// This is thread safe. We assume it is updated at most every few hours.
+
+class FileTypePolicies {
+ public:
+ virtual ~FileTypePolicies();
+
+ static FileTypePolicies* GetInstance(); // Singleton
+
+ // Update the internal list from a binary proto fetched from the network.
+ // Same integrity checks apply. This can be called multiple times with new
+ // protos.
+ void PopulateFromDynamicUpdate(const std::string& binary_pb);
+
+ //
+ // Static Utils
+ //
+
+ // Returns the final extension with the leading dot, after stripping
+ // trailing dots and spaces. It is difference from FilePath::Extension()
+ // and FilePath::FinalExtension().
+ // TODO(nparker): Consolidate. Maybe add this code to FinalExtension().
+ static base::FilePath::StringType GetFileExtension(
+ const base::FilePath& file);
+
+ //
+ // Accessors
+ //
+ bool IsArchiveFile(const base::FilePath& file) const;
+
+ // SBClientDownloadExtensions UMA histogram bucket for this file's type.
+ int64_t UmaValueForFile(const base::FilePath& file) const;
+
+ // True if download protection should send a ping to check
+ // this type of file.
+ bool IsCheckedBinaryFile(const base::FilePath& file) const;
+
+ // True if the user can select this file type to be opened automatically.
+ bool IsAllowedToOpenAutomatically(const base::FilePath& file) const;
+
+ // Return the danger level of this file type.
+ DownloadFileType::DangerLevel GetFileDangerLevel(
+ const base::FilePath& file) const;
+
+ // Return the type of ping we should send for this file
+ DownloadFileType::PingSetting PingSettingForFile(
+ const base::FilePath& file) const;
+
+ float SampledPingProbability() const;
+
+ DownloadFileType PolicyForFile(const base::FilePath& file) const;
+ DownloadFileType::PlatformSettings SettingsForFile(
+ const base::FilePath& file) const;
+
+ // Return max size for which unpacking and/or binary feature extration is
+ // supported for the given file extension.
+ uint64_t GetMaxFileSizeToAnalyze(const std::string& ascii_ext) const;
+
+ // Return max number of archived_binaries we should add to a download ping.
+ uint64_t GetMaxArchivedBinariesToReport() const;
+
+ protected:
+ // Creator must call one of Populate* before calling other methods.
+ FileTypePolicies();
+
+ // Used in metrics, do not reorder.
+ enum class UpdateResult {
+ SUCCESS = 1,
+ FAILED_EMPTY = 2,
+ FAILED_PROTO_PARSE = 3,
+ FAILED_DELTA_CHECK = 4,
+ FAILED_VERSION_CHECK = 5,
+ FAILED_DEFAULT_SETTING_SET = 6,
+ FAILED_WRONG_SETTINGS_COUNT = 7,
+ SKIPPED_VERSION_CHECK_EQUAL = 8,
+ };
+
+ // Read data from an serialized protobuf and update the internal list
+ // only if it passes integrity checks.
+ virtual UpdateResult PopulateFromBinaryPb(const std::string& binary_pb);
+
+ // Fetch the blob from the main resource bundle.
+ virtual void ReadResourceBundle(std::string* binary_pb);
+
+ // Record the result of an update attempt.
+ virtual void RecordUpdateMetrics(UpdateResult result,
+ const std::string& src_name);
+
+ // Return the ASCII lowercase extension w/o leading dot, or empty.
+ static std::string CanonicalizedExtension(const base::FilePath& file);
+
+ // Look up the policy for a given ASCII ext.
+ virtual const DownloadFileType& PolicyForExtension(
+ const std::string& ext) const;
+
+ private:
+ // Swap in a different config. This will rebuild file_type_by_ext_ index.
+ void SwapConfig(std::unique_ptr<DownloadFileTypeConfig>& new_config);
+ void SwapConfigLocked(std::unique_ptr<DownloadFileTypeConfig>& new_config);
+
+ // Read data from the main ResourceBundle. This updates the internal list
+ // only if the data passes integrity checks. This is normally called once
+ // after construction.
+ void PopulateFromResourceBundle();
+
+ // The latest config we've committed. Starts out null.
+ // Protected by lock_.
+ std::unique_ptr<DownloadFileTypeConfig> config_;
+
+ // This references entries in config_.
+ // Protected by lock_.
+ std::map<std::string, const DownloadFileType*> file_type_by_ext_;
+
+ // Type used if we can't load from disk.
+ // Written only in the constructor.
+ DownloadFileType last_resort_default_;
+
+ mutable base::Lock lock_;
+
+ FRIEND_TEST_ALL_PREFIXES(FileTypePoliciesTest, UnpackResourceBundle);
+ FRIEND_TEST_ALL_PREFIXES(FileTypePoliciesTest, BadProto);
+ FRIEND_TEST_ALL_PREFIXES(FileTypePoliciesTest, BadUpdateFromExisting);
+
+ friend struct FileTypePoliciesSingletonTrait;
+ friend class FileTypePoliciesTestOverlay;
+};
+
+} // namespace safe_browsing
+
+#endif // CHROME_COMMON_SAFE_BROWSING_FILE_TYPE_POLICIES_H_
diff --git a/chromium/chrome/common/safe_browsing/file_type_policies_test_util.cc b/chromium/chrome/common/safe_browsing/file_type_policies_test_util.cc
new file mode 100644
index 00000000000..d0520b9d176
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/file_type_policies_test_util.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 "chrome/common/safe_browsing/file_type_policies_test_util.h"
+
+namespace safe_browsing {
+
+FileTypePoliciesTestOverlay::FileTypePoliciesTestOverlay()
+ : orig_config_(new DownloadFileTypeConfig()) {
+ // Make a copy of the global config so we can put it back later.
+ // Swap out, copy, swap back in.
+ SwapConfig(orig_config_);
+ std::unique_ptr<DownloadFileTypeConfig> copy_config = DuplicateConfig();
+ SwapConfig(copy_config);
+}
+
+FileTypePoliciesTestOverlay::~FileTypePoliciesTestOverlay() {
+ SwapConfig(orig_config_);
+}
+
+void FileTypePoliciesTestOverlay::SwapConfig(
+ std::unique_ptr<DownloadFileTypeConfig>& new_config) const {
+ FileTypePolicies::GetInstance()->SwapConfig(new_config);
+}
+
+std::unique_ptr<DownloadFileTypeConfig>
+FileTypePoliciesTestOverlay::DuplicateConfig() const {
+ std::unique_ptr<DownloadFileTypeConfig> new_config(
+ new DownloadFileTypeConfig());
+ // Deep copy
+ new_config->CopyFrom(*orig_config_);
+ return new_config;
+}
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/file_type_policies_test_util.h b/chromium/chrome/common/safe_browsing/file_type_policies_test_util.h
new file mode 100644
index 00000000000..7d6fd54ceb1
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/file_type_policies_test_util.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 CHROME_COMMON_SAFE_BROWSING_FILE_TYPE_POLICIES_TEST_UTIL_H_
+#define CHROME_COMMON_SAFE_BROWSING_FILE_TYPE_POLICIES_TEST_UTIL_H_
+
+#include "chrome/common/safe_browsing/file_type_policies.h"
+
+namespace safe_browsing {
+
+// This is a test fixture for modifying the proto with FileTypePolicies.
+// While an object of this class is in scope, it will cause callers
+// of FileTypePolicies::GetInstance() to see the modified list.
+// When it goes out of scope, future callers will get the original list.
+//
+// Example:
+// FileTypePoliciesTestOverlay overlay_;
+// std::unique_ptr<DownloadFileTypesConfig> cfg =
+// overlay_.DuplicateConfig();
+// cfg.set_sampled_ping_probability(1.0);
+// overlay_.SwapConfig(cfg);
+// ...
+class FileTypePoliciesTestOverlay {
+ public:
+ FileTypePoliciesTestOverlay();
+ ~FileTypePoliciesTestOverlay();
+
+ // Swaps the contents bewtween the existing config and |new_config|.
+ void SwapConfig(std::unique_ptr<DownloadFileTypeConfig>& new_config) const;
+
+ // Return a new copy of the original config.
+ std::unique_ptr<DownloadFileTypeConfig> DuplicateConfig() const;
+
+ private:
+ std::unique_ptr<DownloadFileTypeConfig> orig_config_;
+};
+
+} // namespace safe_browsing
+
+#endif // CHROME_COMMON_SAFE_BROWSING_FILE_TYPE_POLICIES_TEST_UTIL_H_
diff --git a/chromium/chrome/common/safe_browsing/file_type_policies_unittest.cc b/chromium/chrome/common/safe_browsing/file_type_policies_unittest.cc
new file mode 100644
index 00000000000..f682558dfe0
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/file_type_policies_unittest.cc
@@ -0,0 +1,219 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/file_type_policies.h"
+
+#include <string.h>
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::NiceMock;
+
+namespace safe_browsing {
+
+class MockFileTypePolicies : public FileTypePolicies {
+ public:
+ MockFileTypePolicies() {}
+ ~MockFileTypePolicies() override {}
+
+ MOCK_METHOD2(RecordUpdateMetrics, void(UpdateResult, const std::string&));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockFileTypePolicies);
+};
+
+class FileTypePoliciesTest : public testing::Test {
+ protected:
+ FileTypePoliciesTest() {}
+ ~FileTypePoliciesTest() override {}
+
+ protected:
+ NiceMock<MockFileTypePolicies> policies_;
+};
+
+TEST_F(FileTypePoliciesTest, UnpackResourceBundle) {
+ EXPECT_CALL(policies_,
+ RecordUpdateMetrics(FileTypePolicies::UpdateResult::SUCCESS,
+ "ResourceBundle"));
+ policies_.PopulateFromResourceBundle();
+
+ // Look up a few well known types to ensure they're present.
+ // Some types vary by OS, and we check one per OS to validate
+ // that gen_file_type_proto.py does its job.
+ //
+ // NOTE: If the settings for these change in download_file_types.asciipb,
+ // then you'll need to change them here as well.
+
+ // Lookup .exe that varies on OS_WIN.
+ base::FilePath exe_file(FILE_PATH_LITERAL("a/foo.exe"));
+ DownloadFileType file_type = policies_.PolicyForFile(exe_file);
+ EXPECT_EQ("exe", file_type.extension());
+ EXPECT_EQ(0l, file_type.uma_value());
+ EXPECT_FALSE(file_type.is_archive());
+ EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
+#if defined(OS_WIN)
+ EXPECT_EQ(DownloadFileType::ALLOW_ON_USER_GESTURE,
+ file_type.platform_settings(0).danger_level());
+ EXPECT_EQ(DownloadFileType::DISALLOW_AUTO_OPEN,
+ file_type.platform_settings(0).auto_open_hint());
+#else
+ EXPECT_EQ(DownloadFileType::NOT_DANGEROUS,
+ file_type.platform_settings(0).danger_level());
+ EXPECT_EQ(DownloadFileType::ALLOW_AUTO_OPEN,
+ file_type.platform_settings(0).auto_open_hint());
+#endif
+
+ // Lookup .class that varies on OS_CHROMEOS, and also has a
+ // default setting set.
+ base::FilePath class_file(FILE_PATH_LITERAL("foo.class"));
+ file_type = policies_.PolicyForFile(class_file);
+ EXPECT_EQ("class", file_type.extension());
+ EXPECT_EQ(13l, file_type.uma_value());
+ EXPECT_FALSE(file_type.is_archive());
+ EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
+#if defined(OS_CHROMEOS)
+ EXPECT_EQ(DownloadFileType::NOT_DANGEROUS,
+ file_type.platform_settings(0).danger_level());
+ EXPECT_EQ(DownloadFileType::ALLOW_AUTO_OPEN,
+ file_type.platform_settings(0).auto_open_hint());
+#else
+ EXPECT_EQ(DownloadFileType::DANGEROUS,
+ file_type.platform_settings(0).danger_level());
+ EXPECT_EQ(DownloadFileType::DISALLOW_AUTO_OPEN,
+ file_type.platform_settings(0).auto_open_hint());
+#endif
+
+ // Lookup .dmg that varies on OS_MACOS
+ base::FilePath dmg_file(FILE_PATH_LITERAL("foo.dmg"));
+ file_type = policies_.PolicyForFile(dmg_file);
+ EXPECT_EQ("dmg", file_type.extension());
+ EXPECT_EQ(21, file_type.uma_value());
+ EXPECT_FALSE(file_type.is_archive());
+ EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
+#if defined(OS_MACOSX)
+ EXPECT_EQ(DownloadFileType::ALLOW_ON_USER_GESTURE,
+ file_type.platform_settings(0).danger_level());
+ EXPECT_EQ(DownloadFileType::DISALLOW_AUTO_OPEN,
+ file_type.platform_settings(0).auto_open_hint());
+#else
+ EXPECT_EQ(DownloadFileType::NOT_DANGEROUS,
+ file_type.platform_settings(0).danger_level());
+ EXPECT_EQ(DownloadFileType::ALLOW_AUTO_OPEN,
+ file_type.platform_settings(0).auto_open_hint());
+#endif
+
+ // Lookup .dex that varies on OS_ANDROID and OS_CHROMEOS
+ base::FilePath dex_file(FILE_PATH_LITERAL("foo.dex"));
+ file_type = policies_.PolicyForFile(dex_file);
+ EXPECT_EQ("dex", file_type.extension());
+ EXPECT_EQ(143, file_type.uma_value());
+ EXPECT_FALSE(file_type.is_archive());
+ EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
+#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
+ EXPECT_EQ(DownloadFileType::ALLOW_ON_USER_GESTURE,
+ file_type.platform_settings(0).danger_level());
+ EXPECT_EQ(DownloadFileType::DISALLOW_AUTO_OPEN,
+ file_type.platform_settings(0).auto_open_hint());
+#else
+ EXPECT_EQ(DownloadFileType::NOT_DANGEROUS,
+ file_type.platform_settings(0).danger_level());
+ EXPECT_EQ(DownloadFileType::ALLOW_AUTO_OPEN,
+ file_type.platform_settings(0).auto_open_hint());
+#endif
+
+ // Lookup .rpm that varies on OS_LINUX
+ base::FilePath rpm_file(FILE_PATH_LITERAL("foo.rpm"));
+ file_type = policies_.PolicyForFile(rpm_file);
+ EXPECT_EQ("rpm", file_type.extension());
+ EXPECT_EQ(142, file_type.uma_value());
+ EXPECT_FALSE(file_type.is_archive());
+ EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+ EXPECT_EQ(DownloadFileType::ALLOW_ON_USER_GESTURE,
+ file_type.platform_settings(0).danger_level());
+ EXPECT_EQ(DownloadFileType::DISALLOW_AUTO_OPEN,
+ file_type.platform_settings(0).auto_open_hint());
+#else
+ EXPECT_EQ(DownloadFileType::NOT_DANGEROUS,
+ file_type.platform_settings(0).danger_level());
+ EXPECT_EQ(DownloadFileType::ALLOW_AUTO_OPEN,
+ file_type.platform_settings(0).auto_open_hint());
+#endif
+
+ // Look .zip, an archive. The same on all platforms.
+ base::FilePath zip_file(FILE_PATH_LITERAL("b/bar.txt.zip"));
+ file_type = policies_.PolicyForFile(zip_file);
+ EXPECT_EQ("zip", file_type.extension());
+ EXPECT_EQ(7l, file_type.uma_value());
+ EXPECT_TRUE(file_type.is_archive());
+ EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
+ EXPECT_EQ(DownloadFileType::NOT_DANGEROUS,
+ file_type.platform_settings(0).danger_level());
+
+ // Check other accessors
+ EXPECT_EQ(7l, policies_.UmaValueForFile(zip_file));
+ EXPECT_TRUE(policies_.IsArchiveFile(zip_file));
+ EXPECT_FALSE(policies_.IsArchiveFile(exe_file));
+
+ // Verify settings on the default type.
+ file_type = policies_.PolicyForFile(
+ base::FilePath(FILE_PATH_LITERAL("a/foo.fooobar")));
+ EXPECT_EQ("", file_type.extension());
+ EXPECT_EQ(18l, file_type.uma_value());
+ EXPECT_FALSE(file_type.is_archive());
+ EXPECT_EQ(DownloadFileType::FULL_PING, file_type.ping_setting());
+ EXPECT_EQ(DownloadFileType::NOT_DANGEROUS,
+ file_type.platform_settings(0).danger_level());
+ EXPECT_EQ(DownloadFileType::ALLOW_AUTO_OPEN,
+ file_type.platform_settings(0).auto_open_hint());
+}
+
+TEST_F(FileTypePoliciesTest, BadProto) {
+ base::AutoLock lock(policies_.lock_);
+ EXPECT_EQ(FileTypePolicies::UpdateResult::FAILED_EMPTY,
+ policies_.PopulateFromBinaryPb(std::string()));
+
+ EXPECT_EQ(FileTypePolicies::UpdateResult::FAILED_PROTO_PARSE,
+ policies_.PopulateFromBinaryPb("foobar"));
+
+ DownloadFileTypeConfig cfg;
+ cfg.set_sampled_ping_probability(0.1f);
+ EXPECT_EQ(FileTypePolicies::UpdateResult::FAILED_DEFAULT_SETTING_SET,
+ policies_.PopulateFromBinaryPb(cfg.SerializeAsString()));
+
+ cfg.mutable_default_file_type()->add_platform_settings();
+ // This is missing a platform_setting.
+ auto* file_type = cfg.add_file_types();
+ EXPECT_EQ(FileTypePolicies::UpdateResult::FAILED_WRONG_SETTINGS_COUNT,
+ policies_.PopulateFromBinaryPb(cfg.SerializeAsString()));
+
+ file_type->add_platform_settings();
+ EXPECT_EQ(FileTypePolicies::UpdateResult::SUCCESS,
+ policies_.PopulateFromBinaryPb(cfg.SerializeAsString()));
+}
+
+TEST_F(FileTypePoliciesTest, BadUpdateFromExisting) {
+ base::AutoLock lock(policies_.lock_);
+ // Make a minimum viable config
+ DownloadFileTypeConfig cfg;
+ cfg.mutable_default_file_type()->add_platform_settings();
+ cfg.add_file_types()->add_platform_settings();
+ cfg.set_version_id(2);
+ EXPECT_EQ(FileTypePolicies::UpdateResult::SUCCESS,
+ policies_.PopulateFromBinaryPb(cfg.SerializeAsString()));
+
+ // Can't update to the same version
+ EXPECT_EQ(FileTypePolicies::UpdateResult::SKIPPED_VERSION_CHECK_EQUAL,
+ policies_.PopulateFromBinaryPb(cfg.SerializeAsString()));
+
+ // Can't go backward
+ cfg.set_version_id(1);
+ EXPECT_EQ(FileTypePolicies::UpdateResult::FAILED_VERSION_CHECK,
+ policies_.PopulateFromBinaryPb(cfg.SerializeAsString()));
+}
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/ipc_protobuf_message_macros.h b/chromium/chrome/common/safe_browsing/ipc_protobuf_message_macros.h
new file mode 100644
index 00000000000..db17241ad7f
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/ipc_protobuf_message_macros.h
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Protobuf Messages over IPC
+//
+// Protobuf messages are registered with IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN() and
+// friends in much the same way as other externally-defined structs (see
+// ipc/ipc_message_macros.h). These macros also cause only registration of the
+// protobuf message type IPC with message generation. Within matching calls to
+// _BEGIN() and _END(), one may use:
+// - IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER() to register an
+// optional field of fundamental type (any scalar message field type save
+// "string" and "bytes").
+// - IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER() to register an
+// optional field of complex type (scalar message field type "string" or
+// "bytes", or another message type).
+// - IPC_PROTOBUF_MESSAGE_TRAITS_REPEATED_COMPLEX_MEMBER() to register a
+// repeated field of complex type (scalar message field type "string" or
+// "bytes", or another message type).
+//
+// Enum types in protobuf messages are registered with
+// IPC_ENUM_TRAITS_VALIDATE() as with any other enum. In this case, the
+// validation expression should be the _IsValid() function provided by the
+// generated protobuf code. For example:
+//
+// IPC_ENUM_TRAITS_VALIDATE(MyEnumType, MyEnumType_IsValid(value))
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_IPC_PROTOBUF_MESSAGE_MACROS_H_
+#define CHROME_COMMON_SAFE_BROWSING_IPC_PROTOBUF_MESSAGE_MACROS_H_
+
+#include <string>
+
+#define IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN(message_name) \
+ namespace IPC { \
+ template <> \
+ struct IPC_MESSAGE_EXPORT ParamTraits<message_name> { \
+ typedef message_name param_type; \
+ static void Write(base::Pickle* m, const param_type& p); \
+ static bool Read(const base::Pickle* m, \
+ base::PickleIterator* iter, \
+ param_type* p); \
+ static void Log(const param_type& p, std::string* l); \
+ \
+ private: \
+ template <class P> \
+ static bool ReadParamF(const base::Pickle* m, \
+ base::PickleIterator* iter, \
+ param_type* p, \
+ void (param_type::*setter_function)(P)); \
+ }; \
+ } // namespace IPC
+
+#define IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER(name)
+#define IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER(name)
+#define IPC_PROTOBUF_MESSAGE_TRAITS_REPEATED_COMPLEX_MEMBER(name)
+#define IPC_PROTOBUF_MESSAGE_TRAITS_END()
+
+#endif // CHROME_COMMON_SAFE_BROWSING_IPC_PROTOBUF_MESSAGE_MACROS_H_
diff --git a/chromium/chrome/common/safe_browsing/ipc_protobuf_message_null_macros.h b/chromium/chrome/common/safe_browsing/ipc_protobuf_message_null_macros.h
new file mode 100644
index 00000000000..ffb7fe0f433
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/ipc_protobuf_message_null_macros.h
@@ -0,0 +1,19 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// No include guard, may be included multiple times.
+
+// NULL out all the macros that need NULLing, so that multiple includes of
+// *_generator.h files will not generate noise.
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_REPEATED_COMPLEX_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_END
+
+#define IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN(message_name)
+#define IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER(name)
+#define IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER(name)
+#define IPC_PROTOBUF_MESSAGE_TRAITS_REPEATED_COMPLEX_MEMBER(name)
+#define IPC_PROTOBUF_MESSAGE_TRAITS_END()
diff --git a/chromium/chrome/common/safe_browsing/ipc_protobuf_message_test.proto b/chromium/chrome/common/safe_browsing/ipc_protobuf_message_test.proto
new file mode 100644
index 00000000000..8148461a68b
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/ipc_protobuf_message_test.proto
@@ -0,0 +1,19 @@
+// Copyright 2015 The Chromium 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;
+
+message SubMessage {
+ optional int32 foo = 1;
+}
+
+message TestMessage {
+ optional int32 fund_int = 1;
+ optional string op_comp_string = 2;
+ optional bytes op_comp_bytes = 3;
+ optional SubMessage op_comp_sub = 4;
+ repeated SubMessage rep_comp_sub = 5;
+}
diff --git a/chromium/chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h b/chromium/chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h
new file mode 100644
index 00000000000..64283ffc115
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SAFE_BROWSING_IPC_PROTOBUF_MESSAGE_TEST_MESSAGES_H_
+#define SAFE_BROWSING_IPC_PROTOBUF_MESSAGE_TEST_MESSAGES_H_
+
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_protobuf_utils.h"
+#include "chrome/common/safe_browsing/ipc_protobuf_message_macros.h"
+
+IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN(SubMessage)
+ IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER(foo)
+IPC_PROTOBUF_MESSAGE_TRAITS_END()
+
+IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN(TestMessage)
+ IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER(fund_int)
+ IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER(op_comp_string)
+ IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER(op_comp_bytes)
+ IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER(op_comp_sub)
+ IPC_PROTOBUF_MESSAGE_TRAITS_REPEATED_COMPLEX_MEMBER(rep_comp_sub)
+IPC_PROTOBUF_MESSAGE_TRAITS_END()
+
+#endif // SAFE_BROWSING_IPC_PROTOBUF_MESSAGE_TEST_MESSAGES_H_
diff --git a/chromium/chrome/common/safe_browsing/ipc_protobuf_message_unittest.cc b/chromium/chrome/common/safe_browsing/ipc_protobuf_message_unittest.cc
new file mode 100644
index 00000000000..b66377511fc
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/ipc_protobuf_message_unittest.cc
@@ -0,0 +1,162 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/ipc_protobuf_message_test.pb.h"
+#include "ipc/ipc_message.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define IPC_MESSAGE_IMPL
+#undef SAFE_BROWSING_IPC_PROTOBUF_MESSAGE_TEST_MESSAGES_H_
+#include "chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h"
+
+// Generate ipc protobuf traits write methods.
+#include "chrome/common/safe_browsing/protobuf_message_write_macros.h"
+namespace IPC {
+#undef SAFE_BROWSING_IPC_PROTOBUF_MESSAGE_TEST_MESSAGES_H_
+#include "chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h"
+} // namespace IPC
+
+// Generate ipc protobuf traits read methods.
+#include "chrome/common/safe_browsing/protobuf_message_read_macros.h"
+namespace IPC {
+#undef SAFE_BROWSING_IPC_PROTOBUF_MESSAGE_TEST_MESSAGES_H_
+#include "chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h"
+} // namespace IPC
+
+// Generate ipc protobuf traits log methods.
+#include "chrome/common/safe_browsing/protobuf_message_log_macros.h"
+namespace IPC {
+#undef SAFE_BROWSING_IPC_PROTOBUF_MESSAGE_TEST_MESSAGES_H_
+#include "chrome/common/safe_browsing/ipc_protobuf_message_test_messages.h"
+} // namespace IPC
+
+class IPCProtobufMessageTest : public ::testing::TestWithParam<bool> {
+ protected:
+ IPCProtobufMessageTest() : field_is_present_(GetParam()) {}
+
+ bool field_is_present_;
+};
+
+// Tests writing and reading a message with an optional fundamental field.
+TEST_P(IPCProtobufMessageTest, FundamentalField) {
+ TestMessage input;
+
+ if (field_is_present_)
+ input.set_fund_int(42);
+
+ IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+ IPC::WriteParam(&msg, input);
+
+ TestMessage output;
+ base::PickleIterator iter(msg);
+ ASSERT_TRUE(IPC::ReadParam(&msg, &iter, &output));
+
+ if (field_is_present_) {
+ ASSERT_TRUE(output.has_fund_int());
+ EXPECT_EQ(input.fund_int(), output.fund_int());
+ } else {
+ ASSERT_FALSE(output.has_fund_int());
+ }
+}
+
+// Tests writing and reading a message with an optional string field.
+TEST_P(IPCProtobufMessageTest, StringField) {
+ TestMessage input;
+
+ if (field_is_present_)
+ input.set_op_comp_string("some string");
+
+ IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+ IPC::WriteParam(&msg, input);
+
+ TestMessage output;
+ base::PickleIterator iter(msg);
+ ASSERT_TRUE(IPC::ReadParam(&msg, &iter, &output));
+
+ if (field_is_present_) {
+ ASSERT_TRUE(output.has_op_comp_string());
+ EXPECT_EQ(input.op_comp_string(), output.op_comp_string());
+ } else {
+ ASSERT_FALSE(output.has_op_comp_string());
+ }
+}
+
+// Tests writing and reading a message with an optional bytes field.
+TEST_P(IPCProtobufMessageTest, BytesField) {
+ TestMessage input;
+
+ if (field_is_present_)
+ input.set_op_comp_bytes("some string");
+
+ IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+ IPC::WriteParam(&msg, input);
+
+ TestMessage output;
+ base::PickleIterator iter(msg);
+ ASSERT_TRUE(IPC::ReadParam(&msg, &iter, &output));
+
+ if (field_is_present_) {
+ ASSERT_TRUE(output.has_op_comp_bytes());
+ EXPECT_EQ(input.op_comp_bytes(), output.op_comp_bytes());
+ } else {
+ ASSERT_FALSE(output.has_op_comp_bytes());
+ }
+}
+
+// Tests writing and reading a message with an optional submessage field.
+TEST_P(IPCProtobufMessageTest, OptionalSubmessage) {
+ TestMessage input;
+
+ if (field_is_present_)
+ input.mutable_op_comp_sub()->set_foo(47);
+
+ IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+ IPC::WriteParam(&msg, input);
+
+ TestMessage output;
+ base::PickleIterator iter(msg);
+ ASSERT_TRUE(IPC::ReadParam(&msg, &iter, &output));
+
+ if (field_is_present_) {
+ ASSERT_TRUE(output.has_op_comp_sub());
+ ASSERT_TRUE(output.op_comp_sub().has_foo());
+ EXPECT_EQ(input.op_comp_sub().foo(), output.op_comp_sub().foo());
+ } else {
+ ASSERT_FALSE(output.has_op_comp_sub());
+ }
+}
+
+// Tests writing and reading a message with a repeated submessage field.
+TEST_P(IPCProtobufMessageTest, RepeatedSubmessage) {
+ TestMessage input;
+
+ if (field_is_present_) {
+ input.add_rep_comp_sub()->set_foo(0);
+ input.add_rep_comp_sub()->set_foo(1);
+ input.add_rep_comp_sub()->set_foo(2);
+ }
+
+ IPC::Message msg(1, 2, IPC::Message::PRIORITY_NORMAL);
+ IPC::WriteParam(&msg, input);
+
+ TestMessage output;
+ base::PickleIterator iter(msg);
+ ASSERT_TRUE(IPC::ReadParam(&msg, &iter, &output));
+
+ if (field_is_present_) {
+ ASSERT_EQ(3, output.rep_comp_sub_size());
+ ASSERT_TRUE(output.rep_comp_sub(0).has_foo());
+ EXPECT_EQ(input.rep_comp_sub(0).foo(), output.rep_comp_sub(0).foo());
+ ASSERT_TRUE(output.rep_comp_sub(1).has_foo());
+ EXPECT_EQ(input.rep_comp_sub(1).foo(), output.rep_comp_sub(1).foo());
+ ASSERT_TRUE(output.rep_comp_sub(2).has_foo());
+ EXPECT_EQ(input.rep_comp_sub(2).foo(), output.rep_comp_sub(2).foo());
+ } else {
+ ASSERT_EQ(0, output.rep_comp_sub_size());
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(IPCProtobufMessage,
+ IPCProtobufMessageTest,
+ ::testing::Bool());
diff --git a/chromium/chrome/common/safe_browsing/mach_o_image_reader_mac.cc b/chromium/chrome/common/safe_browsing/mach_o_image_reader_mac.cc
new file mode 100644
index 00000000000..655fc56c6d8
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/mach_o_image_reader_mac.cc
@@ -0,0 +1,257 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/mach_o_image_reader_mac.h"
+
+#include <libkern/OSByteOrder.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
+
+namespace safe_browsing {
+
+// ByteSlice is a bounds-checking view of an arbitrary byte array.
+class ByteSlice {
+ public:
+ // Creates an invalid byte slice.
+ ByteSlice() : ByteSlice(nullptr, 0) {}
+
+ // Creates a slice for a given data array.
+ explicit ByteSlice(const uint8_t* data, size_t size)
+ : data_(data), size_(size) {}
+ ~ByteSlice() {}
+
+ bool IsValid() {
+ return data_ != nullptr;
+ }
+
+ // Creates a sub-slice from the current slice.
+ ByteSlice Slice(size_t at, size_t size) {
+ if (!RangeCheck(at, size))
+ return ByteSlice();
+ return ByteSlice(data_ + at, size);
+ }
+
+ // Casts an offset to a specific type.
+ template <typename T>
+ const T* GetPointerAt(size_t at) {
+ if (!RangeCheck(at, sizeof(T)))
+ return nullptr;
+ return reinterpret_cast<const T*>(data_ + at);
+ }
+
+ // Copies data from an offset to a buffer.
+ bool CopyDataAt(size_t at, size_t size, uint8_t* out_data) {
+ if (!RangeCheck(at, size))
+ return false;
+ memcpy(out_data, data_ + at, size);
+ return true;
+ }
+
+ bool RangeCheck(size_t offset, size_t size) {
+ if (offset >= size_)
+ return false;
+ base::CheckedNumeric<size_t> range(offset);
+ range += size;
+ if (!range.IsValid())
+ return false;
+ return range.ValueOrDie() <= size_;
+ }
+
+ const uint8_t* data() const { return data_; }
+ size_t size() const { return size_; }
+
+ private:
+ const uint8_t* data_;
+ size_t size_;
+
+ // Copy and assign allowed.
+};
+
+MachOImageReader::LoadCommand::LoadCommand() {}
+
+MachOImageReader::LoadCommand::LoadCommand(const LoadCommand& other) = default;
+
+MachOImageReader::LoadCommand::~LoadCommand() {}
+
+// static
+bool MachOImageReader::IsMachOMagicValue(uint32_t magic) {
+ return magic == FAT_MAGIC || magic == FAT_CIGAM ||
+ magic == MH_MAGIC || magic == MH_CIGAM ||
+ magic == MH_MAGIC_64 || magic == MH_CIGAM_64;
+}
+
+MachOImageReader::MachOImageReader()
+ : data_(),
+ is_fat_(false),
+ is_64_bit_(false),
+ commands_() {
+}
+
+MachOImageReader::~MachOImageReader() {}
+
+bool MachOImageReader::Initialize(const uint8_t* image, size_t image_size) {
+ if (!image)
+ return false;
+
+ data_.reset(new ByteSlice(image, image_size));
+
+ const uint32_t* magic = data_->GetPointerAt<uint32_t>(0);
+ if (!magic)
+ return false;
+
+ // Check if this is a fat file. Note that the fat_header and fat_arch
+ // structs are always in big endian.
+ is_fat_ = *magic == FAT_MAGIC || *magic == FAT_CIGAM;
+ if (is_fat_) {
+ const fat_header* header = data_->GetPointerAt<fat_header>(0);
+ if (!header)
+ return false;
+
+ bool do_swap = header->magic == FAT_CIGAM;
+ uint32_t nfat_arch = do_swap ? OSSwapInt32(header->nfat_arch)
+ : header->nfat_arch;
+
+ size_t offset = sizeof(*header);
+ for (uint32_t i = 0; i < nfat_arch; ++i) {
+ const fat_arch* arch = data_->GetPointerAt<fat_arch>(offset);
+ if (!arch)
+ return false;
+
+ uint32_t arch_offset = do_swap ? OSSwapInt32(arch->offset) : arch->offset;
+ uint32_t arch_size = do_swap ? OSSwapInt32(arch->size) : arch->size;
+
+ // Cannot refer back to headers of previous arches to cause
+ // recursive processing.
+ if (arch_offset < offset)
+ return false;
+
+ ByteSlice slice = data_->Slice(arch_offset, arch_size);
+ if (!slice.IsValid())
+ return false;
+
+ fat_images_.push_back(std::make_unique<MachOImageReader>());
+ if (!fat_images_.back()->Initialize(slice.data(), slice.size()))
+ return false;
+
+ offset += sizeof(*arch);
+ }
+
+ return true;
+ }
+
+ bool do_swap = *magic == MH_CIGAM || *magic == MH_CIGAM_64;
+
+ // Make sure this is a Mach-O file.
+ is_64_bit_ = *magic == MH_MAGIC_64 || *magic == MH_CIGAM_64;
+ if (!(is_64_bit_ || *magic == MH_MAGIC || do_swap))
+ return false;
+
+ // Read the full Mach-O image header.
+ if (is_64_bit_) {
+ if (!GetMachHeader64())
+ return false;
+ } else {
+ if (!GetMachHeader())
+ return false;
+ }
+
+ // Collect all the load commands for the binary.
+ const size_t load_command_size = sizeof(load_command);
+ size_t offset = is_64_bit_ ? sizeof(mach_header_64) : sizeof(mach_header);
+ const uint32_t num_commands = do_swap ? OSSwapInt32(GetMachHeader()->ncmds)
+ : GetMachHeader()->ncmds;
+ commands_.resize(num_commands);
+ for (uint32_t i = 0; i < num_commands; ++i) {
+ LoadCommand* command = &commands_[i];
+
+ command->data.resize(load_command_size);
+ if (!data_->CopyDataAt(offset, load_command_size, &command->data[0])) {
+ return false;
+ }
+
+ uint32_t cmdsize = do_swap ? OSSwapInt32(command->cmdsize())
+ : command->cmdsize();
+ // If the load_command's reported size is smaller than the size of the base
+ // struct, do not try to copy additional data (or resize to be smaller
+ // than the base struct). This may not be valid Mach-O.
+ if (cmdsize < load_command_size) {
+ offset += load_command_size;
+ continue;
+ }
+
+ command->data.resize(cmdsize);
+ if (!data_->CopyDataAt(offset, cmdsize, &command->data[0])) {
+ return false;
+ }
+
+ offset += cmdsize;
+ }
+
+ return true;
+}
+
+bool MachOImageReader::IsFat() {
+ return is_fat_;
+}
+
+std::vector<MachOImageReader*> MachOImageReader::GetFatImages() {
+ DCHECK(is_fat_);
+ std::vector<MachOImageReader*> images;
+ for (const auto& image : fat_images_)
+ images.push_back(image.get());
+ return images;
+}
+
+bool MachOImageReader::Is64Bit() {
+ DCHECK(!is_fat_);
+ return is_64_bit_;
+}
+
+const mach_header* MachOImageReader::GetMachHeader() {
+ DCHECK(!is_fat_);
+ return data_->GetPointerAt<mach_header>(0);
+}
+
+const mach_header_64* MachOImageReader::GetMachHeader64() {
+ DCHECK(is_64_bit_);
+ DCHECK(!is_fat_);
+ return data_->GetPointerAt<mach_header_64>(0);
+}
+
+uint32_t MachOImageReader::GetFileType() {
+ DCHECK(!is_fat_);
+ return GetMachHeader()->filetype;
+}
+
+const std::vector<MachOImageReader::LoadCommand>&
+MachOImageReader::GetLoadCommands() {
+ DCHECK(!is_fat_);
+ return commands_;
+}
+
+bool MachOImageReader::GetCodeSignatureInfo(std::vector<uint8_t>* info) {
+ DCHECK(!is_fat_);
+ DCHECK(info->empty());
+
+ // Find the LC_CODE_SIGNATURE command and cast it to its linkedit format.
+ const linkedit_data_command* lc_code_signature = nullptr;
+ for (const auto& command : commands_) {
+ if (command.cmd() == LC_CODE_SIGNATURE) {
+ lc_code_signature = command.as_command<linkedit_data_command>();
+ break;
+ }
+ }
+ if (lc_code_signature == nullptr)
+ return false;
+
+ info->resize(lc_code_signature->datasize);
+ return data_->CopyDataAt(lc_code_signature->dataoff,
+ lc_code_signature->datasize,
+ &(*info)[0]);
+}
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/mach_o_image_reader_mac.h b/chromium/chrome/common/safe_browsing/mach_o_image_reader_mac.h
new file mode 100644
index 00000000000..5f93e6285fb
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/mach_o_image_reader_mac.h
@@ -0,0 +1,107 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_MACH_O_IMAGE_READER_MAC_H_
+#define CHROME_COMMON_SAFE_BROWSING_MACH_O_IMAGE_READER_MAC_H_
+
+#include <mach-o/loader.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/macros.h"
+
+namespace safe_browsing {
+
+class ByteSlice;
+
+// MachOImageReader is used to extract information about a Mach-O binary image.
+// This class supports fat and thin images. Initialize() must be called before
+// any other methods; if it returns false, it is illegal to call any other
+// methods on this class.
+class MachOImageReader {
+ public:
+ // Represents a Mach-O load command, including all of its data.
+ struct LoadCommand {
+ LoadCommand();
+ LoadCommand(const LoadCommand& other);
+ ~LoadCommand();
+
+ uint32_t cmd() const {
+ return as_command<load_command>()->cmd;
+ }
+
+ uint32_t cmdsize() const {
+ return as_command<load_command>()->cmdsize;
+ }
+
+ template <typename T>
+ const T* as_command() const {
+ if (data.size() < sizeof(T))
+ return nullptr;
+ return reinterpret_cast<const T*>(&data[0]);
+ }
+
+ std::vector<uint8_t> data;
+ };
+
+ // Returns true if |magic| is any Mach-O magic number. This can be used on the
+ // first four bytes of a file (either in little- or big-endian) to quickly
+ // determine whether or not the file is potentially a Mach-O file. An instance
+ // of this class must be used for a true validity check.
+ static bool IsMachOMagicValue(uint32_t magic);
+
+ MachOImageReader();
+ ~MachOImageReader();
+
+ // Initializes the instance and verifies that the data is a valid Mach-O
+ // image. This does not take ownership of the bytes, so the data must
+ // remain valid for the lifetime of this object. Returns true if the
+ // instance is initialized and valid, false if the file could not be parsed
+ // as a Mach-O image.
+ bool Initialize(const uint8_t* image, size_t image_size);
+
+ // Returns whether this is a fat Mach-O image. If this returns true, it is
+ // only valid to call GetFatImages() and none of the other methods.
+ bool IsFat();
+
+ // It is only valid to call this method if IsFat() returns true. This
+ // returns an image reader for each architecture in the fat file.
+ std::vector<MachOImageReader*> GetFatImages();
+
+ // Returns whether the image is a 64-bit image.
+ bool Is64Bit();
+
+ // Retrieves the mach_header structure for the appropriate architecture.
+ const mach_header* GetMachHeader();
+ const mach_header_64* GetMachHeader64();
+
+ // Returns the Mach-O filetype field from the header.
+ uint32_t GetFileType();
+
+ // Returns an array of all the load commands in the image.
+ const std::vector<MachOImageReader::LoadCommand>& GetLoadCommands();
+
+ // If the image has a LC_CODE_SIGNATURE command, this retreives the code
+ // signature blob in the __LINKEDIT segment.
+ bool GetCodeSignatureInfo(std::vector<uint8_t>* info);
+
+ private:
+ std::unique_ptr<ByteSlice> data_;
+
+ bool is_fat_;
+ std::vector<std::unique_ptr<MachOImageReader>> fat_images_;
+
+ bool is_64_bit_;
+ std::vector<LoadCommand> commands_;
+
+ DISALLOW_COPY_AND_ASSIGN(MachOImageReader);
+};
+
+} // namespace safe_browsing
+
+#endif // CHROME_COMMON_SAFE_BROWSING_MACH_O_IMAGE_READER_MAC_H_
diff --git a/chromium/chrome/common/safe_browsing/mach_o_image_reader_mac_unittest.cc b/chromium/chrome/common/safe_browsing/mach_o_image_reader_mac_unittest.cc
new file mode 100644
index 00000000000..5d6d270dbfa
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/mach_o_image_reader_mac_unittest.cc
@@ -0,0 +1,515 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/mach_o_image_reader_mac.h"
+
+#include <arpa/inet.h>
+#include <libkern/OSByteOrder.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <uuid/uuid.h>
+
+#include "base/files/file_path.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/common/chrome_paths.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+namespace {
+
+// Definitions from
+// <http://opensource.apple.com/source/xnu/xnu-2782.1.97/bsd/sys/codesign.h>.
+
+enum {
+ CSMAGIC_CODEDIRECTORY = 0xfade0c02,
+ CSMAGIC_EMBEDDED_SIGNATURE = 0xfade0cc0,
+
+ CSSLOT_CODEDIRECTORY = 0,
+};
+
+struct CodeSigningBlob {
+ uint32_t type;
+ uint32_t offset;
+};
+
+struct CodeSigningSuperBlob {
+ uint32_t magic;
+ uint32_t length;
+ uint32_t count;
+ CodeSigningBlob index[];
+};
+
+struct CodeSigningDirectory {
+ uint32_t magic;
+ uint32_t length;
+ uint32_t version;
+ uint32_t flags;
+ uint32_t hashOffset;
+ uint32_t identOffset;
+ uint32_t nSpecialSlots;
+ uint32_t nCodeSlots;
+ uint32_t codeLimit;
+ uint8_t hashSize;
+ uint8_t hashType;
+ uint8_t spare1;
+ uint8_t pageSize;
+ uint32_t spare2;
+ // Version 0x20100.
+ uint32_t scatterOffset;
+ // Version 0x20200.
+ uint32_t teamOffset;
+};
+
+class MachOImageReaderTest : public testing::Test {
+ protected:
+ void OpenTestFile(const char* file_name, base::MemoryMappedFile* file) {
+ base::FilePath test_data;
+ ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data));
+
+ base::FilePath path = test_data.AppendASCII("safe_browsing")
+ .AppendASCII("mach_o")
+ .AppendASCII(file_name);
+
+ ASSERT_TRUE(file->Initialize(path));
+ }
+
+ // Returns the identity of the signed code data.
+ void GetSigningIdentity(const std::vector<uint8_t>& signature,
+ std::string* identity) {
+ auto* super_blob =
+ reinterpret_cast<const CodeSigningSuperBlob*>(&signature[0]);
+ EXPECT_EQ(CSMAGIC_EMBEDDED_SIGNATURE, ntohl(super_blob->magic));
+ ASSERT_EQ(CSSLOT_CODEDIRECTORY, ntohl(super_blob->index[0].type));
+ size_t dir_offset = ntohl(super_blob->index[0].offset);
+ auto* directory =
+ reinterpret_cast<const CodeSigningDirectory*>(&signature[dir_offset]);
+ ASSERT_EQ(CSMAGIC_CODEDIRECTORY, ntohl(directory->magic));
+ size_t ident_offset = ntohl(directory->identOffset) + dir_offset;
+ *identity =
+ std::string(reinterpret_cast<const char*>(&signature[ident_offset]));
+ }
+
+ // Returns the hash of the code data itself. Note that this is not the
+ // CDHash, but is instead the hash in the CodeDirectory blob, which is
+ // over the contents of the signed data. This is visible as hash #0
+ // when using `codesign -d -vvvvvv`.
+ void GetCodeSignatureHash(const std::vector<uint8_t>& signature,
+ std::vector<uint8_t>* hash) {
+ auto* super_blob =
+ reinterpret_cast<const CodeSigningSuperBlob*>(&signature[0]);
+ EXPECT_EQ(CSMAGIC_EMBEDDED_SIGNATURE, ntohl(super_blob->magic));
+ ASSERT_EQ(CSSLOT_CODEDIRECTORY, ntohl(super_blob->index[0].type));
+ size_t dir_offset = ntohl(super_blob->index[0].offset);
+ auto* directory =
+ reinterpret_cast<const CodeSigningDirectory*>(&signature[dir_offset]);
+ ASSERT_EQ(CSMAGIC_CODEDIRECTORY, ntohl(directory->magic));
+ size_t hash_offset = ntohl(directory->hashOffset) + dir_offset;
+ std::vector<uint8_t> actual_hash(&signature[hash_offset],
+ &signature[hash_offset + directory->hashSize]);
+ EXPECT_EQ(20u, actual_hash.size());
+ *hash = actual_hash;
+ }
+
+ void ExpectCodeSignatureHash(const std::vector<uint8_t>& signature,
+ const char* expected) {
+ std::vector<uint8_t> actual_hash;
+ GetCodeSignatureHash(signature, &actual_hash);
+
+ std::vector<uint8_t> expected_hash;
+ ASSERT_TRUE(base::HexStringToBytes(expected, &expected_hash));
+ EXPECT_EQ(expected_hash, actual_hash);
+ }
+};
+
+TEST_F(MachOImageReaderTest, Executable32) {
+ base::MemoryMappedFile file;
+ ASSERT_NO_FATAL_FAILURE(OpenTestFile("executable32", &file));
+ MachOImageReader reader;
+ ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+ EXPECT_FALSE(reader.IsFat());
+ EXPECT_FALSE(reader.Is64Bit());
+ EXPECT_TRUE(reader.GetMachHeader());
+ EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.GetFileType());
+ EXPECT_EQ(15u, reader.GetLoadCommands().size());
+
+ std::vector<uint8_t> signature;
+ EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
+ EXPECT_TRUE(signature.empty());
+
+ // Test an arbitrary load command.
+ auto commands = reader.GetLoadCommands();
+ ASSERT_EQ(15u, commands.size());
+ auto command = commands[11];
+ ASSERT_EQ(static_cast<uint32_t>(LC_LOAD_DYLIB), command.cmd());
+ auto* actual = command.as_command<dylib_command>();
+ EXPECT_EQ(2u, actual->dylib.timestamp);
+ EXPECT_EQ(0x4ad0101u, actual->dylib.current_version);
+ EXPECT_EQ(0x10000u, actual->dylib.compatibility_version);
+}
+
+TEST_F(MachOImageReaderTest, Executable64) {
+ base::MemoryMappedFile file;
+ ASSERT_NO_FATAL_FAILURE(OpenTestFile("executable64", &file));
+ MachOImageReader reader;
+ ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+ EXPECT_FALSE(reader.IsFat());
+ EXPECT_TRUE(reader.Is64Bit());
+ EXPECT_TRUE(reader.GetMachHeader());
+ EXPECT_TRUE(reader.GetMachHeader64());
+ EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.GetFileType());
+ EXPECT_EQ(15u, reader.GetLoadCommands().size());
+
+ std::vector<uint8_t> signature;
+ EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
+ EXPECT_TRUE(signature.empty());
+}
+
+TEST_F(MachOImageReaderTest, ExecutableFat) {
+ base::MemoryMappedFile file;
+ ASSERT_NO_FATAL_FAILURE(OpenTestFile("executablefat", &file));
+ MachOImageReader reader;
+ ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+ EXPECT_TRUE(reader.IsFat());
+ auto images = reader.GetFatImages();
+ ASSERT_EQ(2u, images.size());
+
+ // Note: this image is crafted to have 32-bit first.
+ {
+ EXPECT_FALSE(images[0]->IsFat());
+ EXPECT_FALSE(images[0]->Is64Bit());
+ EXPECT_TRUE(images[0]->GetMachHeader());
+ EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[0]->GetFileType());
+
+ std::vector<uint8_t> signature;
+ EXPECT_FALSE(images[0]->GetCodeSignatureInfo(&signature));
+ EXPECT_TRUE(signature.empty());
+ }
+
+ {
+ EXPECT_FALSE(images[1]->IsFat());
+ EXPECT_TRUE(images[1]->Is64Bit());
+ EXPECT_TRUE(images[1]->GetMachHeader());
+ EXPECT_TRUE(images[1]->GetMachHeader64());
+ EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[1]->GetFileType());
+
+ std::vector<uint8_t> signature;
+ EXPECT_FALSE(images[1]->GetCodeSignatureInfo(&signature));
+ EXPECT_TRUE(signature.empty());
+
+ // Test an arbitrary load command.
+ auto commands = images[1]->GetLoadCommands();
+ ASSERT_EQ(15u, commands.size());
+ auto command = commands[1];
+ ASSERT_EQ(static_cast<uint32_t>(LC_SEGMENT_64), command.cmd());
+ auto* actual = command.as_command<segment_command_64>();
+ EXPECT_EQ("__TEXT", std::string(actual->segname));
+ EXPECT_EQ(0u, actual->fileoff);
+ EXPECT_EQ(4096u, actual->filesize);
+ EXPECT_EQ(0x7, actual->maxprot);
+ EXPECT_EQ(0x5, actual->initprot);
+ EXPECT_EQ(3u, actual->nsects);
+ EXPECT_EQ(0u, actual->flags);
+ }
+}
+
+TEST_F(MachOImageReaderTest, ExecutablePPC) {
+ base::MemoryMappedFile file;
+ ASSERT_NO_FATAL_FAILURE(OpenTestFile("executableppc", &file));
+ MachOImageReader reader;
+ ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+ EXPECT_FALSE(reader.IsFat());
+ EXPECT_FALSE(reader.Is64Bit());
+ EXPECT_TRUE(reader.GetMachHeader());
+ EXPECT_EQ(OSSwapInt32(MH_EXECUTE), reader.GetFileType());
+ EXPECT_EQ(10u, reader.GetLoadCommands().size());
+
+ std::vector<uint8_t> signature;
+ EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
+ EXPECT_TRUE(signature.empty());
+}
+
+TEST_F(MachOImageReaderTest, Dylib32) {
+ base::MemoryMappedFile file;
+ ASSERT_NO_FATAL_FAILURE(OpenTestFile("lib32.dylib", &file));
+ MachOImageReader reader;
+ ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+ EXPECT_FALSE(reader.IsFat());
+ EXPECT_FALSE(reader.Is64Bit());
+ EXPECT_TRUE(reader.GetMachHeader());
+ EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), reader.GetFileType());
+ EXPECT_EQ(13u, reader.GetLoadCommands().size());
+
+ std::vector<uint8_t> signature;
+ EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
+ EXPECT_TRUE(signature.empty());
+}
+
+TEST_F(MachOImageReaderTest, Dylib64) {
+ base::MemoryMappedFile file;
+ ASSERT_NO_FATAL_FAILURE(OpenTestFile("lib64.dylib", &file));
+ MachOImageReader reader;
+ ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+ EXPECT_FALSE(reader.IsFat());
+ EXPECT_TRUE(reader.Is64Bit());
+ EXPECT_TRUE(reader.GetMachHeader());
+ EXPECT_TRUE(reader.GetMachHeader64());
+ EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), reader.GetFileType());
+ EXPECT_EQ(13u, reader.GetLoadCommands().size());
+
+ std::vector<uint8_t> signature;
+ EXPECT_FALSE(reader.GetCodeSignatureInfo(&signature));
+ EXPECT_TRUE(signature.empty());
+
+ // Test an arbitrary load command.
+ auto commands = reader.GetLoadCommands();
+ ASSERT_EQ(13u, commands.size());
+ auto command = commands[6];
+ ASSERT_EQ(static_cast<uint32_t>(LC_UUID), command.cmd());
+ uuid_t expected = {0xB6, 0xB5, 0x12, 0xD7,
+ 0x64, 0xE9,
+ 0x3F, 0x7A,
+ 0xAB, 0x4A,
+ 0x87, 0x46, 0x36, 0x76, 0x87, 0x47};
+ EXPECT_EQ(0, uuid_compare(expected,
+ command.as_command<uuid_command>()->uuid));
+}
+
+TEST_F(MachOImageReaderTest, DylibFat) {
+ base::MemoryMappedFile file;
+ ASSERT_NO_FATAL_FAILURE(OpenTestFile("libfat.dylib", &file));
+ MachOImageReader reader;
+ ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+ EXPECT_TRUE(reader.IsFat());
+ auto images = reader.GetFatImages();
+ ASSERT_EQ(2u, images.size());
+
+ // Note: this image is crafted to have 64-bit first.
+ {
+ EXPECT_FALSE(images[0]->IsFat());
+ EXPECT_TRUE(images[0]->Is64Bit());
+ EXPECT_TRUE(images[0]->GetMachHeader());
+ EXPECT_TRUE(images[0]->GetMachHeader64());
+ EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), images[0]->GetFileType());
+
+ std::vector<uint8_t> signature;
+ EXPECT_FALSE(images[0]->GetCodeSignatureInfo(&signature));
+ EXPECT_TRUE(signature.empty());
+ }
+
+ {
+ EXPECT_FALSE(images[1]->IsFat());
+ EXPECT_FALSE(images[1]->Is64Bit());
+ EXPECT_TRUE(images[1]->GetMachHeader());
+ EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), images[1]->GetFileType());
+
+ std::vector<uint8_t> signature;
+ EXPECT_FALSE(images[1]->GetCodeSignatureInfo(&signature));
+ EXPECT_TRUE(signature.empty());
+ }
+}
+
+TEST_F(MachOImageReaderTest, SignedExecutable32) {
+ base::MemoryMappedFile file;
+ ASSERT_NO_FATAL_FAILURE(OpenTestFile("signedexecutable32", &file));
+ MachOImageReader reader;
+ ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+ EXPECT_FALSE(reader.IsFat());
+ EXPECT_FALSE(reader.Is64Bit());
+ EXPECT_TRUE(reader.GetMachHeader());
+ EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.GetFileType());
+ EXPECT_EQ(16u, reader.GetLoadCommands().size());
+
+ std::vector<uint8_t> signature;
+ EXPECT_TRUE(reader.GetCodeSignatureInfo(&signature));
+ EXPECT_EQ(9344u, signature.size());
+
+ std::string identity;
+ GetSigningIdentity(signature, &identity);
+ EXPECT_EQ("signedexecutable32", identity);
+
+ ExpectCodeSignatureHash(signature,
+ "11fb88eb63c10dfc3d24a2545ea2a9c50c2921b5");
+}
+
+TEST_F(MachOImageReaderTest, SignedExecutableFat) {
+ base::MemoryMappedFile file;
+ ASSERT_NO_FATAL_FAILURE(OpenTestFile("signedexecutablefat", &file));
+ MachOImageReader reader;
+ ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+ EXPECT_TRUE(reader.IsFat());
+ auto images = reader.GetFatImages();
+ ASSERT_EQ(2u, images.size());
+
+ // Note: this image is crafted to have 32-bit first.
+ {
+ EXPECT_FALSE(images[0]->IsFat());
+ EXPECT_FALSE(images[0]->Is64Bit());
+ EXPECT_TRUE(images[0]->GetMachHeader());
+ EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[0]->GetFileType());
+
+ std::vector<uint8_t> signature;
+ EXPECT_TRUE(images[0]->GetCodeSignatureInfo(&signature));
+ EXPECT_EQ(9344u, signature.size());
+
+ std::string identity;
+ GetSigningIdentity(signature, &identity);
+ EXPECT_EQ("signedexecutablefat", identity);
+
+ ExpectCodeSignatureHash(signature,
+ "11fb88eb63c10dfc3d24a2545ea2a9c50c2921b5");
+ }
+
+ {
+ EXPECT_FALSE(images[1]->IsFat());
+ EXPECT_TRUE(images[1]->Is64Bit());
+ EXPECT_TRUE(images[1]->GetMachHeader());
+ EXPECT_TRUE(images[1]->GetMachHeader64());
+ EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), images[1]->GetFileType());
+
+ std::vector<uint8_t> signature;
+ EXPECT_TRUE(images[1]->GetCodeSignatureInfo(&signature));
+ EXPECT_EQ(9344u, signature.size());
+
+ std::string identity;
+ GetSigningIdentity(signature, &identity);
+ EXPECT_EQ("signedexecutablefat", identity);
+
+ ExpectCodeSignatureHash(signature,
+ "750a57326ba85857371094900475defd837f5e14");
+ }
+}
+
+TEST_F(MachOImageReaderTest, SignedDylib64) {
+ base::MemoryMappedFile file;
+ ASSERT_NO_FATAL_FAILURE(OpenTestFile("libsigned64.dylib", &file));
+ MachOImageReader reader;
+ ASSERT_TRUE(reader.Initialize(file.data(), file.length()));
+
+ EXPECT_FALSE(reader.IsFat());
+ EXPECT_TRUE(reader.Is64Bit());
+ EXPECT_TRUE(reader.GetMachHeader());
+ EXPECT_TRUE(reader.GetMachHeader64());
+ EXPECT_EQ(static_cast<uint32_t>(MH_DYLIB), reader.GetFileType());
+ EXPECT_EQ(14u, reader.GetLoadCommands().size());
+
+ std::vector<uint8_t> signature;
+ EXPECT_TRUE(reader.GetCodeSignatureInfo(&signature));
+ EXPECT_EQ(9328u, signature.size());
+
+ std::string identity;
+ GetSigningIdentity(signature, &identity);
+ EXPECT_EQ("libsigned64", identity);
+
+ ExpectCodeSignatureHash(signature,
+ "8b1c79b60bb53a7f17b5618d5feb10dc8b88d806");
+}
+
+TEST_F(MachOImageReaderTest, NotMachO) {
+ base::MemoryMappedFile file;
+ ASSERT_NO_FATAL_FAILURE(OpenTestFile("src.c", &file));
+ MachOImageReader reader;
+ EXPECT_FALSE(reader.Initialize(file.data(), file.length()));
+}
+
+TEST_F(MachOImageReaderTest, IsMachOMagicValue) {
+ static const uint32_t kMagics[] = { MH_MAGIC, MH_MAGIC, FAT_MAGIC };
+ for (uint32_t magic : kMagics) {
+ SCOPED_TRACE(base::StringPrintf("0x%x", magic));
+ EXPECT_TRUE(MachOImageReader::IsMachOMagicValue(magic));
+ EXPECT_TRUE(MachOImageReader::IsMachOMagicValue(OSSwapInt32(magic)));
+ }
+}
+
+// https://crbug.com/524044
+TEST_F(MachOImageReaderTest, CmdsizeSmallerThanLoadCommand) {
+#pragma pack(push, 1)
+ struct TestImage {
+ mach_header_64 header;
+ segment_command_64 page_zero;
+ load_command small_sized;
+ segment_command_64 fake_code;
+ };
+#pragma pack(pop)
+
+ TestImage test_image = {};
+
+ test_image.header.magic = MH_MAGIC_64;
+ test_image.header.cputype = CPU_TYPE_X86_64;
+ test_image.header.filetype = MH_EXECUTE;
+ test_image.header.ncmds = 3;
+ test_image.header.sizeofcmds = sizeof(test_image) - sizeof(test_image.header);
+
+ test_image.page_zero.cmd = LC_SEGMENT;
+ test_image.page_zero.cmdsize = sizeof(test_image.page_zero);
+ strcpy(test_image.page_zero.segname, SEG_PAGEZERO);
+ test_image.page_zero.vmsize = PAGE_SIZE;
+
+ test_image.small_sized.cmd = LC_SYMSEG;
+ test_image.small_sized.cmdsize = sizeof(test_image.small_sized) - 3;
+
+ test_image.fake_code.cmd = LC_SEGMENT;
+ test_image.fake_code.cmdsize = sizeof(test_image.fake_code);
+ strcpy(test_image.fake_code.segname, SEG_TEXT);
+
+ MachOImageReader reader;
+ EXPECT_TRUE(reader.Initialize(reinterpret_cast<const uint8_t*>(&test_image),
+ sizeof(test_image)));
+
+ EXPECT_FALSE(reader.IsFat());
+ EXPECT_TRUE(reader.Is64Bit());
+
+ const auto& load_commands = reader.GetLoadCommands();
+ EXPECT_EQ(3u, load_commands.size());
+
+ EXPECT_EQ(static_cast<uint32_t>(LC_SEGMENT), load_commands[0].cmd());
+ EXPECT_EQ(static_cast<uint32_t>(LC_SYMSEG), load_commands[1].cmd());
+ EXPECT_EQ(sizeof(load_command) - 3, load_commands[1].cmdsize());
+ EXPECT_EQ(static_cast<uint32_t>(LC_SEGMENT), load_commands[2].cmd());
+}
+
+// https://crbug.com/591194
+TEST_F(MachOImageReaderTest, RecurseFatHeader) {
+#pragma pack(push, 1)
+ struct TestImage {
+ fat_header header;
+ fat_arch arch1;
+ fat_arch arch2;
+ mach_header_64 macho64;
+ mach_header macho;
+ };
+#pragma pack(pop)
+
+ TestImage test_image = {};
+ test_image.header.magic = FAT_MAGIC;
+ test_image.header.nfat_arch = 2;
+ test_image.arch1.offset = offsetof(TestImage, macho64);
+ test_image.arch1.size = sizeof(mach_header_64);
+ test_image.arch2.offset = 0; // Cannot point back at the fat_header.
+ test_image.arch2.size = sizeof(test_image);
+
+ test_image.macho64.magic = MH_MAGIC_64;
+ test_image.macho.magic = MH_MAGIC;
+
+ MachOImageReader reader;
+ EXPECT_FALSE(reader.Initialize(reinterpret_cast<const uint8_t*>(&test_image),
+ sizeof(test_image)));
+}
+
+} // namespace
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/mock_binary_feature_extractor.cc b/chromium/chrome/common/safe_browsing/mock_binary_feature_extractor.cc
new file mode 100644
index 00000000000..0f5baa80c6d
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/mock_binary_feature_extractor.cc
@@ -0,0 +1,13 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/mock_binary_feature_extractor.h"
+
+namespace safe_browsing {
+
+MockBinaryFeatureExtractor::MockBinaryFeatureExtractor() {}
+
+MockBinaryFeatureExtractor::~MockBinaryFeatureExtractor() {}
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/mock_binary_feature_extractor.h b/chromium/chrome/common/safe_browsing/mock_binary_feature_extractor.h
new file mode 100644
index 00000000000..a3223f149e3
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/mock_binary_feature_extractor.h
@@ -0,0 +1,34 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_MOCK_BINARY_FEATURE_EXTRACTOR_H_
+#define CHROME_COMMON_SAFE_BROWSING_MOCK_BINARY_FEATURE_EXTRACTOR_H_
+
+#include "chrome/common/safe_browsing/binary_feature_extractor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace safe_browsing {
+
+class MockBinaryFeatureExtractor : public BinaryFeatureExtractor {
+ public:
+ MockBinaryFeatureExtractor();
+ MOCK_METHOD2(CheckSignature,
+ void(const base::FilePath&,
+ ClientDownloadRequest_SignatureInfo*));
+ MOCK_METHOD4(ExtractImageFeatures,
+ bool(const base::FilePath&,
+ ExtractHeadersOption,
+ ClientDownloadRequest_ImageHeaders*,
+ google::protobuf::RepeatedPtrField<std::string>*));
+
+ protected:
+ ~MockBinaryFeatureExtractor() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockBinaryFeatureExtractor);
+};
+
+} // namespace safe_browsing
+
+#endif // CHROME_COMMON_SAFE_BROWSING_MOCK_BINARY_FEATURE_EXTRACTOR_H_
diff --git a/chromium/chrome/common/safe_browsing/pe_image_reader_win.cc b/chromium/chrome/common/safe_browsing/pe_image_reader_win.cc
new file mode 100644
index 00000000000..db678abc008
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/pe_image_reader_win.cc
@@ -0,0 +1,390 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/pe_image_reader_win.h"
+
+#include <wintrust.h>
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/numerics/safe_math.h"
+
+namespace safe_browsing {
+
+// A class template of traits pertaining to IMAGE_OPTIONAL_HEADER{32,64}.
+template<class HEADER_TYPE>
+struct OptionalHeaderTraits {
+};
+
+template<>
+struct OptionalHeaderTraits<IMAGE_OPTIONAL_HEADER32> {
+ static const PeImageReader::WordSize word_size = PeImageReader::WORD_SIZE_32;
+};
+
+template<>
+struct OptionalHeaderTraits<IMAGE_OPTIONAL_HEADER64> {
+ static const PeImageReader::WordSize word_size = PeImageReader::WORD_SIZE_64;
+};
+
+// A template for type-specific optional header implementations. This, in
+// conjunction with the OptionalHeader interface, effectively erases the
+// underlying structure type from the point of view of the PeImageReader.
+template<class OPTIONAL_HEADER_TYPE>
+class PeImageReader::OptionalHeaderImpl : public PeImageReader::OptionalHeader {
+ public:
+ typedef OptionalHeaderTraits<OPTIONAL_HEADER_TYPE> TraitsType;
+
+ explicit OptionalHeaderImpl(const uint8_t* optional_header_start)
+ : optional_header_(reinterpret_cast<const OPTIONAL_HEADER_TYPE*>(
+ optional_header_start)) {}
+
+ WordSize GetWordSize() override {
+ return TraitsType::word_size;
+ }
+
+ size_t GetDataDirectoryOffset() override {
+ return offsetof(OPTIONAL_HEADER_TYPE, DataDirectory);
+ }
+
+ DWORD GetDataDirectorySize() override {
+ return optional_header_->NumberOfRvaAndSizes;
+ }
+
+ const IMAGE_DATA_DIRECTORY* GetDataDirectoryEntries() override {
+ return &optional_header_->DataDirectory[0];
+ }
+
+ DWORD GetSizeOfImage() override { return optional_header_->SizeOfImage; }
+
+ private:
+ const OPTIONAL_HEADER_TYPE* optional_header_;
+ DISALLOW_COPY_AND_ASSIGN(OptionalHeaderImpl);
+};
+
+PeImageReader::PeImageReader()
+ : image_data_(),
+ image_size_(),
+ validation_state_() {}
+
+PeImageReader::~PeImageReader() {
+ Clear();
+}
+
+bool PeImageReader::Initialize(const uint8_t* image_data, size_t image_size) {
+ image_data_ = image_data;
+ image_size_ = image_size;
+
+ if (!ValidateDosHeader() ||
+ !ValidatePeSignature() ||
+ !ValidateCoffFileHeader() ||
+ !ValidateOptionalHeader() ||
+ !ValidateSectionHeaders()) {
+ Clear();
+ return false;
+ }
+
+ return true;
+}
+
+PeImageReader::WordSize PeImageReader::GetWordSize() {
+ return optional_header_->GetWordSize();
+}
+
+const IMAGE_DOS_HEADER* PeImageReader::GetDosHeader() {
+ DCHECK_NE((validation_state_ & VALID_DOS_HEADER), 0U);
+ return reinterpret_cast<const IMAGE_DOS_HEADER*>(image_data_);
+}
+
+const IMAGE_FILE_HEADER* PeImageReader::GetCoffFileHeader() {
+ DCHECK_NE((validation_state_ & VALID_COFF_FILE_HEADER), 0U);
+ return reinterpret_cast<const IMAGE_FILE_HEADER*>(
+ image_data_ + GetDosHeader()->e_lfanew + sizeof(DWORD));
+}
+
+const uint8_t* PeImageReader::GetOptionalHeaderData(
+ size_t* optional_header_size) {
+ *optional_header_size = GetOptionalHeaderSize();
+ return GetOptionalHeaderStart();
+}
+
+size_t PeImageReader::GetNumberOfSections() {
+ return GetCoffFileHeader()->NumberOfSections;
+}
+
+const IMAGE_SECTION_HEADER* PeImageReader::GetSectionHeaderAt(size_t index) {
+ DCHECK_NE((validation_state_ & VALID_SECTION_HEADERS), 0U);
+ DCHECK_LT(index, GetNumberOfSections());
+ return reinterpret_cast<const IMAGE_SECTION_HEADER*>(
+ GetOptionalHeaderStart() +
+ GetOptionalHeaderSize() +
+ (sizeof(IMAGE_SECTION_HEADER) * index));
+}
+
+const uint8_t* PeImageReader::GetExportSection(size_t* section_size) {
+ size_t data_size = 0;
+ const uint8_t* data = GetImageData(IMAGE_DIRECTORY_ENTRY_EXPORT, &data_size);
+
+ // The export section data must be big enough for the export directory.
+ if (!data || data_size < sizeof(IMAGE_EXPORT_DIRECTORY))
+ return NULL;
+
+ *section_size = data_size;
+ return data;
+}
+
+size_t PeImageReader::GetNumberOfDebugEntries() {
+ size_t data_size = 0;
+ const uint8_t* data = GetImageData(IMAGE_DIRECTORY_ENTRY_DEBUG, &data_size);
+ return data ? (data_size / sizeof(IMAGE_DEBUG_DIRECTORY)) : 0;
+}
+
+const IMAGE_DEBUG_DIRECTORY* PeImageReader::GetDebugEntry(
+ size_t index,
+ const uint8_t** raw_data,
+ size_t* raw_data_size) {
+ DCHECK_LT(index, GetNumberOfDebugEntries());
+
+ // Get the debug directory.
+ size_t debug_directory_size = 0;
+ const IMAGE_DEBUG_DIRECTORY* entries =
+ reinterpret_cast<const IMAGE_DEBUG_DIRECTORY*>(
+ GetImageData(IMAGE_DIRECTORY_ENTRY_DEBUG, &debug_directory_size));
+ if (!entries)
+ return NULL;
+
+ const IMAGE_DEBUG_DIRECTORY& entry = entries[index];
+ const uint8_t* debug_data = NULL;
+ if (GetStructureAt(entry.PointerToRawData, entry.SizeOfData, &debug_data)) {
+ *raw_data = debug_data;
+ *raw_data_size = entry.SizeOfData;
+ }
+ return &entry;
+}
+
+bool PeImageReader::EnumCertificates(EnumCertificatesCallback callback,
+ void* context) {
+ size_t data_size = 0;
+ const uint8_t* data = GetImageData(IMAGE_DIRECTORY_ENTRY_SECURITY,
+ &data_size);
+ if (!data)
+ return false; // Certificate table is out of bounds.
+ const size_t kWinCertificateSize = offsetof(WIN_CERTIFICATE, bCertificate);
+ while (data_size) {
+ const WIN_CERTIFICATE* win_certificate =
+ reinterpret_cast<const WIN_CERTIFICATE*>(data);
+ if (kWinCertificateSize > data_size ||
+ kWinCertificateSize > win_certificate->dwLength ||
+ win_certificate->dwLength > data_size) {
+ return false;
+ }
+ if (!(*callback)(win_certificate->wRevision,
+ win_certificate->wCertificateType,
+ &win_certificate->bCertificate[0],
+ win_certificate->dwLength - kWinCertificateSize,
+ context)) {
+ return false;
+ }
+ size_t padded_length = (win_certificate->dwLength + 7) & ~0x7;
+ // Don't overflow when recalculating data_size, since padded_length can be
+ // attacker controlled.
+ if (!base::CheckSub(data_size, padded_length).AssignIfValid(&data_size))
+ return false;
+ data += padded_length;
+ }
+ return true;
+}
+
+DWORD PeImageReader::GetSizeOfImage() {
+ return optional_header_->GetSizeOfImage();
+}
+
+void PeImageReader::Clear() {
+ image_data_ = NULL;
+ image_size_ = 0;
+ validation_state_ = 0;
+ optional_header_.reset();
+}
+
+bool PeImageReader::ValidateDosHeader() {
+ const IMAGE_DOS_HEADER* dos_header = NULL;
+ if (!GetStructureAt(0, &dos_header) ||
+ dos_header->e_magic != IMAGE_DOS_SIGNATURE ||
+ dos_header->e_lfanew < 0) {
+ return false;
+ }
+
+ validation_state_ |= VALID_DOS_HEADER;
+ return true;
+}
+
+bool PeImageReader::ValidatePeSignature() {
+ const DWORD* signature = NULL;
+ if (!GetStructureAt(GetDosHeader()->e_lfanew, &signature) ||
+ *signature != IMAGE_NT_SIGNATURE) {
+ return false;
+ }
+
+ validation_state_ |= VALID_PE_SIGNATURE;
+ return true;
+}
+
+bool PeImageReader::ValidateCoffFileHeader() {
+ DCHECK_NE((validation_state_ & VALID_PE_SIGNATURE), 0U);
+ const IMAGE_FILE_HEADER* file_header = NULL;
+ if (!GetStructureAt(GetDosHeader()->e_lfanew +
+ offsetof(IMAGE_NT_HEADERS32, FileHeader),
+ &file_header)) {
+ return false;
+ }
+
+ validation_state_ |= VALID_COFF_FILE_HEADER;
+ return true;
+}
+
+bool PeImageReader::ValidateOptionalHeader() {
+ const IMAGE_FILE_HEADER* file_header = GetCoffFileHeader();
+ const size_t optional_header_offset =
+ GetDosHeader()->e_lfanew + offsetof(IMAGE_NT_HEADERS32, OptionalHeader);
+ const size_t optional_header_size = file_header->SizeOfOptionalHeader;
+ const WORD* optional_header_magic = NULL;
+
+ if (optional_header_size < sizeof(*optional_header_magic) ||
+ !GetStructureAt(optional_header_offset, &optional_header_magic)) {
+ return false;
+ }
+
+ std::unique_ptr<OptionalHeader> optional_header;
+ if (*optional_header_magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ optional_header.reset(new OptionalHeaderImpl<IMAGE_OPTIONAL_HEADER32>(
+ image_data_ + optional_header_offset));
+ } else if (*optional_header_magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ optional_header.reset(new OptionalHeaderImpl<IMAGE_OPTIONAL_HEADER64>(
+ image_data_ + optional_header_offset));
+ } else {
+ return false;
+ }
+
+ // Does all of the claimed optional header fit in the image?
+ if (optional_header_size > image_size_ - optional_header_offset)
+ return false;
+
+ // Is the claimed optional header big enough for everything but the dir?
+ if (optional_header->GetDataDirectoryOffset() > optional_header_size)
+ return false;
+
+ // Is there enough room for all of the claimed directory entries?
+ if (optional_header->GetDataDirectorySize() >
+ ((optional_header_size - optional_header->GetDataDirectoryOffset()) /
+ sizeof(IMAGE_DATA_DIRECTORY))) {
+ return false;
+ }
+
+ optional_header_.swap(optional_header);
+ validation_state_ |= VALID_OPTIONAL_HEADER;
+ return true;
+}
+
+bool PeImageReader::ValidateSectionHeaders() {
+ const uint8_t* first_section_header =
+ GetOptionalHeaderStart() + GetOptionalHeaderSize();
+ const size_t number_of_sections = GetNumberOfSections();
+
+ // Do all section headers fit in the image?
+ if (!GetStructureAt(first_section_header - image_data_,
+ number_of_sections * sizeof(IMAGE_SECTION_HEADER),
+ &first_section_header)) {
+ return false;
+ }
+
+ validation_state_ |= VALID_SECTION_HEADERS;
+ return true;
+}
+
+const uint8_t* PeImageReader::GetOptionalHeaderStart() {
+ DCHECK_NE((validation_state_ & VALID_OPTIONAL_HEADER), 0U);
+ return (image_data_ +
+ GetDosHeader()->e_lfanew +
+ offsetof(IMAGE_NT_HEADERS32, OptionalHeader));
+}
+
+size_t PeImageReader::GetOptionalHeaderSize() {
+ return GetCoffFileHeader()->SizeOfOptionalHeader;
+}
+
+const IMAGE_DATA_DIRECTORY* PeImageReader::GetDataDirectoryEntryAt(
+ size_t index) {
+ DCHECK_NE((validation_state_ & VALID_OPTIONAL_HEADER), 0U);
+ if (index >= optional_header_->GetDataDirectorySize())
+ return NULL;
+ return &optional_header_->GetDataDirectoryEntries()[index];
+}
+
+const IMAGE_SECTION_HEADER* PeImageReader::FindSectionFromRva(
+ uint32_t relative_address) {
+ const size_t number_of_sections = GetNumberOfSections();
+ for (size_t i = 0; i < number_of_sections; ++i) {
+ const IMAGE_SECTION_HEADER* section_header = GetSectionHeaderAt(i);
+ // Is the raw data present in the image? If no, optimistically keep looking.
+ const uint8_t* section_data = NULL;
+ if (!GetStructureAt(section_header->PointerToRawData,
+ section_header->SizeOfRawData,
+ &section_data)) {
+ continue;
+ }
+ // Does the RVA lie on or after this section's start when mapped? If no,
+ // bail.
+ if (section_header->VirtualAddress > relative_address)
+ break;
+ // Does the RVA lie within the section when mapped? If no, keep looking.
+ size_t address_offset = relative_address - section_header->VirtualAddress;
+ if (address_offset > section_header->Misc.VirtualSize)
+ continue;
+ // We have a winner.
+ return section_header;
+ }
+ return NULL;
+}
+
+const uint8_t* PeImageReader::GetImageData(size_t index, size_t* data_length) {
+ // Get the requested directory entry.
+ const IMAGE_DATA_DIRECTORY* entry = GetDataDirectoryEntryAt(index);
+ if (!entry)
+ return NULL;
+
+ // The entry for the certificate table is special in that its address is a
+ // file pointer rather than an RVA.
+ if (index == IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ // Does the data fit within the file.
+ if (entry->VirtualAddress > image_size_ ||
+ image_size_ - entry->VirtualAddress < entry->Size) {
+ return nullptr;
+ }
+ *data_length = entry->Size;
+ return image_data_ + entry->VirtualAddress;
+ }
+
+ // Find the section containing the data.
+ const IMAGE_SECTION_HEADER* header =
+ FindSectionFromRva(entry->VirtualAddress);
+ if (!header)
+ return NULL;
+
+ // Does the data fit within the section when mapped?
+ size_t data_offset = entry->VirtualAddress - header->VirtualAddress;
+ if (entry->Size > (header->Misc.VirtualSize - data_offset))
+ return NULL;
+
+ // Is the data entirely present on disk (if not it's zeroed out when loaded)?
+ if (data_offset >= header->SizeOfRawData ||
+ header->SizeOfRawData - data_offset < entry->Size) {
+ return NULL;
+ }
+
+ *data_length = entry->Size;
+ return image_data_ + header->PointerToRawData + data_offset;
+}
+
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/pe_image_reader_win.h b/chromium/chrome/common/safe_browsing/pe_image_reader_win.h
new file mode 100644
index 00000000000..30c2d255cd8
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/pe_image_reader_win.h
@@ -0,0 +1,164 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_PE_IMAGE_READER_WIN_H_
+#define CHROME_COMMON_SAFE_BROWSING_PE_IMAGE_READER_WIN_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <windows.h>
+
+#include <memory>
+
+#include "base/macros.h"
+
+namespace safe_browsing {
+
+// Parses headers and various data from a PE image. This parser is safe for use
+// on untrusted data.
+class PeImageReader {
+ public:
+ enum WordSize {
+ WORD_SIZE_32,
+ WORD_SIZE_64,
+ };
+
+ // A callback invoked by EnumCertificates once for each attribute certificate
+ // entry in the image's attribute certificate table. |revision| and
+ // |certificate_type| identify the contents of |certificate_data| (which is of
+ // |certificate_data_size| bytes). |context| is the value provided by the
+ // caller to EnumCertificates(). Implementations must return true to continue
+ // the enumeration, or false to abort.
+ typedef bool (*EnumCertificatesCallback)(uint16_t revision,
+ uint16_t certificate_type,
+ const uint8_t* certificate_data,
+ size_t certificate_data_size,
+ void* context);
+
+ PeImageReader();
+ ~PeImageReader();
+
+ // Returns false if the given data does not appear to be a valid PE image.
+ bool Initialize(const uint8_t* image_data, size_t image_size);
+
+ // Returns the machine word size for the image.
+ WordSize GetWordSize();
+
+ const IMAGE_DOS_HEADER* GetDosHeader();
+ const IMAGE_FILE_HEADER* GetCoffFileHeader();
+
+ // Returns a pointer to the optional header and its size.
+ const uint8_t* GetOptionalHeaderData(size_t* optional_data_size);
+ size_t GetNumberOfSections();
+ const IMAGE_SECTION_HEADER* GetSectionHeaderAt(size_t index);
+
+ // Returns a pointer to the image's export data (.edata) section and its size,
+ // or NULL if the section is not present.
+ const uint8_t* GetExportSection(size_t* section_size);
+
+ size_t GetNumberOfDebugEntries();
+ const IMAGE_DEBUG_DIRECTORY* GetDebugEntry(size_t index,
+ const uint8_t** raw_data,
+ size_t* raw_data_size);
+
+ // Invokes |callback| once per attribute certificate entry. |context| is a
+ // caller-specific value that is passed to |callback|. Returns true if all
+ // certificate entries are visited (even if there are no such entries) and
+ // |callback| returns true for each. Conversely, returns |false| if |callback|
+ // returns false or if the image is malformed in any way.
+ bool EnumCertificates(EnumCertificatesCallback callback,
+ void* context);
+
+ // Returns the size of the image file.
+ DWORD GetSizeOfImage();
+
+ private:
+ // Bits indicating what portions of the image have been validated.
+ enum ValidationStages {
+ VALID_DOS_HEADER = 1 << 0,
+ VALID_PE_SIGNATURE = 1 << 1,
+ VALID_COFF_FILE_HEADER = 1 << 2,
+ VALID_OPTIONAL_HEADER = 1 << 3,
+ VALID_SECTION_HEADERS = 1 << 4,
+ };
+
+ // An interface to an image's optional header.
+ class OptionalHeader {
+ public:
+ virtual ~OptionalHeader() {}
+
+ virtual WordSize GetWordSize() = 0;
+
+ // Returns the offset of the DataDirectory member relative to the start of
+ // the optional header.
+ virtual size_t GetDataDirectoryOffset() = 0;
+
+ // Returns the number of entries in the data directory.
+ virtual DWORD GetDataDirectorySize() = 0;
+
+ // Returns a pointer to the first data directory entry.
+ virtual const IMAGE_DATA_DIRECTORY* GetDataDirectoryEntries() = 0;
+
+ // Returns the size of the image file.
+ virtual DWORD GetSizeOfImage() = 0;
+ };
+
+ template<class OPTIONAL_HEADER_TYPE>
+ class OptionalHeaderImpl;
+
+ void Clear();
+ bool ValidateDosHeader();
+ bool ValidatePeSignature();
+ bool ValidateCoffFileHeader();
+ bool ValidateOptionalHeader();
+ bool ValidateSectionHeaders();
+
+ // Return a pointer to the first byte of the image's optional header.
+ const uint8_t* GetOptionalHeaderStart();
+ size_t GetOptionalHeaderSize();
+
+ // Returns the desired directory entry, or NULL if |index| is out of bounds.
+ const IMAGE_DATA_DIRECTORY* GetDataDirectoryEntryAt(size_t index);
+
+ // Returns the header for the section that contains the given address, or NULL
+ // if the address is out of bounds or the image does not contain the section.
+ const IMAGE_SECTION_HEADER* FindSectionFromRva(uint32_t relative_address);
+
+ // Returns a pointer to the |data_length| bytes referenced by the |index|'th
+ // data directory entry.
+ const uint8_t* GetImageData(size_t index, size_t* data_length);
+
+ // Populates |structure| with a pointer to a desired structure of type T at
+ // the given offset if the image is sufficiently large to contain it. Returns
+ // false if the structure does not fully fit within the image at the given
+ // offset.
+ template<typename T> bool GetStructureAt(size_t offset, const T** structure) {
+ return GetStructureAt(offset, sizeof(**structure), structure);
+ }
+
+ // Populates |structure| with a pointer to a desired structure of type T at
+ // the given offset if the image is sufficiently large to contain
+ // |structure_size| bytes. Returns false if the structure does not fully fit
+ // within the image at the given offset.
+ template<typename T> bool GetStructureAt(size_t offset,
+ size_t structure_size,
+ const T** structure) {
+ if (offset > image_size_)
+ return false;
+ if (structure_size > image_size_ - offset)
+ return false;
+ *structure = reinterpret_cast<const T*>(image_data_ + offset);
+ return true;
+ }
+
+ const uint8_t* image_data_;
+ size_t image_size_;
+ uint32_t validation_state_;
+ std::unique_ptr<OptionalHeader> optional_header_;
+ DISALLOW_COPY_AND_ASSIGN(PeImageReader);
+};
+
+} // namespace safe_browsing
+
+#endif // CHROME_COMMON_SAFE_BROWSING_PE_IMAGE_READER_WIN_H_
diff --git a/chromium/chrome/common/safe_browsing/pe_image_reader_win_unittest.cc b/chromium/chrome/common/safe_browsing/pe_image_reader_win_unittest.cc
new file mode 100644
index 00000000000..f31c417e95b
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/pe_image_reader_win_unittest.cc
@@ -0,0 +1,294 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <wintrust.h>
+
+#include "base/files/file_path.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/macros.h"
+#include "base/path_service.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/safe_browsing/pe_image_reader_win.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Gt;
+using ::testing::NotNull;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+struct TestData {
+ const char* filename;
+ safe_browsing::PeImageReader::WordSize word_size;
+ WORD machine_identifier;
+ WORD optional_header_size;
+ size_t number_of_sections;
+ size_t number_of_debug_entries;
+};
+
+// A test fixture parameterized on test data containing the name of a PE image
+// to parse and the expected values to be read from it. The file is read from
+// the src/chrome/test/data/safe_browsing directory.
+class PeImageReaderTest : public testing::TestWithParam<const TestData*> {
+ protected:
+ PeImageReaderTest() : expected_data_(GetParam()) {}
+
+ void SetUp() override {
+ ASSERT_TRUE(
+ base::PathService::Get(chrome::DIR_TEST_DATA, &data_file_path_));
+ data_file_path_ = data_file_path_.AppendASCII("safe_browsing");
+ data_file_path_ = data_file_path_.AppendASCII(expected_data_->filename);
+
+ ASSERT_TRUE(data_file_.Initialize(data_file_path_));
+
+ ASSERT_TRUE(image_reader_.Initialize(data_file_.data(),
+ data_file_.length()));
+ }
+
+ const TestData* expected_data_;
+ base::FilePath data_file_path_;
+ base::MemoryMappedFile data_file_;
+ safe_browsing::PeImageReader image_reader_;
+};
+
+TEST_P(PeImageReaderTest, GetWordSize) {
+ EXPECT_EQ(expected_data_->word_size, image_reader_.GetWordSize());
+}
+
+TEST_P(PeImageReaderTest, GetDosHeader) {
+ const IMAGE_DOS_HEADER* dos_header = image_reader_.GetDosHeader();
+ ASSERT_NE(reinterpret_cast<const IMAGE_DOS_HEADER*>(NULL), dos_header);
+ EXPECT_EQ(IMAGE_DOS_SIGNATURE, dos_header->e_magic);
+}
+
+TEST_P(PeImageReaderTest, GetCoffFileHeader) {
+ const IMAGE_FILE_HEADER* file_header = image_reader_.GetCoffFileHeader();
+ ASSERT_NE(reinterpret_cast<const IMAGE_FILE_HEADER*>(NULL), file_header);
+ EXPECT_EQ(expected_data_->machine_identifier, file_header->Machine);
+ EXPECT_EQ(expected_data_->optional_header_size,
+ file_header->SizeOfOptionalHeader);
+}
+
+TEST_P(PeImageReaderTest, GetOptionalHeaderData) {
+ size_t optional_header_size = 0;
+ const uint8_t* optional_header_data =
+ image_reader_.GetOptionalHeaderData(&optional_header_size);
+ ASSERT_NE(reinterpret_cast<const uint8_t*>(NULL), optional_header_data);
+ EXPECT_EQ(expected_data_->optional_header_size, optional_header_size);
+}
+
+TEST_P(PeImageReaderTest, GetNumberOfSections) {
+ EXPECT_EQ(expected_data_->number_of_sections,
+ image_reader_.GetNumberOfSections());
+}
+
+TEST_P(PeImageReaderTest, GetSectionHeaderAt) {
+ size_t number_of_sections = image_reader_.GetNumberOfSections();
+ for (size_t i = 0; i < number_of_sections; ++i) {
+ const IMAGE_SECTION_HEADER* section_header =
+ image_reader_.GetSectionHeaderAt(i);
+ ASSERT_NE(reinterpret_cast<const IMAGE_SECTION_HEADER*>(NULL),
+ section_header);
+ }
+}
+
+TEST_P(PeImageReaderTest, InitializeFailTruncatedFile) {
+ // Compute the size of all headers through the section headers.
+ const IMAGE_SECTION_HEADER* last_section_header =
+ image_reader_.GetSectionHeaderAt(image_reader_.GetNumberOfSections() - 1);
+ const uint8_t* headers_end =
+ reinterpret_cast<const uint8_t*>(last_section_header) +
+ sizeof(*last_section_header);
+ size_t header_size = headers_end - data_file_.data();
+ safe_browsing::PeImageReader short_reader;
+
+ // Initialize should succeed when all headers are present.
+ EXPECT_TRUE(short_reader.Initialize(data_file_.data(), header_size));
+
+ // But fail if anything is missing.
+ for (size_t i = 0; i < header_size; ++i) {
+ EXPECT_FALSE(short_reader.Initialize(data_file_.data(), i));
+ }
+}
+
+TEST_P(PeImageReaderTest, GetExportSection) {
+ size_t section_size = 0;
+ const uint8_t* export_section = image_reader_.GetExportSection(&section_size);
+ ASSERT_NE(reinterpret_cast<const uint8_t*>(NULL), export_section);
+ EXPECT_NE(0U, section_size);
+}
+
+TEST_P(PeImageReaderTest, GetNumberOfDebugEntries) {
+ EXPECT_EQ(expected_data_->number_of_debug_entries,
+ image_reader_.GetNumberOfDebugEntries());
+}
+
+TEST_P(PeImageReaderTest, GetDebugEntry) {
+ size_t number_of_debug_entries = image_reader_.GetNumberOfDebugEntries();
+ for (size_t i = 0; i < number_of_debug_entries; ++i) {
+ const uint8_t* raw_data = NULL;
+ size_t raw_data_size = 0;
+ const IMAGE_DEBUG_DIRECTORY* entry =
+ image_reader_.GetDebugEntry(i, &raw_data, &raw_data_size);
+ EXPECT_NE(reinterpret_cast<const IMAGE_DEBUG_DIRECTORY*>(NULL), entry);
+ EXPECT_NE(reinterpret_cast<const uint8_t*>(NULL), raw_data);
+ EXPECT_NE(0U, raw_data_size);
+ }
+}
+
+namespace {
+
+const TestData kTestData[] = {
+ {
+ "module_with_exports_x86.dll",
+ safe_browsing::PeImageReader::WORD_SIZE_32,
+ IMAGE_FILE_MACHINE_I386,
+ sizeof(IMAGE_OPTIONAL_HEADER32),
+ 4,
+ 1,
+ }, {
+ "module_with_exports_x64.dll",
+ safe_browsing::PeImageReader::WORD_SIZE_64,
+ IMAGE_FILE_MACHINE_AMD64,
+ sizeof(IMAGE_OPTIONAL_HEADER64),
+ 5,
+ 1,
+ },
+};
+
+} // namespace
+
+INSTANTIATE_TEST_SUITE_P(WordSize32,
+ PeImageReaderTest,
+ testing::Values(&kTestData[0]));
+INSTANTIATE_TEST_SUITE_P(WordSize64,
+ PeImageReaderTest,
+ testing::Values(&kTestData[1]));
+
+// An object exposing a PeImageReader::EnumCertificatesCallback that invokes a
+// virtual OnCertificate() method. This method is suitable for mocking in tests.
+class CertificateReceiver {
+ public:
+ void* AsContext() { return this; }
+ static bool OnCertificateCallback(uint16_t revision,
+ uint16_t certificate_type,
+ const uint8_t* certificate_data,
+ size_t certificate_data_size,
+ void* context) {
+ return reinterpret_cast<CertificateReceiver*>(context)->OnCertificate(
+ revision, certificate_type, certificate_data, certificate_data_size);
+ }
+
+ protected:
+ CertificateReceiver() {}
+ virtual ~CertificateReceiver() {}
+ virtual bool OnCertificate(uint16_t revision,
+ uint16_t certificate_type,
+ const uint8_t* certificate_data,
+ size_t certificate_data_size) = 0;
+};
+
+class MockCertificateReceiver : public CertificateReceiver {
+ public:
+ MockCertificateReceiver() {}
+ MOCK_METHOD4(OnCertificate, bool(uint16_t, uint16_t, const uint8_t*, size_t));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCertificateReceiver);
+};
+
+struct CertificateTestData {
+ const char* filename;
+ int num_signers;
+};
+
+// A test fixture parameterized on test data containing the name of a PE image
+// to parse and the expected values to be read from it. The file is read from
+// the src/chrome/test/data/safe_browsing/download_protection directory.
+class PeImageReaderCertificateTest
+ : public testing::TestWithParam<const CertificateTestData*> {
+ protected:
+ PeImageReaderCertificateTest() : expected_data_(GetParam()) {}
+
+ void SetUp() override {
+ ASSERT_TRUE(
+ base::PathService::Get(chrome::DIR_TEST_DATA, &data_file_path_));
+ data_file_path_ = data_file_path_.AppendASCII("safe_browsing");
+ data_file_path_ = data_file_path_.AppendASCII("download_protection");
+ data_file_path_ = data_file_path_.AppendASCII(expected_data_->filename);
+ ASSERT_TRUE(data_file_.Initialize(data_file_path_));
+ ASSERT_TRUE(image_reader_.Initialize(data_file_.data(),
+ data_file_.length()));
+ }
+
+ const CertificateTestData* expected_data_;
+ base::FilePath data_file_path_;
+ base::MemoryMappedFile data_file_;
+ safe_browsing::PeImageReader image_reader_;
+};
+
+TEST_P(PeImageReaderCertificateTest, EnumCertificates) {
+ StrictMock<MockCertificateReceiver> receiver;
+ if (expected_data_->num_signers) {
+ EXPECT_CALL(receiver, OnCertificate(WIN_CERT_REVISION_2_0,
+ WIN_CERT_TYPE_PKCS_SIGNED_DATA,
+ NotNull(),
+ Gt(0U)))
+ .Times(expected_data_->num_signers)
+ .WillRepeatedly(Return(true));
+ }
+ EXPECT_TRUE(image_reader_.EnumCertificates(
+ &CertificateReceiver::OnCertificateCallback, receiver.AsContext()));
+}
+
+TEST_P(PeImageReaderCertificateTest, AbortEnum) {
+ StrictMock<MockCertificateReceiver> receiver;
+ if (expected_data_->num_signers) {
+ // Return false for the first cert, thereby stopping the enumeration.
+ EXPECT_CALL(receiver, OnCertificate(_, _, _, _)).WillOnce(Return(false));
+ EXPECT_FALSE(image_reader_.EnumCertificates(
+ &CertificateReceiver::OnCertificateCallback, receiver.AsContext()));
+ } else {
+ // An unsigned file always reports true with no invocations of the callback.
+ EXPECT_TRUE(image_reader_.EnumCertificates(
+ &CertificateReceiver::OnCertificateCallback, receiver.AsContext()));
+ }
+}
+
+namespace {
+
+const CertificateTestData kCertificateTestData[] = {
+ {
+ "signed.exe",
+ 1,
+ }, {
+ "unsigned.exe",
+ 0,
+ }, {
+ "disable_outdated_build_detector.exe",
+ 1,
+ }, {
+ "signed_twice.exe",
+ 2,
+ },
+};
+
+} // namespace
+
+INSTANTIATE_TEST_SUITE_P(SignedExe,
+ PeImageReaderCertificateTest,
+ testing::Values(&kCertificateTestData[0]));
+INSTANTIATE_TEST_SUITE_P(UnsignedExe,
+ PeImageReaderCertificateTest,
+ testing::Values(&kCertificateTestData[1]));
+INSTANTIATE_TEST_SUITE_P(DisableOutdatedBuildDetectorExe,
+ PeImageReaderCertificateTest,
+ testing::Values(&kCertificateTestData[2]));
+INSTANTIATE_TEST_SUITE_P(SignedTwiceExe,
+ PeImageReaderCertificateTest,
+ testing::Values(&kCertificateTestData[3]));
diff --git a/chromium/chrome/common/safe_browsing/protobuf_message_log_macros.h b/chromium/chrome/common/safe_browsing/protobuf_message_log_macros.h
new file mode 100644
index 00000000000..330ed1fae5d
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/protobuf_message_log_macros.h
@@ -0,0 +1,39 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_LOG_MACROS_H_
+#define CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_LOG_MACROS_H_
+
+// Null out all the macros that need nulling.
+#include "chrome/common/safe_browsing/ipc_protobuf_message_null_macros.h"
+
+// Set up so next include will generate log methods.
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_REPEATED_COMPLEX_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_END
+
+#define IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN(message_name) \
+ void ParamTraits<message_name>::Log(const param_type& p, std::string* l) { \
+ bool needs_comma = false; \
+ l->append("(");
+#define IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER(name) \
+ if (needs_comma) \
+ l->append(", "); \
+ LogParam(p.name(), l); \
+ needs_comma = true;
+#define IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER(name) \
+ if (needs_comma) \
+ l->append(", "); \
+ LogParam(p.name(), l); \
+ needs_comma = true;
+#define IPC_PROTOBUF_MESSAGE_TRAITS_REPEATED_COMPLEX_MEMBER(name) \
+ if (needs_comma) \
+ l->append(", "); \
+ LogParam(p.name(), l); \
+ needs_comma = true;
+#define IPC_PROTOBUF_MESSAGE_TRAITS_END() }
+
+#endif // CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_LOG_MACROS_H_
diff --git a/chromium/chrome/common/safe_browsing/protobuf_message_read_macros.h b/chromium/chrome/common/safe_browsing/protobuf_message_read_macros.h
new file mode 100644
index 00000000000..9c7720dbef4
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/protobuf_message_read_macros.h
@@ -0,0 +1,61 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_READ_MACROS_H_
+#define CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_READ_MACROS_H_
+
+// Null out all the macros that need nulling.
+#include "chrome/common/safe_browsing/ipc_protobuf_message_null_macros.h"
+
+// Set up so next include will generate read methods.
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_REPEATED_COMPLEX_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_END
+
+#define IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN(message_name) \
+ template <class P> \
+ bool ParamTraits<message_name>::ReadParamF( \
+ const base::Pickle* m, base::PickleIterator* iter, param_type* p, \
+ void (param_type::*setter_function)(P)) { \
+ P value; \
+ if (!ReadParam(m, iter, &value)) \
+ return false; \
+ (p->*setter_function)(value); \
+ return true; \
+ } \
+ bool ParamTraits<message_name>::Read( \
+ const base::Pickle* m, base::PickleIterator* iter, param_type* p) {
+#define IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER(name) \
+ { \
+ bool is_present; \
+ if (!iter->ReadBool(&is_present)) \
+ return false; \
+ if (!is_present) \
+ p->clear_##name(); \
+ else if (!ReadParamF(m, iter, p, &param_type::set_##name)) \
+ return false; \
+ }
+
+#define IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER(name) \
+ { \
+ bool is_present; \
+ if (!iter->ReadBool(&is_present)) \
+ return false; \
+ if (!is_present) \
+ p->clear_##name(); \
+ else if (!ReadParam(m, iter, p->mutable_##name())) \
+ return false; \
+ }
+
+#define IPC_PROTOBUF_MESSAGE_TRAITS_REPEATED_COMPLEX_MEMBER(name) \
+ if (!ReadParam(m, iter, p->mutable_##name())) \
+ return false;
+
+#define IPC_PROTOBUF_MESSAGE_TRAITS_END() \
+ return true; \
+ }
+
+#endif // CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_READ_MACROS_H_
diff --git a/chromium/chrome/common/safe_browsing/protobuf_message_write_macros.h b/chromium/chrome/common/safe_browsing/protobuf_message_write_macros.h
new file mode 100644
index 00000000000..578d23b2b18
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/protobuf_message_write_macros.h
@@ -0,0 +1,33 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_WRITE_MACROS_H_
+#define CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_WRITE_MACROS_H_
+
+// Null out all the macros that need nulling.
+#include "chrome/common/safe_browsing/ipc_protobuf_message_null_macros.h"
+
+// Set up so next include will generate write methods.
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_REPEATED_COMPLEX_MEMBER
+#undef IPC_PROTOBUF_MESSAGE_TRAITS_END
+
+#define IPC_PROTOBUF_MESSAGE_TRAITS_BEGIN(message_name) \
+ void ParamTraits<message_name>::Write(base::Pickle* m, const param_type& p) {
+#define IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_COMPLEX_MEMBER \
+ IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER
+#define IPC_PROTOBUF_MESSAGE_TRAITS_OPTIONAL_FUNDAMENTAL_MEMBER(name) \
+ if (p.has_##name()) { \
+ m->WriteBool(true); \
+ WriteParam(m, p.name()); \
+ } else { \
+ m->WriteBool(false); \
+ }
+#define IPC_PROTOBUF_MESSAGE_TRAITS_REPEATED_COMPLEX_MEMBER(name) \
+ WriteParam(m, p.name());
+#define IPC_PROTOBUF_MESSAGE_TRAITS_END() }
+
+#endif // CHROME_COMMON_SAFE_BROWSING_PROTOBUF_MESSAGE_WRITE_MACROS_H_
diff --git a/chromium/chrome/common/safe_browsing/rar_analyzer.cc b/chromium/chrome/common/safe_browsing/rar_analyzer.cc
new file mode 100644
index 00000000000..62af2be4fb8
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/rar_analyzer.cc
@@ -0,0 +1,74 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/safe_browsing/rar_analyzer.h"
+
+#include <memory>
+#include <string>
+
+#include "base/feature_list.h"
+#include "base/files/file_path.h"
+#include "base/i18n/streaming_utf8_validator.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "chrome/common/safe_browsing/archive_analyzer_results.h"
+#include "chrome/common/safe_browsing/download_type_util.h"
+#include "chrome/common/safe_browsing/file_type_policies.h"
+#include "components/safe_browsing/features.h"
+#include "third_party/unrar/src/unrar_wrapper.h"
+
+namespace safe_browsing {
+namespace rar_analyzer {
+
+namespace {
+
+// The maximum duration of RAR analysis, in milliseconds.
+const int kRarAnalysisTimeoutMs = 10000;
+
+} // namespace
+
+void AnalyzeRarFile(base::File rar_file,
+ base::File temp_file,
+ ArchiveAnalyzerResults* results) {
+ base::Time start_time = base::Time::Now();
+ results->success = false;
+ results->file_count = 0;
+ results->directory_count = 0;
+
+ // If the file is too big to unpack, return failure. This will still send a
+ // ping as an "invalid" RAR.
+ bool too_big_to_unpack =
+ base::checked_cast<uint64_t>(rar_file.GetLength()) >
+ FileTypePolicies::GetInstance()->GetMaxFileSizeToAnalyze("rar");
+ if (too_big_to_unpack)
+ return;
+
+ third_party_unrar::RarReader reader;
+ if (!reader.Open(std::move(rar_file), temp_file.Duplicate()))
+ return;
+
+ bool timeout = false;
+ while (reader.ExtractNextEntry()) {
+ if (base::Time::Now() - start_time >
+ base::TimeDelta::FromMilliseconds(kRarAnalysisTimeoutMs)) {
+ timeout = true;
+ break;
+ }
+ const third_party_unrar::RarReader::EntryInfo& entry =
+ reader.current_entry();
+ UpdateArchiveAnalyzerResultsWithFile(entry.file_path, &temp_file,
+ entry.file_size, entry.is_encrypted,
+ results);
+ if (entry.is_directory)
+ results->directory_count++;
+ else
+ results->file_count++;
+ }
+
+ results->success = !timeout;
+}
+
+} // namespace rar_analyzer
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/rar_analyzer.h b/chromium/chrome/common/safe_browsing/rar_analyzer.h
new file mode 100644
index 00000000000..0952ccad919
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/rar_analyzer.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file contains the rar file analysis implementation for download
+// protection, which runs in a sandbox. The reason for running in a sandbox is
+// to isolate the browser and other renderer processes from any vulnerabilities
+// that the attacker-controlled download file may try to exploit.
+//
+// Here's the call flow for inspecting .rar files upon download:
+// 1. File is downloaded.
+// 2. |CheckClientDownloadRequest::AnalyzeFile()| is called to analyze the Safe
+// Browsing reputation of the downloaded file.
+// 3. It calls |CheckClientDownloadRequest::StartExtractRarFeatures()|, which
+// creates an instance of |SandboxedRarAnalyzer|, and calls |Start()|.
+// 4. |SandboxedRarAnalyzer::Start()| leads to a mojo call to
+// |SafeArchiveAnalyzer::AnalyzeRarFile()| in a sandbox.
+// 5. Finally, |SafeArchiveAnalyzer::AnalyzeRarFile()| calls |AnalyzeRarFile()|
+// defined in this file to actually inspect the file.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_RAR_ANALYZER_H_
+#define CHROME_COMMON_SAFE_BROWSING_RAR_ANALYZER_H_
+
+#include "base/files/file.h"
+
+namespace safe_browsing {
+
+struct ArchiveAnalyzerResults;
+
+namespace rar_analyzer {
+
+// |rar_file| is a platform-agnostic handle to the file, and |temp_file| is a
+// handle for a temporary file the sandbox can write to. Since |AnalyzeRarFile|
+// runs inside a sandbox, it isn't allowed to open file handles. So both files
+// are opened in |SandboxedRarAnalyzer|, which runs in the browser process, and
+// the handles are passed here. The function populates the various fields in
+// |results| based on the results of parsing the rar file. If the parsing fails
+// for any reason, including crashing the sandbox process, the browser process
+// considers the file safe.
+void AnalyzeRarFile(base::File rar_file,
+ base::File temp_file,
+ ArchiveAnalyzerResults* results);
+
+} // namespace rar_analyzer
+} // namespace safe_browsing
+
+#endif // CHROME_COMMON_SAFE_BROWSING_RAR_ANALYZER_H_
diff --git a/chromium/chrome/common/safe_browsing/zip_analyzer.cc b/chromium/chrome/common/safe_browsing/zip_analyzer.cc
new file mode 100644
index 00000000000..ac14ff66f79
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/zip_analyzer.cc
@@ -0,0 +1,111 @@
+// 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 "chrome/common/safe_browsing/zip_analyzer.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+#include <set>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/numerics/checked_math.h"
+#include "base/numerics/ranges.h"
+#include "base/rand_util.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "chrome/common/safe_browsing/archive_analyzer_results.h"
+#include "chrome/common/safe_browsing/file_type_policies.h"
+#include "components/safe_browsing/proto/csd.pb.h"
+#include "third_party/zlib/google/zip_reader.h"
+
+namespace safe_browsing {
+namespace zip_analyzer {
+
+namespace {
+
+// The maximum duration of ZIP analysis, in milliseconds.
+const int kZipAnalysisTimeoutMs = 10000;
+
+} // namespace
+
+void AnalyzeZipFile(base::File zip_file,
+ base::File temp_file,
+ ArchiveAnalyzerResults* results) {
+ base::Time start_time = base::Time::Now();
+ zip::ZipReader reader;
+ if (!reader.OpenFromPlatformFile(zip_file.GetPlatformFile())) {
+ DVLOG(1) << "Failed to open zip file";
+ return;
+ }
+
+ bool too_big_to_unpack =
+ base::checked_cast<uint64_t>(zip_file.GetLength()) >
+ FileTypePolicies::GetInstance()->GetMaxFileSizeToAnalyze("zip");
+ if (too_big_to_unpack) {
+ results->success = false;
+ return;
+ }
+
+ bool timeout = false;
+ bool advanced = true;
+ results->file_count = 0;
+ results->directory_count = 0;
+ base::CheckedNumeric<uint64_t> total_uncompressed_size = 0u;
+ for (; reader.HasMore(); advanced = reader.AdvanceToNextEntry()) {
+ if (!advanced) {
+ DVLOG(1) << "Could not advance to next entry, aborting zip scan.";
+ return;
+ }
+ if (!reader.OpenCurrentEntryInZip()) {
+ DVLOG(1) << "Failed to open current entry in zip file";
+ continue;
+ }
+ if (base::Time::Now() - start_time >
+ base::TimeDelta::FromMilliseconds(kZipAnalysisTimeoutMs)) {
+ timeout = true;
+ break;
+ }
+
+ // Clear the |temp_file| between extractions.
+ temp_file.Seek(base::File::Whence::FROM_BEGIN, 0);
+ temp_file.SetLength(0);
+ zip::FileWriterDelegate writer(&temp_file);
+ reader.ExtractCurrentEntry(&writer, std::numeric_limits<uint64_t>::max());
+ UpdateArchiveAnalyzerResultsWithFile(
+ reader.current_entry_info()->file_path(), &temp_file,
+ writer.file_length(), reader.current_entry_info()->is_encrypted(),
+ results);
+
+ UMA_HISTOGRAM_MEMORY_LARGE_MB("SBClientDownload.ZipEntrySize",
+ writer.file_length());
+ total_uncompressed_size += writer.file_length();
+
+ if (reader.current_entry_info()->is_directory())
+ results->directory_count++;
+ else
+ results->file_count++;
+ }
+
+ // We represent the size as a percent, so multiply by 100, then check for
+ // overflow.
+ total_uncompressed_size *= 100;
+ UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipArchiveUncompressedSizeOverflow",
+ !total_uncompressed_size.IsValid());
+ if (total_uncompressed_size.IsValid() && zip_file.GetLength() > 0) {
+ UMA_HISTOGRAM_COUNTS_10000(
+ "SBClientDownload.ZipCompressionRatio",
+ static_cast<uint64_t>(total_uncompressed_size.ValueOrDie()) /
+ zip_file.GetLength());
+ }
+
+ results->success = !timeout;
+}
+
+} // namespace zip_analyzer
+} // namespace safe_browsing
diff --git a/chromium/chrome/common/safe_browsing/zip_analyzer.h b/chromium/chrome/common/safe_browsing/zip_analyzer.h
new file mode 100644
index 00000000000..176ab651b09
--- /dev/null
+++ b/chromium/chrome/common/safe_browsing/zip_analyzer.h
@@ -0,0 +1,26 @@
+// 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 contains the zip file analysis implementation for download
+// protection, which runs in a sandboxed utility process.
+
+#ifndef CHROME_COMMON_SAFE_BROWSING_ZIP_ANALYZER_H_
+#define CHROME_COMMON_SAFE_BROWSING_ZIP_ANALYZER_H_
+
+#include "base/files/file.h"
+
+namespace safe_browsing {
+
+struct ArchiveAnalyzerResults;
+
+namespace zip_analyzer {
+
+void AnalyzeZipFile(base::File zip_file,
+ base::File temp_file,
+ ArchiveAnalyzerResults* results);
+
+} // namespace zip_analyzer
+} // namespace safe_browsing
+
+#endif // CHROME_COMMON_SAFE_BROWSING_ZIP_ANALYZER_H_
diff --git a/chromium/chrome/common/search/OWNERS b/chromium/chrome/common/search/OWNERS
new file mode 100644
index 00000000000..8d760b139d7
--- /dev/null
+++ b/chromium/chrome/common/search/OWNERS
@@ -0,0 +1,2 @@
+file://chrome/browser/search/OWNERS
+# COMPONENT: UI>Browser>NewTabPage
diff --git a/chromium/chrome/common/search/chrome_colors_icon_template.h b/chromium/chrome/common/search/chrome_colors_icon_template.h
new file mode 100644
index 00000000000..fd99be1b377
--- /dev/null
+++ b/chromium/chrome/common/search/chrome_colors_icon_template.h
@@ -0,0 +1,23 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SEARCH_CHROME_COLORS_ICON_TEMPLATE_H_
+#define CHROME_COMMON_SEARCH_CHROME_COLORS_ICON_TEMPLATE_H_
+
+// Template for the icon svg.
+// $1 - primary color
+// $2 - secondary color
+const char kChromeColorsIconTemplate[] =
+ "<svg xmlns=\"http://www.w3.org/2000/svg\" "
+ "xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"64\" "
+ "height=\"64\"><defs><path d=\"M32 64C14.34 64 0 49.66 0 32S14.34 0 32 "
+ "0s32 14.34 32 32-14.34 32-32 32z\" id=\"a\"/><linearGradient id=\"b\" "
+ "gradientUnits=\"userSpaceOnUse\" x1=\"32\" y1=\"32\" x2=\"32.08\" "
+ "y2=\"32\"><stop offset=\"0\%\" stop-color=\"$2\"/><stop offset=\"100\%\" "
+ "stop-color=\"$1\"/></linearGradient><clipPath id=\"c\"><use "
+ "xlink:href=\"#a\"/></clipPath></defs><use xlink:href=\"#a\" "
+ "fill=\"url(#b)\"/><g clip-path=\"url(#c)\"><use xlink:href=\"#a\" "
+ "fill-opacity=\"0\" stroke=\"$1\" stroke-width=\"2\"/></g></svg>";
+
+#endif // CHROME_COMMON_SEARCH_CHROME_COLORS_ICON_TEMPLATE_H_
diff --git a/chromium/chrome/common/search/generate_colors_info.cc b/chromium/chrome/common/search/generate_colors_info.cc
new file mode 100644
index 00000000000..bba9e5bec5d
--- /dev/null
+++ b/chromium/chrome/common/search/generate_colors_info.cc
@@ -0,0 +1,120 @@
+// Copyright 2019 The Chromium Authors. 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/base64.h"
+#include "base/files/file_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/common/search/chrome_colors_icon_template.h"
+#include "chrome/common/search/selected_colors_info.h"
+#include "chrome/common/themes/autogenerated_theme_util.h"
+
+// Template for color info line.
+// $1 - color id
+// $2 - red value of primary color
+// $3 - green value of primary color
+// $4 - blue value of primary color
+// $5 - color label id
+// $6 - icon data
+const char kColorInfoLineTemplate[] =
+ " ColorInfo($1, SkColorSetRGB($2, $3, $4), $5, "
+ "\"data:image/svg+xml;base64,$6\")";
+
+// Template for the generated file content.
+// $1 - lines for updated color info.
+// $2 - number of colors.
+const char kFileContentTemplate[] =
+ "// Generated from generate_colors_info.cc. Do not edit!\n"
+ "\n"
+ "#ifndef CHROME_COMMON_SEARCH_GENERATED_COLORS_INFO_H_\n"
+ "#define CHROME_COMMON_SEARCH_GENERATED_COLORS_INFO_H_\n"
+ "\n"
+ "#include <stdint.h>\n"
+ "\n"
+ "#include \"chrome/common/search/selected_colors_info.h\"\n"
+ "#include \"third_party/skia/include/core/SkColor.h\"\n"
+ "\n"
+ "namespace chrome_colors {\n"
+ "\n"
+ "// List of preselected colors with icon data to show in Chrome Colors"
+ " menu.\n"
+ "constexpr ColorInfo kGeneratedColorsInfo[] = {\n"
+ "$1\n"
+ "};\n"
+ "\n"
+ "const size_t kNumColorsInfo = $2;"
+ "\n"
+ "} // namespace chrome_colors\n"
+ "\n"
+ "#endif // CHROME_COMMON_SEARCH_GENERATED_COLORS_INFO_H_\n";
+
+// Returns hex string representation for the |color| in "#FFFFFF" format.
+std::string SkColorToHexString(SkColor color) {
+ return base::StringPrintf("#%02X%02X%02X", SkColorGetR(color),
+ SkColorGetG(color), SkColorGetB(color));
+}
+
+// Returns icon data for the given |color| as encoded svg.
+// The returned string can be later directly set in JS with the following
+// format: "data:image/svg+xml;base64<ENCODED_SVG>"
+std::string GenerateIconDataForColor(SkColor color) {
+ AutogeneratedThemeColors colors = GetAutogeneratedThemeColors(color);
+
+ std::vector<std::string> subst;
+ subst.push_back(SkColorToHexString(colors.frame_color));
+ subst.push_back(SkColorToHexString(colors.active_tab_color));
+
+ std::string svg_base64;
+ base::Base64Encode(
+ base::ReplaceStringPlaceholders(kChromeColorsIconTemplate, subst, NULL),
+ &svg_base64);
+ return svg_base64;
+}
+
+// Generates color info line in the following format:
+// ColorInfo(ID, SkColorSetRGB(R, G, B), LABEL, ICON_DATA)
+std::string GenerateColorLine(chrome_colors::ColorInfo color_info) {
+ std::vector<std::string> subst;
+ subst.push_back(base::NumberToString(color_info.id));
+ subst.push_back(base::NumberToString(SkColorGetR(color_info.color)));
+ subst.push_back(base::NumberToString(SkColorGetG(color_info.color)));
+ subst.push_back(base::NumberToString(SkColorGetB(color_info.color)));
+ subst.push_back(base::NumberToString(color_info.label_id));
+ subst.push_back(GenerateIconDataForColor(color_info.color));
+ return base::ReplaceStringPlaceholders(kColorInfoLineTemplate, subst, NULL);
+}
+
+// Generates 'generated_colors_info.h' that contains selected colors from
+// |chrome_colors::kSelectedColorsInfo| along with generated icon data.
+void GenerateColorsInfoFile(std::string output_dir) {
+ std::vector<std::string> updated_color_info;
+ int colors_num = 0;
+ for (chrome_colors::ColorInfo color_info :
+ chrome_colors::kSelectedColorsInfo) {
+ updated_color_info.push_back(GenerateColorLine(color_info));
+ colors_num++;
+ }
+
+ std::vector<std::string> subst;
+ subst.push_back(base::JoinString(updated_color_info, ",\n"));
+ subst.push_back(base::NumberToString(colors_num));
+ std::string output =
+ base::ReplaceStringPlaceholders(kFileContentTemplate, subst, NULL);
+
+ base::FilePath output_path = base::FilePath::FromUTF8Unsafe(output_dir);
+ base::FilePath directory = output_path.DirName();
+ if (!base::DirectoryExists(directory))
+ base::CreateDirectory(directory);
+
+ if (base::WriteFile(output_path, output.c_str(),
+ static_cast<uint32_t>(output.size())) <= 0) {
+ LOG(ERROR) << "Failed to write output to " << output_path;
+ }
+}
+
+int main(int argc, char* argv[]) {
+ GenerateColorsInfoFile(argv[1]);
+ return 0;
+}
diff --git a/chromium/chrome/common/search/instant_types.cc b/chromium/chrome/common/search/instant_types.cc
new file mode 100644
index 00000000000..f94c1be9813
--- /dev/null
+++ b/chromium/chrome/common/search/instant_types.cc
@@ -0,0 +1,54 @@
+// 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 "chrome/common/search/instant_types.h"
+
+ThemeBackgroundInfo::ThemeBackgroundInfo() = default;
+
+ThemeBackgroundInfo::ThemeBackgroundInfo(const ThemeBackgroundInfo& other) =
+ default;
+
+ThemeBackgroundInfo::~ThemeBackgroundInfo() = default;
+
+bool ThemeBackgroundInfo::operator==(const ThemeBackgroundInfo& rhs) const {
+ return using_default_theme == rhs.using_default_theme &&
+ using_dark_colors == rhs.using_dark_colors &&
+ custom_background_url == rhs.custom_background_url &&
+ custom_background_attribution_line_1 ==
+ rhs.custom_background_attribution_line_1 &&
+ custom_background_attribution_line_2 ==
+ rhs.custom_background_attribution_line_2 &&
+ custom_background_attribution_action_url ==
+ rhs.custom_background_attribution_action_url &&
+ collection_id == rhs.collection_id &&
+ background_color == rhs.background_color &&
+ text_color == rhs.text_color &&
+ text_color_light == rhs.text_color_light && theme_id == rhs.theme_id &&
+ image_horizontal_alignment == rhs.image_horizontal_alignment &&
+ image_vertical_alignment == rhs.image_vertical_alignment &&
+ image_tiling == rhs.image_tiling &&
+ has_attribution == rhs.has_attribution &&
+ logo_alternate == rhs.logo_alternate &&
+ has_theme_image == rhs.has_theme_image &&
+ theme_name == rhs.theme_name && color_id == rhs.color_id &&
+ color_dark == rhs.color_dark && color_light == rhs.color_light &&
+ color_picked == rhs.color_picked && logo_color == rhs.logo_color &&
+ shortcut_color == rhs.shortcut_color;
+}
+
+InstantMostVisitedItem::InstantMostVisitedItem()
+ : title_source(ntp_tiles::TileTitleSource::UNKNOWN),
+ source(ntp_tiles::TileSource::TOP_SITES) {}
+
+InstantMostVisitedItem::InstantMostVisitedItem(
+ const InstantMostVisitedItem& other) = default;
+
+InstantMostVisitedItem::~InstantMostVisitedItem() {}
+
+InstantMostVisitedInfo::InstantMostVisitedInfo() = default;
+
+InstantMostVisitedInfo::InstantMostVisitedInfo(
+ const InstantMostVisitedInfo& other) = default;
+
+InstantMostVisitedInfo::~InstantMostVisitedInfo() {}
diff --git a/chromium/chrome/common/search/instant_types.h b/chromium/chrome/common/search/instant_types.h
new file mode 100644
index 00000000000..99916b21c4d
--- /dev/null
+++ b/chromium/chrome/common/search/instant_types.h
@@ -0,0 +1,188 @@
+// 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 CHROME_COMMON_SEARCH_INSTANT_TYPES_H_
+#define CHROME_COMMON_SEARCH_INSTANT_TYPES_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "components/ntp_tiles/tile_source.h"
+#include "components/ntp_tiles/tile_title_source.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/color_palette.h"
+#include "url/gurl.h"
+
+// ID used by Instant code to refer to objects (e.g. Autocomplete results, Most
+// Visited items) that the Instant page needs access to.
+typedef int InstantRestrictedID;
+
+// The alignment of the theme background image.
+enum ThemeBackgroundImageAlignment {
+ THEME_BKGRND_IMAGE_ALIGN_CENTER,
+ THEME_BKGRND_IMAGE_ALIGN_LEFT,
+ THEME_BKGRND_IMAGE_ALIGN_TOP,
+ THEME_BKGRND_IMAGE_ALIGN_RIGHT,
+ THEME_BKGRND_IMAGE_ALIGN_BOTTOM,
+
+ THEME_BKGRND_IMAGE_ALIGN_LAST = THEME_BKGRND_IMAGE_ALIGN_BOTTOM,
+};
+
+// The tiling of the theme background image.
+enum ThemeBackgroundImageTiling {
+ THEME_BKGRND_IMAGE_NO_REPEAT,
+ THEME_BKGRND_IMAGE_REPEAT_X,
+ THEME_BKGRND_IMAGE_REPEAT_Y,
+ THEME_BKGRND_IMAGE_REPEAT,
+
+ THEME_BKGRND_IMAGE_LAST = THEME_BKGRND_IMAGE_REPEAT,
+};
+
+// Theme background settings for the NTP.
+struct ThemeBackgroundInfo {
+ ThemeBackgroundInfo();
+ ThemeBackgroundInfo(const ThemeBackgroundInfo& other);
+ ~ThemeBackgroundInfo();
+
+ bool operator==(const ThemeBackgroundInfo& rhs) const;
+
+ // True if the default theme is selected.
+ bool using_default_theme = true;
+
+ // True if the system theme uses a light-on-dark color scheme instead of
+ // dark-on-light.
+ bool using_dark_colors = false;
+
+ // Url of the custom background selected by the user.
+ GURL custom_background_url;
+
+ // First attribution string for custom background.
+ std::string custom_background_attribution_line_1;
+
+ // Second attribution string for custom background.
+ std::string custom_background_attribution_line_2;
+
+ // Url to learn more info about the custom background.
+ GURL custom_background_attribution_action_url;
+
+ // Id of the collection being used for "daily refresh".
+ std::string collection_id;
+
+ // The theme background color. Always valid.
+ SkColor background_color = gfx::kPlaceholderColor;
+
+ // The theme text color.
+ SkColor text_color = gfx::kPlaceholderColor;
+
+ // The theme text color light.
+ SkColor text_color_light = gfx::kPlaceholderColor;
+
+ // The theme id for the theme background image.
+ // Value is only valid if there's a custom theme background image.
+ std::string theme_id;
+
+ // The theme background image horizontal alignment is only valid if |theme_id|
+ // is valid.
+ ThemeBackgroundImageAlignment image_horizontal_alignment =
+ THEME_BKGRND_IMAGE_ALIGN_CENTER;
+
+ // The theme background image vertical alignment is only valid if |theme_id|
+ // is valid.
+ ThemeBackgroundImageAlignment image_vertical_alignment =
+ THEME_BKGRND_IMAGE_ALIGN_CENTER;
+
+ // The theme background image tiling is only valid if |theme_id| is valid.
+ ThemeBackgroundImageTiling image_tiling = THEME_BKGRND_IMAGE_NO_REPEAT;
+
+ // True if theme has attribution logo.
+ // Value is only valid if |theme_id| is valid.
+ bool has_attribution = false;
+
+ // True if theme has an alternate logo.
+ bool logo_alternate = false;
+
+ // True if theme has NTP image.
+ bool has_theme_image = false;
+
+ // The theme name.
+ std::string theme_name;
+
+ // The color id for Chrome Colors. It is -1 if Chrome Colors is not set, 0
+ // when Chrome Colors is set but not from predefined color list, and > 0 if
+ // Chrome Colors is set from predefined color list.
+ int color_id = -1;
+
+ // The dark color for Chrome Colors. Valid only if Chrome Colors is set.
+ SkColor color_dark = gfx::kPlaceholderColor;
+
+ // The light color for Chrome Colors. Valid only if Chrome Colors is set.
+ SkColor color_light = gfx::kPlaceholderColor;
+
+ // The picked custom color for Chrome Colors. Valid only if Chrome Colors is
+ // set.
+ SkColor color_picked = gfx::kPlaceholderColor;
+
+ // Color used for alternative Google logo on NTP.
+ SkColor logo_color = gfx::kPlaceholderColor;
+
+ // Color for NTP shortcut backgrounds.
+ SkColor shortcut_color = gfx::kPlaceholderColor;
+};
+
+struct InstantMostVisitedItem {
+ InstantMostVisitedItem();
+ InstantMostVisitedItem(const InstantMostVisitedItem& other);
+ ~InstantMostVisitedItem();
+
+ // The URL of the Most Visited item.
+ GURL url;
+
+ // The title of the Most Visited page. May be empty, in which case the |url|
+ // is used as the title.
+ base::string16 title;
+
+ // The external URL of the favicon associated with this page.
+ GURL favicon;
+
+ // The source of the item's |title|.
+ ntp_tiles::TileTitleSource title_source;
+
+ // The source of the item, e.g. server-side or client-side.
+ ntp_tiles::TileSource source;
+
+ // The timestamp representing when the tile data (e.g. URL) was generated
+ // originally, regardless of the impression timestamp.
+ base::Time data_generation_time;
+};
+
+struct InstantMostVisitedInfo {
+ InstantMostVisitedInfo();
+ InstantMostVisitedInfo(const InstantMostVisitedInfo& other);
+ ~InstantMostVisitedInfo();
+
+ std::vector<InstantMostVisitedItem> items;
+
+ // True if the source of the |items| is custom links (i.e.
+ // ntp_tiles::TileSource::CUSTOM_LINKS). Required since the source cannot be
+ // checked if |items| is empty.
+ bool items_are_custom_links = false;
+
+ // True if Most Visited functionality is enabled instead of customizable
+ // shortcuts.
+ bool use_most_visited = false;
+
+ // True if the items are visible and not hidden by the user.
+ bool is_visible = true;
+};
+
+// An InstantMostVisitedItem along with its assigned restricted ID.
+typedef std::pair<InstantRestrictedID, InstantMostVisitedItem>
+ InstantMostVisitedItemIDPair;
+
+#endif // CHROME_COMMON_SEARCH_INSTANT_TYPES_H_
diff --git a/chromium/chrome/common/search/mock_embedded_search_client.cc b/chromium/chrome/common/search/mock_embedded_search_client.cc
new file mode 100644
index 00000000000..7e11eb3356c
--- /dev/null
+++ b/chromium/chrome/common/search/mock_embedded_search_client.cc
@@ -0,0 +1,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.
+
+#include "chrome/common/search/mock_embedded_search_client.h"
+
+MockEmbeddedSearchClient::MockEmbeddedSearchClient() = default;
+MockEmbeddedSearchClient::~MockEmbeddedSearchClient() = default;
diff --git a/chromium/chrome/common/search/mock_embedded_search_client.h b/chromium/chrome/common/search/mock_embedded_search_client.h
new file mode 100644
index 00000000000..f5008ea9677
--- /dev/null
+++ b/chromium/chrome/common/search/mock_embedded_search_client.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 CHROME_COMMON_SEARCH_MOCK_EMBEDDED_SEARCH_CLIENT_H_
+#define CHROME_COMMON_SEARCH_MOCK_EMBEDDED_SEARCH_CLIENT_H_
+
+#include "chrome/common/search.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+class MockEmbeddedSearchClient : public chrome::mojom::EmbeddedSearchClient {
+ public:
+ MockEmbeddedSearchClient();
+ ~MockEmbeddedSearchClient() override;
+
+ MOCK_METHOD1(SetPageSequenceNumber, void(int));
+ MOCK_METHOD2(FocusChanged, void(OmniboxFocusState, OmniboxFocusChangeReason));
+ MOCK_METHOD1(MostVisitedInfoChanged, void(const InstantMostVisitedInfo&));
+ MOCK_METHOD1(SetInputInProgress, void(bool));
+ MOCK_METHOD1(ThemeChanged, void(const ThemeBackgroundInfo&));
+ MOCK_METHOD0(LocalBackgroundSelected, void());
+};
+
+#endif // CHROME_COMMON_SEARCH_MOCK_EMBEDDED_SEARCH_CLIENT_H_
diff --git a/chromium/chrome/common/search/ntp_logging_events.h b/chromium/chrome/common/search/ntp_logging_events.h
new file mode 100644
index 00000000000..c15685d496e
--- /dev/null
+++ b/chromium/chrome/common/search/ntp_logging_events.h
@@ -0,0 +1,190 @@
+// 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 CHROME_COMMON_SEARCH_NTP_LOGGING_EVENTS_H_
+#define CHROME_COMMON_SEARCH_NTP_LOGGING_EVENTS_H_
+
+// The different types of events that are logged from the NTP. This enum is used
+// to transfer information from the NTP javascript to the renderer and is *not*
+// used as a UMA enum histogram's logged value.
+// Note: Keep in sync with browser/resources/local_ntp/local_ntp.js, voice.js,
+// most_visited_single.js, and custom_backgrounds.js.
+enum NTPLoggingEventType {
+ // Deleted: NTP_SERVER_SIDE_SUGGESTION = 0,
+ // Deleted: NTP_CLIENT_SIDE_SUGGESTION = 1,
+ // Deleted: NTP_TILE = 2,
+ // Deleted: NTP_THUMBNAIL_TILE = 3,
+ // Deleted: NTP_GRAY_TILE = 4,
+ // Deleted: NTP_EXTERNAL_TILE = 5,
+ // Deleted: NTP_THUMBNAIL_ERROR = 6,
+ // Deleted: NTP_GRAY_TILE_FALLBACK = 7,
+ // Deleted: NTP_EXTERNAL_TILE_FALLBACK = 8,
+ // Deleted: NTP_MOUSEOVER = 9
+ // Deleted: NTP_TILE_LOADED = 10,
+ // Deleted: NTP_ALL_TILES_RECEIVED = 12,
+
+ // All NTP tiles have finished loading (successfully or failing). Logged only
+ // by the single-iframe version of the NTP.
+ NTP_ALL_TILES_LOADED = 11,
+
+ // Activated by clicking on the fakebox icon. Logged by Voice Search.
+ NTP_VOICE_ACTION_ACTIVATE_FAKEBOX = 13,
+ // Activated by keyboard shortcut.
+ NTP_VOICE_ACTION_ACTIVATE_KEYBOARD = 14,
+ // Close the voice overlay by a user's explicit action.
+ NTP_VOICE_ACTION_CLOSE_OVERLAY = 15,
+ // Submitted voice query.
+ NTP_VOICE_ACTION_QUERY_SUBMITTED = 16,
+ // Clicked on support link in error message.
+ NTP_VOICE_ACTION_SUPPORT_LINK_CLICKED = 17,
+ // Retried by clicking Try Again link.
+ NTP_VOICE_ACTION_TRY_AGAIN_LINK = 18,
+ // Retried by clicking microphone button.
+ NTP_VOICE_ACTION_TRY_AGAIN_MIC_BUTTON = 19,
+ // Errors received from the Speech Recognition API.
+ NTP_VOICE_ERROR_NO_SPEECH = 20,
+ NTP_VOICE_ERROR_ABORTED = 21,
+ NTP_VOICE_ERROR_AUDIO_CAPTURE = 22,
+ NTP_VOICE_ERROR_NETWORK = 23,
+ NTP_VOICE_ERROR_NOT_ALLOWED = 24,
+ NTP_VOICE_ERROR_SERVICE_NOT_ALLOWED = 25,
+ NTP_VOICE_ERROR_BAD_GRAMMAR = 26,
+ NTP_VOICE_ERROR_LANGUAGE_NOT_SUPPORTED = 27,
+ NTP_VOICE_ERROR_NO_MATCH = 28,
+ NTP_VOICE_ERROR_OTHER = 29,
+
+ // A static Doodle was shown, coming from cache.
+ NTP_STATIC_LOGO_SHOWN_FROM_CACHE = 30,
+ // A static Doodle was shown, coming from the network.
+ NTP_STATIC_LOGO_SHOWN_FRESH = 31,
+ // A call-to-action Doodle image was shown, coming from cache.
+ NTP_CTA_LOGO_SHOWN_FROM_CACHE = 32,
+ // A call-to-action Doodle image was shown, coming from the network.
+ NTP_CTA_LOGO_SHOWN_FRESH = 33,
+
+ // A static Doodle was clicked.
+ NTP_STATIC_LOGO_CLICKED = 34,
+ // A call-to-action Doodle was clicked.
+ NTP_CTA_LOGO_CLICKED = 35,
+ // An animated Doodle was clicked.
+ NTP_ANIMATED_LOGO_CLICKED = 36,
+
+ // The One Google Bar was shown.
+ NTP_ONE_GOOGLE_BAR_SHOWN = 37,
+
+ // The NTP background has been customized with an image.
+ NTP_BACKGROUND_CUSTOMIZED = 38,
+ // Shortcuts have been customized on the NTP.
+ NTP_SHORTCUT_CUSTOMIZED = 39,
+
+ // The 'Chrome backgrounds' menu item was clicked.
+ NTP_CUSTOMIZE_CHROME_BACKGROUNDS_CLICKED = 40,
+ // The 'Upload an image' menu item was clicked.
+ NTP_CUSTOMIZE_LOCAL_IMAGE_CLICKED = 41,
+ // The 'Restore default background' menu item was clicked.
+ NTP_CUSTOMIZE_RESTORE_BACKGROUND_CLICKED = 42,
+ // The attribution link on a customized background image was clicked.
+ NTP_CUSTOMIZE_ATTRIBUTION_CLICKED = 43,
+ // The 'Add shortcut' link was clicked.
+ NTP_CUSTOMIZE_ADD_SHORTCUT_CLICKED = 44,
+ // The 'Edit shortcut' link was clicked.
+ NTP_CUSTOMIZE_EDIT_SHORTCUT_CLICKED = 45,
+ // The 'Restore default shortcuts' menu item was clicked.
+ NTP_CUSTOMIZE_RESTORE_SHORTCUTS_CLICKED = 46,
+
+ // A collection was selected in the 'Chrome backgrounds' dialog.
+ NTP_CUSTOMIZE_CHROME_BACKGROUND_SELECT_COLLECTION = 47,
+ // An image was selected in the 'Chrome backgrounds' dialog.
+ NTP_CUSTOMIZE_CHROME_BACKGROUND_SELECT_IMAGE = 48,
+ // 'Cancel' was clicked in the 'Chrome backgrounds' dialog.
+ NTP_CUSTOMIZE_CHROME_BACKGROUND_CANCEL = 49,
+ // 'Done' was clicked in the 'Chrome backgrounds' dialog.
+ NTP_CUSTOMIZE_CHROME_BACKGROUND_DONE = 50,
+
+ // 'Cancel' was clicked in the 'Upload an image' dialog.
+ NTP_CUSTOMIZE_LOCAL_IMAGE_CANCEL = 51,
+ // 'Done' was clicked in the 'Upload an image' dialog.
+ NTP_CUSTOMIZE_LOCAL_IMAGE_DONE = 52,
+
+ // A custom shortcut was removed.
+ NTP_CUSTOMIZE_SHORTCUT_REMOVE = 53,
+ // 'Cancel' was clicked in the 'Edit shortcut' dialog.
+ NTP_CUSTOMIZE_SHORTCUT_CANCEL = 54,
+ // 'Done' was clicked in the 'Edit shortcut' dialog.
+ NTP_CUSTOMIZE_SHORTCUT_DONE = 55,
+ // A custom shortcut action was undone.
+ NTP_CUSTOMIZE_SHORTCUT_UNDO = 56,
+ // All custom shortcuts were restored.
+ NTP_CUSTOMIZE_SHORTCUT_RESTORE_ALL = 57,
+ // A custom shortcut was added.
+ NTP_CUSTOMIZE_SHORTCUT_ADD = 58,
+ // A custom shortcut was updated.
+ NTP_CUSTOMIZE_SHORTCUT_UPDATE = 59,
+
+ // A middle slot promo was shown.
+ NTP_MIDDLE_SLOT_PROMO_SHOWN = 60,
+ // A promo link was clicked.
+ NTP_MIDDLE_SLOT_PROMO_LINK_CLICKED = 61,
+
+ // The shortcut type displayed (i.e. Most Visited or custom links) was
+ // changed.
+ NTP_CUSTOMIZE_SHORTCUT_TOGGLE_TYPE = 62,
+ // The visibility of shortcuts was changed.
+ NTP_CUSTOMIZE_SHORTCUT_TOGGLE_VISIBILITY = 63,
+
+ // The richer picker was opened.
+ NTP_CUSTOMIZATION_MENU_OPENED = 64,
+ // 'Cancel' was clicked in the richer picker.
+ NTP_CUSTOMIZATION_MENU_CANCEL = 65,
+ // 'Done' was clicked in the richer picker.
+ NTP_CUSTOMIZATION_MENU_DONE = 66,
+
+ // 'Upload from device' was selected in the richer picker.
+ NTP_BACKGROUND_UPLOAD_FROM_DEVICE = 67,
+ // A collection tile was selected in the richer picker.
+ NTP_BACKGROUND_OPEN_COLLECTION = 68,
+ // A image tile was selected in the richer picker.
+ NTP_BACKGROUND_SELECT_IMAGE = 69,
+ // An image was set as the NTP background.
+ NTP_BACKGROUND_IMAGE_SET = 71,
+ // The back arrow was clicked in the richer picker.
+ NTP_BACKGROUND_BACK_CLICK = 72,
+ // The 'No background' tile was selected in the richer picker.
+ NTP_BACKGROUND_DEFAULT_SELECTED = 73,
+ // 'Cancel' was clicked in the image selection dialog.
+ NTP_BACKGROUND_UPLOAD_CANCEL = 75,
+ // 'Done' was clicked in the image selection dialog.
+ NTP_BACKGROUND_UPLOAD_DONE = 76,
+ // The NTP background image was reset in the richer picker.
+ NTP_BACKGROUND_IMAGE_RESET = 77,
+
+ // The 'My shortcuts' (i.e. custom links) option was clicked in the richer
+ // picker.
+ NTP_CUSTOMIZE_SHORTCUT_CUSTOM_LINKS_CLICKED = 78,
+ // The 'Most visited sites' option was clicked in the richer picker.
+ NTP_CUSTOMIZE_SHORTCUT_MOST_VISITED_CLICKED = 79,
+ // The 'Hide shortcuts' toggle was clicked in the richer picker.
+ NTP_CUSTOMIZE_SHORTCUT_VISIBILITY_TOGGLE_CLICKED = 80,
+
+ // The 'refresh daily' toggle was licked in the richer picker.
+ NTP_BACKGROUND_REFRESH_TOGGLE_CLICKED = 81,
+ // Daily refresh was enabled by clicked 'Done' in the richer picker.
+ NTP_BACKGROUND_DAILY_REFRESH_ENABLED = 82,
+
+ NTP_EVENT_TYPE_LAST = NTP_BACKGROUND_DAILY_REFRESH_ENABLED
+};
+
+// The different types of events that are logged for NTP search suggestions,
+// such as number of chips shown and the index of chips that are clicked. This
+// enum is used to transfer information from the NTP javascript to the renderer
+// and is *not* used as a UMA enum histogram's logged value. These events may be
+// logged by javascript served from GWS, see
+// google3/java/com/google/gws/plugins/newtab/suggestions.js.
+enum class NTPSuggestionsLoggingEventType {
+ kShownCount = 0,
+ kIndexClicked = 1,
+ kMaxValue = kIndexClicked,
+};
+
+#endif // CHROME_COMMON_SEARCH_NTP_LOGGING_EVENTS_H_
diff --git a/chromium/chrome/common/search/selected_colors_info.h b/chromium/chrome/common/search/selected_colors_info.h
new file mode 100644
index 00000000000..d1c6aa450c2
--- /dev/null
+++ b/chromium/chrome/common/search/selected_colors_info.h
@@ -0,0 +1,65 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SEARCH_SELECTED_COLORS_INFO_H_
+#define CHROME_COMMON_SEARCH_SELECTED_COLORS_INFO_H_
+
+#include <stdint.h>
+
+#include "chrome/grit/generated_resources.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace chrome_colors {
+
+struct ColorInfo {
+ constexpr ColorInfo(int id, SkColor color, int label_id)
+ : ColorInfo(id, color, label_id, nullptr) {}
+ constexpr ColorInfo(int id,
+ SkColor color,
+ int label_id,
+ const char* icon_data)
+ : id(id), color(color), label_id(label_id), icon_data(icon_data) {}
+ int id;
+ SkColor color;
+ int label_id;
+ const char* icon_data;
+};
+
+// List of preselected colors to show in Chrome Colors menu. This array should
+// always be in sync with ChromeColorsInfo in enums.xml.
+constexpr ColorInfo kSelectedColorsInfo[] = {
+ // 0 - reserved for any color not in this set.
+ ColorInfo(1, SkColorSetRGB(239, 235, 233), IDS_NTP_COLORS_WARM_GREY),
+ ColorInfo(2, SkColorSetRGB(120, 127, 145), IDS_NTP_COLORS_COOL_GREY),
+ ColorInfo(3, SkColorSetRGB(55, 71, 79), IDS_NTP_COLORS_MIDNIGHT_BLUE),
+ ColorInfo(4, SkColorSetRGB(0, 0, 0), IDS_NTP_COLORS_BLACK),
+ ColorInfo(5, SkColorSetRGB(252, 219, 201), IDS_NTP_COLORS_BEIGE_AND_WHITE),
+ ColorInfo(6, SkColorSetRGB(255, 249, 228), IDS_NTP_COLORS_YELLOW_AND_WHITE),
+ ColorInfo(7, SkColorSetRGB(203, 233, 191), IDS_NTP_COLORS_GREEN_AND_WHITE),
+ ColorInfo(8,
+ SkColorSetRGB(221, 244, 249),
+ IDS_NTP_COLORS_LIGHT_TEAL_AND_WHITE),
+ ColorInfo(9,
+ SkColorSetRGB(233, 212, 255),
+ IDS_NTP_COLORS_LIGHT_PURPLE_AND_WHITE),
+ ColorInfo(10, SkColorSetRGB(249, 226, 237), IDS_NTP_COLORS_PINK_AND_WHITE),
+ ColorInfo(11, SkColorSetRGB(227, 171, 154), IDS_NTP_COLORS_BEIGE),
+ ColorInfo(12, SkColorSetRGB(255, 171, 64), IDS_NTP_COLORS_ORANGE),
+ ColorInfo(13, SkColorSetRGB(67, 160, 71), IDS_NTP_COLORS_LIGHT_GREEN),
+ ColorInfo(14, SkColorSetRGB(25, 157, 169), IDS_NTP_COLORS_LIGHT_TEAL),
+ ColorInfo(15, SkColorSetRGB(93, 147, 228), IDS_NTP_COLORS_LIGHT_BLUE),
+ ColorInfo(16, SkColorSetRGB(255, 174, 189), IDS_NTP_COLORS_PINK),
+ ColorInfo(17, SkColorSetRGB(189, 22, 92), IDS_NTP_COLORS_DARK_PINK_AND_RED),
+ ColorInfo(18,
+ SkColorSetRGB(183, 28, 28),
+ IDS_NTP_COLORS_DARK_RED_AND_ORANGE),
+ ColorInfo(19, SkColorSetRGB(46, 125, 50), IDS_NTP_COLORS_DARK_GREEN),
+ ColorInfo(20, SkColorSetRGB(0, 110, 120), IDS_NTP_COLORS_DARK_TEAL),
+ ColorInfo(21, SkColorSetRGB(21, 101, 192), IDS_NTP_COLORS_DARK_BLUE),
+ ColorInfo(22, SkColorSetRGB(91, 54, 137), IDS_NTP_COLORS_DARK_PURPLE),
+};
+
+} // namespace chrome_colors
+
+#endif // CHROME_COMMON_SEARCH_SELECTED_COLORS_INFO_H_
diff --git a/chromium/chrome/common/secure_origin_whitelist.cc b/chromium/chrome/common/secure_origin_whitelist.cc
new file mode 100644
index 00000000000..e6a2a3ba1e0
--- /dev/null
+++ b/chromium/chrome/common/secure_origin_whitelist.cc
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/secure_origin_whitelist.h"
+
+#include <set>
+#include <string>
+
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "extensions/common/constants.h"
+
+namespace secure_origin_whitelist {
+
+std::set<std::string> GetSchemesBypassingSecureContextCheck() {
+ std::set<std::string> schemes;
+ schemes.insert(extensions::kExtensionScheme);
+ return schemes;
+}
+
+void RegisterPrefs(PrefRegistrySimple* local_state) {
+ local_state->RegisterStringPref(prefs::kUnsafelyTreatInsecureOriginAsSecure,
+ /* default_value */ "");
+}
+
+} // namespace secure_origin_whitelist
diff --git a/chromium/chrome/common/secure_origin_whitelist.h b/chromium/chrome/common/secure_origin_whitelist.h
new file mode 100644
index 00000000000..e55ca47d2fd
--- /dev/null
+++ b/chromium/chrome/common/secure_origin_whitelist.h
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_SECURE_ORIGIN_WHITELIST_H_
+#define CHROME_COMMON_SECURE_ORIGIN_WHITELIST_H_
+
+#include <set>
+#include <string>
+
+class PrefRegistrySimple;
+
+namespace secure_origin_whitelist {
+
+// Returns a whitelist of schemes that should bypass the Is Privileged Context
+// check. See http://www.w3.org/TR/powerful-features/#settings-privileged.
+std::set<std::string> GetSchemesBypassingSecureContextCheck();
+
+// Register preferences for Secure Origin Whitelists.
+void RegisterPrefs(PrefRegistrySimple* local_state);
+
+} // namespace secure_origin_whitelist
+
+#endif // CHROME_COMMON_SECURE_ORIGIN_WHITELIST_H_
diff --git a/chromium/chrome/common/service_process_util.cc b/chromium/chrome/common/service_process_util.cc
new file mode 100644
index 00000000000..2ebaab1c8eb
--- /dev/null
+++ b/chromium/chrome/common/service_process_util.cc
@@ -0,0 +1,276 @@
+// 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 "chrome/common/service_process_util.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/hash/sha1.h"
+#include "base/logging.h"
+#include "base/memory/shared_memory_mapping.h"
+#include "base/memory/singleton.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/version.h"
+#include "build/build_config.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "components/cloud_devices/common/cloud_devices_switches.h"
+#include "components/network_session_configurator/common/network_switches.h"
+#include "components/version_info/version_info.h"
+#include "content/public/common/content_paths.h"
+#include "content/public/common/content_switches.h"
+#include "google_apis/gaia/gaia_switches.h"
+#include "services/network/public/cpp/network_switches.h"
+#include "ui/base/ui_base_switches.h"
+
+#if !defined(OS_MACOSX)
+
+namespace {
+
+// This should be more than enough to hold a version string assuming each part
+// of the version string is an int64_t.
+const uint32_t kMaxVersionStringLength = 256;
+
+// The structure that gets written to shared memory.
+struct ServiceProcessSharedData {
+ char service_process_version[kMaxVersionStringLength];
+ base::ProcessId service_process_pid;
+};
+
+} // namespace
+
+// Return a name that is scoped to this instance of the service process. We
+// use the user-data-dir and the version as a scoping prefix.
+std::string GetServiceProcessScopedVersionedName(
+ const std::string& append_str) {
+ std::string versioned_str = version_info::GetVersionNumber();
+ versioned_str.append(append_str);
+ return GetServiceProcessScopedName(versioned_str);
+}
+
+// Reads the named shared memory to get the shared data. Returns false if no
+// matching shared memory was found.
+// static
+bool ServiceProcessState::GetServiceProcessData(std::string* version,
+ base::ProcessId* pid) {
+ base::ReadOnlySharedMemoryMapping service_process_data_mapping =
+ OpenServiceProcessDataMapping(sizeof(ServiceProcessSharedData));
+ if (!service_process_data_mapping.IsValid())
+ return false;
+
+ const ServiceProcessSharedData* service_data =
+ service_process_data_mapping.GetMemoryAs<ServiceProcessSharedData>();
+ // Make sure the version in shared memory is null-terminated. If it is not,
+ // treat it as invalid.
+ if (version && memchr(service_data->service_process_version, '\0',
+ sizeof(service_data->service_process_version)))
+ *version = service_data->service_process_version;
+ if (pid)
+ *pid = service_data->service_process_pid;
+ return true;
+}
+#endif // !OS_MACOSX
+
+// Return a name that is scoped to this instance of the service process. We
+// use the hash of the user-data-dir as a scoping prefix. We can't use
+// the user-data-dir itself as we have limits on the size of the lock names.
+std::string GetServiceProcessScopedName(const std::string& append_str) {
+ base::FilePath user_data_dir;
+ base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+#if defined(OS_WIN)
+ std::string user_data_dir_path = base::WideToUTF8(user_data_dir.value());
+#elif defined(OS_POSIX)
+ std::string user_data_dir_path = user_data_dir.value();
+#endif // defined(OS_WIN)
+ std::string hash = base::SHA1HashString(user_data_dir_path);
+ std::string hex_hash = base::HexEncode(hash.c_str(), hash.length());
+ return hex_hash + "." + append_str;
+}
+
+std::unique_ptr<base::CommandLine> CreateServiceProcessCommandLine() {
+ base::FilePath exe_path;
+ base::PathService::Get(content::CHILD_PROCESS_EXE, &exe_path);
+ DCHECK(!exe_path.empty()) << "Unable to get service process binary name.";
+ std::unique_ptr<base::CommandLine> command_line(
+ new base::CommandLine(exe_path));
+ command_line->AppendSwitchASCII(switches::kProcessType,
+ switches::kCloudPrintServiceProcess);
+
+#if defined(OS_WIN)
+ command_line->AppendArg(switches::kPrefetchArgumentOther);
+#endif // defined(OS_WIN)
+
+ static const char* const kSwitchesToCopy[] = {
+ network::switches::kIgnoreUrlFetcherCertRequests,
+ switches::kCloudPrintSetupProxy,
+ switches::kCloudPrintURL,
+ switches::kCloudPrintXmppEndpoint,
+#if defined(OS_WIN)
+ switches::kEnableCloudPrintXps,
+#endif
+ switches::kEnableLogging,
+ switches::kLang,
+ switches::kLoggingLevel,
+ switches::kLsoUrl,
+ switches::kNoServiceAutorun,
+ switches::kUserDataDir,
+ switches::kV,
+ switches::kVModule,
+ switches::kWaitForDebugger,
+ };
+
+ command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
+ kSwitchesToCopy, base::size(kSwitchesToCopy));
+ return command_line;
+}
+
+ServiceProcessState::ServiceProcessState() : state_(NULL) {
+ autorun_command_line_ = CreateServiceProcessCommandLine();
+ CreateState();
+}
+
+ServiceProcessState::~ServiceProcessState() {
+#if !defined(OS_MACOSX)
+ if (service_process_data_region_.IsValid()) {
+ service_process_data_region_ = {};
+ DeleteServiceProcessDataRegion();
+ }
+#endif // !OS_MACOSX
+ TearDownState();
+}
+
+void ServiceProcessState::SignalStopped() {
+ TearDownState();
+#if !defined(OS_MACOSX)
+ service_process_data_region_ = {};
+#endif // !OS_MACOSX
+}
+
+#if !defined(OS_MACOSX)
+bool ServiceProcessState::Initialize() {
+ if (!TakeSingletonLock()) {
+ return false;
+ }
+ // Now that we have the singleton, take care of killing an older version, if
+ // it exists.
+ if (!HandleOtherVersion())
+ return false;
+
+ // Write the version we are using to shared memory. This can be used by a
+ // newer service to signal us to exit.
+ return CreateSharedData();
+}
+
+// static
+std::string ServiceProcessState::GetServiceProcessSharedMemName() {
+ return GetServiceProcessScopedName("_service_shmem");
+}
+
+bool ServiceProcessState::HandleOtherVersion() {
+ std::string running_version;
+ base::ProcessId process_id = 0;
+ ServiceProcessRunningState state =
+ GetServiceProcessRunningState(&running_version, &process_id);
+ switch (state) {
+ case SERVICE_SAME_VERSION_RUNNING:
+ case SERVICE_NEWER_VERSION_RUNNING:
+ return false;
+ case SERVICE_OLDER_VERSION_RUNNING:
+ // If an older version is running, kill it.
+ ForceServiceProcessShutdown(running_version, process_id);
+ break;
+ case SERVICE_NOT_RUNNING:
+ break;
+ }
+ return true;
+}
+
+bool ServiceProcessState::CreateSharedData() {
+ if (version_info::GetVersionNumber().length() >= kMaxVersionStringLength) {
+ NOTREACHED() << "Version string length is << "
+ << version_info::GetVersionNumber().length()
+ << " which is longer than" << kMaxVersionStringLength;
+ return false;
+ }
+
+ uint32_t alloc_size = sizeof(ServiceProcessSharedData);
+ service_process_data_region_ = CreateServiceProcessDataRegion(alloc_size);
+ if (!service_process_data_region_.IsValid())
+ return false;
+ base::WritableSharedMemoryMapping mapping =
+ service_process_data_region_.Map();
+ if (!mapping.IsValid())
+ return false;
+ memset(mapping.memory(), 0, alloc_size);
+ ServiceProcessSharedData* shared_data =
+ mapping.GetMemoryAs<ServiceProcessSharedData>();
+ DCHECK(shared_data);
+ memcpy(shared_data->service_process_version,
+ version_info::GetVersionNumber().c_str(),
+ version_info::GetVersionNumber().length());
+ shared_data->service_process_pid = base::GetCurrentProcId();
+ return true;
+}
+
+// static
+ServiceProcessState::ServiceProcessRunningState
+ServiceProcessState::GetServiceProcessRunningState(
+ std::string* service_version_out,
+ base::ProcessId* pid_out) {
+ std::string version;
+ if (!ServiceProcessState::GetServiceProcessData(&version, pid_out))
+ return SERVICE_NOT_RUNNING;
+
+#if defined(OS_POSIX)
+ // We only need to check for service running on POSIX because Windows cleans
+ // up shared memory files when an app crashes, so there isn't a chance of
+ // us reading bogus data from shared memory for an app that has died.
+ if (!CheckServiceProcessReady()) {
+ return SERVICE_NOT_RUNNING;
+ }
+#endif // defined(OS_POSIX)
+
+ // At this time we have a version string. Set the out param if it exists.
+ if (service_version_out)
+ *service_version_out = version;
+
+ base::Version service_version(version);
+ // If the version string is invalid, treat it like an older version.
+ if (!service_version.IsValid())
+ return SERVICE_OLDER_VERSION_RUNNING;
+
+ // Get the version of the currently *running* instance of Chrome.
+ const base::Version& running_version = version_info::GetVersion();
+ if (!running_version.IsValid()) {
+ NOTREACHED() << "Failed to parse version info";
+ // Our own version is invalid. This is an error case. Pretend that we
+ // are out of date.
+ return SERVICE_NEWER_VERSION_RUNNING;
+ }
+
+ int comp = running_version.CompareTo(service_version);
+ if (comp == 0)
+ return SERVICE_SAME_VERSION_RUNNING;
+ return comp > 0 ? SERVICE_OLDER_VERSION_RUNNING
+ : SERVICE_NEWER_VERSION_RUNNING;
+}
+
+mojo::NamedPlatformChannel::ServerName
+ServiceProcessState::GetServiceProcessServerName() {
+ return ::GetServiceProcessServerName();
+}
+
+#endif // !OS_MACOSX
diff --git a/chromium/chrome/common/service_process_util.h b/chromium/chrome/common/service_process_util.h
new file mode 100644
index 00000000000..cb9e903c0e9
--- /dev/null
+++ b/chromium/chrome/common/service_process_util.h
@@ -0,0 +1,197 @@
+// 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 CHROME_COMMON_SERVICE_PROCESS_UTIL_H_
+#define CHROME_COMMON_SERVICE_PROCESS_UTIL_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/read_only_shared_memory_region.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/writable_shared_memory_region.h"
+#include "base/process/process.h"
+#include "base/single_thread_task_runner.h"
+#include "build/build_config.h"
+#include "mojo/public/cpp/platform/named_platform_channel.h"
+#include "mojo/public/cpp/platform/platform_channel_server_endpoint.h"
+
+class MultiProcessLock;
+
+#if defined(OS_MACOSX)
+#ifdef __OBJC__
+@class NSString;
+#else
+class NSString;
+#endif
+#endif
+
+namespace base {
+class CommandLine;
+}
+
+// Return the IPC channel to connect to the service process.
+mojo::NamedPlatformChannel::ServerName GetServiceProcessServerName();
+
+// Return a name that is scoped to this instance of the service process. We
+// use the user-data-dir as a scoping prefix.
+std::string GetServiceProcessScopedName(const std::string& append_str);
+
+#if !defined(OS_MACOSX)
+// Return a name that is scoped to this instance of the service process. We
+// use the user-data-dir and the version as a scoping prefix.
+std::string GetServiceProcessScopedVersionedName(const std::string& append_str);
+#endif // !OS_MACOSX
+
+#if defined(OS_POSIX)
+// Attempts to take a lock named |name|. If |waiting| is true then this will
+// make multiple attempts to acquire the lock.
+// Caller is responsible for ownership of the MultiProcessLock.
+MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting);
+#endif
+
+// The following method is used in a process that acts as a client to the
+// service process (typically the browser process). It method checks that if the
+// service process is ready to receive IPC commands.
+bool CheckServiceProcessReady();
+
+// --------------------------------------------------------------------------
+
+// Forces a service process matching the specified version to shut down.
+bool ForceServiceProcessShutdown(const std::string& version,
+ base::ProcessId process_id);
+
+// Creates command-line to run the service process.
+std::unique_ptr<base::CommandLine> CreateServiceProcessCommandLine();
+
+// This is a class that is used by the service process to signal events and
+// share data with external clients. This class lives in this file because the
+// internal data structures and mechanisms used by the utility methods above
+// and this class are shared.
+class ServiceProcessState {
+ public:
+ ServiceProcessState();
+ ~ServiceProcessState();
+
+ // Tries to become the sole service process for the current user data dir.
+ // Returns false if another service process is already running.
+ bool Initialize();
+
+ // Signal that the service process is ready.
+ // This method is called when the service process is running and initialized.
+ // |terminate_task| is invoked when we get a terminate request from another
+ // process (in the same thread that called SignalReady). It can be NULL.
+ // |task_runner| must be of type IO and is the loop that POSIX uses
+ // to monitor the service process.
+ bool SignalReady(scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const base::Closure& terminate_task);
+
+ // Signal that the service process is stopped.
+ void SignalStopped();
+
+ // Register the service process to run on startup.
+ bool AddToAutoRun();
+
+ // Unregister the service process to run on startup.
+ bool RemoveFromAutoRun();
+
+ // Return the channel handle used for communicating with the service.
+#if defined(OS_MACOSX)
+ mojo::PlatformChannelServerEndpoint GetServiceProcessServerEndpoint();
+#else
+ mojo::NamedPlatformChannel::ServerName GetServiceProcessServerName();
+#endif
+
+ private:
+#if !defined(OS_MACOSX)
+ enum ServiceProcessRunningState {
+ SERVICE_NOT_RUNNING,
+ SERVICE_OLDER_VERSION_RUNNING,
+ SERVICE_SAME_VERSION_RUNNING,
+ SERVICE_NEWER_VERSION_RUNNING,
+ };
+
+ // Create the shared memory data for the service process.
+ bool CreateSharedData();
+
+ // If an older version of the service process running, it should be shutdown.
+ // Returns false if this process needs to exit.
+ bool HandleOtherVersion();
+
+ // Acquires a singleton lock for the service process. A return value of false
+ // means that a service process instance is already running.
+ bool TakeSingletonLock();
+
+ // Return a name used to name a shared memory file that will be used to locate
+ // the currently running service process.
+ static std::string GetServiceProcessSharedMemName();
+
+ // Create a writable service process data shared memory region of the
+ // specified size. Returns an invalid region on error. If the backing file for
+ // the shared memory region already exists but is smaller than |size|, this
+ // function may return a valid region which will fail to be mapped.
+ static base::WritableSharedMemoryRegion CreateServiceProcessDataRegion(
+ size_t size);
+
+ // Open an existing service process data shared memory region of the specified
+ // size. Returns an invalid region on error. Note that if the size of the
+ // existing region is smaller than |size|, this function may return a valid
+ // region which will fail to be mapped. Also note that since the underlying
+ // file is writable, the region cannot be read-only.
+ static base::ReadOnlySharedMemoryMapping OpenServiceProcessDataMapping(
+ size_t size);
+
+ // Deletes a service process data shared memory backing file. Returns false if
+ // the file was not able to be deleted.
+ static bool DeleteServiceProcessDataRegion();
+
+ static ServiceProcessRunningState GetServiceProcessRunningState(
+ std::string* service_version_out,
+ base::ProcessId* pid_out);
+#endif // !OS_MACOSX
+
+ // Returns the process id and version of the currently running service
+ // process. Note: DO NOT use this check whether the service process is ready
+ // because a true return value only means that some process shared data was
+ // available, and not that the process is ready to receive IPC commands, or
+ // even running.
+ static bool GetServiceProcessData(std::string* version, base::ProcessId* pid);
+
+ // Creates the platform specific state.
+ void CreateState();
+
+ // Tear down the platform specific state.
+ void TearDownState();
+
+ // An opaque object that maintains state. The actual definition of this is
+ // platform dependent.
+ struct StateData;
+ StateData* state_;
+
+#if !defined(OS_MACOSX)
+ // The shared memory mapping backing the shared state on non-macos
+ // platforms. This is actually referring to named shared memory, and on some
+ // platforms (eg, Windows) determines the lifetime of when consumers are able
+ // to open the named shared region. This means this region must stay alive
+ // for the named region to be visible.
+ base::WritableSharedMemoryRegion service_process_data_region_;
+#endif
+
+ std::unique_ptr<base::CommandLine> autorun_command_line_;
+
+#if defined(OS_MACOSX)
+ friend bool CheckServiceProcessReady();
+#endif
+
+ FRIEND_TEST_ALL_PREFIXES(ServiceProcessStateTest, SharedMem);
+ FRIEND_TEST_ALL_PREFIXES(ServiceProcessStateTest, ForceShutdown);
+
+ friend class ServiceProcessControlBrowserTest;
+ FRIEND_TEST_ALL_PREFIXES(ServiceProcessControlBrowserTest, ForceShutdown);
+ FRIEND_TEST_ALL_PREFIXES(ServiceProcessControlBrowserTest, CheckPid);
+};
+
+#endif // CHROME_COMMON_SERVICE_PROCESS_UTIL_H_
diff --git a/chromium/chrome/common/service_process_util_linux.cc b/chromium/chrome/common/service_process_util_linux.cc
new file mode 100644
index 00000000000..cb75865b81b
--- /dev/null
+++ b/chromium/chrome/common/service_process_util_linux.cc
@@ -0,0 +1,89 @@
+// 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 <signal.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include "base/base_paths.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/threading/platform_thread.h"
+#include "build/branding_buildflags.h"
+#include "chrome/common/auto_start_linux.h"
+#include "chrome/common/multi_process_lock.h"
+#include "chrome/common/service_process_util_posix.h"
+
+namespace {
+
+MultiProcessLock* TakeServiceInitializingLock(bool waiting) {
+ std::string lock_name =
+ GetServiceProcessScopedName("_service_initializing");
+ return TakeNamedLock(lock_name, waiting);
+}
+
+std::string GetBaseDesktopName() {
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ return "google-chrome-service.desktop";
+#else // BUILDFLAG(CHROMIUM_BRANDING)
+ return "chromium-service.desktop";
+#endif
+}
+} // namespace
+
+MultiProcessLock* TakeServiceRunningLock(bool waiting) {
+ std::string lock_name =
+ GetServiceProcessScopedName("_service_running");
+ return TakeNamedLock(lock_name, waiting);
+}
+
+bool ForceServiceProcessShutdown(const std::string& version,
+ base::ProcessId process_id) {
+ if (kill(process_id, SIGTERM) < 0) {
+ DPLOG(ERROR) << "kill";
+ return false;
+ }
+ return true;
+}
+
+// Gets the name of the service process IPC channel.
+// Returns an absolute path as required.
+mojo::NamedPlatformChannel::ServerName GetServiceProcessServerName() {
+ base::FilePath temp_dir;
+ base::PathService::Get(base::DIR_TEMP, &temp_dir);
+ std::string pipe_name = GetServiceProcessScopedVersionedName("_service_ipc");
+ return temp_dir.Append(pipe_name).value();
+}
+
+bool CheckServiceProcessReady() {
+ std::unique_ptr<MultiProcessLock> running_lock(TakeServiceRunningLock(false));
+ return running_lock.get() == NULL;
+}
+
+bool ServiceProcessState::TakeSingletonLock() {
+ state_->initializing_lock.reset(TakeServiceInitializingLock(true));
+ return state_->initializing_lock.get();
+}
+
+bool ServiceProcessState::AddToAutoRun() {
+ DCHECK(autorun_command_line_.get());
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ std::string app_name = "Google Chrome Service";
+#else // BUILDFLAG(CHROMIUM_BRANDING)
+ std::string app_name = "Chromium Service";
+#endif
+ return AutoStart::AddApplication(
+ GetServiceProcessScopedName(GetBaseDesktopName()),
+ app_name,
+ autorun_command_line_->GetCommandLineString(),
+ false);
+}
+
+bool ServiceProcessState::RemoveFromAutoRun() {
+ return AutoStart::Remove(
+ GetServiceProcessScopedName(GetBaseDesktopName()));
+}
diff --git a/chromium/chrome/common/service_process_util_mac.mm b/chromium/chrome/common/service_process_util_mac.mm
new file mode 100644
index 00000000000..edef9967a03
--- /dev/null
+++ b/chromium/chrome/common/service_process_util_mac.mm
@@ -0,0 +1,405 @@
+// 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.
+
+#import <Foundation/Foundation.h>
+#include <launch.h>
+#include <sys/un.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/files/file_path.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "base/version.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/mac/launchd.h"
+#include "chrome/common/service_process_util_posix.h"
+#include "components/version_info/version_info.h"
+
+using ::base::FilePathWatcher;
+
+namespace {
+
+#define kServiceProcessSessionType "Aqua"
+
+CFStringRef CopyServiceProcessLaunchDName() {
+ @autoreleasepool {
+ NSBundle* bundle = base::mac::FrameworkBundle();
+ return CFStringCreateCopy(kCFAllocatorDefault,
+ base::mac::NSToCFCast([bundle bundleIdentifier]));
+ }
+}
+
+NSString* GetServiceProcessLaunchDLabel() {
+ base::scoped_nsobject<NSString> name(
+ base::mac::CFToNSCast(CopyServiceProcessLaunchDName()));
+ NSString* label = [name stringByAppendingString:@".service_process"];
+ base::FilePath user_data_dir;
+ base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ std::string user_data_dir_path = user_data_dir.value();
+ NSString* ns_path = base::SysUTF8ToNSString(user_data_dir_path);
+ ns_path = [ns_path stringByReplacingOccurrencesOfString:@" "
+ withString:@"_"];
+ label = [label stringByAppendingString:ns_path];
+ return label;
+}
+
+bool RemoveFromLaunchd() {
+ // We're killing a file.
+ base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+ base::BlockingType::MAY_BLOCK);
+ base::ScopedCFTypeRef<CFStringRef> name(CopyServiceProcessLaunchDName());
+ return Launchd::GetInstance()->DeletePlist(Launchd::User,
+ Launchd::Agent,
+ name);
+}
+
+class ExecFilePathWatcherCallback {
+ public:
+ ExecFilePathWatcherCallback() {}
+ ~ExecFilePathWatcherCallback() {}
+
+ bool Init(const base::FilePath& path);
+ void NotifyPathChanged(const base::FilePath& path, bool error);
+
+ private:
+ base::scoped_nsobject<NSURL> executable_fsref_;
+};
+
+NSString* GetServiceProcessMachName() {
+ base::scoped_nsobject<NSString> name(
+ base::mac::CFToNSCast(CopyServiceProcessLaunchDName()));
+ return [name stringByAppendingFormat:@".service_process.%lu",
+ [GetServiceProcessLaunchDLabel() hash]];
+}
+
+} // namespace
+
+mojo::NamedPlatformChannel::ServerName GetServiceProcessServerName() {
+ return base::SysNSStringToUTF8(GetServiceProcessMachName());
+}
+
+bool ForceServiceProcessShutdown(const std::string& /* version */,
+ base::ProcessId /* process_id */) {
+ const std::string& label =
+ base::SysNSStringToUTF8(GetServiceProcessLaunchDLabel());
+ bool ret = Launchd::GetInstance()->RemoveJob(label);
+ if (!ret) {
+ DLOG(ERROR) << "ForceServiceProcessShutdown: " << label;
+ }
+ return ret;
+}
+
+bool ServiceProcessState::GetServiceProcessData(std::string* version,
+ base::ProcessId* pid) {
+ @autoreleasepool {
+ std::string label =
+ base::SysNSStringToUTF8(GetServiceProcessLaunchDLabel());
+ mac::services::JobInfo info;
+ if (!Launchd::GetInstance()->GetJobInfo(label, &info))
+ return false;
+ // Anything past here will return true in that there does appear
+ // to be a service process of some sort registered with launchd.
+ if (version) {
+ *version = "0";
+ NSString* exe_path = base::SysUTF8ToNSString(info.program);
+ if (exe_path) {
+ NSString* bundle_path = [[[exe_path stringByDeletingLastPathComponent]
+ stringByDeletingLastPathComponent]
+ stringByDeletingLastPathComponent];
+ NSBundle* bundle = [NSBundle bundleWithPath:bundle_path];
+ if (bundle) {
+ NSString* ns_version =
+ [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
+ if (ns_version) {
+ *version = base::SysNSStringToUTF8(ns_version);
+ } else {
+ DLOG(ERROR) << "Unable to get version at: "
+ << reinterpret_cast<CFStringRef>(bundle_path);
+ }
+ } else {
+ // The bundle has been deleted out from underneath the registered
+ // job.
+ DLOG(ERROR) << "Unable to get bundle at: "
+ << reinterpret_cast<CFStringRef>(bundle_path);
+ }
+ } else {
+ DLOG(ERROR) << "Unable to get executable path for service process";
+ }
+ }
+ if (pid) {
+ *pid = info.pid ? *info.pid : -1;
+ }
+ return true;
+ }
+}
+
+bool ServiceProcessState::Initialize() {
+ mac::services::JobInfo info;
+ // The Mach service will be checked when GetServiceProcessServerEndpoint()
+ // is called.
+ bool ok = Launchd::GetInstance()->GetJobInfo(
+ base::SysNSStringToUTF8(GetServiceProcessLaunchDLabel()), &info);
+ if (!ok) {
+ DLOG(ERROR) << "Failed to look up job info.";
+ return false;
+ }
+ state_->job_info.program = info.program;
+ return true;
+}
+
+mojo::PlatformChannelServerEndpoint
+ServiceProcessState::GetServiceProcessServerEndpoint() {
+ mojo::NamedPlatformChannel::Options options;
+ options.server_name = base::SysNSStringToUTF8(GetServiceProcessMachName());
+ return mojo::NamedPlatformChannel(options).TakeServerEndpoint();
+}
+
+bool CheckServiceProcessReady() {
+ std::string version;
+ pid_t pid;
+ if (!ServiceProcessState::GetServiceProcessData(&version, &pid)) {
+ return false;
+ }
+ base::Version service_version(version);
+ bool ready = true;
+ if (!service_version.IsValid()) {
+ ready = false;
+ } else {
+ const base::Version& running_version = version_info::GetVersion();
+ if (!running_version.IsValid()) {
+ // Our own version is invalid. This is an error case. Pretend that we
+ // are out of date.
+ NOTREACHED();
+ ready = true;
+ } else {
+ ready = running_version.CompareTo(service_version) <= 0;
+ }
+ }
+ if (!ready) {
+ ForceServiceProcessShutdown(version, pid);
+ }
+ return ready;
+}
+
+mac::services::JobOptions GetServiceProcessJobOptions(
+ base::CommandLine* cmd_line,
+ bool for_auto_launch) {
+ mac::services::JobOptions options;
+
+ options.label = base::SysNSStringToUTF8(GetServiceProcessLaunchDLabel());
+ options.executable_path = cmd_line->GetProgram().value();
+ options.arguments = cmd_line->argv();
+ options.mach_service_name =
+ base::SysNSStringToUTF8(GetServiceProcessMachName());
+ options.run_at_load = for_auto_launch;
+ options.auto_launch = for_auto_launch;
+
+ return options;
+}
+
+CFDictionaryRef CreateServiceProcessLaunchdPlist(base::CommandLine* cmd_line,
+ bool for_auto_launch) {
+ @autoreleasepool {
+ NSString* program = base::SysUTF8ToNSString(cmd_line->GetProgram().value());
+
+ std::vector<std::string> args = cmd_line->argv();
+ NSMutableArray* ns_args = [NSMutableArray arrayWithCapacity:args.size()];
+
+ for (std::vector<std::string>::iterator iter = args.begin();
+ iter < args.end(); ++iter) {
+ [ns_args addObject:base::SysUTF8ToNSString(*iter)];
+ }
+
+ // See the man page for launchd.plist.
+ NSMutableDictionary* launchd_plist = [@{
+ @LAUNCH_JOBKEY_LABEL : GetServiceProcessLaunchDLabel(),
+ @LAUNCH_JOBKEY_PROGRAM : program,
+ @LAUNCH_JOBKEY_PROGRAMARGUMENTS : ns_args,
+ @LAUNCH_JOBKEY_MACHSERVICES : GetServiceProcessMachName(),
+ } mutableCopy];
+
+ if (for_auto_launch) {
+ // We want the service process to be able to exit if there are no services
+ // enabled. With a value of NO in the SuccessfulExit key, launchd will
+ // relaunch the service automatically in any other case than exiting
+ // cleanly with a 0 return code.
+ NSDictionary* keep_alive =
+ @{@LAUNCH_JOBKEY_KEEPALIVE_SUCCESSFULEXIT : @NO};
+ NSDictionary* auto_launchd_plist = @{
+ @LAUNCH_JOBKEY_RUNATLOAD : @YES,
+ @LAUNCH_JOBKEY_KEEPALIVE : keep_alive,
+ @LAUNCH_JOBKEY_LIMITLOADTOSESSIONTYPE : @kServiceProcessSessionType
+ };
+ [launchd_plist addEntriesFromDictionary:auto_launchd_plist];
+ }
+ return reinterpret_cast<CFDictionaryRef>(launchd_plist);
+ }
+}
+
+// Writes the launchd property list into the user's LaunchAgents directory,
+// creating that directory if needed. This will cause the service process to be
+// auto launched on the next user login.
+bool ServiceProcessState::AddToAutoRun() {
+ // We're creating directories and writing a file.
+ base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+ base::BlockingType::MAY_BLOCK);
+ DCHECK(autorun_command_line_.get());
+ base::ScopedCFTypeRef<CFStringRef> name(CopyServiceProcessLaunchDName());
+ base::ScopedCFTypeRef<CFDictionaryRef> plist(
+ CreateServiceProcessLaunchdPlist(autorun_command_line_.get(), true));
+ return Launchd::GetInstance()->WritePlistToFile(Launchd::User,
+ Launchd::Agent,
+ name,
+ plist);
+}
+
+bool ServiceProcessState::RemoveFromAutoRun() {
+ return RemoveFromLaunchd();
+}
+
+bool ServiceProcessState::StateData::WatchExecutable() {
+ @autoreleasepool {
+ base::FilePath executable_path = base::FilePath(job_info.program);
+ std::unique_ptr<ExecFilePathWatcherCallback> callback(
+ new ExecFilePathWatcherCallback);
+ if (!callback->Init(executable_path)) {
+ DLOG(ERROR) << "executable_watcher.Init " << executable_path.value();
+ return false;
+ }
+ if (!executable_watcher.Watch(
+ executable_path, false,
+ base::Bind(&ExecFilePathWatcherCallback::NotifyPathChanged,
+ base::Owned(callback.release())))) {
+ DLOG(ERROR) << "executable_watcher.watch " << executable_path.value();
+ return false;
+ }
+ return true;
+ }
+}
+
+bool ExecFilePathWatcherCallback::Init(const base::FilePath& path) {
+ NSString* path_string = base::mac::FilePathToNSString(path);
+ NSURL* path_url = [NSURL fileURLWithPath:path_string isDirectory:NO];
+ executable_fsref_.reset([[path_url fileReferenceURL] retain]);
+ return executable_fsref_.get() != nil;
+}
+
+void ExecFilePathWatcherCallback::NotifyPathChanged(const base::FilePath& path,
+ bool error) {
+ if (error) {
+ NOTREACHED(); // TODO(darin): Do something smarter?
+ return;
+ }
+
+ @autoreleasepool {
+ bool needs_shutdown = false;
+ bool needs_restart = false;
+ bool good_bundle = false;
+
+ // Go from bundle/Contents/MacOS/executable to bundle.
+ NSURL* bundle_url = [[[executable_fsref_ URLByDeletingLastPathComponent]
+ URLByDeletingLastPathComponent] URLByDeletingLastPathComponent];
+ if (bundle_url) {
+ base::ScopedCFTypeRef<CFBundleRef> bundle(CFBundleCreate(
+ kCFAllocatorDefault, base::mac::NSToCFCast(bundle_url)));
+ good_bundle = CFBundleGetIdentifier(bundle) != NULL;
+ }
+
+ if (!good_bundle) {
+ needs_shutdown = true;
+ } else {
+ bool in_trash = false;
+ NSFileManager* file_manager = [NSFileManager defaultManager];
+ NSURLRelationship relationship;
+ if ([file_manager getRelationship:&relationship
+ ofDirectory:NSTrashDirectory
+ inDomain:0
+ toItemAtURL:executable_fsref_
+ error:nil]) {
+ in_trash = relationship == NSURLRelationshipContains;
+ }
+ if (in_trash) {
+ needs_shutdown = true;
+ } else {
+ bool was_moved = true;
+ NSString* path_string = base::mac::FilePathToNSString(path);
+ NSURL* path_url = [NSURL fileURLWithPath:path_string isDirectory:NO];
+ NSURL* path_ref = [path_url fileReferenceURL];
+ if (path_ref != nil) {
+ if ([path_ref isEqual:executable_fsref_]) {
+ was_moved = false;
+ }
+ }
+ if (was_moved) {
+ needs_restart = true;
+ }
+ }
+ }
+ if (needs_shutdown || needs_restart) {
+ // First deal with the plist.
+ base::ScopedCFTypeRef<CFStringRef> name(CopyServiceProcessLaunchDName());
+ if (needs_restart) {
+ base::ScopedCFTypeRef<CFMutableDictionaryRef> plist(
+ Launchd::GetInstance()->CreatePlistFromFile(Launchd::User,
+ Launchd::Agent, name));
+ if (plist.get()) {
+ NSMutableDictionary* ns_plist = base::mac::CFToNSCast(plist);
+ NSURL* new_path = [executable_fsref_ filePathURL];
+ DCHECK([new_path isFileURL]);
+ NSString* ns_new_path = [new_path path];
+ ns_plist[@LAUNCH_JOBKEY_PROGRAM] = ns_new_path;
+ base::scoped_nsobject<NSMutableArray> args(
+ [ns_plist[@LAUNCH_JOBKEY_PROGRAMARGUMENTS] mutableCopy]);
+ args[0] = ns_new_path;
+ ns_plist[@LAUNCH_JOBKEY_PROGRAMARGUMENTS] = args;
+ if (!Launchd::GetInstance()->WritePlistToFile(
+ Launchd::User, Launchd::Agent, name, plist)) {
+ DLOG(ERROR) << "Unable to rewrite plist.";
+ needs_shutdown = true;
+ }
+ } else {
+ DLOG(ERROR) << "Unable to read plist.";
+ needs_shutdown = true;
+ }
+ }
+ if (needs_shutdown) {
+ if (!RemoveFromLaunchd()) {
+ DLOG(ERROR) << "Unable to RemoveFromLaunchd.";
+ }
+ }
+
+ // Then deal with the process.
+ CFStringRef session_type = CFSTR(kServiceProcessSessionType);
+ if (needs_restart) {
+ if (!Launchd::GetInstance()->RestartJob(Launchd::User, Launchd::Agent,
+ name, session_type)) {
+ DLOG(ERROR) << "RestartLaunchdJob";
+ needs_shutdown = true;
+ }
+ }
+ if (needs_shutdown) {
+ const std::string& label =
+ base::SysNSStringToUTF8(GetServiceProcessLaunchDLabel());
+ if (!Launchd::GetInstance()->RemoveJob(label)) {
+ DLOG(ERROR) << "RemoveJob " << label;
+ // Exiting with zero, so launchd doesn't restart the process.
+ exit(0);
+ }
+ }
+ }
+ }
+}
diff --git a/chromium/chrome/common/service_process_util_mac_unittest.mm b/chromium/chrome/common/service_process_util_mac_unittest.mm
new file mode 100644
index 00000000000..06c8e07cc7e
--- /dev/null
+++ b/chromium/chrome/common/service_process_util_mac_unittest.mm
@@ -0,0 +1,191 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/service_process_util.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_pump_type.h"
+#include "base/process/launch.h"
+#include "base/run_loop.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/test/task_environment.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/thread.h"
+#include "chrome/common/mac/launchd.h"
+#include "chrome/common/mac/mock_launchd.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class ServiceProcessStateFileManipulationTest : public ::testing::Test {
+ public:
+ void TrashFunc(const base::FilePath& src) {
+ NSURL* url = [NSURL fileURLWithPath:base::SysUTF8ToNSString(src.value())];
+ ASSERT_TRUE(url);
+ NSURL* resultingItemURL = nil;
+ BOOL success =
+ [[NSFileManager defaultManager] trashItemAtURL:url
+ resultingItemURL:&resultingItemURL
+ error:nil];
+ ASSERT_TRUE(success);
+ trashed_url_.reset([resultingItemURL retain]);
+ }
+
+ protected:
+ ServiceProcessStateFileManipulationTest()
+ : io_thread_("ServiceProcessStateFileManipulationTest_IO") {}
+
+ void SetUp() override {
+ base::Thread::Options options;
+ options.message_pump_type = base::MessagePumpType::IO;
+ ASSERT_TRUE(io_thread_.StartWithOptions(options));
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ ASSERT_TRUE(MockLaunchd::MakeABundle(GetTempDirPath(), "Test",
+ &bundle_path_, &executable_path_));
+ mock_launchd_.reset(new MockLaunchd(
+ executable_path_, task_environment_.GetMainThreadTaskRunner(),
+ run_loop_.QuitClosure(), true));
+ scoped_launchd_instance_.reset(
+ new Launchd::ScopedInstance(mock_launchd_.get()));
+ ASSERT_TRUE(service_process_state_.Initialize());
+ ASSERT_TRUE(service_process_state_.SignalReady(
+ io_thread_.task_runner().get(), base::Closure()));
+ task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
+ FROM_HERE, run_loop_.QuitWhenIdleClosure(),
+ TestTimeouts::action_max_timeout());
+ }
+
+ const MockLaunchd* mock_launchd() const { return mock_launchd_.get(); }
+ const base::FilePath& executable_path() const { return executable_path_; }
+ const base::FilePath& bundle_path() const { return bundle_path_; }
+ const base::FilePath& GetTempDirPath() const { return temp_dir_.GetPath(); }
+
+ base::SingleThreadTaskRunner* GetIOTaskRunner() {
+ return io_thread_.task_runner().get();
+ }
+ void Run() { run_loop_.Run(); }
+
+ base::scoped_nsobject<NSURL> trashed_url_;
+
+ private:
+ base::ScopedTempDir temp_dir_;
+ base::test::SingleThreadTaskEnvironment task_environment_{
+ base::test::SingleThreadTaskEnvironment::MainThreadType::UI};
+ base::RunLoop run_loop_;
+ base::Thread io_thread_;
+ base::FilePath executable_path_, bundle_path_;
+ std::unique_ptr<MockLaunchd> mock_launchd_;
+ std::unique_ptr<Launchd::ScopedInstance> scoped_launchd_instance_;
+ ServiceProcessState service_process_state_;
+};
+
+void DeleteFunc(const base::FilePath& file) {
+ EXPECT_TRUE(base::DeleteFile(file, true));
+}
+
+void MoveFunc(const base::FilePath& from, const base::FilePath& to) {
+ EXPECT_TRUE(base::Move(from, to));
+}
+
+void ChangeAttr(const base::FilePath& from, int mode) {
+ EXPECT_EQ(chmod(from.value().c_str(), mode), 0);
+}
+
+class ScopedAttributesRestorer {
+ public:
+ ScopedAttributesRestorer(const base::FilePath& path, int mode)
+ : path_(path), mode_(mode) {}
+ ~ScopedAttributesRestorer() { ChangeAttr(path_, mode_); }
+
+ private:
+ base::FilePath path_;
+ int mode_;
+};
+
+TEST_F(ServiceProcessStateFileManipulationTest, VerifyLaunchD) {
+ // There have been problems where launchd has gotten into a bad state, usually
+ // because something had deleted all the files in /tmp. launchd depends on
+ // a Unix Domain Socket that it creates at /tmp/launchd*/sock.
+ // The symptom of this problem is that the service process connect fails
+ // on Mac and "launch_msg(): Socket is not connected" appears.
+ // This test is designed to make sure that launchd is working.
+ // http://crbug/75518
+ // Note: This particular problem no longer affects launchd in 10.10+, since
+ // there is no user owned launchd process and sockets are no longer made at
+ // /tmp/launchd*/sock. This test is still useful as a sanity check to make
+ // sure that launchd appears to be working.
+
+ base::CommandLine cl(base::FilePath("/bin/launchctl"));
+ cl.AppendArg("limit");
+
+ std::string output;
+ int exit_code = -1;
+ ASSERT_TRUE(base::GetAppOutputWithExitCode(cl, &output, &exit_code) &&
+ exit_code == 0)
+ << " exit_code:" << exit_code << " " << output;
+}
+
+// Flaky: https://crbug.com/903823
+TEST_F(ServiceProcessStateFileManipulationTest, DISABLED_DeleteFile) {
+ GetIOTaskRunner()->PostTask(FROM_HERE,
+ base::BindOnce(&DeleteFunc, executable_path()));
+ Run();
+ ASSERT_TRUE(mock_launchd()->remove_called());
+ ASSERT_TRUE(mock_launchd()->delete_called());
+}
+
+TEST_F(ServiceProcessStateFileManipulationTest, DeleteBundle) {
+ GetIOTaskRunner()->PostTask(FROM_HERE,
+ base::BindOnce(&DeleteFunc, bundle_path()));
+ Run();
+ ASSERT_TRUE(mock_launchd()->remove_called());
+ ASSERT_TRUE(mock_launchd()->delete_called());
+}
+
+TEST_F(ServiceProcessStateFileManipulationTest, MoveBundle) {
+ base::FilePath new_loc = GetTempDirPath().AppendASCII("MoveBundle");
+ GetIOTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&MoveFunc, bundle_path(), new_loc));
+ Run();
+ ASSERT_TRUE(mock_launchd()->restart_called());
+ ASSERT_TRUE(mock_launchd()->write_called());
+}
+
+TEST_F(ServiceProcessStateFileManipulationTest, MoveFile) {
+ base::FilePath new_loc = GetTempDirPath().AppendASCII("MoveFile");
+ GetIOTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&MoveFunc, executable_path(), new_loc));
+ Run();
+ ASSERT_TRUE(mock_launchd()->remove_called());
+ ASSERT_TRUE(mock_launchd()->delete_called());
+}
+
+TEST_F(ServiceProcessStateFileManipulationTest, TrashBundle) {
+ GetIOTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ServiceProcessStateFileManipulationTest::TrashFunc,
+ base::Unretained(this), bundle_path()));
+ Run();
+ ASSERT_TRUE(mock_launchd()->remove_called());
+ ASSERT_TRUE(mock_launchd()->delete_called());
+ std::string path(base::SysNSStringToUTF8([trashed_url_ path]));
+ base::FilePath file_path(path);
+ ASSERT_TRUE(base::DeleteFile(file_path, true));
+}
+
+TEST_F(ServiceProcessStateFileManipulationTest, ChangeAttr) {
+ ScopedAttributesRestorer restorer(bundle_path(), 0777);
+ GetIOTaskRunner()->PostTask(FROM_HERE,
+ base::BindOnce(&ChangeAttr, bundle_path(), 0222));
+ Run();
+ ASSERT_TRUE(mock_launchd()->remove_called());
+ ASSERT_TRUE(mock_launchd()->delete_called());
+}
diff --git a/chromium/chrome/common/service_process_util_posix.cc b/chromium/chrome/common/service_process_util_posix.cc
new file mode 100644
index 00000000000..698cf49c19c
--- /dev/null
+++ b/chromium/chrome/common/service_process_util_posix.cc
@@ -0,0 +1,360 @@
+// 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 "chrome/common/service_process_util_posix.h"
+
+#include <fcntl.h>
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop_current.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/synchronization/waitable_event.h"
+#include "build/branding_buildflags.h"
+#include "chrome/common/multi_process_lock.h"
+
+#if defined(OS_ANDROID)
+#error "Should not be built on android"
+#endif
+
+namespace {
+int g_signal_socket = -1;
+
+#if !defined(OS_MACOSX)
+
+bool FilePathForMemoryName(const std::string& mem_name, base::FilePath* path) {
+ // mem_name will be used for a filename; make sure it doesn't
+ // contain anything which will confuse us.
+ DCHECK_EQ(std::string::npos, mem_name.find('/'));
+ DCHECK_EQ(std::string::npos, mem_name.find('\0'));
+
+ base::FilePath temp_dir;
+ if (!GetShmemTempDir(false, &temp_dir))
+ return false;
+
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ static const char kShmem[] = "com.google.Chrome.shmem.";
+#else
+ static const char kShmem[] = "org.chromium.Chromium.shmem.";
+#endif
+ *path = temp_dir.AppendASCII(kShmem + mem_name);
+ return true;
+}
+
+#endif // !defined(OS_MACOSX)
+
+} // namespace
+
+#if !defined(OS_MACOSX)
+
+// static
+base::WritableSharedMemoryRegion
+ServiceProcessState::CreateServiceProcessDataRegion(size_t size) {
+ base::FilePath path;
+
+ if (!FilePathForMemoryName(GetServiceProcessSharedMemName(), &path))
+ return {};
+
+ // Make sure that the file is opened without any permission
+ // to other users on the system.
+ const mode_t kOwnerOnly = S_IRUSR | S_IWUSR;
+
+ bool fix_size = true;
+
+ // First, try to create the file.
+ base::ScopedFD fd(HANDLE_EINTR(
+ open(path.value().c_str(), O_RDWR | O_CREAT | O_EXCL, kOwnerOnly)));
+ if (!fd.is_valid()) {
+ // If this doesn't work, try and open an existing file in append mode.
+ // Opening an existing file in a world writable directory has two main
+ // security implications:
+ // - Attackers could plant a file under their control, so ownership of
+ // the file is checked below.
+ // - Attackers could plant a symbolic link so that an unexpected file
+ // is opened, so O_NOFOLLOW is passed to open().
+#if !defined(OS_AIX)
+ fd.reset(HANDLE_EINTR(
+ open(path.value().c_str(), O_RDWR | O_APPEND | O_NOFOLLOW)));
+#else
+ // AIX has no 64-bit support for open flags such as -
+ // O_CLOEXEC, O_NOFOLLOW and O_TTY_INIT.
+ fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDWR | O_APPEND)));
+#endif
+ // Check that the current user owns the file.
+ // If uid != euid, then a more complex permission model is used and this
+ // API is not appropriate.
+ const uid_t real_uid = getuid();
+ const uid_t effective_uid = geteuid();
+ struct stat sb;
+ if (fd.is_valid() && (fstat(fd.get(), &sb) != 0 || sb.st_uid != real_uid ||
+ sb.st_uid != effective_uid)) {
+ DLOG(ERROR) << "Invalid owner when opening existing shared memory file.";
+ return {};
+ }
+
+ // An existing file was opened, so its size should not be fixed.
+ fix_size = false;
+ }
+
+ if (fd.is_valid() && fix_size) {
+ // Get current size.
+ struct stat stat;
+ if (fstat(fd.get(), &stat) != 0)
+ return {};
+ const size_t current_size = stat.st_size;
+ if (current_size != size) {
+ if (HANDLE_EINTR(ftruncate(fd.get(), size)) != 0)
+ return {};
+ }
+ }
+
+ // Everything has worked out so far, so open a read-only handle to the region
+ // in order to be able to create a writable region (which needs a read-only
+ // handle in order to convert to a read-only region.
+ base::ScopedFD read_only_fd(
+ HANDLE_EINTR(open(path.value().c_str(), O_RDONLY, kOwnerOnly)));
+ if (!read_only_fd.is_valid()) {
+ DPLOG(ERROR) << "Could not reopen shared memory region as read-only";
+ return {};
+ }
+
+ base::WritableSharedMemoryRegion writable_region =
+ base::WritableSharedMemoryRegion::Deserialize(
+ base::subtle::PlatformSharedMemoryRegion::Take(
+ base::subtle::ScopedFDPair(std::move(fd),
+ std::move(read_only_fd)),
+ base::subtle::PlatformSharedMemoryRegion::Mode::kWritable, size,
+ base::UnguessableToken::Create()));
+ if (!writable_region.IsValid()) {
+ DLOG(ERROR) << "Could not deserialize named region";
+ return {};
+ }
+ return writable_region;
+}
+
+// static
+base::ReadOnlySharedMemoryMapping
+ServiceProcessState::OpenServiceProcessDataMapping(size_t size) {
+ base::FilePath path;
+ if (!FilePathForMemoryName(GetServiceProcessSharedMemName(), &path))
+ return {};
+
+ base::ScopedFD fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
+ if (!fd.is_valid()) {
+ DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
+ return {};
+ }
+ return base::ReadOnlySharedMemoryRegion::Deserialize(
+ base::subtle::PlatformSharedMemoryRegion::Take(
+ base::subtle::ScopedFDPair(std::move(fd), base::ScopedFD()),
+ base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly,
+ size, base::UnguessableToken::Create()))
+ .Map();
+}
+
+// static
+bool ServiceProcessState::DeleteServiceProcessDataRegion() {
+ base::FilePath path;
+ if (!FilePathForMemoryName(GetServiceProcessSharedMemName(), &path))
+ return false;
+
+ if (PathExists(path))
+ return DeleteFile(path, false);
+
+ // Doesn't exist, so success.
+ return true;
+}
+
+#endif // !defined(OS_MACOSX)
+
+// Attempts to take a lock named |name|. If |waiting| is true then this will
+// make multiple attempts to acquire the lock.
+// Caller is responsible for ownership of the MultiProcessLock.
+MultiProcessLock* TakeNamedLock(const std::string& name, bool waiting) {
+ std::unique_ptr<MultiProcessLock> lock = MultiProcessLock::Create(name);
+ if (lock == NULL) return NULL;
+ bool got_lock = false;
+ for (int i = 0; i < 10; ++i) {
+ if (lock->TryLock()) {
+ got_lock = true;
+ break;
+ }
+ if (!waiting) break;
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100 * i));
+ }
+ if (!got_lock) {
+ lock.reset();
+ }
+ return lock.release();
+}
+
+ServiceProcessTerminateMonitor::ServiceProcessTerminateMonitor(
+ const base::Closure& terminate_task)
+ : terminate_task_(terminate_task) {
+}
+
+ServiceProcessTerminateMonitor::~ServiceProcessTerminateMonitor() {
+}
+
+void ServiceProcessTerminateMonitor::OnFileCanReadWithoutBlocking(int fd) {
+ if (!terminate_task_.is_null()) {
+ int buffer;
+ int length = read(fd, &buffer, sizeof(buffer));
+ if ((length == sizeof(buffer)) && (buffer == kTerminateMessage)) {
+ terminate_task_.Run();
+ terminate_task_.Reset();
+ } else if (length > 0) {
+ DLOG(ERROR) << "Unexpected read: " << buffer;
+ } else if (length == 0) {
+ DLOG(ERROR) << "Unexpected fd close";
+ } else if (length < 0) {
+ DPLOG(ERROR) << "read";
+ }
+ }
+}
+
+void ServiceProcessTerminateMonitor::OnFileCanWriteWithoutBlocking(int fd) {
+ NOTIMPLEMENTED();
+}
+
+// "Forced" Shutdowns on POSIX are done via signals. The magic signal for
+// a shutdown is SIGTERM. "write" is a signal safe function. PLOG(ERROR) is
+// not, but we don't ever expect it to be called.
+static void SigTermHandler(int sig, siginfo_t* info, void* uap) {
+ // TODO(dmaclach): add security here to make sure that we are being shut
+ // down by an appropriate process.
+ int message = ServiceProcessTerminateMonitor::kTerminateMessage;
+ if (write(g_signal_socket, &message, sizeof(message)) < 0) {
+ DPLOG(ERROR) << "write";
+ }
+}
+
+ServiceProcessState::StateData::StateData()
+ : watcher(FROM_HERE), set_action(false) {
+ memset(sockets, -1, sizeof(sockets));
+ memset(&old_action, 0, sizeof(old_action));
+}
+
+void ServiceProcessState::StateData::SignalReady(base::WaitableEvent* signal,
+ bool* success) {
+ DCHECK(task_runner->BelongsToCurrentThread());
+ DCHECK_EQ(g_signal_socket, -1);
+ DCHECK(!signal->IsSignaled());
+ *success = base::MessageLoopCurrentForIO::Get()->WatchFileDescriptor(
+ sockets[0], true, base::MessagePumpForIO::WATCH_READ, &watcher,
+ terminate_monitor.get());
+ if (!*success) {
+ DLOG(ERROR) << "WatchFileDescriptor";
+ signal->Signal();
+ return;
+ }
+ g_signal_socket = sockets[1];
+
+ // Set up signal handler for SIGTERM.
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ action.sa_sigaction = SigTermHandler;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = SA_SIGINFO;
+ *success = sigaction(SIGTERM, &action, &old_action) == 0;
+ if (!*success) {
+ DPLOG(ERROR) << "sigaction";
+ signal->Signal();
+ return;
+ }
+
+ // If the old_action is not default, somebody else has installed a
+ // a competing handler. Our handler is going to override it so it
+ // won't be called. If this occurs it needs to be fixed.
+ DCHECK_EQ(old_action.sa_handler, SIG_DFL);
+ set_action = true;
+
+#if defined(OS_MACOSX)
+ *success = WatchExecutable();
+ if (!*success) {
+ DLOG(ERROR) << "WatchExecutable";
+ signal->Signal();
+ return;
+ }
+#elif defined(OS_POSIX)
+ initializing_lock.reset();
+#endif // OS_POSIX
+ signal->Signal();
+}
+
+ServiceProcessState::StateData::~StateData() {
+ // StateData is destroyed on the thread that called SignalReady() (if any) to
+ // satisfy the requirement that base::FilePathWatcher is destroyed in sequence
+ // with base::FilePathWatcher::Watch().
+ DCHECK(!task_runner || task_runner->BelongsToCurrentThread());
+
+ // Cancel any pending file-descriptor watch before closing the descriptor.
+ watcher.StopWatchingFileDescriptor();
+
+ if (sockets[0] != -1) {
+ if (IGNORE_EINTR(close(sockets[0]))) {
+ DPLOG(ERROR) << "close";
+ }
+ }
+ if (sockets[1] != -1) {
+ if (IGNORE_EINTR(close(sockets[1]))) {
+ DPLOG(ERROR) << "close";
+ }
+ }
+ if (set_action) {
+ if (sigaction(SIGTERM, &old_action, NULL) < 0) {
+ DPLOG(ERROR) << "sigaction";
+ }
+ }
+ g_signal_socket = -1;
+}
+
+void ServiceProcessState::CreateState() {
+ DCHECK(!state_);
+ state_ = new StateData();
+}
+
+bool ServiceProcessState::SignalReady(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const base::Closure& terminate_task) {
+ DCHECK(task_runner);
+ DCHECK(state_);
+
+#if !defined(OS_MACOSX)
+ state_->running_lock.reset(TakeServiceRunningLock(true));
+ if (state_->running_lock.get() == NULL) {
+ return false;
+ }
+#endif
+ state_->terminate_monitor.reset(
+ new ServiceProcessTerminateMonitor(terminate_task));
+ if (pipe(state_->sockets) < 0) {
+ DPLOG(ERROR) << "pipe";
+ return false;
+ }
+ base::WaitableEvent signal_ready(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ bool success = false;
+
+ state_->task_runner = std::move(task_runner);
+ state_->task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ServiceProcessState::StateData::SignalReady,
+ base::Unretained(state_), &signal_ready, &success));
+ signal_ready.Wait();
+ return success;
+}
+
+void ServiceProcessState::TearDownState() {
+ if (state_ && state_->task_runner)
+ state_->task_runner->DeleteSoon(FROM_HERE, state_);
+ else
+ delete state_;
+ state_ = nullptr;
+}
diff --git a/chromium/chrome/common/service_process_util_posix.h b/chromium/chrome/common/service_process_util_posix.h
new file mode 100644
index 00000000000..bcba5bfe7a0
--- /dev/null
+++ b/chromium/chrome/common/service_process_util_posix.h
@@ -0,0 +1,93 @@
+// 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 CHROME_COMMON_SERVICE_PROCESS_UTIL_POSIX_H_
+#define CHROME_COMMON_SERVICE_PROCESS_UTIL_POSIX_H_
+
+#include "chrome/common/service_process_util.h"
+
+#include <signal.h>
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_pump_for_io.h"
+#include "base/single_thread_task_runner.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+#include "chrome/common/multi_process_lock.h"
+MultiProcessLock* TakeServiceRunningLock(bool waiting);
+#endif
+
+#if defined(OS_MACOSX)
+#include "base/files/file_path_watcher.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "chrome/common/mac/service_management.h"
+
+namespace base {
+class CommandLine;
+}
+
+mac::services::JobOptions GetServiceProcessJobOptions(
+ base::CommandLine* cmd_line,
+ bool for_auto_launch);
+#endif // OS_MACOSX
+
+namespace base {
+class WaitableEvent;
+}
+
+// Watches for |kTerminateMessage| to be written to the file descriptor it is
+// watching. When it reads |kTerminateMessage|, it performs |terminate_task_|.
+// Used here to monitor the socket listening to g_signal_socket.
+class ServiceProcessTerminateMonitor
+ : public base::MessagePumpForIO::FdWatcher {
+ public:
+
+ enum {
+ kTerminateMessage = 0xdecea5e
+ };
+
+ explicit ServiceProcessTerminateMonitor(const base::Closure& terminate_task);
+ ~ServiceProcessTerminateMonitor() override;
+
+ // MessagePumpForIO::FdWatcher overrides
+ void OnFileCanReadWithoutBlocking(int fd) override;
+ void OnFileCanWriteWithoutBlocking(int fd) override;
+
+ private:
+ base::Closure terminate_task_;
+};
+
+struct ServiceProcessState::StateData {
+ StateData();
+ ~StateData();
+
+ // WatchFileDescriptor needs to be set up by the thread that is going
+ // to be monitoring it.
+ void SignalReady(base::WaitableEvent* signal, bool* success);
+
+#if defined(OS_MACOSX)
+ bool WatchExecutable();
+
+ mac::services::JobCheckinInfo job_info;
+ base::FilePathWatcher executable_watcher;
+#else
+ std::unique_ptr<MultiProcessLock> initializing_lock;
+ std::unique_ptr<MultiProcessLock> running_lock;
+#endif
+ std::unique_ptr<ServiceProcessTerminateMonitor> terminate_monitor;
+ base::MessagePumpForIO::FdWatchController watcher;
+ int sockets[2];
+ struct sigaction old_action;
+ bool set_action;
+
+ // The SingleThreadTaskRunner on which SignalReady and the destructor are
+ // invoked.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner;
+};
+
+#endif // CHROME_COMMON_SERVICE_PROCESS_UTIL_POSIX_H_
diff --git a/chromium/chrome/common/service_process_util_unittest.cc b/chromium/chrome/common/service_process_util_unittest.cc
new file mode 100644
index 00000000000..99ccc2c2476
--- /dev/null
+++ b/chromium/chrome/common/service_process_util_unittest.cc
@@ -0,0 +1,253 @@
+// 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 "chrome/common/service_process_util.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/location.h"
+#include "base/process/kill.h"
+#include "base/process/launch.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_split.h"
+#include "base/test/task_environment.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/branding_buildflags.h"
+#include "build/build_config.h"
+
+#if !defined(OS_MACOSX)
+#include "base/at_exit.h"
+#include "base/message_loop/message_pump_type.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/thread.h"
+#include "chrome/common/chrome_switches.h"
+#include "components/version_info/version_info.h"
+#include "content/public/common/content_switches.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_WIN)
+#include "base/win/win_util.h"
+#endif
+
+#if defined(OS_POSIX)
+#include "chrome/common/auto_start_linux.h"
+#endif
+
+#if defined(USE_AURA)
+// This test fails http://crbug.com/84854, and is very flaky on CrOS and
+// somewhat flaky on other Linux.
+#define MAYBE_ForceShutdown DISABLED_ForceShutdown
+#else
+#if defined(OS_LINUX) || defined(OS_WIN)
+#define MAYBE_ForceShutdown DISABLED_ForceShutdown
+#else
+#define MAYBE_ForceShutdown ForceShutdown
+#endif
+#endif
+
+namespace {
+
+bool g_good_shutdown = false;
+
+void ShutdownTask(base::RunLoop* loop) {
+ // Quit the main message loop.
+ ASSERT_FALSE(g_good_shutdown);
+ g_good_shutdown = true;
+ loop->QuitWhenIdle();
+}
+
+} // namespace
+
+TEST(ServiceProcessUtilTest, ScopedVersionedName) {
+ std::string test_str = "test";
+ std::string scoped_name = GetServiceProcessScopedVersionedName(test_str);
+ EXPECT_TRUE(base::EndsWith(scoped_name, test_str,
+ base::CompareCase::SENSITIVE));
+ EXPECT_NE(std::string::npos,
+ scoped_name.find(version_info::GetVersionNumber()));
+}
+
+class ServiceProcessStateTest : public base::MultiProcessTest {
+ public:
+ ServiceProcessStateTest();
+ ~ServiceProcessStateTest() override;
+ void SetUp() override;
+ base::SingleThreadTaskRunner* IOTaskRunner() {
+ return io_thread_.task_runner().get();
+ }
+ void LaunchAndWait(const std::string& name);
+
+ private:
+ // This is used to release the ServiceProcessState singleton after each test.
+ base::ShadowingAtExitManager at_exit_manager_;
+ base::Thread io_thread_;
+};
+
+ServiceProcessStateTest::ServiceProcessStateTest()
+ : io_thread_("ServiceProcessStateTestThread") {
+}
+
+ServiceProcessStateTest::~ServiceProcessStateTest() {
+}
+
+void ServiceProcessStateTest::SetUp() {
+ base::Thread::Options options(base::MessagePumpType::IO, 0);
+ ASSERT_TRUE(io_thread_.StartWithOptions(options));
+}
+
+void ServiceProcessStateTest::LaunchAndWait(const std::string& name) {
+ base::Process process = SpawnChild(name);
+ ASSERT_TRUE(process.IsValid());
+ int exit_code = 0;
+ ASSERT_TRUE(process.WaitForExit(&exit_code));
+ ASSERT_EQ(exit_code, 0);
+}
+
+TEST_F(ServiceProcessStateTest, Singleton) {
+ ServiceProcessState state;
+ ASSERT_TRUE(state.Initialize());
+ LaunchAndWait("ServiceProcessStateTestSingleton");
+}
+
+// http://crbug.com/396390
+TEST_F(ServiceProcessStateTest, DISABLED_ReadyState) {
+ ASSERT_FALSE(CheckServiceProcessReady());
+ ServiceProcessState state;
+ ASSERT_TRUE(state.Initialize());
+ ASSERT_TRUE(state.SignalReady(IOTaskRunner(), base::Closure()));
+ LaunchAndWait("ServiceProcessStateTestReadyTrue");
+ state.SignalStopped();
+ LaunchAndWait("ServiceProcessStateTestReadyFalse");
+}
+
+TEST_F(ServiceProcessStateTest, AutoRun) {
+ ServiceProcessState state;
+ ASSERT_TRUE(state.AddToAutoRun());
+ std::unique_ptr<base::CommandLine> autorun_command_line;
+#if defined(OS_WIN)
+ std::string value_name = GetServiceProcessScopedName("_service_run");
+ base::string16 value;
+ EXPECT_TRUE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER,
+ base::UTF8ToWide(value_name),
+ &value));
+ autorun_command_line.reset(
+ new base::CommandLine(base::CommandLine::FromString(value)));
+#elif defined(OS_POSIX) && !defined(OS_MACOSX)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ std::string base_desktop_name = "google-chrome-service.desktop";
+#else // BUILDFLAG(CHROMIUM_BRANDING)
+ std::string base_desktop_name = "chromium-service.desktop";
+#endif
+ std::string exec_value;
+ EXPECT_TRUE(AutoStart::GetAutostartFileValue(
+ GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value));
+
+ // Make sure |exec_value| doesn't contain strings a shell would
+ // treat specially.
+ ASSERT_EQ(std::string::npos, exec_value.find('#'));
+ ASSERT_EQ(std::string::npos, exec_value.find('\n'));
+ ASSERT_EQ(std::string::npos, exec_value.find('"'));
+ ASSERT_EQ(std::string::npos, exec_value.find('\''));
+
+ base::CommandLine::StringVector argv = base::SplitString(
+ exec_value, base::CommandLine::StringType(1, ' '),
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_GE(argv.size(), 2U)
+ << "Expected at least one command-line option in: " << exec_value;
+ autorun_command_line.reset(new base::CommandLine(argv));
+#endif // defined(OS_WIN)
+ if (autorun_command_line.get()) {
+ EXPECT_EQ(autorun_command_line->GetSwitchValueASCII(switches::kProcessType),
+ std::string(switches::kCloudPrintServiceProcess));
+ }
+ ASSERT_TRUE(state.RemoveFromAutoRun());
+#if defined(OS_WIN)
+ EXPECT_FALSE(base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER,
+ base::UTF8ToWide(value_name),
+ &value));
+#elif defined(OS_POSIX) && !defined(OS_MACOSX)
+ EXPECT_FALSE(AutoStart::GetAutostartFileValue(
+ GetServiceProcessScopedName(base_desktop_name), "Exec", &exec_value));
+#endif // defined(OS_WIN)
+}
+
+TEST_F(ServiceProcessStateTest, SharedMem) {
+ std::string version;
+ base::ProcessId pid;
+#if defined(OS_POSIX)
+ // On Posix, named shared memory uses a file on disk. This file could be lying
+ // around from previous crashes which could cause GetServiceProcessPid to lie,
+ // so we aggressively delete it before testing. On Windows, we use a named
+ // event so we don't have this issue.
+ ServiceProcessState::DeleteServiceProcessDataRegion();
+#endif // defined(OS_POSIX)
+ ASSERT_FALSE(ServiceProcessState::GetServiceProcessData(&version, &pid));
+ ServiceProcessState state;
+ ASSERT_TRUE(state.Initialize());
+ ASSERT_TRUE(ServiceProcessState::GetServiceProcessData(&version, &pid));
+ ASSERT_EQ(base::GetCurrentProcId(), pid);
+}
+
+TEST_F(ServiceProcessStateTest, MAYBE_ForceShutdown) {
+ base::Process process = SpawnChild("ServiceProcessStateTestShutdown");
+ ASSERT_TRUE(process.IsValid());
+ for (int i = 0; !CheckServiceProcessReady() && i < 10; ++i) {
+ base::PlatformThread::Sleep(TestTimeouts::tiny_timeout());
+ }
+ ASSERT_TRUE(CheckServiceProcessReady());
+ std::string version;
+ base::ProcessId pid;
+ ASSERT_TRUE(ServiceProcessState::GetServiceProcessData(&version, &pid));
+ ASSERT_TRUE(ForceServiceProcessShutdown(version, pid));
+ int exit_code = 0;
+ ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
+ &exit_code));
+ ASSERT_EQ(exit_code, 0);
+}
+
+MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestSingleton) {
+ ServiceProcessState state;
+ EXPECT_FALSE(state.Initialize());
+ return 0;
+}
+
+MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyTrue) {
+ EXPECT_TRUE(CheckServiceProcessReady());
+ return 0;
+}
+
+MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestReadyFalse) {
+ EXPECT_FALSE(CheckServiceProcessReady());
+ return 0;
+}
+
+MULTIPROCESS_TEST_MAIN(ServiceProcessStateTestShutdown) {
+ base::PlatformThread::SetName("ServiceProcessStateTestShutdownMainThread");
+ base::test::SingleThreadTaskEnvironment task_environment;
+ base::RunLoop run_loop;
+ base::Thread io_thread_("ServiceProcessStateTestShutdownIOThread");
+ base::Thread::Options options(base::MessagePumpType::IO, 0);
+ EXPECT_TRUE(io_thread_.StartWithOptions(options));
+ ServiceProcessState state;
+ EXPECT_TRUE(state.Initialize());
+ EXPECT_TRUE(state.SignalReady(io_thread_.task_runner().get(),
+ base::Bind(&ShutdownTask, &run_loop)));
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitWhenIdleClosure(),
+ TestTimeouts::action_max_timeout());
+ EXPECT_FALSE(g_good_shutdown);
+ run_loop.Run();
+ EXPECT_TRUE(g_good_shutdown);
+ return 0;
+}
+
+#endif // !OS_MACOSX
diff --git a/chromium/chrome/common/service_process_util_win.cc b/chromium/chrome/common/service_process_util_win.cc
new file mode 100644
index 00000000000..47302608826
--- /dev/null
+++ b/chromium/chrome/common/service_process_util_win.cc
@@ -0,0 +1,268 @@
+// 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 "chrome/common/service_process_util.h"
+
+#include <windows.h>
+
+#include <algorithm>
+#include <memory>
+
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/platform_shared_memory_region.h"
+#include "base/memory/writable_shared_memory_region.h"
+#include "base/path_service.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/unguessable_token.h"
+#include "base/win/object_watcher.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/win_util.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+
+namespace {
+
+const char kTerminateEventSuffix[] = "_service_terminate_evt";
+
+base::string16 GetServiceProcessReadyEventName() {
+ return base::UTF8ToWide(
+ GetServiceProcessScopedVersionedName("_service_ready"));
+}
+
+base::string16 GetServiceProcessTerminateEventName() {
+ return base::UTF8ToWide(
+ GetServiceProcessScopedVersionedName(kTerminateEventSuffix));
+}
+
+std::string GetServiceProcessAutoRunKey() {
+ return GetServiceProcessScopedName("_service_run");
+}
+
+// Returns the name of the autotun reg value that we used to use for older
+// versions of Chrome.
+std::string GetObsoleteServiceProcessAutoRunKey() {
+ base::FilePath user_data_dir;
+ base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+ std::string scoped_name = base::WideToUTF8(user_data_dir.value());
+ std::replace(scoped_name.begin(), scoped_name.end(), '\\', '!');
+ std::replace(scoped_name.begin(), scoped_name.end(), '/', '!');
+ scoped_name.append("_service_run");
+ return scoped_name;
+}
+
+class ServiceProcessTerminateMonitor
+ : public base::win::ObjectWatcher::Delegate {
+ public:
+ explicit ServiceProcessTerminateMonitor(const base::Closure& terminate_task)
+ : terminate_task_(terminate_task) {
+ }
+ void Start() {
+ base::string16 event_name = GetServiceProcessTerminateEventName();
+ DCHECK(event_name.length() <= MAX_PATH);
+ terminate_event_.Set(CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
+ watcher_.StartWatchingOnce(terminate_event_.Get(), this);
+ }
+
+ // base::ObjectWatcher::Delegate implementation.
+ void OnObjectSignaled(HANDLE object) override {
+ if (!terminate_task_.is_null()) {
+ terminate_task_.Run();
+ terminate_task_.Reset();
+ }
+ }
+
+ private:
+ base::win::ScopedHandle terminate_event_;
+ base::win::ObjectWatcher watcher_;
+ base::Closure terminate_task_;
+};
+
+} // namespace
+
+// Gets the name of the service process IPC channel.
+mojo::NamedPlatformChannel::ServerName GetServiceProcessServerName() {
+ return mojo::NamedPlatformChannel::ServerNameFromUTF8(
+ GetServiceProcessScopedVersionedName("_service_ipc"));
+}
+
+bool ForceServiceProcessShutdown(const std::string& version,
+ base::ProcessId process_id) {
+ base::win::ScopedHandle terminate_event;
+ std::string versioned_name = version;
+ versioned_name.append(kTerminateEventSuffix);
+ base::string16 event_name =
+ base::UTF8ToWide(GetServiceProcessScopedName(versioned_name));
+ terminate_event.Set(OpenEvent(EVENT_MODIFY_STATE, FALSE, event_name.c_str()));
+ if (!terminate_event.IsValid())
+ return false;
+ SetEvent(terminate_event.Get());
+ return true;
+}
+
+// static
+base::WritableSharedMemoryRegion
+ServiceProcessState::CreateServiceProcessDataRegion(size_t size) {
+ // Check maximum accounting for overflow.
+ if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+ return {};
+
+ base::string16 name = base::ASCIIToUTF16(GetServiceProcessSharedMemName());
+
+ SECURITY_ATTRIBUTES sa = {sizeof(sa), nullptr, FALSE};
+ HANDLE raw_handle =
+ CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, 0,
+ static_cast<DWORD>(size), base::as_wcstr(name));
+ if (!raw_handle) {
+ auto error = GetLastError();
+ DLOG(ERROR) << "Cannot create named mapping " << name << ": " << error;
+ return {};
+ }
+ base::win::ScopedHandle handle(raw_handle);
+
+ base::WritableSharedMemoryRegion writable_region =
+ base::WritableSharedMemoryRegion::Deserialize(
+ base::subtle::PlatformSharedMemoryRegion::Take(
+ std::move(handle),
+ base::subtle::PlatformSharedMemoryRegion::Mode::kWritable, size,
+ base::UnguessableToken::Create()));
+ if (!writable_region.IsValid()) {
+ DLOG(ERROR) << "Cannot deserialize file mapping";
+ return {};
+ }
+ return writable_region;
+}
+
+// static
+base::ReadOnlySharedMemoryMapping
+ServiceProcessState::OpenServiceProcessDataMapping(size_t size) {
+ DWORD access = FILE_MAP_READ | SECTION_QUERY;
+ base::string16 name = base::ASCIIToUTF16(GetServiceProcessSharedMemName());
+ HANDLE raw_handle = OpenFileMapping(access, false, base::as_wcstr(name));
+ if (!raw_handle) {
+ auto err = GetLastError();
+ DLOG(ERROR) << "OpenFileMapping failed for " << name << " / "
+ << GetServiceProcessSharedMemName() << " / " << err;
+ return {};
+ }
+
+ // The region is writable for this user, so the handle is converted to a
+ // WritableSharedMemoryMapping which is then downgraded to read-only for the
+ // mapping.
+ base::WritableSharedMemoryRegion writable_region =
+ base::WritableSharedMemoryRegion::Deserialize(
+ base::subtle::PlatformSharedMemoryRegion::Take(
+ base::win::ScopedHandle(raw_handle),
+ base::subtle::PlatformSharedMemoryRegion::Mode::kWritable, size,
+ base::UnguessableToken::Create()));
+ if (!writable_region.IsValid()) {
+ DLOG(ERROR) << "Unable to deserialize raw file mapping handle to "
+ << "WritableSharedMemoryRegion";
+ return {};
+ }
+ base::ReadOnlySharedMemoryRegion readonly_region =
+ base::WritableSharedMemoryRegion::ConvertToReadOnly(
+ std::move(writable_region));
+ if (!readonly_region.IsValid()) {
+ DLOG(ERROR) << "Unable to convert to read-only region";
+ return {};
+ }
+ base::ReadOnlySharedMemoryMapping mapping = readonly_region.Map();
+ if (!mapping.IsValid()) {
+ DLOG(ERROR) << "Unable to map region";
+ return {};
+ }
+ // The region will be closed on return, leaving on the mapping.
+ return mapping;
+}
+
+// static
+bool ServiceProcessState::DeleteServiceProcessDataRegion() {
+ // intentionally empty -- there is nothing for us to do on Windows.
+ return true;
+}
+
+bool CheckServiceProcessReady() {
+ base::string16 event_name = GetServiceProcessReadyEventName();
+ base::win::ScopedHandle event(
+ OpenEvent(SYNCHRONIZE | READ_CONTROL, false, event_name.c_str()));
+ if (!event.IsValid())
+ return false;
+ // Check if the event is signaled.
+ return WaitForSingleObject(event.Get(), 0) == WAIT_OBJECT_0;
+}
+
+struct ServiceProcessState::StateData {
+ // An event that is signaled when a service process is ready.
+ base::win::ScopedHandle ready_event;
+ std::unique_ptr<ServiceProcessTerminateMonitor> terminate_monitor;
+};
+
+void ServiceProcessState::CreateState() {
+ DCHECK(!state_);
+ state_ = new StateData;
+}
+
+bool ServiceProcessState::TakeSingletonLock() {
+ DCHECK(state_);
+ base::string16 event_name = GetServiceProcessReadyEventName();
+ DCHECK(event_name.length() <= MAX_PATH);
+ base::win::ScopedHandle service_process_ready_event;
+ service_process_ready_event.Set(
+ CreateEvent(NULL, TRUE, FALSE, event_name.c_str()));
+ DWORD error = GetLastError();
+ if ((error == ERROR_ALREADY_EXISTS) || (error == ERROR_ACCESS_DENIED))
+ return false;
+ DCHECK(service_process_ready_event.IsValid());
+ state_->ready_event.Set(service_process_ready_event.Take());
+ return true;
+}
+
+bool ServiceProcessState::SignalReady(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ const base::Closure& terminate_task) {
+ DCHECK(state_);
+ DCHECK(state_->ready_event.IsValid());
+ if (!SetEvent(state_->ready_event.Get())) {
+ return false;
+ }
+ if (!terminate_task.is_null()) {
+ state_->terminate_monitor.reset(
+ new ServiceProcessTerminateMonitor(terminate_task));
+ state_->terminate_monitor->Start();
+ }
+ return true;
+}
+
+bool ServiceProcessState::AddToAutoRun() {
+ DCHECK(autorun_command_line_.get());
+ // Remove the old autorun value first because we changed the naming scheme
+ // for the autorun value name.
+ base::win::RemoveCommandFromAutoRun(
+ HKEY_CURRENT_USER,
+ base::UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
+ return base::win::AddCommandToAutoRun(
+ HKEY_CURRENT_USER,
+ base::UTF8ToWide(GetServiceProcessAutoRunKey()),
+ autorun_command_line_->GetCommandLineString());
+}
+
+bool ServiceProcessState::RemoveFromAutoRun() {
+ // Remove the old autorun value first because we changed the naming scheme
+ // for the autorun value name.
+ base::win::RemoveCommandFromAutoRun(
+ HKEY_CURRENT_USER,
+ base::UTF8ToWide(GetObsoleteServiceProcessAutoRunKey()));
+ return base::win::RemoveCommandFromAutoRun(
+ HKEY_CURRENT_USER, base::UTF8ToWide(GetServiceProcessAutoRunKey()));
+}
+
+void ServiceProcessState::TearDownState() {
+ delete state_;
+ state_ = NULL;
+}
diff --git a/chromium/chrome/common/ssl_insecure_content.cc b/chromium/chrome/common/ssl_insecure_content.cc
new file mode 100644
index 00000000000..d8c91c930e2
--- /dev/null
+++ b/chromium/chrome/common/ssl_insecure_content.cc
@@ -0,0 +1,45 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/ssl_insecure_content.h"
+
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_util.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Constants for UMA statistic collection.
+static const char kDotJS[] = ".js";
+static const char kDotCSS[] = ".css";
+static const char kDotSWF[] = ".swf";
+static const char kDotHTML[] = ".html";
+
+} // namespace
+
+void ReportInsecureContent(SslInsecureContentType signal) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "SSL.InsecureContent", static_cast<int>(signal),
+ static_cast<int>(SslInsecureContentType::NUM_EVENTS));
+}
+
+void FilteredReportInsecureContentDisplayed(const GURL& resource_gurl) {
+ if (base::EndsWith(resource_gurl.path(), kDotHTML,
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ ReportInsecureContent(SslInsecureContentType::DISPLAY_HTML);
+ }
+}
+
+void FilteredReportInsecureContentRan(const GURL& resource_gurl) {
+ if (base::EndsWith(resource_gurl.path(), kDotJS,
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ ReportInsecureContent(SslInsecureContentType::RUN_JS);
+ } else if (base::EndsWith(resource_gurl.path(), kDotCSS,
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ ReportInsecureContent(SslInsecureContentType::RUN_CSS);
+ } else if (base::EndsWith(resource_gurl.path(), kDotSWF,
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ ReportInsecureContent(SslInsecureContentType::RUN_SWF);
+ }
+}
diff --git a/chromium/chrome/common/ssl_insecure_content.h b/chromium/chrome/common/ssl_insecure_content.h
new file mode 100644
index 00000000000..45ce1597d03
--- /dev/null
+++ b/chromium/chrome/common/ssl_insecure_content.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 CHROME_COMMON_SSL_INSECURE_CONTENT_H_
+#define CHROME_COMMON_SSL_INSECURE_CONTENT_H_
+
+class GURL;
+
+// Insecure content types used in the SSL.InsecureContent histogram.
+// This enum is histogrammed, so do not add, reorder, or remove values.
+enum class SslInsecureContentType {
+ DISPLAY = 0,
+ DISPLAY_HOST_GOOGLE, // deprecated
+ DISPLAY_HOST_WWW_GOOGLE, // deprecated
+ DISPLAY_HTML,
+ RUN,
+ RUN_HOST_GOOGLE, // deprecated
+ RUN_HOST_WWW_GOOGLE, // deprecated
+ RUN_TARGET_YOUTUBE, // deprecated
+ RUN_JS,
+ RUN_CSS,
+ RUN_SWF,
+ DISPLAY_HOST_YOUTUBE, // deprecated
+ RUN_HOST_YOUTUBE, // deprecated
+ RUN_HOST_GOOGLEUSERCONTENT, // deprecated
+ DISPLAY_HOST_MAIL_GOOGLE, // deprecated
+ RUN_HOST_MAIL_GOOGLE, // deprecated
+ DISPLAY_HOST_PLUS_GOOGLE, // deprecated
+ RUN_HOST_PLUS_GOOGLE, // deprecated
+ DISPLAY_HOST_DOCS_GOOGLE, // deprecated
+ RUN_HOST_DOCS_GOOGLE, // deprecated
+ DISPLAY_HOST_SITES_GOOGLE, // deprecated
+ RUN_HOST_SITES_GOOGLE, // deprecated
+ DISPLAY_HOST_PICASAWEB_GOOGLE, // deprecated
+ RUN_HOST_PICASAWEB_GOOGLE, // deprecated
+ DISPLAY_HOST_GOOGLE_READER, // deprecated
+ RUN_HOST_GOOGLE_READER, // deprecated
+ DISPLAY_HOST_CODE_GOOGLE, // deprecated
+ RUN_HOST_CODE_GOOGLE, // deprecated
+ DISPLAY_HOST_GROUPS_GOOGLE, // deprecated
+ RUN_HOST_GROUPS_GOOGLE, // deprecated
+ DISPLAY_HOST_MAPS_GOOGLE, // deprecated
+ RUN_HOST_MAPS_GOOGLE, // deprecated
+ DISPLAY_HOST_GOOGLE_SUPPORT, // deprecated
+ RUN_HOST_GOOGLE_SUPPORT, // deprecated
+ DISPLAY_HOST_GOOGLE_INTL, // deprecated
+ RUN_HOST_GOOGLE_INTL, // deprecated
+ NUM_EVENTS
+};
+
+// Reports insecure content to the SSL.InsecureContent histogram using the
+// provided |signal|.
+void ReportInsecureContent(SslInsecureContentType signal);
+
+// Reports insecure content displayed or ran if |resource_URL| matches specific
+// file types.
+void FilteredReportInsecureContentDisplayed(const GURL& resource_gurl);
+void FilteredReportInsecureContentRan(const GURL& resource_gurl);
+
+#endif // CHROME_COMMON_SSL_INSECURE_CONTENT_H_
diff --git a/chromium/chrome/common/stack_sampling_configuration.cc b/chromium/chrome/common/stack_sampling_configuration.cc
new file mode 100644
index 00000000000..2d8c22e6b0d
--- /dev/null
+++ b/chromium/chrome/common/stack_sampling_configuration.cc
@@ -0,0 +1,219 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/stack_sampling_configuration.h"
+
+#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/rand_util.h"
+#include "build/branding_buildflags.h"
+#include "build/build_config.h"
+#include "chrome/common/channel_info.h"
+#include "chrome/common/chrome_switches.h"
+#include "components/version_info/version_info.h"
+#include "content/public/common/content_switches.h"
+#include "extensions/buildflags/buildflags.h"
+
+#if defined(OS_WIN)
+#include "base/win/static_constants.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "base/mac/mac_util.h"
+#endif
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "extensions/common/switches.h"
+#endif
+
+namespace {
+
+base::LazyInstance<StackSamplingConfiguration>::Leaky g_configuration =
+ LAZY_INSTANCE_INITIALIZER;
+
+// The profiler is currently only implemented for Windows x64 and Mac x64.
+bool IsProfilerSupported() {
+#if (defined(OS_WIN) && defined(ARCH_CPU_X86_64)) || defined(OS_MACOSX)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+ // Only run on canary and dev.
+ const version_info::Channel channel = chrome::GetChannel();
+ return channel == version_info::Channel::CANARY ||
+ channel == version_info::Channel::DEV;
+#else
+ return true;
+#endif
+#else
+ return false;
+#endif
+}
+
+// Returns true if the current execution is taking place in the browser process.
+bool IsBrowserProcess() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ std::string process_type =
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+ return process_type.empty();
+}
+
+// True if the command line corresponds to an extension renderer process.
+bool IsExtensionRenderer(const base::CommandLine& command_line) {
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ return command_line.HasSwitch(extensions::switches::kExtensionProcess);
+#else
+ return false;
+#endif
+}
+
+bool ShouldEnableProfilerForNextRendererProcess() {
+ // Enable for every N-th renderer process, where N = 5.
+ return base::RandInt(0, 4) == 0;
+}
+
+} // namespace
+
+StackSamplingConfiguration::StackSamplingConfiguration()
+ : configuration_(GenerateConfiguration()) {
+}
+
+base::StackSamplingProfiler::SamplingParams
+StackSamplingConfiguration::GetSamplingParamsForCurrentProcess() const {
+ base::StackSamplingProfiler::SamplingParams params;
+ params.initial_delay = base::TimeDelta::FromMilliseconds(0);
+ params.sampling_interval = base::TimeDelta::FromMilliseconds(0);
+ params.samples_per_profile = 0;
+
+ if (IsProfilerEnabledForCurrentProcess()) {
+ const base::TimeDelta duration = base::TimeDelta::FromSeconds(30);
+ params.sampling_interval = base::TimeDelta::FromMilliseconds(100);
+ params.samples_per_profile = duration / params.sampling_interval;
+ }
+
+ return params;
+}
+
+bool StackSamplingConfiguration::IsProfilerEnabledForCurrentProcess() const {
+ if (IsBrowserProcess()) {
+ return configuration_ == PROFILE_ENABLED ||
+ configuration_ == PROFILE_CONTROL;
+ }
+
+ DCHECK_EQ(PROFILE_FROM_COMMAND_LINE, configuration_);
+ // This is a child process. The |kStartStackProfiler| switch passed by the
+ // browser process determines whether the profiler is enabled for the process.
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ return command_line->HasSwitch(switches::kStartStackProfiler);
+}
+
+bool StackSamplingConfiguration::GetSyntheticFieldTrial(
+ std::string* trial_name,
+ std::string* group_name) const {
+ DCHECK(IsBrowserProcess());
+
+ if (!IsProfilerSupported())
+ return false;
+
+ *trial_name = "SyntheticStackProfilingConfiguration";
+ *group_name = std::string();
+ switch (configuration_) {
+ case PROFILE_DISABLED:
+ *group_name = "Disabled";
+ break;
+
+ case PROFILE_CONTROL:
+ *group_name = "Control";
+ break;
+
+ case PROFILE_ENABLED:
+ *group_name = "Enabled";
+ break;
+
+ case PROFILE_FROM_COMMAND_LINE:
+ NOTREACHED();
+ break;
+ }
+
+ return !group_name->empty();
+}
+
+void StackSamplingConfiguration::AppendCommandLineSwitchForChildProcess(
+ const std::string& process_type,
+ base::CommandLine* command_line) const {
+ DCHECK(IsBrowserProcess());
+
+ bool enable =
+ configuration_ == PROFILE_ENABLED || configuration_ == PROFILE_CONTROL;
+ if (!enable)
+ return;
+ if (process_type == switches::kGpuProcess ||
+ (process_type == switches::kRendererProcess &&
+ // Do not start the profiler for extension processes since profiling the
+ // compositor thread in them is not useful.
+ !IsExtensionRenderer(*command_line) &&
+ ShouldEnableProfilerForNextRendererProcess())) {
+ command_line->AppendSwitch(switches::kStartStackProfiler);
+ }
+}
+
+// static
+StackSamplingConfiguration* StackSamplingConfiguration::Get() {
+ return g_configuration.Pointer();
+}
+
+// static
+StackSamplingConfiguration::ProfileConfiguration
+StackSamplingConfiguration::ChooseConfiguration(
+ const std::vector<Variation>& variations) {
+ int total_weight = 0;
+ for (const Variation& variation : variations)
+ total_weight += variation.weight;
+ DCHECK_EQ(100, total_weight);
+
+ int chosen = base::RandInt(0, total_weight - 1); // Max is inclusive.
+ int cumulative_weight = 0;
+ for (const auto& variation : variations) {
+ if (chosen >= cumulative_weight &&
+ chosen < cumulative_weight + variation.weight) {
+ return variation.config;
+ }
+ cumulative_weight += variation.weight;
+ }
+ NOTREACHED();
+ return PROFILE_DISABLED;
+}
+
+// static
+StackSamplingConfiguration::ProfileConfiguration
+StackSamplingConfiguration::GenerateConfiguration() {
+ if (!IsBrowserProcess())
+ return PROFILE_FROM_COMMAND_LINE;
+
+ if (!IsProfilerSupported())
+ return PROFILE_DISABLED;
+
+#if defined(OS_WIN)
+ // Do not start the profiler when Application Verifier is in use; running them
+ // simultaneously can cause crashes and has no known use case.
+ if (GetModuleHandleA(base::win::kApplicationVerifierDllName))
+ return PROFILE_DISABLED;
+#endif
+
+ switch (chrome::GetChannel()) {
+ // Enable the profiler unconditionally for development/waterfall builds.
+ case version_info::Channel::UNKNOWN:
+ return PROFILE_ENABLED;
+
+#if (defined(OS_WIN) && defined(ARCH_CPU_X86_64)) || defined(OS_MACOSX)
+ case version_info::Channel::CANARY:
+ case version_info::Channel::DEV:
+ return ChooseConfiguration({{PROFILE_ENABLED, 80},
+ {PROFILE_CONTROL, 10},
+ {PROFILE_DISABLED, 10}});
+#endif
+
+ default:
+ return PROFILE_DISABLED;
+ }
+}
diff --git a/chromium/chrome/common/stack_sampling_configuration.h b/chromium/chrome/common/stack_sampling_configuration.h
new file mode 100644
index 00000000000..8a51ae921db
--- /dev/null
+++ b/chromium/chrome/common/stack_sampling_configuration.h
@@ -0,0 +1,88 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_STACK_SAMPLING_CONFIGURATION_H_
+#define CHROME_COMMON_STACK_SAMPLING_CONFIGURATION_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/profiler/stack_sampling_profiler.h"
+
+namespace base {
+class CommandLine;
+} // namespace base
+
+// StackSamplingConfiguration chooses a configuration for the enable state of
+// the stack sampling profiler across all processes. This configuration is
+// determined once at browser process startup. Configurations for child
+// processes are communicated via command line arguments.
+class StackSamplingConfiguration {
+ public:
+ StackSamplingConfiguration();
+
+ // Get the stack sampling params to use for this process.
+ base::StackSamplingProfiler::SamplingParams
+ GetSamplingParamsForCurrentProcess() const;
+
+ // Returns true if the profiler should be started for the current process.
+ bool IsProfilerEnabledForCurrentProcess() const;
+
+ // Get the synthetic field trial configuration. Returns true if a synthetic
+ // field trial should be registered. This should only be called from the
+ // browser process. When run at startup, the profiler must use a synthetic
+ // field trial since it runs before the metrics field trials are initialized.
+ bool GetSyntheticFieldTrial(std::string* trial_name,
+ std::string* group_name) const;
+
+ // Add a command line switch that instructs the child process to run the
+ // profiler. This should only be called from the browser process.
+ void AppendCommandLineSwitchForChildProcess(
+ const std::string& process_type,
+ base::CommandLine* command_line) const;
+
+ // Returns the StackSamplingConfiguration for the process.
+ static StackSamplingConfiguration* Get();
+
+ private:
+ // Configuration to use for this Chrome instance.
+ enum ProfileConfiguration {
+ // Chrome-wide configurations set in the browser process.
+ PROFILE_DISABLED,
+ PROFILE_CONTROL,
+ PROFILE_ENABLED,
+
+ // Configuration set in the child processes, which receive their enable
+ // state on the command line from the browser process.
+ PROFILE_FROM_COMMAND_LINE
+ };
+
+ // Configuration variations, along with weights to use when randomly choosing
+ // one of a set of variations.
+ struct Variation {
+ ProfileConfiguration config;
+ int weight;
+ };
+
+ // Randomly chooses a configuration from the weighted variations. Weights are
+ // expected to sum to 100 as a sanity check.
+ static ProfileConfiguration ChooseConfiguration(
+ const std::vector<Variation>& variations);
+
+ // Generates sampling profiler configurations for all processes.
+ static ProfileConfiguration GenerateConfiguration();
+
+ // NOTE: all state in this class must be const and initialized at construction
+ // time to ensure thread-safe access post-construction.
+
+ // In the browser process this represents the configuration to use across all
+ // Chrome processes. In the child processes it is always
+ // PROFILE_FROM_COMMAND_LINE.
+ const ProfileConfiguration configuration_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackSamplingConfiguration);
+};
+
+#endif // CHROME_COMMON_STACK_SAMPLING_CONFIGURATION_H_
diff --git a/chromium/chrome/common/themes/OWNERS b/chromium/chrome/common/themes/OWNERS
new file mode 100644
index 00000000000..81117d8a81e
--- /dev/null
+++ b/chromium/chrome/common/themes/OWNERS
@@ -0,0 +1,3 @@
+gayane@chromium.org
+
+file://chrome/browser/themes/OWNERS \ No newline at end of file
diff --git a/chromium/chrome/common/themes/autogenerated_theme_util.cc b/chromium/chrome/common/themes/autogenerated_theme_util.cc
new file mode 100644
index 00000000000..6a6b8d74fd7
--- /dev/null
+++ b/chromium/chrome/common/themes/autogenerated_theme_util.cc
@@ -0,0 +1,136 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/themes/autogenerated_theme_util.h"
+
+#include "ui/gfx/color_utils.h"
+
+// Decreases the lightness of the given color.
+SkColor DarkenColor(SkColor color, float change) {
+ color_utils::HSL hsl;
+ SkColorToHSL(color, &hsl);
+ hsl.l -= change;
+ if (hsl.l >= 0.0f)
+ return HSLToSkColor(hsl, 255);
+ return color;
+}
+
+// Increases the lightness of |source| until it reaches |contrast_ratio| with
+// |base| or reaches |white_contrast| with white. This avoids decreasing
+// saturation, as the alternative contrast-guaranteeing functions in color_utils
+// would do.
+SkColor LightenUntilContrast(SkColor source,
+ SkColor base,
+ float contrast_ratio,
+ float white_contrast) {
+ const float kBaseLuminance = color_utils::GetRelativeLuminance(base);
+ constexpr float kWhiteLuminance = 1.0f;
+
+ color_utils::HSL hsl;
+ SkColorToHSL(source, &hsl);
+ float min_l = hsl.l;
+ float max_l = 1.0f;
+
+ // Need only precision of 2 digits.
+ while (max_l - min_l > 0.01) {
+ hsl.l = min_l + (max_l - min_l) / 2;
+ float luminance = color_utils::GetRelativeLuminance(HSLToSkColor(hsl, 255));
+ if (color_utils::GetContrastRatio(kBaseLuminance, luminance) >=
+ contrast_ratio ||
+ (color_utils::GetContrastRatio(kWhiteLuminance, luminance) <
+ white_contrast)) {
+ max_l = hsl.l;
+ } else {
+ min_l = hsl.l;
+ }
+ }
+
+ hsl.l = max_l;
+ return HSLToSkColor(hsl, 255);
+}
+
+AutogeneratedThemeColors GetAutogeneratedThemeColors(SkColor color) {
+ SkColor frame_color = color;
+ SkColor frame_text_color;
+ SkColor active_tab_color = color;
+ SkColor active_tab_text_color;
+
+ constexpr float kDarkenStep = 0.03f;
+ constexpr float kMinWhiteContrast = 1.3f;
+ constexpr float kNoWhiteContrast = 0.0f;
+
+ // Used to determine what we consider a very dark color.
+ constexpr float kMaxLuminosityForDark = 0.05f;
+
+ // Increasingly darken frame color and calculate the rest until colors with
+ // sufficient contrast are found.
+ while (true) {
+ // Calculate frame color to have sufficient contrast with white or dark grey
+ // text.
+ frame_text_color = color_utils::GetColorWithMaxContrast(frame_color);
+ SkColor blend_target =
+ color_utils::GetColorWithMaxContrast(frame_text_color);
+ frame_color = color_utils::BlendForMinContrast(
+ frame_color, frame_text_color, blend_target,
+ kAutogeneratedThemeTextPreferredContrast)
+ .color;
+
+ // Generate active tab color so that it has enough contrast with the
+ // |frame_color| to avoid the isolation line in the tab strip.
+ active_tab_color = LightenUntilContrast(
+ frame_color, frame_color, kAutogeneratedThemeActiveTabMinContrast,
+ kNoWhiteContrast);
+
+ // We want more contrast between frame and active tab for dark colors.
+ color_utils::HSL hsl;
+ SkColorToHSL(frame_color, &hsl);
+ float preferred_contrast =
+ hsl.l <= kMaxLuminosityForDark
+ ? kAutogeneratedThemeActiveTabPreferredContrastForDark
+ : kAutogeneratedThemeActiveTabPreferredContrast;
+
+ // Try lightening the color to get more contrast with frame without getting
+ // too close to white.
+ active_tab_color = LightenUntilContrast(
+ active_tab_color, frame_color, preferred_contrast, kMinWhiteContrast);
+
+ // If we didn't succeed in generating active tab color with minimum
+ // contrast with frame, then darken the frame color and try again.
+ if (color_utils::GetContrastRatio(frame_color, active_tab_color) <
+ kAutogeneratedThemeActiveTabMinContrast) {
+ frame_color = DarkenColor(frame_color, kDarkenStep);
+ continue;
+ }
+
+ // Select active tab text color, if possible.
+ active_tab_text_color =
+ color_utils::GetColorWithMaxContrast(active_tab_color);
+
+ if (!color_utils::IsDark(active_tab_color)) {
+ // If active tab is light color then continue lightening it until enough
+ // contrast with dark text is reached.
+ active_tab_text_color =
+ color_utils::GetColorWithMaxContrast(active_tab_color);
+ active_tab_color = LightenUntilContrast(
+ active_tab_color, active_tab_text_color,
+ kAutogeneratedThemeTextPreferredContrast, kNoWhiteContrast);
+ break;
+ }
+
+ // If the active tab color is dark and has enough contrast with white text.
+ // Then we are all set.
+ if (color_utils::GetContrastRatio(active_tab_color, SK_ColorWHITE) >=
+ kAutogeneratedThemeTextPreferredContrast)
+ break;
+
+ // If the active tab color is a dark color but the contrast with white is
+ // not enough then we should darken the active tab color to reach the
+ // contrast with white. But to keep the contrast with the frame we should
+ // also darken the frame color. Therefore, just darken the frame color and
+ // try again.
+ frame_color = DarkenColor(frame_color, kDarkenStep);
+ }
+ return {frame_color, frame_text_color, active_tab_color,
+ active_tab_text_color};
+}
diff --git a/chromium/chrome/common/themes/autogenerated_theme_util.h b/chromium/chrome/common/themes/autogenerated_theme_util.h
new file mode 100644
index 00000000000..ba84c4028ca
--- /dev/null
+++ b/chromium/chrome/common/themes/autogenerated_theme_util.h
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_THEMES_AUTOGENERATED_THEME_UTIL_H_
+#define CHROME_COMMON_THEMES_AUTOGENERATED_THEME_UTIL_H_
+
+#include "third_party/skia/include/core/SkColor.h"
+
+// Constants for autogenerated themes.
+// Minimum contrast for active tab and frame color to avoid isolation line in
+// the tab strip.
+constexpr float kAutogeneratedThemeActiveTabMinContrast = 1.3f;
+constexpr float kAutogeneratedThemeActiveTabPreferredContrast = 1.6f;
+constexpr float kAutogeneratedThemeActiveTabPreferredContrastForDark = 1.7f;
+
+// Contrast between foreground and background.
+constexpr float kAutogeneratedThemeTextPreferredContrast = 7.0f;
+
+struct AutogeneratedThemeColors {
+ SkColor frame_color;
+ SkColor frame_text_color;
+ SkColor active_tab_color;
+ SkColor active_tab_text_color;
+};
+
+// Generates theme colors for the given |color|.
+AutogeneratedThemeColors GetAutogeneratedThemeColors(SkColor color);
+
+#endif // CHROME_COMMON_THEMES_AUTOGENERATED_THEME_UTIL_H_
diff --git a/chromium/chrome/common/thread_profiler.cc b/chromium/chrome/common/thread_profiler.cc
new file mode 100644
index 00000000000..4197d329d86
--- /dev/null
+++ b/chromium/chrome/common/thread_profiler.cc
@@ -0,0 +1,312 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/thread_profiler.h"
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/message_loop/work_id_provider.h"
+#include "base/no_destructor.h"
+#include "base/profiler/sample_metadata.h"
+#include "base/rand_util.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/sequence_local_storage_slot.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "chrome/common/stack_sampling_configuration.h"
+#include "components/metrics/call_stack_profile_builder.h"
+#include "components/metrics/call_stack_profile_metrics_provider.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/service_names.mojom.h"
+#include "services/service_manager/embedder/switches.h"
+
+using CallStackProfileBuilder = metrics::CallStackProfileBuilder;
+using CallStackProfileParams = metrics::CallStackProfileParams;
+using StackSamplingProfiler = base::StackSamplingProfiler;
+
+namespace {
+
+// Pointer to the main thread instance, if any. Stored as a global because it's
+// created very early in chrome/app - and is thus otherwise inaccessible from
+// chrome_dll, by the time we need to register the main thread task runner.
+ThreadProfiler* g_main_thread_instance = nullptr;
+
+// Run continuous profiling 2% of the time.
+constexpr const double kFractionOfExecutionTimeToSample = 0.02;
+
+constexpr struct StackSamplingProfiler::SamplingParams kSamplingParams = {
+ /* initial_delay= */ base::TimeDelta::FromMilliseconds(0),
+ /* samples_per_profile= */ 300,
+ /* sampling_interval= */ base::TimeDelta::FromMilliseconds(100),
+ /* keep_consistent_sampling_interval= */ true};
+
+CallStackProfileParams::Process GetProcess() {
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ std::string process_type =
+ command_line->GetSwitchValueASCII(switches::kProcessType);
+ if (process_type.empty())
+ return CallStackProfileParams::BROWSER_PROCESS;
+ if (process_type == switches::kRendererProcess)
+ return CallStackProfileParams::RENDERER_PROCESS;
+ if (process_type == switches::kGpuProcess)
+ return CallStackProfileParams::GPU_PROCESS;
+ if (process_type == switches::kUtilityProcess)
+ return CallStackProfileParams::UTILITY_PROCESS;
+ if (process_type == service_manager::switches::kZygoteProcess)
+ return CallStackProfileParams::ZYGOTE_PROCESS;
+ if (process_type == switches::kPpapiPluginProcess)
+ return CallStackProfileParams::PPAPI_PLUGIN_PROCESS;
+ if (process_type == switches::kPpapiBrokerProcess)
+ return CallStackProfileParams::PPAPI_BROKER_PROCESS;
+ return CallStackProfileParams::UNKNOWN_PROCESS;
+}
+
+} // namespace
+
+// The scheduler works by splitting execution time into repeated periods such
+// that the time to take one collection represents
+// |fraction_of_execution_time_to_sample| of the period, and the time not spent
+// sampling represents 1 - |fraction_of_execution_time_to_sample| of the period.
+// The collection start time is chosen randomly within each period such that the
+// entire collection is contained within the period.
+//
+// The kFractionOfExecutionTimeToSample and SamplingParams settings at the top
+// of the file specify fraction = 0.02 and sampling period = 1 sample / .1s
+// sampling interval * 300 samples = 30s. The period length works out to
+// 30s/0.02 = 1500s = 25m. So every 25 minutes a random 30 second continuous
+// interval will be picked to sample.
+PeriodicSamplingScheduler::PeriodicSamplingScheduler(
+ base::TimeDelta sampling_duration,
+ double fraction_of_execution_time_to_sample,
+ base::TimeTicks start_time)
+ : period_duration_(
+ base::TimeDelta::FromSecondsD(sampling_duration.InSecondsF() /
+ fraction_of_execution_time_to_sample)),
+ sampling_duration_(sampling_duration),
+ period_start_time_(start_time) {
+ DCHECK(sampling_duration_ <= period_duration_);
+}
+
+PeriodicSamplingScheduler::~PeriodicSamplingScheduler() = default;
+
+base::TimeDelta PeriodicSamplingScheduler::GetTimeToNextCollection() {
+ const base::TimeTicks now = Now();
+ // Avoid scheduling in the past in the presence of discontinuous jumps in
+ // the current TimeTicks.
+ period_start_time_ = std::max(period_start_time_, now);
+
+ double sampling_offset_seconds =
+ (period_duration_ - sampling_duration_).InSecondsF() * RandDouble();
+ base::TimeTicks next_collection_time =
+ period_start_time_ +
+ base::TimeDelta::FromSecondsD(sampling_offset_seconds);
+ period_start_time_ += period_duration_;
+ return next_collection_time - now;
+}
+
+double PeriodicSamplingScheduler::RandDouble() const {
+ return base::RandDouble();
+}
+
+base::TimeTicks PeriodicSamplingScheduler::Now() const {
+ return base::TimeTicks::Now();
+}
+
+// Records the current unique id for the work item being executed in the target
+// thread's message loop.
+class ThreadProfiler::WorkIdRecorder : public metrics::WorkIdRecorder {
+ public:
+ explicit WorkIdRecorder(base::WorkIdProvider* work_id_provider)
+ : work_id_provider_(work_id_provider) {}
+
+ // Invoked on the profiler thread while the target thread is suspended.
+ unsigned int RecordWorkId() const override {
+ return work_id_provider_->GetWorkId();
+ }
+
+ WorkIdRecorder(const WorkIdRecorder&) = delete;
+ WorkIdRecorder& operator=(const WorkIdRecorder&) = delete;
+
+ private:
+ base::WorkIdProvider* const work_id_provider_;
+};
+
+ThreadProfiler::~ThreadProfiler() {
+ if (g_main_thread_instance == this)
+ g_main_thread_instance = nullptr;
+}
+
+// static
+std::unique_ptr<ThreadProfiler> ThreadProfiler::CreateAndStartOnMainThread() {
+ // If running in single process mode, there may be multiple "main thread"
+ // profilers created. In this case, we assume the first created one is the
+ // browser one.
+ auto* command_line = base::CommandLine::ForCurrentProcess();
+ bool is_single_process = command_line->HasSwitch(switches::kSingleProcess) ||
+ command_line->HasSwitch(switches::kInProcessGPU);
+ DCHECK(!g_main_thread_instance || is_single_process);
+ auto instance = std::unique_ptr<ThreadProfiler>(
+ new ThreadProfiler(CallStackProfileParams::MAIN_THREAD));
+ if (!g_main_thread_instance)
+ g_main_thread_instance = instance.get();
+ return instance;
+}
+
+// static
+void ThreadProfiler::SetMainThreadTaskRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ DCHECK(g_main_thread_instance);
+ g_main_thread_instance->SetMainThreadTaskRunnerImpl(task_runner);
+}
+
+void ThreadProfiler::SetAuxUnwinderFactory(
+ const base::RepeatingCallback<std::unique_ptr<base::Unwinder>()>& factory) {
+ if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
+ return;
+
+ aux_unwinder_factory_ = factory;
+ startup_profiler_->AddAuxUnwinder(aux_unwinder_factory_.Run());
+ if (periodic_profiler_)
+ periodic_profiler_->AddAuxUnwinder(aux_unwinder_factory_.Run());
+}
+
+// static
+void ThreadProfiler::StartOnChildThread(CallStackProfileParams::Thread thread) {
+ // The profiler object is stored in a SequenceLocalStorageSlot on child
+ // threads to give it the same lifetime as the threads.
+ static base::NoDestructor<
+ base::SequenceLocalStorageSlot<std::unique_ptr<ThreadProfiler>>>
+ child_thread_profiler_sequence_local_storage;
+
+ if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
+ return;
+
+ child_thread_profiler_sequence_local_storage->emplace(
+ new ThreadProfiler(thread, base::ThreadTaskRunnerHandle::Get()));
+}
+
+// static
+void ThreadProfiler::SetBrowserProcessReceiverCallback(
+ const base::RepeatingCallback<void(base::TimeTicks,
+ metrics::SampledProfile)>& callback) {
+ CallStackProfileBuilder::SetBrowserProcessReceiverCallback(callback);
+}
+
+// static
+void ThreadProfiler::SetCollectorForChildProcess(
+ mojo::PendingRemote<metrics::mojom::CallStackProfileCollector> collector) {
+ if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
+ return;
+
+ DCHECK_NE(CallStackProfileParams::BROWSER_PROCESS, GetProcess());
+ CallStackProfileBuilder::SetParentProfileCollectorForChildProcess(
+ std::move(collector));
+}
+
+// ThreadProfiler implementation synopsis:
+//
+// On creation, the profiler creates and starts the startup
+// StackSamplingProfiler, and configures the PeriodicSamplingScheduler such that
+// it starts scheduling from the time the startup profiling will be complete.
+// When a message loop is available (either in the constructor, or via
+// SetMainThreadTaskRunner) a task is posted to start the first periodic
+// collection at the initial scheduled collection time.
+//
+// When the periodic collection task executes, it creates and starts a new
+// periodic profiler and configures it to call OnPeriodicCollectionCompleted as
+// its completion callback. OnPeriodicCollectionCompleted is called on the
+// profiler thread and schedules a task on the original thread to schedule
+// another periodic collection. When the task runs, it posts a new task to start
+// another periodic collection at the next scheduled collection time.
+//
+// The process in previous paragraph continues until the ThreadProfiler is
+// destroyed prior to thread exit.
+ThreadProfiler::ThreadProfiler(
+ CallStackProfileParams::Thread thread,
+ scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner)
+ : thread_(thread),
+ owning_thread_task_runner_(owning_thread_task_runner),
+ work_id_recorder_(std::make_unique<WorkIdRecorder>(
+ base::WorkIdProvider::GetForCurrentThread())) {
+ if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
+ return;
+
+ startup_profiler_ = std::make_unique<StackSamplingProfiler>(
+ base::PlatformThread::CurrentId(), kSamplingParams,
+ std::make_unique<CallStackProfileBuilder>(
+ CallStackProfileParams(GetProcess(), thread,
+ CallStackProfileParams::PROCESS_STARTUP),
+ work_id_recorder_.get()));
+
+ startup_profiler_->Start();
+
+ // Estimated time at which the startup profiling will be completed. It's OK if
+ // this doesn't exactly coincide with the end of the startup profiling, since
+ // there's no harm in having a brief overlap of startup and periodic
+ // profiling.
+ base::TimeTicks startup_profiling_completion_time =
+ base::TimeTicks::Now() +
+ kSamplingParams.samples_per_profile * kSamplingParams.sampling_interval;
+
+ periodic_sampling_scheduler_ = std::make_unique<PeriodicSamplingScheduler>(
+ kSamplingParams.samples_per_profile * kSamplingParams.sampling_interval,
+ kFractionOfExecutionTimeToSample, startup_profiling_completion_time);
+
+ if (owning_thread_task_runner_)
+ ScheduleNextPeriodicCollection();
+}
+
+// static
+void ThreadProfiler::OnPeriodicCollectionCompleted(
+ scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner,
+ base::WeakPtr<ThreadProfiler> thread_profiler) {
+ owning_thread_task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&ThreadProfiler::ScheduleNextPeriodicCollection,
+ thread_profiler));
+}
+
+void ThreadProfiler::SetMainThreadTaskRunnerImpl(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+ if (!StackSamplingConfiguration::Get()->IsProfilerEnabledForCurrentProcess())
+ return;
+
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ // This should only be called if the task runner wasn't provided in the
+ // constructor.
+ DCHECK(!owning_thread_task_runner_);
+ owning_thread_task_runner_ = task_runner;
+ ScheduleNextPeriodicCollection();
+}
+
+void ThreadProfiler::ScheduleNextPeriodicCollection() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ owning_thread_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&ThreadProfiler::StartPeriodicSamplingCollection,
+ weak_factory_.GetWeakPtr()),
+ periodic_sampling_scheduler_->GetTimeToNextCollection());
+}
+
+void ThreadProfiler::StartPeriodicSamplingCollection() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ // NB: Destroys the previous profiler as side effect.
+ periodic_profiler_ = std::make_unique<StackSamplingProfiler>(
+ base::PlatformThread::CurrentId(), kSamplingParams,
+ std::make_unique<CallStackProfileBuilder>(
+ CallStackProfileParams(GetProcess(), thread_,
+ CallStackProfileParams::PERIODIC_COLLECTION),
+ work_id_recorder_.get(),
+ base::BindOnce(&ThreadProfiler::OnPeriodicCollectionCompleted,
+ owning_thread_task_runner_,
+ weak_factory_.GetWeakPtr())));
+ if (aux_unwinder_factory_)
+ periodic_profiler_->AddAuxUnwinder(aux_unwinder_factory_.Run());
+
+ periodic_profiler_->Start();
+}
diff --git a/chromium/chrome/common/thread_profiler.h b/chromium/chrome/common/thread_profiler.h
new file mode 100644
index 00000000000..21e3db7dc46
--- /dev/null
+++ b/chromium/chrome/common/thread_profiler.h
@@ -0,0 +1,155 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_COMMON_THREAD_PROFILER_H_
+#define CHROME_COMMON_THREAD_PROFILER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/profiler/stack_sampling_profiler.h"
+#include "base/profiler/unwinder.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "components/metrics/call_stack_profile_params.h"
+#include "components/metrics/public/mojom/call_stack_profile_collector.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "third_party/metrics_proto/sampled_profile.pb.h"
+
+// PeriodicSamplingScheduler repeatedly schedules periodic sampling of the
+// thread through calls to GetTimeToNextCollection(). This class is exposed
+// to allow testing.
+class PeriodicSamplingScheduler {
+ public:
+ PeriodicSamplingScheduler(base::TimeDelta sampling_duration,
+ double fraction_of_execution_time_to_sample,
+ base::TimeTicks start_time);
+ virtual ~PeriodicSamplingScheduler();
+
+ // Returns the amount of time between now and the next collection.
+ base::TimeDelta GetTimeToNextCollection();
+
+ protected:
+ // Virtual to provide seams for test use.
+ virtual double RandDouble() const;
+ virtual base::TimeTicks Now() const;
+
+ private:
+ const base::TimeDelta period_duration_;
+ const base::TimeDelta sampling_duration_;
+ base::TimeTicks period_start_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(PeriodicSamplingScheduler);
+};
+
+// ThreadProfiler performs startup and periodic profiling of Chrome
+// threads.
+class ThreadProfiler {
+ public:
+ ~ThreadProfiler();
+
+ // Creates a profiler for a main thread and immediately starts it. This
+ // function should only be used when profiling the main thread of a
+ // process. The returned profiler must be destroyed prior to thread exit to
+ // stop the profiling.
+ //
+ // SetMainThreadTaskRunner() should be called after the message loop has been
+ // started on the thread. It is the caller's responsibility to ensure that
+ // the instance returned by this function is still alive when the static API
+ // SetMainThreadTaskRunner() is used. The latter is static to support Chrome's
+ // set up where the ThreadProfiler is created in chrome/app which cannot be
+ // easily accessed from chrome_browser_main.cc which sets the task runner.
+ static std::unique_ptr<ThreadProfiler> CreateAndStartOnMainThread();
+
+ // Sets the task runner when profiling on the main thread. This occurs in a
+ // separate call from CreateAndStartOnMainThread so that startup profiling can
+ // occur prior to message loop start. The task runner is associated with the
+ // instance returned by CreateAndStartOnMainThread(), which must be alive when
+ // this is called.
+ static void SetMainThreadTaskRunner(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+ // Sets a callback to create auxiliary unwinders, for handling additional,
+ // non-native-code unwind scenarios. Currently used to support
+ // unwinding V8 JavaScript frames.
+ void SetAuxUnwinderFactory(
+ const base::RepeatingCallback<std::unique_ptr<base::Unwinder>()>&
+ factory);
+
+ // Creates a profiler for a child thread and immediately starts it. This
+ // should be called from a task posted on the child thread immediately after
+ // thread start. The thread will be profiled until exit.
+ static void StartOnChildThread(
+ metrics::CallStackProfileParams::Thread thread);
+
+ // Sets the callback to use for reporting browser process profiles. This
+ // indirection is required to avoid a dependency on unnecessary metrics code
+ // in child processes.
+ static void SetBrowserProcessReceiverCallback(
+ const base::RepeatingCallback<void(base::TimeTicks,
+ metrics::SampledProfile)>& callback);
+
+ // This function must be called within child processes to supply the Service
+ // Manager's connector, to bind the interface through which a profile is sent
+ // back to the browser process.
+ //
+ // Note that the metrics::CallStackProfileCollector interface also must be
+ // exposed to the child process, and metrics::mojom::CallStackProfileCollector
+ // declared in chrome_content_browser_manifest_overlay.json, for the binding
+ // to succeed.
+ static void SetCollectorForChildProcess(
+ mojo::PendingRemote<metrics::mojom::CallStackProfileCollector> collector);
+
+ private:
+ class WorkIdRecorder;
+
+ // Creates the profiler. The task runner will be supplied for child threads
+ // but not for main threads.
+ ThreadProfiler(
+ metrics::CallStackProfileParams::Thread thread,
+ scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner =
+ scoped_refptr<base::SingleThreadTaskRunner>());
+
+ // Posts a task on |owning_thread_task_runner| to start the next periodic
+ // sampling collection on the completion of the previous collection.
+ static void OnPeriodicCollectionCompleted(
+ scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner,
+ base::WeakPtr<ThreadProfiler> thread_profiler);
+
+ // Sets the task runner when profiling on the main thread. This occurs in a
+ // separate call from CreateAndStartOnMainThread so that startup profiling can
+ // occur prior to message loop start.
+ void SetMainThreadTaskRunnerImpl(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+ // Posts a delayed task to start the next periodic sampling collection.
+ void ScheduleNextPeriodicCollection();
+
+ // Creates a new periodic profiler and initiates a collection with it.
+ void StartPeriodicSamplingCollection();
+
+ metrics::CallStackProfileParams::Thread thread_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> owning_thread_task_runner_;
+
+ std::unique_ptr<WorkIdRecorder> work_id_recorder_;
+
+ base::RepeatingCallback<std::unique_ptr<base::Unwinder>()>
+ aux_unwinder_factory_;
+
+ std::unique_ptr<base::StackSamplingProfiler> startup_profiler_;
+
+ std::unique_ptr<base::StackSamplingProfiler> periodic_profiler_;
+ std::unique_ptr<PeriodicSamplingScheduler> periodic_sampling_scheduler_;
+
+ THREAD_CHECKER(thread_checker_);
+ base::WeakPtrFactory<ThreadProfiler> weak_factory_{this};
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadProfiler);
+};
+
+#endif // CHROME_COMMON_THREAD_PROFILER_H_
diff --git a/chromium/chrome/common/thread_profiler_unittest.cc b/chromium/chrome/common/thread_profiler_unittest.cc
new file mode 100644
index 00000000000..cf8018139a6
--- /dev/null
+++ b/chromium/chrome/common/thread_profiler_unittest.cc
@@ -0,0 +1,98 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/common/thread_profiler.h"
+
+#include "base/macros.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class TestScheduler : public PeriodicSamplingScheduler {
+ public:
+ TestScheduler(base::TimeDelta sampling_duration,
+ double fraction_of_execution_time_to_sample)
+ : PeriodicSamplingScheduler(sampling_duration,
+ fraction_of_execution_time_to_sample,
+ kStartTime),
+ rand_double_value_(0.0) {
+ tick_clock_.SetNowTicks(kStartTime);
+ }
+
+ double RandDouble() const override { return rand_double_value_; }
+ base::TimeTicks Now() const override { return tick_clock_.NowTicks(); }
+
+ void SetRandDouble(double value) { rand_double_value_ = value; }
+ base::SimpleTestTickClock& tick_clock() { return tick_clock_; }
+
+ private:
+ static constexpr base::TimeTicks kStartTime = base::TimeTicks();
+ base::SimpleTestTickClock tick_clock_;
+ double rand_double_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestScheduler);
+};
+
+constexpr base::TimeTicks TestScheduler::kStartTime;
+
+} // namespace
+
+TEST(ThreadProfilerTest, PeriodicSamplingScheduler) {
+ const base::TimeDelta sampling_duration = base::TimeDelta::FromSeconds(30);
+ const double fraction_of_execution_time_to_sample = 0.01;
+
+ const base::TimeDelta expected_period =
+ sampling_duration / fraction_of_execution_time_to_sample;
+
+ TestScheduler scheduler(sampling_duration,
+ fraction_of_execution_time_to_sample);
+
+ // The first collection should be exactly at the start time, since the random
+ // value is 0.0.
+ scheduler.SetRandDouble(0.0);
+ EXPECT_EQ(base::TimeDelta::FromSeconds(0),
+ scheduler.GetTimeToNextCollection());
+
+ // With a random value of 1.0 the second collection should be at the end of
+ // the second period.
+ scheduler.SetRandDouble(1.0);
+ EXPECT_EQ(2 * expected_period - sampling_duration,
+ scheduler.GetTimeToNextCollection());
+
+ // With a random value of 0.25 the second collection should be a quarter into
+ // the third period exclusive of the sampling duration.
+ scheduler.SetRandDouble(0.25);
+ EXPECT_EQ(2 * expected_period + 0.25 * (expected_period - sampling_duration),
+ scheduler.GetTimeToNextCollection());
+}
+
+TEST(ThreadProfilerTest, PeriodicSamplingSchedulerWithJumpInTimeTicks) {
+ const base::TimeDelta sampling_duration = base::TimeDelta::FromSeconds(30);
+ const double fraction_of_execution_time_to_sample = 0.01;
+
+ const base::TimeDelta expected_period =
+ sampling_duration / fraction_of_execution_time_to_sample;
+
+ TestScheduler scheduler(sampling_duration,
+ fraction_of_execution_time_to_sample);
+
+ // The first collection should be exactly at the start time, since the random
+ // value is 0.0.
+ scheduler.SetRandDouble(0.0);
+ EXPECT_EQ(base::TimeDelta::FromSeconds(0),
+ scheduler.GetTimeToNextCollection());
+
+ // Simulate a non-continuous jump in the current TimeTicks such that the next
+ // period would start before the current time. In this case the
+ // period start should be reset to the current time, and the next collection
+ // chosen within that period.
+ scheduler.tick_clock().Advance(expected_period +
+ base::TimeDelta::FromSeconds(1));
+ scheduler.SetRandDouble(0.5);
+ EXPECT_EQ(0.5 * (expected_period - sampling_duration),
+ scheduler.GetTimeToNextCollection());
+}
diff --git a/chromium/chrome/common/time_format_browsertest.cc b/chromium/chrome/common/time_format_browsertest.cc
new file mode 100644
index 00000000000..0a110aacafc
--- /dev/null
+++ b/chromium/chrome/common/time_format_browsertest.cc
@@ -0,0 +1,42 @@
+// 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 whole test runs as a separate browser_test because it depends on a
+// static initialization inside third_party/icu (gDecimal in digitlst.cpp).
+//
+// That initialization depends on the current locale, and on certain locales
+// will lead to wrong behavior. To make sure that the locale is set before
+// icu is used, and that the "wrong" static value doesn't affect other tests,
+// this test is executed on its own process.
+
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_locale.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "ui/base/l10n/time_format.h"
+
+using base::TimeDelta;
+
+class TimeFormatBrowserTest : public InProcessBrowserTest {
+ public:
+ TimeFormatBrowserTest() : scoped_locale_("fr_FR.utf-8") {
+ }
+
+ private:
+ base::ScopedLocale scoped_locale_;
+};
+
+IN_PROC_BROWSER_TEST_F(TimeFormatBrowserTest, DecimalPointNotDot) {
+ // Some locales use a comma ',' instead of a dot '.' as the separator for
+ // decimal digits. The icu library wasn't handling this, leading to "1"
+ // being internally converted to "+1,0e00" and ultimately leading to "NaN".
+ // This showed up on the browser on estimated download time, for example.
+ // http://crbug.com/60476
+
+ base::string16 one_min =
+ ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_DURATION,
+ ui::TimeFormat::LENGTH_SHORT,
+ TimeDelta::FromMinutes(1));
+ EXPECT_EQ(base::ASCIIToUTF16("1 min"), one_min);
+}
diff --git a/chromium/chrome/common/web_application_info.cc b/chromium/chrome/common/web_application_info.cc
new file mode 100644
index 00000000000..340eeb360b2
--- /dev/null
+++ b/chromium/chrome/common/web_application_info.cc
@@ -0,0 +1,19 @@
+// 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 "chrome/common/web_application_info.h"
+
+WebApplicationIconInfo::WebApplicationIconInfo() : width(0), height(0) {}
+
+WebApplicationIconInfo::~WebApplicationIconInfo() = default;
+
+WebApplicationInfo::WebApplicationInfo()
+ : mobile_capable(MOBILE_CAPABLE_UNSPECIFIED),
+ generated_icon_color(SK_ColorTRANSPARENT),
+ open_as_window(false) {}
+
+WebApplicationInfo::WebApplicationInfo(const WebApplicationInfo& other) =
+ default;
+
+WebApplicationInfo::~WebApplicationInfo() = default;
diff --git a/chromium/chrome/common/web_application_info.h b/chromium/chrome/common/web_application_info.h
new file mode 100644
index 00000000000..1d75589011f
--- /dev/null
+++ b/chromium/chrome/common/web_application_info.h
@@ -0,0 +1,75 @@
+// 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 CHROME_COMMON_WEB_APPLICATION_INFO_H_
+#define CHROME_COMMON_WEB_APPLICATION_INFO_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/optional.h"
+#include "base/strings/string16.h"
+#include "third_party/blink/public/common/manifest/manifest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/size.h"
+#include "url/gurl.h"
+
+struct WebApplicationIconInfo {
+ WebApplicationIconInfo();
+ ~WebApplicationIconInfo();
+
+ GURL url;
+ int width;
+ int height;
+ SkBitmap data;
+};
+
+// Structure used when installing a web page as an app.
+struct WebApplicationInfo {
+ enum MobileCapable {
+ MOBILE_CAPABLE_UNSPECIFIED,
+ MOBILE_CAPABLE,
+ MOBILE_CAPABLE_APPLE
+ };
+
+ WebApplicationInfo();
+ WebApplicationInfo(const WebApplicationInfo& other);
+ ~WebApplicationInfo();
+
+ // Title of the application.
+ base::string16 title;
+
+ // Description of the application.
+ base::string16 description;
+
+ // The launch URL for the app.
+ GURL app_url;
+
+ // Scope for the app. Dictates what URLs will be opened in the app.
+ GURL scope;
+
+ // Set of available icons.
+ std::vector<WebApplicationIconInfo> icons;
+
+ // Whether the page is marked as mobile-capable, including apple specific meta
+ // tag.
+ MobileCapable mobile_capable;
+
+ // The color to use if an icon needs to be generated for the web app.
+ SkColor generated_icon_color;
+
+ // The color to use for the web app frame.
+ base::Optional<SkColor> theme_color;
+
+ // Whether the app should be opened in a window. If false, the app will be
+ // opened in a tab.
+ bool open_as_window;
+
+ // The extensions and mime types the app can handle.
+ base::Optional<blink::Manifest::FileHandler> file_handler;
+};
+
+#endif // CHROME_COMMON_WEB_APPLICATION_INFO_H_
diff --git a/chromium/chrome/common/web_application_info_provider_param_traits.h b/chromium/chrome/common/web_application_info_provider_param_traits.h
new file mode 100644
index 00000000000..f23ff915a9e
--- /dev/null
+++ b/chromium/chrome/common/web_application_info_provider_param_traits.h
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// NOLINT(build/header_guard)
+// no-include-guard-because-multiply-included
+
+#include "chrome/common/web_application_info.h"
+#include "ipc/ipc_message_macros.h"
+
+IPC_ENUM_TRAITS_MAX_VALUE(WebApplicationInfo::MobileCapable,
+ WebApplicationInfo::MOBILE_CAPABLE_APPLE)
+
+IPC_STRUCT_TRAITS_BEGIN(WebApplicationIconInfo)
+ IPC_STRUCT_TRAITS_MEMBER(url)
+ IPC_STRUCT_TRAITS_MEMBER(width)
+ IPC_STRUCT_TRAITS_MEMBER(height)
+ IPC_STRUCT_TRAITS_MEMBER(data)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(WebApplicationInfo)
+ IPC_STRUCT_TRAITS_MEMBER(title)
+ IPC_STRUCT_TRAITS_MEMBER(description)
+ IPC_STRUCT_TRAITS_MEMBER(app_url)
+ IPC_STRUCT_TRAITS_MEMBER(icons)
+ IPC_STRUCT_TRAITS_MEMBER(mobile_capable)
+IPC_STRUCT_TRAITS_END()
diff --git a/chromium/chrome/common/win/OWNERS b/chromium/chrome/common/win/OWNERS
new file mode 100644
index 00000000000..5bbda7a59c4
--- /dev/null
+++ b/chromium/chrome/common/win/OWNERS
@@ -0,0 +1 @@
+# COMPONENT: Platform>Apps>API>Windows
diff --git a/chromium/chrome/common/win/eventlog_messages.mc b/chromium/chrome/common/win/eventlog_messages.mc
new file mode 100644
index 00000000000..bfc16319bb1
--- /dev/null
+++ b/chromium/chrome/common/win/eventlog_messages.mc
@@ -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.
+;//
+;// Defines the names and types of messages that are logged with the SYSLOG
+;// macro.
+SeverityNames=(Informational=0x0:STATUS_SEVERITY_INFORMATIONAL
+ Warning=0x1:STATUS_SEVERITY_WARNING
+ Error=0x2:STATUS_SEVERITY_ERROR
+ Fatal=0x3:STATUS_SEVERITY_FATAL
+ )
+FacilityNames=(Browser=0x0:FACILITY_SYSTEM)
+LanguageNames=(English=0x409:MSG00409)
+
+;// TODO(pastarmovj): Subdivide into more categories if needed.
+MessageIdTypedef=WORD
+
+MessageId=0x1
+SymbolicName=BROWSER_CATEGORY
+Language=English
+Browser Events
+.
+
+MessageIdTypedef=DWORD
+
+MessageId=0x100
+Severity=Error
+Facility=Browser
+SymbolicName=MSG_LOG_MESSAGE
+Language=English
+%1!S!
+.
diff --git a/chromium/chrome/common/win/eventlog_provider.cc b/chromium/chrome/common/win/eventlog_provider.cc
new file mode 100644
index 00000000000..d4116c26584
--- /dev/null
+++ b/chromium/chrome/common/win/eventlog_provider.cc
@@ -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.
+
+// Force the generation of a .lib file for the .dll since Ninja expects shared
+// libraries to generate a .dll and a .lib file.
+__declspec(dllexport) bool fn() {
+ return true;
+}
diff --git a/chromium/chrome/common/win/eventlog_provider.ver b/chromium/chrome/common/win/eventlog_provider.ver
new file mode 100644
index 00000000000..2d6c97c0125
--- /dev/null
+++ b/chromium/chrome/common/win/eventlog_provider.ver
@@ -0,0 +1,2 @@
+INTERNAL_NAME=eventlog_provider_dll
+ORIGINAL_FILENAME=eventlog_provider.dll