diff --git a/DEPS b/DEPS index 369de67..fee2358 100644 --- a/DEPS +++ b/DEPS
@@ -44,7 +44,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '2644e367904984e9cced64eaf3b911a0acb231d8', + 'v8_revision': '5ba6e0d1657de49d441efa7d599b7cb58c2c568e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'c7739322e5cdcc5779bdde2a1560ea3dee891e51', + 'pdfium_revision': '37b12ad873198a9644f3de0d2eff001285e1ad42', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'ab7345371ad03603c5434f2a775ec65830067920', + 'catapult_revision': 'f87ce97ea1faeb9e553108218910551fd6492d2f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other.
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index da46670..861990e 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -1925,7 +1925,7 @@ return [] -def _CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api): +def _CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api): """Checks for old style compiled_resources.gyp files.""" is_compiled_resource = lambda fp: fp.endswith('compiled_resources.gyp') @@ -1969,7 +1969,7 @@ ( "-webkit-repeating-radial-gradient", "repeating-radial-gradient" ), ] -def _CheckNoDeprecatedCSS(input_api, output_api): +def _CheckNoDeprecatedCss(input_api, output_api): """ Make sure that we don't use deprecated CSS properties, functions or values. Our external documentation and iOS CSS for dom distiller @@ -2004,7 +2004,7 @@ ( "__defineSetter__", "Object.defineProperty" ), ] -def _CheckNoDeprecatedJS(input_api, output_api): +def _CheckNoDeprecatedJs(input_api, output_api): """Make sure that we don't use deprecated JS in Chrome code.""" results = [] file_inclusion_pattern = (r".+\.js$",) # TODO(dbeam): .html? @@ -2022,6 +2022,27 @@ return results +def _CheckForRiskyJsFeatures(input_api, output_api): + maybe_ios_js = (r"^(ios|components|ui\/webui\/resources)\/.+\.js$", ) + file_filter = lambda f: input_api.FilterSourceFile(f, white_list=maybe_ios_js) + + arrow_lines = [] + for f in input_api.AffectedFiles(file_filter=file_filter): + for lnum, line in f.ChangedContents(): + if ' => ' in line: + arrow_lines.append((f.LocalPath(), lnum)) + + if not arrow_lines: + return [] + + return [output_api.PresubmitPromptWarning(""" +Use of => operator detected in: +%s +Please ensure your code does not run on iOS9 (=> (arrow) does not work there). +https://chromium.googlesource.com/chromium/src/+/master/docs/es6_chromium.md#Arrow-Functions +""" % "\n".join(" %s:%d\n" % line for line in arrow_lines))] + + def _AndroidSpecificOnUploadChecks(input_api, output_api): """Groups checks that target android code.""" results = [] @@ -2070,18 +2091,19 @@ results.extend(_CheckForAnonymousVariables(input_api, output_api)) results.extend(_CheckCygwinShell(input_api, output_api)) results.extend(_CheckUserActionUpdate(input_api, output_api)) - results.extend(_CheckNoDeprecatedCSS(input_api, output_api)) - results.extend(_CheckNoDeprecatedJS(input_api, output_api)) + results.extend(_CheckNoDeprecatedCss(input_api, output_api)) + results.extend(_CheckNoDeprecatedJs(input_api, output_api)) results.extend(_CheckParseErrors(input_api, output_api)) results.extend(_CheckForIPCRules(input_api, output_api)) results.extend(_CheckForWindowsLineEndings(input_api, output_api)) results.extend(_CheckSingletonInHeaders(input_api, output_api)) - results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api)) + results.extend(_CheckNoDeprecatedCompiledResourcesGyp(input_api, output_api)) results.extend(_CheckPydepsNeedsUpdating(input_api, output_api)) results.extend(_CheckJavaStyle(input_api, output_api)) results.extend(_CheckIpcOwners(input_api, output_api)) results.extend(_CheckMojoUsesNewWrapperTypes(input_api, output_api)) results.extend(_CheckUselessForwardDeclarations(input_api, output_api)) + results.extend(_CheckForRiskyJsFeatures(input_api, output_api)) if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()): results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
diff --git a/PRESUBMIT_test.py b/PRESUBMIT_test.py index e5f6215..34da837 100755 --- a/PRESUBMIT_test.py +++ b/PRESUBMIT_test.py
@@ -412,16 +412,16 @@ self.assertEqual(0, len(warnings)) -class CheckNoDeprecatedCompiledResourcesGYPTest(unittest.TestCase): - def testNoDeprecatedCompiledResourcsGYP(self): +class CheckNoDeprecatedCompiledResourcesGypTest(unittest.TestCase): + def testNoDeprecatedCompiledResourcsGyp(self): mock_input_api = MockInputApi() mock_input_api.files = [MockFile('some/js/compiled_resources.gyp', [])] - errors = PRESUBMIT._CheckNoDeprecatedCompiledResourcesGYP(mock_input_api, + errors = PRESUBMIT._CheckNoDeprecatedCompiledResourcesGyp(mock_input_api, MockOutputApi()) self.assertEquals(1, len(errors)) mock_input_api.files = [MockFile('some/js/compiled_resources2.gyp', [])] - errors = PRESUBMIT._CheckNoDeprecatedCompiledResourcesGYP(mock_input_api, + errors = PRESUBMIT._CheckNoDeprecatedCompiledResourcesGyp(mock_input_api, MockOutputApi()) self.assertEquals(0, len(errors)) @@ -1188,5 +1188,41 @@ self.assertEqual(4, len(warnings)) +class RiskyJsTest(unittest.TestCase): + def testArrowWarnInIos9Code(self): + mock_input_api = MockInputApi() + mock_output_api = MockOutputApi() + + mock_input_api.files = [ + MockAffectedFile('components/blah.js', ["shouldn't use => here"]), + ] + warnings = PRESUBMIT._CheckForRiskyJsFeatures( + mock_input_api, mock_output_api) + self.assertEqual(1, len(warnings)) + + mock_input_api.files = [ + MockAffectedFile('ios/blee.js', ['might => break folks']), + ] + warnings = PRESUBMIT._CheckForRiskyJsFeatures( + mock_input_api, mock_output_api) + self.assertEqual(1, len(warnings)) + + mock_input_api.files = [ + MockAffectedFile('ui/webui/resources/blarg.js', ['on => iOS9']), + ] + warnings = PRESUBMIT._CheckForRiskyJsFeatures( + mock_input_api, mock_output_api) + self.assertEqual(1, len(warnings)) + + def testArrowsAllowedInChromeCode(self): + mock_input_api = MockInputApi() + mock_input_api.files = [ + MockAffectedFile('chrome/browser/resources/blah.js', 'arrow => OK here'), + ] + warnings = PRESUBMIT._CheckForRiskyJsFeatures( + mock_input_api, MockOutputApi()) + self.assertEqual(0, len(warnings)) + + if __name__ == '__main__': unittest.main()
diff --git a/android_webview/browser/DEPS b/android_webview/browser/DEPS index d601fd2a..7ab5e1d 100644 --- a/android_webview/browser/DEPS +++ b/android_webview/browser/DEPS
@@ -44,6 +44,8 @@ "+services/service_manager/public/cpp", + "+storage/browser/quota", + "+ui/gfx", "+ui/gl",
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index a6bb565..5f90c45 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -47,6 +47,7 @@ #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" #include "content/public/common/service_names.mojom.h" @@ -58,6 +59,7 @@ #include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_info.h" #include "services/service_manager/public/cpp/interface_registry.h" +#include "storage/browser/quota/quota_settings.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle_android.h" #include "ui/resources/grit/ui_resources.h" @@ -353,6 +355,17 @@ return new AwQuotaPermissionContext; } +void AwContentBrowserClient::GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + content::BrowserThread::PostTaskAndReplyWithResult( + content::BrowserThread::FILE, FROM_HERE, + base::Bind(&storage::CalculateNominalDynamicSettings, + partition->GetPath(), context->IsOffTheRecord()), + callback); +} + void AwContentBrowserClient::AllowCertificateError( content::WebContents* web_contents, int cert_error,
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h index a3472c5..6b8c6638 100644 --- a/android_webview/browser/aw_content_browser_client.h +++ b/android_webview/browser/aw_content_browser_client.h
@@ -74,6 +74,10 @@ content::ResourceContext* context, const std::vector<std::pair<int, int>>& render_frames) override; content::QuotaPermissionContext* CreateQuotaPermissionContext() override; + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override; void AllowCertificateError( content::WebContents* web_contents, int cert_error,
diff --git a/ash/common/system/tray/fixed_sized_scroll_view.cc b/ash/common/system/tray/fixed_sized_scroll_view.cc index 33fcef69..d3c4a35 100644 --- a/ash/common/system/tray/fixed_sized_scroll_view.cc +++ b/ash/common/system/tray/fixed_sized_scroll_view.cc
@@ -5,7 +5,6 @@ #include "ash/common/system/tray/fixed_sized_scroll_view.h" #include "ash/common/material_design/material_design_controller.h" -#include "ui/views/controls/scrollbar/overlay_scroll_bar.h" namespace ash { @@ -19,10 +18,6 @@ FixedSizedScrollView::FixedSizedScrollView() { set_notify_enter_exit_on_child(true); - if (UseMd()) { - SetVerticalScrollBar(new views::OverlayScrollBar(false)); - SetHorizontalScrollBar(new views::OverlayScrollBar(true)); - } } FixedSizedScrollView::~FixedSizedScrollView() {}
diff --git a/ash/shell/content/client/DEPS b/ash/shell/content/client/DEPS index f71262e8..08c4461 100644 --- a/ash/shell/content/client/DEPS +++ b/ash/shell/content/client/DEPS
@@ -1,4 +1,5 @@ include_rules = [ "+content/public", "+content/shell", + "+storage/browser/quota", ]
diff --git a/ash/shell/content/client/shell_content_browser_client.cc b/ash/shell/content/client/shell_content_browser_client.cc index 60da706..7cb284d 100644 --- a/ash/shell/content/client/shell_content_browser_client.cc +++ b/ash/shell/content/client/shell_content_browser_client.cc
@@ -8,6 +8,10 @@ #include "ash/shell/content/client/shell_browser_main_parts.h" #include "base/command_line.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/storage_partition.h" +#include "storage/browser/quota/quota_settings.h" #include "third_party/skia/include/core/SkBitmap.h" namespace ash { @@ -24,5 +28,16 @@ return shell_browser_main_parts_; } +void ShellContentBrowserClient::GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + content::BrowserThread::PostTaskAndReplyWithResult( + content::BrowserThread::FILE, FROM_HERE, + base::Bind(&storage::CalculateNominalDynamicSettings, + partition->GetPath(), context->IsOffTheRecord()), + callback); +} + } // namespace examples } // namespace views
diff --git a/ash/shell/content/client/shell_content_browser_client.h b/ash/shell/content/client/shell_content_browser_client.h index 29752753..c91183e3 100644 --- a/ash/shell/content/client/shell_content_browser_client.h +++ b/ash/shell/content/client/shell_content_browser_client.h
@@ -28,6 +28,10 @@ // Overridden from content::ContentBrowserClient: content::BrowserMainParts* CreateBrowserMainParts( const content::MainFunctionParams& parameters) override; + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override; private: ShellBrowserMainParts* shell_browser_main_parts_;
diff --git a/base/time/time.cc b/base/time/time.cc index df3942c..9fb9cdfa 100644 --- a/base/time/time.cc +++ b/base/time/time.cc
@@ -21,11 +21,6 @@ // TimeDelta ------------------------------------------------------------------ -// static -TimeDelta TimeDelta::Max() { - return TimeDelta(std::numeric_limits<int64_t>::max()); -} - int TimeDelta::InDays() const { if (is_max()) { // Preserve max to prevent overflow.
diff --git a/base/time/time.h b/base/time/time.h index ece4fe8..74aff23 100644 --- a/base/time/time.h +++ b/base/time/time.h
@@ -130,7 +130,7 @@ // Returns the maximum time delta, which should be greater than any reasonable // time delta we might compare it to. Adding or subtracting the maximum time // delta to a time or another time delta has an undefined result. - static TimeDelta Max(); + static constexpr TimeDelta Max(); // Returns the internal numeric value of the TimeDelta object. Please don't // use this and do arithmetic on it, as it is more error prone than using the @@ -671,6 +671,11 @@ } // static +constexpr TimeDelta TimeDelta::Max() { + return TimeDelta(std::numeric_limits<int64_t>::max()); +} + +// static constexpr TimeDelta TimeDelta::FromDouble(double value) { // TODO(crbug.com/612601): Use saturated_cast<int64_t>(value) once we sort out // the Min() behavior.
diff --git a/blimp/engine/DEPS b/blimp/engine/DEPS index 7e4c0fe..50d5e50bd 100644 --- a/blimp/engine/DEPS +++ b/blimp/engine/DEPS
@@ -14,6 +14,7 @@ "+mojo/public", "+net", "+services/service_manager/public/cpp", + "+storage/browser/quota", "+third_party/blimp_fonts", "+third_party/khronos/GLES2/gl2.h", "+third_party/WebKit/public/platform/WebGestureEvent.h",
diff --git a/blimp/engine/app/blimp_content_browser_client.cc b/blimp/engine/app/blimp_content_browser_client.cc index 5e8c42b3..0a94405 100644 --- a/blimp/engine/app/blimp_content_browser_client.cc +++ b/blimp/engine/app/blimp_content_browser_client.cc
@@ -8,9 +8,12 @@ #include "blimp/engine/app/settings_manager.h" #include "blimp/engine/grit/blimp_browser_resources.h" #include "blimp/engine/mojo/blob_channel_service.h" +#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/storage_partition.h" #include "content/public/common/service_names.mojom.h" #include "services/service_manager/public/cpp/interface_registry.h" +#include "storage/browser/quota/quota_settings.h" #include "ui/base/resource/resource_bundle.h" namespace blimp { @@ -69,5 +72,16 @@ return base::JSONReader::Read(manifest_contents); } +void BlimpContentBrowserClient::GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + content::BrowserThread::PostTaskAndReplyWithResult( + content::BrowserThread::FILE, FROM_HERE, + base::Bind(&storage::CalculateNominalDynamicSettings, + partition->GetPath(), context->IsOffTheRecord()), + callback); +} + } // namespace engine } // namespace blimp
diff --git a/blimp/engine/app/blimp_content_browser_client.h b/blimp/engine/app/blimp_content_browser_client.h index d843da0..0aa2582 100644 --- a/blimp/engine/app/blimp_content_browser_client.h +++ b/blimp/engine/app/blimp_content_browser_client.h
@@ -33,6 +33,10 @@ content::RenderProcessHost* render_process_host) override; std::unique_ptr<base::Value> GetServiceManifestOverlay( const std::string& name) override; + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override; BlimpBrowserContext* GetBrowserContext();
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc index dbccde90..e5eefafe 100644 --- a/build/sanitizers/tsan_suppressions.cc +++ b/build/sanitizers/tsan_suppressions.cc
@@ -270,6 +270,9 @@ // http://crbug.com/638583 "race:webrtc/modules/audio_processing/aec/aec_rdft.cc\n" +// http://crbug.com/587199 +"race:base::TimerTest_OneShotTimer_CustomTaskRunner_Test::TestBody\n" + // End of suppressions. ; // Please keep this semicolon.
diff --git a/chrome/VERSION b/chrome/VERSION index 653ceaf..bed3715 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=57 MINOR=0 -BUILD=2952 +BUILD=2953 PATCH=0
diff --git a/chrome/app/theme/default_100_percent/common/update_menu_severity_high.png b/chrome/app/theme/default_100_percent/common/update_menu_severity_high.png deleted file mode 100644 index e6a259f..0000000 --- a/chrome/app/theme/default_100_percent/common/update_menu_severity_high.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/update_menu_severity_low.png b/chrome/app/theme/default_100_percent/common/update_menu_severity_low.png deleted file mode 100644 index 9c6c8a5d..0000000 --- a/chrome/app/theme/default_100_percent/common/update_menu_severity_low.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/update_menu_severity_medium.png b/chrome/app/theme/default_100_percent/common/update_menu_severity_medium.png deleted file mode 100644 index 29e42af..0000000 --- a/chrome/app/theme/default_100_percent/common/update_menu_severity_medium.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/update_menu_severity_high.png b/chrome/app/theme/default_200_percent/common/update_menu_severity_high.png deleted file mode 100644 index 1c00329c..0000000 --- a/chrome/app/theme/default_200_percent/common/update_menu_severity_high.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/update_menu_severity_low.png b/chrome/app/theme/default_200_percent/common/update_menu_severity_low.png deleted file mode 100644 index 2374b69a7..0000000 --- a/chrome/app/theme/default_200_percent/common/update_menu_severity_low.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/update_menu_severity_medium.png b/chrome/app/theme/default_200_percent/common/update_menu_severity_medium.png deleted file mode 100644 index fbbcefd4..0000000 --- a/chrome/app/theme/default_200_percent/common/update_menu_severity_medium.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index 7ad26d30..724e8ab 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -627,9 +627,6 @@ <structure type="chrome_scaled_image" name="IDR_TRANSLATE" file="legacy/translate.png" /> <structure type="chrome_scaled_image" name="IDR_TRANSLATE_ACTIVE" file="legacy/translate_active.png" /> </if> - <structure type="chrome_scaled_image" name="IDR_UPDATE_MENU_SEVERITY_LOW" file="common/update_menu_severity_low.png" /> - <structure type="chrome_scaled_image" name="IDR_UPDATE_MENU_SEVERITY_MEDIUM" file="common/update_menu_severity_medium.png" /> - <structure type="chrome_scaled_image" name="IDR_UPDATE_MENU_SEVERITY_HIGH" file="common/update_menu_severity_high.png" /> <structure type="chrome_scaled_image" name="IDR_USB_NOTIFICATION_ICON" file="common/notification_usb_icon.png" /> <if expr="chromeos"> <structure type="chrome_scaled_image" name="IDR_USER_IMAGE_CAPTURE" file="cros/snapshot_wide.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 828c551..0acff67 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -354,8 +354,6 @@ "download/save_package_file_picker.h", "engagement/important_sites_util.cc", "engagement/important_sites_util.h", - "engagement/site_engagement_eviction_policy.cc", - "engagement/site_engagement_eviction_policy.h", "engagement/site_engagement_helper.cc", "engagement/site_engagement_helper.h", "engagement/site_engagement_metrics.cc", @@ -1298,6 +1296,8 @@ "usb/web_usb_permission_provider.h", "web_data_service_factory.cc", "web_data_service_factory.h", + "webshare/share_service_impl.cc", + "webshare/share_service_impl.h", "win/app_icon.cc", "win/app_icon.h", "win/browser_util.cc",
diff --git a/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc index e8a97eb3..2c5781d 100644 --- a/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc +++ b/chrome/browser/browsing_data/browsing_data_quota_helper_unittest.cc
@@ -37,8 +37,8 @@ quota_manager_ = new storage::QuotaManager( false, dir_.GetPath(), BrowserThread::GetTaskRunnerForThread(BrowserThread::IO).get(), - BrowserThread::GetTaskRunnerForThread(BrowserThread::DB).get(), - nullptr); + BrowserThread::GetTaskRunnerForThread(BrowserThread::DB).get(), nullptr, + storage::GetQuotaSettingsFunc()); helper_ = new BrowsingDataQuotaHelperImpl(quota_manager_.get()); }
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 2d7a02d6..66f1290 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -48,7 +48,6 @@ #include "chrome/browser/content_settings/tab_specific_content_settings.h" #include "chrome/browser/defaults.h" #include "chrome/browser/download/download_prefs.h" -#include "chrome/browser/engagement/site_engagement_eviction_policy.h" #include "chrome/browser/field_trial_recorder.h" #include "chrome/browser/font_family_cache.h" #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" @@ -98,6 +97,7 @@ #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h" #include "chrome/browser/ui/webui/log_web_ui_url.h" #include "chrome/browser/usb/usb_tab_helper.h" +#include "chrome/browser/webshare/share_service_impl.h" #include "chrome/common/channel_info.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" @@ -405,6 +405,8 @@ // thread. base::LazyInstance<std::string> g_io_thread_application_locale; +const storage::QuotaSettings* g_default_quota_settings; + #if BUILDFLAG(ENABLE_PLUGINS) // TODO(teravest): Add renderer-side API-specific checking for these APIs so // that blanket permission isn't granted to all dev channel APIs for these. @@ -2164,12 +2166,20 @@ return new ChromeQuotaPermissionContext(); } -std::unique_ptr<storage::QuotaEvictionPolicy> -ChromeContentBrowserClient::GetTemporaryStorageEvictionPolicy( - content::BrowserContext* context) { - return SiteEngagementEvictionPolicy::IsEnabled() - ? base::MakeUnique<SiteEngagementEvictionPolicy>(context) - : nullptr; +void ChromeContentBrowserClient::GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + if (g_default_quota_settings) { + // For debugging tests harness can inject settings. + callback.Run(*g_default_quota_settings); + return; + } + content::BrowserThread::PostTaskAndReplyWithResult( + content::BrowserThread::FILE, FROM_HERE, + base::Bind(&storage::CalculateNominalDynamicSettings, + partition->GetPath(), context->IsOffTheRecord()), + callback); } void ChromeContentBrowserClient::AllowCertificateError( @@ -3057,6 +3067,11 @@ } #endif +#if defined(OS_LINUX) || defined(OS_WIN) + if (!ChromeOriginTrialPolicy().IsFeatureDisabled("WebShare")) { + registry->AddInterface(base::Bind(&ShareServiceImpl::Create)); + } +#endif } void ChromeContentBrowserClient::ExposeInterfacesToGpuProcess( @@ -3356,3 +3371,9 @@ task_scheduler_util::variations:: MaybePerformBrowserTaskSchedulerRedirection(); } + +//static +void ChromeContentBrowserClient::SetDefaultQuotaSettingsForTesting( + const storage::QuotaSettings* settings) { + g_default_quota_settings = settings; +}
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index be14cef..352f156 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h
@@ -171,8 +171,11 @@ const GURL& url, content::ResourceContext* context) override; content::QuotaPermissionContext* CreateQuotaPermissionContext() override; - std::unique_ptr<storage::QuotaEvictionPolicy> - GetTemporaryStorageEvictionPolicy(content::BrowserContext* context) override; + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override; + void AllowCertificateError( content::WebContents* web_contents, int cert_error, @@ -326,6 +329,7 @@ private: friend class DisableWebRtcEncryptionFlagTest; + friend class InProcessBrowserTest; #if BUILDFLAG(ENABLE_WEBRTC) // Copies disable WebRTC encryption switch depending on the channel. @@ -356,6 +360,11 @@ const base::Callback<void(bool)>& callback); #endif + // The value pointed to by |settings| should remain valid until the + // the function is called again with a new value or a nullptr. + static void SetDefaultQuotaSettingsForTesting( + const storage::QuotaSettings *settings); + #if BUILDFLAG(ENABLE_PLUGINS) // Set of origins that can use TCP/UDP private APIs from NaCl. std::set<std::string> allowed_socket_origins_;
diff --git a/chrome/browser/chromeos/policy/device_status_collector.cc b/chrome/browser/chromeos/policy/device_status_collector.cc index eee5156..8bfcfec 100644 --- a/chrome/browser/chromeos/policy/device_status_collector.cc +++ b/chrome/browser/chromeos/policy/device_status_collector.cc
@@ -109,11 +109,17 @@ std::vector<em::VolumeInfo> result; for (const std::string& mount_point : mount_points) { base::FilePath mount_path(mount_point); + + // Non-native file systems do not have a mount point in the local file + // system. However, it's worth checking here, as it's easier than checking + // earlier which mount point is local, and which one is not. + if (mount_point.empty() || !base::PathExists(mount_path)) + continue; + int64_t free_size = base::SysInfo::AmountOfFreeDiskSpace(mount_path); int64_t total_size = base::SysInfo::AmountOfTotalDiskSpace(mount_path); if (free_size < 0 || total_size < 0) { - LOG_IF(ERROR, !mount_point.empty()) << "Unable to get volume status for " - << mount_point; + LOG(ERROR) << "Unable to get volume status for " << mount_point; continue; } em::VolumeInfo info;
diff --git a/chrome/browser/engagement/site_engagement_eviction_policy.cc b/chrome/browser/engagement/site_engagement_eviction_policy.cc deleted file mode 100644 index 7d52f56..0000000 --- a/chrome/browser/engagement/site_engagement_eviction_policy.cc +++ /dev/null
@@ -1,144 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/engagement/site_engagement_eviction_policy.h" - -#include "base/command_line.h" -#include "base/metrics/field_trial.h" -#include "base/strings/string_util.h" -#include "chrome/browser/browser_process.h" -#include "chrome/browser/engagement/site_engagement_service.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "chrome/common/chrome_switches.h" -#include "content/public/browser/browser_thread.h" - -namespace { - -const int kExpectedEngagementSites = 200; - -// Gets the quota that an origin deserves based on its site engagement. -int64_t GetSoftQuotaForOrigin(const GURL& origin, - int score, - int total_engagement_points, - int64_t global_quota) { - double quota_per_point = - global_quota / - std::max(kExpectedEngagementSites * SiteEngagementService::GetMaxPoints(), - static_cast<double>(total_engagement_points)); - - return score * quota_per_point; -} - -GURL DoCalculateEvictionOrigin( - const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy, - SiteEngagementScoreProvider* score_provider, - const std::set<GURL>& exceptions, - const std::map<GURL, int64_t>& usage_map, - int64_t global_quota) { - // TODO(calamity): Integrate storage access frequency as an input to this - // heuristic. - - // This heuristic is intended to optimize for two criteria: - // - evict the site that the user cares about least - // - evict the least number of sites to get under the quota limit - // - // The heuristic for deciding the next eviction origin calculates a soft - // quota for each origin which is the amount the origin should be allowed to - // use based on its engagement and the global quota. The origin that most - // exceeds its soft quota is chosen. - GURL origin_to_evict; - int64_t max_overuse = std::numeric_limits<int64_t>::min(); - int total_engagement_points = score_provider->GetTotalEngagementPoints(); - - for (const auto& usage : usage_map) { - GURL origin = usage.first; - if (special_storage_policy && - (special_storage_policy->IsStorageUnlimited(origin) || - special_storage_policy->IsStorageDurable(origin))) { - continue; - } - - // |overuse| can be negative if the soft quota exceeds the usage. - int64_t overuse = - usage.second - - GetSoftQuotaForOrigin(origin, score_provider->GetScore(origin), - total_engagement_points, global_quota); - if (overuse > max_overuse && !base::ContainsKey(exceptions, origin)) { - max_overuse = overuse; - origin_to_evict = origin; - } - } - - return origin_to_evict; -} - -GURL GetSiteEngagementEvictionOriginOnUIThread( - const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy, - content::BrowserContext* browser_context, - const std::set<GURL>& exceptions, - const std::map<GURL, int64_t>& usage_map, - int64_t global_quota) { - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - - Profile* profile = Profile::FromBrowserContext(browser_context); - SiteEngagementScoreProvider* score_provider = - g_browser_process->profile_manager()->IsValidProfile(profile) - ? SiteEngagementService::Get(profile) - : nullptr; - - if (!score_provider) - return GURL(); - - return DoCalculateEvictionOrigin(special_storage_policy, score_provider, - exceptions, usage_map, global_quota); -} - -} // namespace - -// static -bool SiteEngagementEvictionPolicy::IsEnabled() { - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableSiteEngagementEvictionPolicy)) { - return true; - } - - const std::string group_name = base::FieldTrialList::FindFullName( - SiteEngagementService::kEngagementParams); - return base::StartsWith(group_name, "StorageEvictionEnabled", - base::CompareCase::SENSITIVE); -} - -SiteEngagementEvictionPolicy::SiteEngagementEvictionPolicy( - content::BrowserContext* browser_context) - : browser_context_(browser_context) {} - -SiteEngagementEvictionPolicy::~SiteEngagementEvictionPolicy() {} - -void SiteEngagementEvictionPolicy::GetEvictionOrigin( - const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy, - const std::set<GURL>& exceptions, - const std::map<GURL, int64_t>& usage_map, - int64_t global_quota, - const storage::GetOriginCallback& callback) { - DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - - content::BrowserThread::PostTaskAndReplyWithResult( - content::BrowserThread::UI, FROM_HERE, - base::Bind(&GetSiteEngagementEvictionOriginOnUIThread, - special_storage_policy, browser_context_, exceptions, - usage_map, global_quota), - callback); -} - -// static -GURL SiteEngagementEvictionPolicy::CalculateEvictionOriginForTests( - const scoped_refptr<storage::SpecialStoragePolicy>& special_storage_policy, - SiteEngagementScoreProvider* score_provider, - const std::set<GURL>& exceptions, - const std::map<GURL, int64_t>& usage_map, - int64_t global_quota) { - return DoCalculateEvictionOrigin(special_storage_policy, score_provider, - exceptions, usage_map, global_quota); -}
diff --git a/chrome/browser/engagement/site_engagement_eviction_policy.h b/chrome/browser/engagement/site_engagement_eviction_policy.h deleted file mode 100644 index 4266449..0000000 --- a/chrome/browser/engagement/site_engagement_eviction_policy.h +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_ENGAGEMENT_SITE_ENGAGEMENT_EVICTION_POLICY_H_ -#define CHROME_BROWSER_ENGAGEMENT_SITE_ENGAGEMENT_EVICTION_POLICY_H_ - -#include <stdint.h> - -#include <map> -#include <memory> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "storage/browser/quota/quota_manager.h" -#include "url/gurl.h" - -namespace content { -class BrowserContext; -} - -class SiteEngagementScoreProvider; - -class SiteEngagementEvictionPolicy : public storage::QuotaEvictionPolicy { - public: - static bool IsEnabled(); - - explicit SiteEngagementEvictionPolicy( - content::BrowserContext* browser_context); - ~SiteEngagementEvictionPolicy() override; - - // Overridden from storage::QuotaEvictionPolicy: - void GetEvictionOrigin(const scoped_refptr<storage::SpecialStoragePolicy>& - special_storage_policy, - const std::set<GURL>& exceptions, - const std::map<GURL, int64_t>& usage_map, - int64_t global_quota, - const storage::GetOriginCallback& callback) override; - - private: - friend class SiteEngagementEvictionPolicyTest; - - static GURL CalculateEvictionOriginForTests( - const scoped_refptr<storage::SpecialStoragePolicy>& - special_storage_policy, - SiteEngagementScoreProvider* score_provider, - const std::set<GURL>& exceptions, - const std::map<GURL, int64_t>& usage_map, - int64_t global_quota); - - content::BrowserContext* const browser_context_; - - DISALLOW_COPY_AND_ASSIGN(SiteEngagementEvictionPolicy); -}; - -#endif // CHROME_BROWSER_ENGAGEMENT_SITE_ENGAGEMENT_EVICTION_POLICY_H_
diff --git a/chrome/browser/engagement/site_engagement_eviction_policy_unittest.cc b/chrome/browser/engagement/site_engagement_eviction_policy_unittest.cc deleted file mode 100644 index edfb8e1e..0000000 --- a/chrome/browser/engagement/site_engagement_eviction_policy_unittest.cc +++ /dev/null
@@ -1,173 +0,0 @@ -// Copyright 2015 The Chromium Authors. 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/browser/engagement/site_engagement_eviction_policy.h" - -#include <stdint.h> - -#include <memory> - -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/memory/weak_ptr.h" -#include "base/run_loop.h" -#include "base/threading/thread_task_runner_handle.h" -#include "chrome/browser/engagement/site_engagement_service.h" -#include "content/public/test/mock_special_storage_policy.h" -#include "content/public/test/mock_storage_client.h" -#include "content/public/test/test_browser_thread_bundle.h" -#include "storage/browser/quota/quota_manager.h" -#include "storage/browser/quota/quota_manager_proxy.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -const int64_t kGlobalQuota = 25 * 1024; - -} // namespace - -class TestSiteEngagementScoreProvider : public SiteEngagementScoreProvider { - public: - TestSiteEngagementScoreProvider() {} - - virtual ~TestSiteEngagementScoreProvider() {} - - double GetScore(const GURL& url) const override { - const auto& it = engagement_score_map_.find(url); - if (it != engagement_score_map_.end()) - return it->second; - return 0.0; - } - - double GetTotalEngagementPoints() const override { - double total = 0; - for (const auto& site : engagement_score_map_) - total += site.second; - return total; - } - - void SetScore(const GURL& origin, double score) { - engagement_score_map_[origin] = score; - } - - private: - std::map<GURL, double> engagement_score_map_; - - DISALLOW_COPY_AND_ASSIGN(TestSiteEngagementScoreProvider); -}; - -class SiteEngagementEvictionPolicyTest : public testing::Test { - public: - SiteEngagementEvictionPolicyTest() - : score_provider_(new TestSiteEngagementScoreProvider()), - storage_policy_(new content::MockSpecialStoragePolicy()) {} - - ~SiteEngagementEvictionPolicyTest() override {} - - GURL CalculateEvictionOriginWithExceptions( - const std::map<GURL, int64_t>& usage, - const std::set<GURL>& exceptions) { - return SiteEngagementEvictionPolicy::CalculateEvictionOriginForTests( - storage_policy_, score_provider_.get(), exceptions, usage, - kGlobalQuota); - } - - GURL CalculateEvictionOrigin(const std::map<GURL, int64_t>& usage) { - return CalculateEvictionOriginWithExceptions(usage, std::set<GURL>()); - } - - TestSiteEngagementScoreProvider* score_provider() { - return score_provider_.get(); - } - - content::MockSpecialStoragePolicy* storage_policy() { - return storage_policy_.get(); - } - - private: - std::unique_ptr<TestSiteEngagementScoreProvider> score_provider_; - scoped_refptr<content::MockSpecialStoragePolicy> storage_policy_; - - DISALLOW_COPY_AND_ASSIGN(SiteEngagementEvictionPolicyTest); -}; - -TEST_F(SiteEngagementEvictionPolicyTest, GetEvictionOrigin) { - GURL url1("http://www.google.com"); - GURL url2("http://www.example.com"); - GURL url3("http://www.spam.me"); - - std::map<GURL, int64_t> usage; - usage[url1] = 10 * 1024; - usage[url2] = 10 * 1024; - usage[url3] = 10 * 1024; - - score_provider()->SetScore(url1, 50); - score_provider()->SetScore(url2, 25); - - // When 3 sites have equal usage, evict the site with the least engagement. - EXPECT_EQ(url3, CalculateEvictionOrigin(usage)); - - usage[url2] = usage[url3] + 10; - - // Now |url2| has the most usage but |url3| has the least engagement score so - // one of them should be evicted. In this case the heuristic chooses |url3|. - EXPECT_EQ(url3, CalculateEvictionOrigin(usage)); - - // But exceeding allocated usage too much will still result in being evicted - // even though the engagement with |url2| is higher. - usage[url2] = 15 * 1024; - EXPECT_EQ(url2, CalculateEvictionOrigin(usage)); - - // When all origins have the same engagement, the origin with the highest - // usage is evicted. - score_provider()->SetScore(url1, 50); - score_provider()->SetScore(url2, 50); - score_provider()->SetScore(url3, 50); - - usage[url2] = 10 * 1024; - usage[url3] = 20 * 1024; - EXPECT_EQ(url3, CalculateEvictionOrigin(usage)); -} - -// Test that durable and unlimited storage origins are exempt from eviction. -TEST_F(SiteEngagementEvictionPolicyTest, SpecialStoragePolicy) { - GURL url1("http://www.google.com"); - GURL url2("http://www.example.com"); - - std::map<GURL, int64_t> usage; - usage[url1] = 10 * 1024; - usage[url2] = 10 * 1024; - - score_provider()->SetScore(url1, 50); - score_provider()->SetScore(url2, 25); - - EXPECT_EQ(url2, CalculateEvictionOrigin(usage)); - - // Durable storage doesn't get evicted. - storage_policy()->AddDurable(url2); - EXPECT_EQ(url1, CalculateEvictionOrigin(usage)); - - // Unlimited storage doesn't get evicted. - storage_policy()->AddUnlimited(url1); - EXPECT_EQ(GURL(), CalculateEvictionOrigin(usage)); -} - -TEST_F(SiteEngagementEvictionPolicyTest, Exceptions) { - GURL url1("http://www.google.com"); - GURL url2("http://www.example.com"); - - std::map<GURL, int64_t> usage; - usage[url1] = 10 * 1024; - usage[url2] = 10 * 1024; - - score_provider()->SetScore(url1, 50); - score_provider()->SetScore(url2, 25); - - EXPECT_EQ(url2, CalculateEvictionOrigin(usage)); - - // The policy should respect exceptions. - std::set<GURL> exceptions; - exceptions.insert(url2); - EXPECT_EQ(url1, CalculateEvictionOriginWithExceptions(usage, exceptions)); -}
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc index 3fa29c7..7104d0d 100644 --- a/chrome/browser/engagement/site_engagement_service.cc +++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -20,7 +20,6 @@ #include "base/values.h" #include "chrome/browser/banners/app_banner_settings_helper.h" #include "chrome/browser/content_settings/host_content_settings_map_factory.h" -#include "chrome/browser/engagement/site_engagement_eviction_policy.h" #include "chrome/browser/engagement/site_engagement_metrics.h" #include "chrome/browser/engagement/site_engagement_score.h" #include "chrome/browser/engagement/site_engagement_service_factory.h"
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc index a8a9eca7..ab6d4a2a 100644 --- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc +++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -17,8 +17,8 @@ #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" +#include "base/run_loop.h" #include "base/strings/stringprintf.h" -#include "base/synchronization/waitable_event.h" #include "build/build_config.h" #include "chrome/browser/download/download_file_icon_extractor.h" #include "chrome/browser/download/download_service.h" @@ -703,29 +703,25 @@ } // Invoke the fileapi to copy it into the sandboxed filesystem. bool result = false; - base::WaitableEvent done_event( - base::WaitableEvent::ResetPolicy::MANUAL, - base::WaitableEvent::InitialState::NOT_SIGNALED); + base::RunLoop run_loop; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&CreateFileForTestingOnIOThread, - base::Unretained(context), - path, temp_file, - base::Unretained(&result), - base::Unretained(&done_event))); + base::Bind(&CreateFileForTestingOnIOThread, base::Unretained(context), + path, temp_file, base::Unretained(&result), + run_loop.QuitClosure())); // Wait for that to finish. - done_event.Wait(); + run_loop.Run(); base::DeleteFile(temp_file, false); return result; } private: static void CopyInCompletion(bool* result, - base::WaitableEvent* done_event, + const base::Closure& quit_closure, base::File::Error error) { DCHECK_CURRENTLY_ON(BrowserThread::IO); *result = error == base::File::FILE_OK; - done_event->Signal(); + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_closure); } static void CreateFileForTestingOnIOThread( @@ -733,13 +729,11 @@ const storage::FileSystemURL& path, const base::FilePath& temp_file, bool* result, - base::WaitableEvent* done_event) { + const base::Closure& quit_closure) { DCHECK_CURRENTLY_ON(BrowserThread::IO); context->operation_runner()->CopyInForeignFile( temp_file, path, - base::Bind(&CopyInCompletion, - base::Unretained(result), - base::Unretained(done_event))); + base::Bind(&CopyInCompletion, base::Unretained(result), quit_closure)); } };
diff --git a/chrome/browser/extensions/api/sync_file_system/sync_file_system_apitest.cc b/chrome/browser/extensions/api/sync_file_system/sync_file_system_apitest.cc index 1ee2199..18b1bf3 100644 --- a/chrome/browser/extensions/api/sync_file_system/sync_file_system_apitest.cc +++ b/chrome/browser/extensions/api/sync_file_system/sync_file_system_apitest.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/sync_file_system/sync_status_code.h" #include "chrome/browser/sync_file_system/syncable_file_system_util.h" #include "chrome/test/base/test_switches.h" +#include "content/public/browser/storage_partition.h" #include "extensions/browser/extension_function.h" #include "storage/browser/fileapi/file_system_url.h" #include "storage/browser/quota/quota_manager.h" @@ -40,16 +41,11 @@ public: SyncFileSystemApiTest() : mock_remote_service_(NULL), - real_minimum_preserved_space_(0), real_default_quota_(0) {} void SetUpInProcessBrowserTestFixture() override { ExtensionApiTest::SetUpInProcessBrowserTestFixture(); - real_minimum_preserved_space_ = - storage::QuotaManager::kMinimumPreserveForSystem; - storage::QuotaManager::kMinimumPreserveForSystem = 0; - // TODO(calvinlo): Update test code after default quota is made const // (http://crbug.com/155488). real_default_quota_ = @@ -58,8 +54,6 @@ } void TearDownInProcessBrowserTestFixture() override { - storage::QuotaManager::kMinimumPreserveForSystem = - real_minimum_preserved_space_; storage::QuotaManager::kSyncableStorageDefaultHostQuota = real_default_quota_; ExtensionApiTest::TearDownInProcessBrowserTestFixture(); @@ -81,7 +75,6 @@ private: ::testing::NiceMock<MockRemoteFileSyncService>* mock_remote_service_; - int64_t real_minimum_preserved_space_; int64_t real_default_quota_; };
diff --git a/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc b/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc index 549b4aaa..0e13258 100644 --- a/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc +++ b/chrome/browser/extensions/api/sync_file_system/sync_file_system_browsertest.cc
@@ -18,6 +18,7 @@ #include "chrome/browser/sync_file_system/sync_file_system_service.h" #include "chrome/browser/sync_file_system/sync_file_system_service_factory.h" #include "components/drive/service/fake_drive_service.h" +#include "content/public/browser/storage_partition.h" #include "extensions/test/extension_test_message_listener.h" #include "extensions/test/result_catcher.h" #include "storage/browser/quota/quota_manager.h" @@ -61,19 +62,6 @@ : remote_service_(NULL) { } - void SetUpInProcessBrowserTestFixture() override { - ExtensionApiTest::SetUpInProcessBrowserTestFixture(); - real_minimum_preserved_space_ = - storage::QuotaManager::kMinimumPreserveForSystem; - storage::QuotaManager::kMinimumPreserveForSystem = 0; - } - - void TearDownInProcessBrowserTestFixture() override { - storage::QuotaManager::kMinimumPreserveForSystem = - real_minimum_preserved_space_; - ExtensionApiTest::TearDownInProcessBrowserTestFixture(); - } - scoped_refptr<base::SequencedTaskRunner> MakeSequencedTaskRunner() { scoped_refptr<base::SequencedWorkerPool> worker_pool = content::BrowserThread::GetBlockingPool(); @@ -157,8 +145,6 @@ drive_backend::SyncEngine* remote_service_; - int64_t real_minimum_preserved_space_; - DISALLOW_COPY_AND_ASSIGN(SyncFileSystemTest); };
diff --git a/chrome/browser/extensions/extension_special_storage_policy.cc b/chrome/browser/extensions/extension_special_storage_policy.cc index 2abb046..331c9a3 100644 --- a/chrome/browser/extensions/extension_special_storage_policy.cc +++ b/chrome/browser/extensions/extension_special_storage_policy.cc
@@ -114,11 +114,6 @@ return cookie_settings_->IsCookieSessionOnly(origin); } -bool ExtensionSpecialStoragePolicy::CanQueryDiskSize(const GURL& origin) { - base::AutoLock locker(lock_); - return installed_apps_.Contains(origin); -} - bool ExtensionSpecialStoragePolicy::HasSessionOnlyOrigins() { if (cookie_settings_.get() == NULL) return false; @@ -177,9 +172,6 @@ extension->is_app()) { if (NeedsProtection(extension) && protected_apps_.Add(extension)) change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED; - // FIXME: Does GrantRightsForExtension imply |extension| is installed? - if (extension->is_app()) - installed_apps_.Add(extension); if (extension->permissions_data()->HasAPIPermission( APIPermission::kUnlimitedStorage) && @@ -225,9 +217,6 @@ if (NeedsProtection(extension) && protected_apps_.Remove(extension)) change_flags |= SpecialStoragePolicy::STORAGE_PROTECTED; - if (extension->is_app()) - installed_apps_.Remove(extension); - if (extension->permissions_data()->HasAPIPermission( APIPermission::kUnlimitedStorage) && unlimited_extensions_.Remove(extension)) @@ -251,7 +240,6 @@ { base::AutoLock locker(lock_); protected_apps_.Clear(); - installed_apps_.Clear(); unlimited_extensions_.Clear(); file_handler_extensions_.Clear(); isolated_extensions_.Clear();
diff --git a/chrome/browser/extensions/extension_special_storage_policy.h b/chrome/browser/extensions/extension_special_storage_policy.h index 5f4ffbb..cce5b043 100644 --- a/chrome/browser/extensions/extension_special_storage_policy.h +++ b/chrome/browser/extensions/extension_special_storage_policy.h
@@ -39,7 +39,6 @@ bool IsStorageProtected(const GURL& origin) override; bool IsStorageUnlimited(const GURL& origin) override; bool IsStorageSessionOnly(const GURL& origin) override; - bool CanQueryDiskSize(const GURL& origin) override; bool HasIsolatedStorage(const GURL& origin) override; bool HasSessionOnlyOrigins() override; bool IsStorageDurable(const GURL& origin) override; @@ -88,7 +87,6 @@ base::Lock lock_; // Synchronize all access to the collections. SpecialCollection protected_apps_; - SpecialCollection installed_apps_; SpecialCollection unlimited_extensions_; SpecialCollection file_handler_extensions_; SpecialCollection isolated_extensions_;
diff --git a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc index b25b31f..1916e30 100644 --- a/chrome/browser/extensions/extension_special_storage_policy_unittest.cc +++ b/chrome/browser/extensions/extension_special_storage_policy_unittest.cc
@@ -251,23 +251,6 @@ EXPECT_FALSE(policy_->IsStorageUnlimited(GURL("https://bar.wildcards/"))); } -TEST_F(ExtensionSpecialStoragePolicyTest, CanQueryDiskSize) { - const GURL kHttpUrl("http://foo"); - const GURL kExtensionUrl("chrome-extension://bar"); - scoped_refptr<Extension> regular_app(CreateRegularApp()); - scoped_refptr<Extension> protected_app(CreateProtectedApp()); - scoped_refptr<Extension> unlimited_app(CreateUnlimitedApp()); - policy_->GrantRightsForExtension(regular_app.get(), NULL); - policy_->GrantRightsForExtension(protected_app.get(), NULL); - policy_->GrantRightsForExtension(unlimited_app.get(), NULL); - - EXPECT_FALSE(policy_->CanQueryDiskSize(kHttpUrl)); - EXPECT_FALSE(policy_->CanQueryDiskSize(kExtensionUrl)); - EXPECT_TRUE(policy_->CanQueryDiskSize(regular_app->url())); - EXPECT_TRUE(policy_->CanQueryDiskSize(protected_app->url())); - EXPECT_TRUE(policy_->CanQueryDiskSize(unlimited_app->url())); -} - TEST_F(ExtensionSpecialStoragePolicyTest, HasIsolatedStorage) { const GURL kHttpUrl("http://foo"); const GURL kExtensionUrl("chrome-extension://bar");
diff --git a/chrome/browser/extensions/extension_storage_monitor.cc b/chrome/browser/extensions/extension_storage_monitor.cc index 7294fbd4..81394f5 100644 --- a/chrome/browser/extensions/extension_storage_monitor.cc +++ b/chrome/browser/extensions/extension_storage_monitor.cc
@@ -84,17 +84,16 @@ extension_id, ExtensionRegistry::EVERYTHING); } -void LogTemporaryStorageUsage(int64_t usage, - storage::QuotaStatusCode status, - int64_t global_quota) { - if (status == storage::kQuotaStatusOk) { - int64_t per_app_quota = - global_quota / storage::QuotaManager::kPerHostTemporaryPortion; +void LogTemporaryStorageUsage( + scoped_refptr<storage::QuotaManager> quota_manager, + int64_t usage) { + const storage::QuotaSettings& settings = quota_manager->settings(); + if (settings.per_host_quota > 0) { // Note we use COUNTS_100 (instead of PERCENT) because this can potentially // exceed 100%. UMA_HISTOGRAM_COUNTS_100( "Extensions.HostedAppUnlimitedStorageTemporaryStorageUsage", - 100.0 * usage / per_app_quota); + 100.0 * usage / settings.per_host_quota); } } @@ -235,12 +234,9 @@ } else { // We can't use the quota in the event because it assumes unlimited // storage. - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&storage::QuotaManager::GetTemporaryGlobalQuota, - state.quota_manager, - base::Bind(&LogTemporaryStorageUsage, event.usage))); + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&LogTemporaryStorageUsage, + state.quota_manager, event.usage)); } }
diff --git a/chrome/browser/extensions/mock_extension_special_storage_policy.cc b/chrome/browser/extensions/mock_extension_special_storage_policy.cc index d4d609b..ca32e2d 100644 --- a/chrome/browser/extensions/mock_extension_special_storage_policy.cc +++ b/chrome/browser/extensions/mock_extension_special_storage_policy.cc
@@ -20,10 +20,6 @@ return false; } -bool MockExtensionSpecialStoragePolicy::CanQueryDiskSize(const GURL& origin) { - return false; -} - bool MockExtensionSpecialStoragePolicy::HasSessionOnlyOrigins() { return false; }
diff --git a/chrome/browser/extensions/mock_extension_special_storage_policy.h b/chrome/browser/extensions/mock_extension_special_storage_policy.h index edc142e7..f25676de 100644 --- a/chrome/browser/extensions/mock_extension_special_storage_policy.h +++ b/chrome/browser/extensions/mock_extension_special_storage_policy.h
@@ -23,7 +23,6 @@ bool IsStorageProtected(const GURL& origin) override; bool IsStorageUnlimited(const GURL& origin) override; bool IsStorageSessionOnly(const GURL& origin) override; - bool CanQueryDiskSize(const GURL& origin) override; bool HasSessionOnlyOrigins() override; void AddProtected(const GURL& origin) {
diff --git a/chrome/browser/recovery/recovery_install_global_error.cc b/chrome/browser/recovery/recovery_install_global_error.cc index 8e2964a..0b4d55b 100644 --- a/chrome/browser/recovery/recovery_install_global_error.cc +++ b/chrome/browser/recovery/recovery_install_global_error.cc
@@ -14,10 +14,11 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "chrome/grit/chromium_strings.h" -#include "chrome/grit/theme_resources.h" #include "components/prefs/pref_service.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/paint_vector_icon.h" +#include "ui/gfx/vector_icons_public.h" +#include "ui/native_theme/native_theme.h" RecoveryInstallGlobalError::RecoveryInstallGlobalError(Profile* profile) : elevation_needed_(false), @@ -43,8 +44,7 @@ base::Unretained(this))); } -RecoveryInstallGlobalError::~RecoveryInstallGlobalError() { -} +RecoveryInstallGlobalError::~RecoveryInstallGlobalError() {} void RecoveryInstallGlobalError::Shutdown() { GlobalErrorServiceFactory::GetForProfile(profile_)->RemoveUnownedGlobalError( @@ -68,8 +68,10 @@ } gfx::Image RecoveryInstallGlobalError::MenuItemIcon() { - return ResourceBundle::GetSharedInstance().GetNativeImageNamed( - IDR_UPDATE_MENU_SEVERITY_HIGH); + return gfx::Image(gfx::CreateVectorIcon( + gfx::VectorIconId::BROWSER_TOOLS_UPDATE, + ui::NativeTheme::GetInstanceForNativeUi()->GetSystemColor( + ui::NativeTheme::kColorId_AlertSeverityHigh))); } void RecoveryInstallGlobalError::ExecuteMenuItem(Browser* browser) { @@ -94,8 +96,9 @@ } gfx::Image RecoveryInstallGlobalError::GetBubbleViewIcon() { - return ResourceBundle::GetSharedInstance().GetNativeImageNamed( - IDR_UPDATE_MENU_SEVERITY_HIGH); + // TODO(estade): there shouldn't be an icon in the bubble, but + // GlobalErrorBubbleView currently requires it. See crbug.com/673995 + return MenuItemIcon(); } base::string16 RecoveryInstallGlobalError::GetBubbleViewTitle() {
diff --git a/chrome/browser/resources/settings/advanced_page/advanced_page.html b/chrome/browser/resources/settings/advanced_page/advanced_page.html deleted file mode 100644 index 45db38c..0000000 --- a/chrome/browser/resources/settings/advanced_page/advanced_page.html +++ /dev/null
@@ -1,104 +0,0 @@ -<link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="/a11y_page/a11y_page.html"> -<link rel="import" href="/downloads_page/downloads_page.html"> -<link rel="import" href="/languages_page/languages_page.html"> -<link rel="import" href="/passwords_and_forms_page/passwords_and_forms_page.html"> -<link rel="import" href="/printing_page/printing_page.html"> -<link rel="import" href="/privacy_page/privacy_page.html"> -<link rel="import" href="/reset_page/reset_page.html"> -<link rel="import" href="/settings_page/main_page_behavior.html"> -<link rel="import" href="/settings_page/settings_page_visibility.html"> -<link rel="import" href="/settings_page/settings_section.html"> -<link rel="import" href="/settings_page_css.html"> - -<if expr="chromeos"> -<link rel="import" href="/bluetooth_page/bluetooth_page.html"> -<link rel="import" href="/date_time_page/date_time_page.html"> -</if> - -<if expr="not chromeos"> -<link rel="import" href="/system_page/system_page.html"> -</if> - -<dom-module id="settings-advanced-page"> - <template> - <style include="settings-page-styles"></style> - <div> -<if expr="chromeos"> - <template is="dom-if" if="[[showPage(pageVisibility.dateTime)]]" restamp> - <settings-section page-title="$i18n{dateTimePageTitle}" - section="dateTime"> - <settings-date-time-page prefs="{{prefs}}" - page-visibility="[[pageVisibility.dateTime]]"> - </settings-date-time-page> - </settings-section> - </template> -</if> - <template is="dom-if" if="[[showPage(pageVisibility.privacy)]]" restamp> - <settings-section page-title="$i18n{privacyPageTitle}" - section="privacy"> - <settings-privacy-page prefs="{{prefs}}" - page-visibility="[[pageVisibility.privacy]]"> - </settings-privacy-page> - </settings-section> - </template> -<if expr="chromeos"> - <template is="dom-if" if="[[showPage(pageVisibility.bluetooth)]]" restamp> - <settings-section page-title="$i18n{bluetoothPageTitle}" - section="bluetooth"> - <settings-bluetooth-page prefs="{{prefs}}"></settings-bluetooth-page> - </settings-section> - </template> -</if> - <template is="dom-if" if="[[showPage(pageVisibility.passwordsAndForms)]]" - restamp> - <settings-section - page-title="$i18n{passwordsAndAutofillPageTitle}" - section="passwordsAndForms"> - <settings-passwords-and-forms-page prefs="{{prefs}}"> - </settings-passwords-and-forms-page> - </settings-section> - </template> - <template is="dom-if" if="[[showPage(pageVisibility.languages)]]" restamp> - <settings-section page-title="$i18n{languagesPageTitle}" - section="languages"> - <settings-languages-page prefs="{{prefs}}"></settings-languages-page> - </settings-section> - </template> - <template is="dom-if" if="[[showPage(pageVisibility.downloads)]]" restamp> - <settings-section page-title="$i18n{downloadsPageTitle}" - section="downloads"> - <settings-downloads-page prefs="{{prefs}}" - page-visibility="[[pageVisibility.downloads]]"> - </settings-downloads-page> - </settings-section> - </template> - <template is="dom-if" if="[[showPage(pageVisibility.printing)]]" restamp> - <settings-section page-title="$i18n{printingPageTitle}" - section="printing"> - <settings-printing-page prefs="{{prefs}}"></settings-printing-page> - </settings-section> - </template> - <template is="dom-if" if="[[showPage(pageVisibility.a11y)]]" restamp> - <settings-section page-title="$i18n{a11yPageTitle}" section="a11y"> - <settings-a11y-page prefs="{{prefs}}" - current-route="{{currentRoute}}"> - </settings-a11y-page> - </settings-section> - </template> -<if expr="not chromeos"> - <template is="dom-if" if="[[showPage(pageVisibility.system)]]" restamp> - <settings-section page-title="$i18n{systemPageTitle}" section="system"> - <settings-system-page prefs="{{prefs}}"></settings-system-page> - </settings-section> - </template> -</if> - <template is="dom-if" if="[[showPage(pageVisibility.reset)]]" restamp> - <settings-section page-title="$i18n{resetPageTitle}" section="reset"> - <settings-reset-page></settings-reset-page> - </settings-section> - </template> - </div> - </template> - <script src="/advanced_page/advanced_page.js"></script> -</dom-module>
diff --git a/chrome/browser/resources/settings/advanced_page/advanced_page.js b/chrome/browser/resources/settings/advanced_page/advanced_page.js deleted file mode 100644 index 336b5f4..0000000 --- a/chrome/browser/resources/settings/advanced_page/advanced_page.js +++ /dev/null
@@ -1,22 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview - * 'settings-advanced-page' is the settings page containing the advanced - * settings. - */ -Polymer({ - is: 'settings-advanced-page', - - behaviors: [SettingsPageVisibility, MainPageBehavior], - - properties: { - /** Preferences state. */ - prefs: { - type: Object, - notify: true, - }, - }, -});
diff --git a/chrome/browser/resources/settings/advanced_page/compiled_resources2.gyp b/chrome/browser/resources/settings/advanced_page/compiled_resources2.gyp deleted file mode 100644 index 36f8252..0000000 --- a/chrome/browser/resources/settings/advanced_page/compiled_resources2.gyp +++ /dev/null
@@ -1,17 +0,0 @@ -# Copyright 2016 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -{ - 'targets': [ - { - 'target_name': 'advanced_page', - 'dependencies': [ - '../compiled_resources2.gyp:route', - '../settings_page/compiled_resources2.gyp:main_page_behavior', - '../settings_page/compiled_resources2.gyp:settings_page_visibility', - '../system_page/compiled_resources2.gyp:system_page', - ], - 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], - }, - ], -}
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html index 73b5e03..817b967d 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.html +++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -1,94 +1,252 @@ <link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="/a11y_page/a11y_page.html"> <link rel="import" href="/appearance_page/appearance_page.html"> +<link rel="import" href="/downloads_page/downloads_page.html"> +<link rel="import" href="/languages_page/languages_page.html"> +<link rel="import" href="/on_startup_page/on_startup_page.html"> +<link rel="import" href="/passwords_and_forms_page/passwords_and_forms_page.html"> +<link rel="import" href="/people_page/people_page.html"> +<link rel="import" href="/printing_page/printing_page.html"> +<link rel="import" href="/privacy_page/privacy_page.html"> +<link rel="import" href="/reset_page/reset_page.html"> +<link rel="import" href="/reset_page/reset_profile_banner.html"> <link rel="import" href="/search_page/search_page.html"> <link rel="import" href="/settings_page/main_page_behavior.html"> <link rel="import" href="/settings_page/settings_page_visibility.html"> <link rel="import" href="/settings_page/settings_section.html"> -<link rel="import" href="/on_startup_page/on_startup_page.html"> -<link rel="import" href="/people_page/people_page.html"> -<link rel="import" href="/reset_page/reset_profile_banner.html"> <link rel="import" href="/settings_page_css.html"> +<link rel="import" href="/settings_vars_css.html"> <if expr="chromeos"> <link rel="import" href="/android_apps_page/android_apps_page.html"> +<link rel="import" href="/bluetooth_page/bluetooth_page.html"> +<link rel="import" href="/date_time_page/date_time_page.html"> <link rel="import" href="/device_page/device_page.html"> <link rel="import" href="/internet_page/internet_page.html"> </if> <if expr="not chromeos"> <link rel="import" href="/default_browser_page/default_browser_page.html"> +<link rel="import" href="/system_page/system_page.html"> </if> +<!-- TODO(michaelpg): Rename to something better than "basic" now that this page + includes both the basic and advanced settings. --> <dom-module id="settings-basic-page"> <template> - <style include="settings-page-styles"></style> - <div> - <template is="dom-if" if="[[showResetProfileBanner_]]"> - <settings-reset-profile-banner on-reset-done="onResetDone_"> - </settings-reset-profile-banner> - </template> + <style include="settings-page-styles"> + #advancedToggle { + --paper-button: { + text-transform: none; + } + @apply(--settings-actionable); + align-items: center; + display: flex; + margin-bottom: 3px; + margin-top: 12px; /* Part of a 48px spacer (33px + 12px + 3px). */ + min-height: 32px; + padding: 0 12px; + } + + #toggleContainer { + align-items: center; + display: flex; + font: inherit; + justify-content: center; + margin-bottom: 0; + margin-top: 0; + } + + #toggleSpacer { + padding-top: 33px; /* Part of a 48px spacer (33px + 12px + 3px). */ + } + + iron-icon { + -webkit-margin-start: 16px; + } + </style> + <template is="dom-if" if="[[showBasicPage_( + currentRoute_, inSearchMode, hasExpandedSection_)]]"> + <div id="basicPage"> + <template is="dom-if" if="[[showResetProfileBanner_]]"> + <settings-reset-profile-banner on-reset-done="onResetDone_"> + </settings-reset-profile-banner> + </template> <if expr="chromeos"> - <template is="dom-if" if="[[showPage(pageVisibility.internet)]]" restamp> - <settings-section page-title="$i18n{internetPageTitle}" - section="internet"> - <settings-internet-page prefs="{{prefs}}"> - </settings-internet-page> - </settings-section> - </template> + <template is="dom-if" if="[[showPage(pageVisibility.internet)]]" + restamp> + <settings-section page-title="$i18n{internetPageTitle}" + section="internet"> + <settings-internet-page prefs="{{prefs}}"> + </settings-internet-page> + </settings-section> + </template> </if> - <template is="dom-if" if="[[showPage(pageVisibility.people)]]" restamp> - <settings-section page-title="$i18n{peoplePageTitle}" section="people"> - <settings-people-page prefs="{{prefs}}"></settings-people-page> - </settings-section> - </template> - <template is="dom-if" if="[[showPage(pageVisibility.appearance)]]" - restamp> - <settings-section page-title="$i18n{appearancePageTitle}" - section="appearance"> - <settings-appearance-page prefs="{{prefs}}" - page-visibility="[[pageVisibility.appearance]]"> - </settings-appearance-page> - </settings-section> - </template> + <template is="dom-if" if="[[showPage(pageVisibility.people)]]" restamp> + <settings-section page-title="$i18n{peoplePageTitle}" + section="people"> + <settings-people-page prefs="{{prefs}}"></settings-people-page> + </settings-section> + </template> + <template is="dom-if" if="[[showPage(pageVisibility.appearance)]]" + restamp> + <settings-section page-title="$i18n{appearancePageTitle}" + section="appearance"> + <settings-appearance-page prefs="{{prefs}}" + page-visibility="[[pageVisibility.appearance]]"> + </settings-appearance-page> + </settings-section> + </template> <if expr="chromeos"> - <template is="dom-if" if="[[showPage(pageVisibility.device)]]" restamp> - <settings-section page-title="$i18n{devicePageTitle}" section="device"> - <settings-device-page prefs="{{prefs}}"></settings-device-page> - </settings-section> - </template> + <template is="dom-if" if="[[showPage(pageVisibility.device)]]" restamp> + <settings-section page-title="$i18n{devicePageTitle}" + section="device"> + <settings-device-page prefs="{{prefs}}"></settings-device-page> + </settings-section> + </template> </if> - <template is="dom-if" if="[[showPage(pageVisibility.search)]]" restamp> - <settings-section page-title="$i18n{searchPageTitle}" section="search"> - <settings-search-page prefs="[[prefs]]"></settings-search-page> - </settings-section> - </template> + <template is="dom-if" if="[[showPage(pageVisibility.search)]]" restamp> + <settings-section page-title="$i18n{searchPageTitle}" section="search"> + <settings-search-page prefs="[[prefs]]"></settings-search-page> + </settings-section> + </template> <if expr="chromeos"> - <template is="dom-if" - if="[[shouldShowAndroidApps_(showAndroidApps, pageVisibility)]]" - restamp> - <settings-section page-title="$i18n{androidAppsPageTitle}" - section="androidApps"> - <settings-android-apps-page prefs="{{prefs}}"> - </settings-android-apps-page> - </settings-section> - </template> + <template is="dom-if" + if="[[shouldShowAndroidApps_(showAndroidApps, pageVisibility)]]" + restamp> + <settings-section page-title="$i18n{androidAppsPageTitle}" + section="androidApps"> + <settings-android-apps-page prefs="{{prefs}}"> + </settings-android-apps-page> + </settings-section> + </template> </if> <if expr="not chromeos"> - <template is="dom-if" if="[[showPage(pageVisibility.defaultBrowser)]]" - restamp> - <settings-section page-title="$i18n{defaultBrowser}" - section="defaultBrowser"> - <settings-default-browser-page></settings-default-browser-page> - </settings-section> - </template> + <template is="dom-if" if="[[showPage(pageVisibility.defaultBrowser)]]" + restamp> + <settings-section page-title="$i18n{defaultBrowser}" + section="defaultBrowser"> + <settings-default-browser-page></settings-default-browser-page> + </settings-section> + </template> </if> - <template is="dom-if" if="[[showPage(pageVisibility.onStartup)]]" restamp> - <settings-section page-title="$i18n{onStartup}" section="onStartup"> - <settings-on-startup-page prefs="{{prefs}}"> - </settings-on-startup-page> - </settings-section> + <template is="dom-if" if="[[showPage(pageVisibility.onStartup)]]" + restamp> + <settings-section page-title="$i18n{onStartup}" section="onStartup"> + <settings-on-startup-page prefs="{{prefs}}"> + </settings-on-startup-page> + </settings-section> + </template> + </div> + </template> + + <template is="dom-if" + if="[[showAdvancedSettings_(pageVisibility.advancedSettings)]]"> + <template is="dom-if" if="[[showAdvancedToggle_( + inSearchMode, hasExpandedSection_)]]"> + <div id="toggleSpacer"></div> + <h2 id="toggleContainer"> + <paper-button id="advancedToggle" active="{{advancedToggleExpanded}}" + aria-active-attribute="aria-expanded" toggles> + <span>$i18n{advancedPageTitle}</span> + <iron-icon icon="[[getArrowIcon_(advancedToggleExpanded)]]"> + </iron-icon> + </paper-button> + </h2> </template> - </div> + + <template is="dom-if" if="[[showAdvancedPage_( + currentRoute_, inSearchMode, hasExpandedSection_, + advancedToggleExpanded)]]"> + <div id="advancedPage"> +<if expr="chromeos"> + <template is="dom-if" if="[[showPage(pageVisibility.dateTime)]]" + restamp> + <settings-section page-title="$i18n{dateTimePageTitle}" + section="dateTime"> + <settings-date-time-page prefs="{{prefs}}" + page-visibility="[[pageVisibility.dateTime]]"> + </settings-date-time-page> + </settings-section> + </template> +</if> + <template is="dom-if" if="[[showPage(pageVisibility.privacy)]]" + restamp> + <settings-section page-title="$i18n{privacyPageTitle}" + section="privacy"> + <settings-privacy-page prefs="{{prefs}}" + page-visibility="[[pageVisibility.privacy]]"> + </settings-privacy-page> + </settings-section> + </template> +<if expr="chromeos"> + <template is="dom-if" if="[[showPage(pageVisibility.bluetooth)]]" + restamp> + <settings-section page-title="$i18n{bluetoothPageTitle}" + section="bluetooth"> + <settings-bluetooth-page prefs="{{prefs}}"> + </settings-bluetooth-page> + </settings-section> + </template> +</if> + <template is="dom-if" + if="[[showPage(pageVisibility.passwordsAndForms)]]" restamp> + <settings-section + page-title="$i18n{passwordsAndAutofillPageTitle}" + section="passwordsAndForms"> + <settings-passwords-and-forms-page prefs="{{prefs}}"> + </settings-passwords-and-forms-page> + </settings-section> + </template> + <template is="dom-if" if="[[showPage(pageVisibility.languages)]]" + restamp> + <settings-section page-title="$i18n{languagesPageTitle}" + section="languages"> + <settings-languages-page prefs="{{prefs}}"> + </settings-languages-page> + </settings-section> + </template> + <template is="dom-if" if="[[showPage(pageVisibility.downloads)]]" + restamp> + <settings-section page-title="$i18n{downloadsPageTitle}" + section="downloads"> + <settings-downloads-page prefs="{{prefs}}" + page-visibility="[[pageVisibility.downloads]]"> + </settings-downloads-page> + </settings-section> + </template> + <template is="dom-if" if="[[showPage(pageVisibility.printing)]]" + restamp> + <settings-section page-title="$i18n{printingPageTitle}" + section="printing"> + <settings-printing-page prefs="{{prefs}}"> + </settings-printing-page> + </settings-section> + </template> + <template is="dom-if" if="[[showPage(pageVisibility.a11y)]]" restamp> + <settings-section page-title="$i18n{a11yPageTitle}" section="a11y"> + <settings-a11y-page prefs="{{prefs}}"></settings-a11y-page> + </settings-section> + </template> +<if expr="not chromeos"> + <template is="dom-if" if="[[showPage(pageVisibility.system)]]" + restamp> + <settings-section page-title="$i18n{systemPageTitle}" + section="system"> + <settings-system-page prefs="{{prefs}}"></settings-system-page> + </settings-section> + </template> +</if> + <template is="dom-if" if="[[showPage(pageVisibility.reset)]]" + restamp> + <settings-section page-title="$i18n{resetPageTitle}" + section="reset"> + <settings-reset-page></settings-reset-page> + </settings-section> + </template> + </div> + </template> + </template> </template> <script src="basic_page.js"></script> </dom-module>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.js b/chrome/browser/resources/settings/basic_page/basic_page.js index 873aa2d..dde5ade 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.js +++ b/chrome/browser/resources/settings/basic_page/basic_page.js
@@ -4,7 +4,7 @@ /** * @fileoverview - * 'settings-basic-page' is the settings page containing the basic settings. + * 'settings-basic-page' is the settings page containing the actual settings. */ Polymer({ is: 'settings-basic-page', @@ -21,6 +21,27 @@ showAndroidApps: Boolean, /** + * Dictionary defining page visibility. + * @type {!GuestModePageVisibility} + */ + pageVisibility: Object, + + advancedToggleExpanded: { + type: Boolean, + notify: true, + }, + + /** + * True if a section is fully expanded to hide other sections beneath it. + * False otherwise (even while animating a section open/closed). + * @private {boolean} + */ + hasExpandedSection_: { + type: Boolean, + value: false, + }, + + /** * True if the basic page should currently display the reset profile banner. * @private {boolean} */ @@ -30,6 +51,60 @@ return loadTimeData.getBoolean('showResetProfileBanner'); }, }, + + /** @private {!settings.Route|undefined} */ + currentRoute_: Object, + }, + + listeners: { + 'subpage-expand': 'onSubpageExpanded_', + }, + + /** @override */ + attached: function() { + this.currentRoute_ = settings.getCurrentRoute(); + }, + + /** + * Overrides MainPageBehaviorImpl from MainPageBehavior. + * @param {!settings.Route} newRoute + * @param {settings.Route} oldRoute + */ + currentRouteChanged: function(newRoute, oldRoute) { + this.currentRoute_ = newRoute; + + if (settings.Route.ADVANCED.contains(newRoute)) + this.advancedToggleExpanded = true; + + if (oldRoute && oldRoute.isSubpage()) { + // If the new route isn't the same expanded section, reset + // hasExpandedSection_ for the next transition. + if (!newRoute.isSubpage() || newRoute.section != oldRoute.section) + this.hasExpandedSection_ = false; + } else { + assert(!this.hasExpandedSection_); + } + + MainPageBehaviorImpl.currentRouteChanged.call(this, newRoute, oldRoute); + }, + + /** + * Queues a task to search the basic sections, then another for the advanced + * sections. + * @param {string} query The text to search for. + * @return {!Promise<!settings.SearchRequest>} A signal indicating that + * searching finished. + */ + searchContents: function(query) { + var whenSearchDone = settings.getSearchManager().search( + query, assert(this.$$('#basicPage'))); + + if (this.pageVisibility.advancedSettings !== false) { + assert(whenSearchDone === settings.getSearchManager().search( + query, assert(this.$$('#advancedPage')))); + } + + return whenSearchDone; }, /** @private */ @@ -46,4 +121,68 @@ this.get('pageVisibility.androidApps')); return this.showAndroidApps && this.showPage(visibility); }, + + /** + * Hides everything but the newly expanded subpage. + * @private + */ + onSubpageExpanded_: function() { + this.hasExpandedSection_ = true; + }, + + /** + * @param {boolean} inSearchMode + * @param {boolean} hasExpandedSection + * @return {boolean} + * @private + */ + showAdvancedToggle_: function(inSearchMode, hasExpandedSection) { + return !inSearchMode && !hasExpandedSection; + }, + + /** + * @param {!settings.Route} currentRoute + * @param {boolean} inSearchMode + * @param {boolean} hasExpandedSection + * @return {boolean} Whether to show the basic page, taking into account + * both routing and search state. + * @private + */ + showBasicPage_: function(currentRoute, inSearchMode, hasExpandedSection) { + return !hasExpandedSection || settings.Route.BASIC.contains(currentRoute); + }, + + /** + * @param {!settings.Route} currentRoute + * @param {boolean} inSearchMode + * @param {boolean} hasExpandedSection + * @param {boolean} advancedToggleExpanded + * @return {boolean} Whether to show the advanced page, taking into account + * both routing and search state. + * @private + */ + showAdvancedPage_: function(currentRoute, inSearchMode, hasExpandedSection, + advancedToggleExpanded) { + return hasExpandedSection ? + settings.Route.ADVANCED.contains(currentRoute) : + advancedToggleExpanded || inSearchMode; + }, + + /** + * @param {(boolean|undefined)} visibility + * @return {boolean} True unless visibility is false. + * @private + */ + showAdvancedSettings_: function(visibility) { + return visibility !== false; + }, + + /** + * @param {boolean} opened Whether the menu is expanded. + * @return {string} Icon name. + * @private + */ + getArrowIcon_: function(opened) { + return opened ? 'settings:arrow-drop-up' : 'cr:arrow-drop-down'; + }, });
diff --git a/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp b/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp index c5fc14019..7a9b9ff0 100644 --- a/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp +++ b/chrome/browser/resources/settings/basic_page/compiled_resources2.gyp
@@ -8,8 +8,10 @@ 'dependencies': [ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', '../compiled_resources2.gyp:route', + '../compiled_resources2.gyp:search_settings', '../settings_page/compiled_resources2.gyp:main_page_behavior', '../settings_page/compiled_resources2.gyp:settings_page_visibility', + '../settings_ui/compiled_resources2.gyp:settings_ui_types', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], },
diff --git a/chrome/browser/resources/settings/compiled_resources2.gyp b/chrome/browser/resources/settings/compiled_resources2.gyp index 74bb172d..c342b40 100644 --- a/chrome/browser/resources/settings/compiled_resources2.gyp +++ b/chrome/browser/resources/settings/compiled_resources2.gyp
@@ -57,7 +57,6 @@ 'dependencies': [ 'a11y_page/compiled_resources2.gyp:*', 'about_page/compiled_resources2.gyp:*', - 'advanced_page/compiled_resources2.gyp:*', 'android_apps_page/compiled_resources2.gyp:*', 'animation/compiled_resources2.gyp:*', 'appearance_page/compiled_resources2.gyp:*',
diff --git a/chrome/browser/resources/settings/search_settings.js b/chrome/browser/resources/settings/search_settings.js index d349f922..942d436 100644 --- a/chrome/browser/resources/settings/search_settings.js +++ b/chrome/browser/resources/settings/search_settings.js
@@ -362,8 +362,8 @@ * @private */ setSectionsVisibility_: function(visible) { - var sections = Polymer.dom( - this.node.root).querySelectorAll('settings-section'); + var sections = this.node.querySelectorAll('settings-section'); + for (var i = 0; i < sections.length; i++) sections[i].hiddenBySearch = !visible; },
diff --git a/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp b/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp index 658e968e..2efdb052 100644 --- a/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp +++ b/chrome/browser/resources/settings/settings_main/compiled_resources2.gyp
@@ -9,7 +9,6 @@ '../compiled_resources2.gyp:route', '../compiled_resources2.gyp:search_settings', '../about_page/compiled_resources2.gyp:about_page', - '../advanced_page/compiled_resources2.gyp:advanced_page', '../basic_page/compiled_resources2.gyp:basic_page', '../settings_page/compiled_resources2.gyp:main_page_behavior', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.html b/chrome/browser/resources/settings/settings_main/settings_main.html index 3a336106..3023de7 100644 --- a/chrome/browser/resources/settings/settings_main/settings_main.html +++ b/chrome/browser/resources/settings/settings_main/settings_main.html
@@ -4,49 +4,17 @@ <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="/about_page/about_page.html"> -<link rel="import" href="/advanced_page/advanced_page.html"> <link rel="import" href="/basic_page/basic_page.html"> <link rel="import" href="/route.html"> -<link rel="import" href="/settings_page/main_page_behavior.html"> <link rel="import" href="/settings_vars_css.html"> <dom-module id="settings-main"> <template> <style> - #advancedToggle { - --paper-button: { - text-transform: none; - } - @apply(--settings-actionable); - align-items: center; - display: flex; - margin-bottom: 3px; - margin-top: 12px; /* Part of a 48px spacer (33px + 12px + 3px). */ - min-height: 32px; - padding: 0 12px; - } - #overscroll { margin-top: 64px; } - #toggleContainer { - align-items: center; - display: flex; - font: inherit; - justify-content: center; - margin-bottom: 0; - margin-top: 0; - } - - #toggleSpacer { - padding-top: 33px; /* Part of a 48px spacer (33px + 12px + 3px). */ - } - - iron-icon { - -webkit-margin-start: 16px; - } - #noSearchResults { align-items: center; display: flex; @@ -64,38 +32,15 @@ <div>$i18n{searchNoResults}</div> <div>$i18nRaw{searchNoResultsHelp}</div> </div> - <template is="dom-if" if="[[showBasicPage_( - showPages_.basic, inSearchMode_, hasExpandedSection_)]]"> + <template is="dom-if" if="[[showPages_.settings]]"> <settings-basic-page prefs="{{prefs}}" page-visibility="[[pageVisibility]]" show-android-apps="[[showAndroidApps]]" on-subpage-expand="onSubpageExpand_" - in-search-mode="[[inSearchMode_]]"> + in-search-mode="[[inSearchMode_]]" + advanced-toggle-expanded="{{advancedToggleExpanded}}"> </settings-basic-page> </template> - <template is="dom-if" - if="[[showAdvancedSettings_(pageVisibility.advancedSettings)]]"> - <template is="dom-if" if="[[showAdvancedToggle_( - showPages_.basic, hasExpandedSection_, inSearchMode_)]]"> - <div id="toggleSpacer"></div> - <h2 id="toggleContainer"> - <paper-button id="advancedToggle" active="{{advancedToggleExpanded}}" - aria-active-attribute="aria-expanded" toggles> - <span>$i18n{advancedPageTitle}</span> - <iron-icon icon="[[arrowState_(advancedToggleExpanded)]]"> - </iron-icon> - </paper-button> - </h2> - </template> - <template is="dom-if" if="[[showAdvancedPage_( - showPages_.advanced, inSearchMode_, hasExpandedSection_)]]"> - <settings-advanced-page prefs="{{prefs}}" - page-visibility="[[pageVisibility]]" - on-subpage-expand="onSubpageExpand_" - in-search-mode="[[inSearchMode_]]"> - </settings-advanced-page> - </template> - </template> <template is="dom-if" if="[[showPages_.about]]"> <settings-about-page in-search-mode="[[inSearchMode_]]"> </settings-about-page>
diff --git a/chrome/browser/resources/settings/settings_main/settings_main.js b/chrome/browser/resources/settings/settings_main/settings_main.js index b5f524a..51bb5f4 100644 --- a/chrome/browser/resources/settings/settings_main/settings_main.js +++ b/chrome/browser/resources/settings/settings_main/settings_main.js
@@ -3,7 +3,7 @@ // found in the LICENSE file. /** - * @typedef {{about: boolean, basic: boolean, advanced: boolean}} + * @typedef {{about: boolean, settings: boolean}} */ var MainPageVisibility; @@ -28,16 +28,8 @@ advancedToggleExpanded: { type: Boolean, notify: true, - observer: 'updatePagesShown_', }, - /** - * True if a section is fully expanded to hide other sections beneath it. - * Not true otherwise (even while animating a section open/closed). - * @private - */ - hasExpandedSection_: Boolean, - /** @private */ overscroll_: { type: Number, @@ -46,13 +38,13 @@ /** * Controls which main pages are displayed via dom-ifs, based on the current - * route and the Advanced toggle state. + * route. * @private {!MainPageVisibility} */ showPages_: { type: Object, value: function() { - return {about: false, basic: false, advanced: false}; + return {about: false, settings: false}; }, }, @@ -93,8 +85,6 @@ /** @override */ attached: function() { this.listen(this, 'freeze-scroll', 'onFreezeScroll_'); - var currentRoute = settings.getCurrentRoute(); - this.hasExpandedSection_ = currentRoute && currentRoute.isSubpage(); }, /** @override */ @@ -162,84 +152,24 @@ } }, - /** - * @param {boolean} opened Whether the menu is expanded. - * @return {string} Which icon to use. - * @private - */ - arrowState_: function(opened) { - return opened ? 'settings:arrow-drop-up' : 'cr:arrow-drop-down'; - }, - - /** - * @return {boolean} - * @private - */ - showAdvancedToggle_: function() { - return !this.inSearchMode_ && this.showPages_.basic && - !this.hasExpandedSection_; - }, - - /** - * @return {boolean} Whether to show the basic page, taking into account both - * routing and search state. - * @private - */ - showBasicPage_: function() { - return this.showPages_.basic || ( - this.inSearchMode_ && !this.hasExpandedSection_); - }, - - /** - * @return {boolean} Whether to show the advanced page, taking into account - * both routing and search state. - * @private - */ - showAdvancedPage_: function() { - return this.showPages_.advanced || ( - this.inSearchMode_ && !this.hasExpandedSection_); - }, - /** @param {!settings.Route} newRoute */ currentRouteChanged: function(newRoute) { - // When the route changes from a sub-page to the main page, immediately - // update hasExpandedSection_ to unhide the other sections. - if (!newRoute.isSubpage()) - this.hasExpandedSection_ = false; - - if (settings.Route.ADVANCED.contains(newRoute)) - this.advancedToggleExpanded = true; - this.updatePagesShown_(); }, /** @private */ onSubpageExpand_: function() { - // The subpage finished expanding fully. Hide pages other than the current - // section's parent page. - this.hasExpandedSection_ = true; this.updatePagesShown_(); }, /** - * Updates the hidden state of the about, basic and advanced pages, based on - * the current route and the Advanced toggle state. + * Updates the hidden state of the about and settings pages based on the + * current route. * @private */ updatePagesShown_: function() { - var currentRoute = settings.getCurrentRoute(); - if (settings.Route.ABOUT.contains(currentRoute)) { - this.showPages_ = {about: true, basic: false, advanced: false}; - } else { - this.showPages_ = { - about: false, - basic: settings.Route.BASIC.contains(currentRoute) || - !this.hasExpandedSection_, - advanced: this.hasExpandedSection_ ? - settings.Route.ADVANCED.contains(currentRoute) : - this.advancedToggleExpanded, - }; - } + var inAbout = settings.Route.ABOUT.contains(settings.getCurrentRoute()); + this.showPages_ = {about: inAbout, settings: !inAbout}; // Calculate and set the overflow padding. this.updateOverscrollForPage_(); @@ -292,27 +222,18 @@ return Math.max(0, this.offsetParent.clientHeight - distance); }, - /** @private */ - toggleAdvancedPage_: function() { - this.advancedToggleExpanded = !this.advancedToggleExpanded; - }, - /** * Returns the root page (if it exists) for a route. * @param {!settings.Route} route - * @return {(?SettingsAboutPageElement|?SettingsAdvancedPageElement| - * ?SettingsBasicPageElement)} + * @return {(?SettingsAboutPageElement|?SettingsBasicPageElement)} */ getPage_: function(route) { if (settings.Route.ABOUT.contains(route)) { return /** @type {?SettingsAboutPageElement} */( this.$$('settings-about-page')); } - if (settings.Route.ADVANCED.contains(route)) { - return /** @type {?SettingsAdvancedPageElement} */( - this.$$('settings-advanced-page')); - } - if (settings.Route.BASIC.contains(route)) { + if (settings.Route.BASIC.contains(route) || + settings.Route.ADVANCED.contains(route)) { return /** @type {?SettingsBasicPageElement} */( this.$$('settings-basic-page')); } @@ -330,14 +251,8 @@ return new Promise(function(resolve, reject) { setTimeout(function() { - var whenSearchDone = settings.getSearchManager().search( - query, assert(this.getPage_(settings.Route.BASIC))); - - if (this.pageVisibility.advancedSettings !== false) { - assert(whenSearchDone === settings.getSearchManager().search( - query, assert(this.getPage_(settings.Route.ADVANCED)))); - } - + var whenSearchDone = + assert(this.getPage_(settings.Route.BASIC)).searchContents(query); whenSearchDone.then(function(request) { resolve(); if (!request.finished) { @@ -355,13 +270,4 @@ }.bind(this), 0); }.bind(this)); }, - - /** - * @param {(boolean|undefined)} visibility - * @return {boolean} True unless visibility is false. - * @private - */ - showAdvancedSettings_: function(visibility) { - return visibility !== false; - }, });
diff --git a/chrome/browser/resources/settings/settings_page/main_page_behavior.js b/chrome/browser/resources/settings/settings_page/main_page_behavior.js index fd15c75..0a51d833 100644 --- a/chrome/browser/resources/settings/settings_page/main_page_behavior.js +++ b/chrome/browser/resources/settings/settings_page/main_page_behavior.js
@@ -101,9 +101,6 @@ // If the section shouldn't be expanded, collapse it. if (!currentRoute.isSubpage() || expandedSection != currentSection) { promise = this.collapseSection_(expandedSection); - // Scroll to the collapsed section. - if (currentSection && scrollToSection) - currentSection.scrollIntoView(); } else { // Scroll to top while sliding to another subpage. this.scroller.scrollTop = 0; @@ -253,7 +250,11 @@ var newSection = settings.getCurrentRoute().section && this.getSection(settings.getCurrentRoute().section); - this.scroller.scrollTop = this.origScrollTop_; + // Scroll to the new section or the original position. + if (newSection && !settings.lastRouteChangeWasPopstate()) + newSection.scrollIntoView(); + else + this.scroller.scrollTop = this.origScrollTop_; this.currentAnimation_ = section.animateCollapse( /** @type {!HTMLElement} */(this.scroller));
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index 9062606e..2ad4aa4 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -65,15 +65,6 @@ <structure name="IDR_SETTINGS_ADD_SITE_DIALOG_JS" file="site_settings/add_site_dialog.js" type="chrome_html" /> - <structure name="IDR_SETTINGS_ADVANCED_PAGE_JS" - file="advanced_page/advanced_page.js" - flattenhtml="true" - type="chrome_html" /> - <structure name="IDR_SETTINGS_ADVANCED_PAGE_HTML" - file="advanced_page/advanced_page.html" - type="chrome_html" - flattenhtml="true" - allowexternalscript="true" /> <structure name="IDR_SETTINGS_ALL_SITES_HTML" file="site_settings/all_sites.html" type="chrome_html" /> @@ -123,6 +114,7 @@ flattenhtml="true" /> <structure name="IDR_SETTINGS_BASIC_PAGE_JS" file="basic_page/basic_page.js" + flattenhtml="true" type="chrome_html" /> <structure name="IDR_SETTINGS_BASIC_PAGE_HTML" file="basic_page/basic_page.html"
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc index fea1e3b7..3efb350 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer.cc
@@ -137,7 +137,10 @@ content::RenderFrameHost* current_frame_host = navigation_handle->GetWebContents()->FindFrameByFrameTreeNodeId( nav_event.frame_id); - if (current_frame_host && + // For browser initiated navigation (e.g. from address bar or bookmark), we + // don't fill the source_url to prevent attributing navigation to the last + // committed navigation. + if (navigation_handle->IsRendererInitiated() && current_frame_host && current_frame_host->GetLastCommittedURL().is_valid()) { nav_event.source_url = SafeBrowsingNavigationObserverManager::ClearEmptyRef( current_frame_host->GetLastCommittedURL()); @@ -210,17 +213,16 @@ } if (!details.url.is_valid() || details.socket_address.IsEmpty()) return; - - manager_->RecordHostToIpMapping(details.url.host(), - details.socket_address.host()); + if (!details.url.host().empty()) { + manager_->RecordHostToIpMapping(details.url.host(), + details.socket_address.host()); + } } void SafeBrowsingNavigationObserver::DidGetUserInteraction( const blink::WebInputEvent::Type type) { last_user_gesture_timestamp_ = base::Time::Now(); has_user_gesture_ = true; - // TODO (jialiul): Refine user gesture logic when DidOpenRequestedURL - // covers all retargetting cases. manager_->RecordUserGestureForWebContents(web_contents(), last_user_gesture_timestamp_); }
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc index 1a09af8..7450d81 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_browsertest.cc
@@ -6,8 +6,10 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/download/download_prefs.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/safe_browsing/download_protection_service.h" #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer.h" #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h" +#include "chrome/browser/safe_browsing/test_safe_browsing_service.h" #include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" @@ -27,6 +29,8 @@ #include "url/gurl.h" #include "url/url_canon.h" +using content::DownloadItem; + namespace safe_browsing { const char kSingleFrameTestURL[] = @@ -50,6 +54,18 @@ "/safe_browsing/download_protection/navigation_observer/" "iframe_retargeting.html"; const char kDownloadItemURL[] = "/safe_browsing/download_protection/signed.exe"; +const char kRedirectToLandingURL[] = + "/safe_browsing/download_protection/navigation_observer/" + "redirect_to_landing.html"; +const char kLandingURL[] = + "/safe_browsing/download_protection/navigation_observer/" + "landing.html"; +const char kLandingReferrerURL[] = + "/safe_browsing/download_protection/navigation_observer/" + "landing_referrer.html"; +const char kPageBeforeLandingReferrerURL[] = + "/safe_browsing/download_protection/navigation_observer/" + "page_before_landing_referrer.html"; // Test class to help create SafeBrowsingNavigationObservers for each // WebContents before they are actually installed through AttachTabHelper. @@ -93,15 +109,15 @@ false); ASSERT_TRUE(embedded_test_server()->Start()); host_resolver()->AddRule("*", "127.0.0.1"); - // Navigate to test page. - ui_test_utils::NavigateToURL( - browser(), embedded_test_server()->GetURL(kSingleFrameTestURL)); observer_manager_ = new TestNavigationObserverManager(); observer_ = new SafeBrowsingNavigationObserver( browser()->tab_strip_model()->GetActiveWebContents(), observer_manager_); ASSERT_TRUE(observer_); ASSERT_TRUE(InitialSetup()); + // Navigate to test page. + ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL(kSingleFrameTestURL)); } bool InitialSetup() { @@ -126,13 +142,17 @@ return true; } - void TearDownOnMainThread() override { delete observer_; } + void TearDownOnMainThread() override { + // Cancel unfinished download if any. + CancelDownloads(); + delete observer_; + } // Most test cases will trigger downloads, though we don't really care if // download completed or not. So we cancel downloads as soon as we record // all the navigation events we need. void CancelDownloads() { - std::vector<content::DownloadItem*> download_items; + std::vector<DownloadItem*> download_items; content::DownloadManager* manager = content::BrowserContext::GetDownloadManager(browser()->profile()); manager->GetAllDownloads(&download_items); @@ -142,11 +162,22 @@ } } - // This function needs javascript support, only works on - // navigation_observer_tests.html and - // navigation_observer_multi_frame_tests.html. - void ClickTestLink(const char* test_name, - int number_of_navigations) { + DownloadItem* GetDownload() { + std::vector<DownloadItem*> download_items; + content::DownloadManager* manager = + content::BrowserContext::GetDownloadManager(browser()->profile()); + manager->GetAllDownloads(&download_items); + EXPECT_EQ(1U, download_items.size()); + return download_items[0]; + } + + // This function needs javascript support from the test page hosted at + // |page_url|. It calls "clickLink(..)" javascript function to "click" on the + // html element with ID specified by |element_id|, and waits for + // |number_of_navigations| to complete. + void ClickTestLink(const char* element_id, + int number_of_navigations, + const GURL& page_url) { TabStripModel* tab_strip = browser()->tab_strip_model(); content::WebContents* current_web_contents = tab_strip->GetActiveWebContents(); @@ -156,13 +187,26 @@ number_of_navigations); navigation_observer.StartWatchingNewWebContents(); // Execute test. - std::string script = base::StringPrintf("clickLink('%s');", test_name); + std::string script = base::StringPrintf("clickLink('%s');", element_id); ASSERT_TRUE(content::ExecuteScript(current_web_contents, script)); // Wait for navigations on current tab and new tab (if any) to finish. navigation_observer.Wait(); navigation_observer.StopWatchingNewWebContents(); - // Cancel unfinished download if any. - CancelDownloads(); + + // Since this test uses javascript to mimic clicking on a link (no actual + // user gesture), and DidGetUserInteraction() does not respond to + // ExecuteScript(), is_user_initiated field in resulting NavigationEvents + // will always be false. Therefore, we need to make some adjustment to + // relevant NavigationEvent. + for (auto it = navigation_map()->begin(); it != navigation_map()->end(); + it++) { + for (NavigationEvent& nav_event : it->second) { + if (nav_event.source_url == page_url) { + nav_event.is_user_initiated = true; + return; + } + } + } } void VerifyNavigationEvent(const GURL& expected_source_url, @@ -185,15 +229,51 @@ actual_nav_event.has_server_redirect); } + void VerifyReferrerChainEntry(const GURL& expected_url, + ReferrerChainEntry::URLType expected_type, + const std::string& expected_ip_address, + const GURL& expected_referrer_url, + const GURL& expected_referrer_main_frame_url, + bool expected_is_retargeting, + ReferrerChainEntry actual_entry) { + EXPECT_EQ(expected_url.spec(), actual_entry.url()); + EXPECT_EQ(expected_type, actual_entry.type()); + if (expected_ip_address.empty()) { + ASSERT_EQ(0, actual_entry.ip_addresses_size()); + } else { + ASSERT_EQ(1, actual_entry.ip_addresses_size()); + EXPECT_EQ(expected_ip_address, actual_entry.ip_addresses(0)); + } + EXPECT_EQ(expected_referrer_url.spec(), actual_entry.referrer_url()); + EXPECT_EQ(expected_referrer_main_frame_url.spec(), + actual_entry.referrer_main_frame_url()); + EXPECT_EQ(expected_is_retargeting, actual_entry.is_retargeting()); + } + + std::vector<ReferrerChainEntry> IdentifyReferrerChain( + DownloadItem* download) { + std::vector<ReferrerChainEntry> referrer_chain; + int download_tab_id = + SessionTabHelper::IdForTab(download->GetWebContents()); + // IdentifyReferrerChain should return SUCCESS(1), SUCCESS_LANDING_PAGE(2), + // or SUCCESS_LANDING_REFERRER(3) in all these tests. + EXPECT_LE(observer_manager_->IdentifyReferrerChain( + download->GetURL(), download_tab_id, + 2, // kDownloadAttributionUserGestureLimit + &referrer_chain), + SafeBrowsingNavigationObserverManager::SUCCESS_LANDING_REFERRER); + return referrer_chain; + } + void VerifyHostToIpMap() { // Since all testing pages have the same host, there is only one entry in // host_to_ip_map_. SafeBrowsingNavigationObserverManager::HostToIpMap* actual_host_ip_map = host_to_ip_map(); - ASSERT_EQ(std::size_t(1), actual_host_ip_map->size()); + ASSERT_EQ(1U, actual_host_ip_map->size()); auto ip_list = actual_host_ip_map->at(embedded_test_server()->base_url().host()); - ASSERT_EQ(std::size_t(1), ip_list.size()); + ASSERT_EQ(1U, ip_list.size()); EXPECT_EQ(embedded_test_server()->host_port_pair().host(), ip_list.back().ip); } @@ -214,63 +294,164 @@ base::ScopedTempDir downloads_directory_; }; -// Click on a link and start download on the same page. -IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, DirectDownload) { - ClickTestLink("direct_download", 1); +// Type download URL into address bar and start download on the same page. +IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, TypeInURLDownload) { + ui_test_utils::NavigateToURL( + browser(), embedded_test_server()->GetURL(kDownloadItemURL)); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(1), nav_map->size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); - // Since this test uses javascript to mimic clicking on a link (no actual user - // gesture), and DidGetUserInteraction() does not respond to ExecuteScript(), - // therefore is_user_initiated is false. - VerifyNavigationEvent(initial_url, // source_url - initial_url, // source_main_frame_url + ASSERT_EQ(2U, nav_map->size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url download_url, // original_request_url download_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, false, // has_committed false, // has_server_redirect nav_map->at(download_url).at(0)); VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(1U, referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); +} +// Click on a link and start download on the same page. +IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, DirectDownload) { + GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("direct_download", 1, initial_url); + GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); + auto nav_map = navigation_map(); + ASSERT_TRUE(nav_map); + ASSERT_EQ(2U, nav_map->size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); + VerifyNavigationEvent(initial_url, // source_url + initial_url, // source_main_frame_url + download_url, // original_request_url + download_url, // destination_url + true, // is_user_initiated, + false, // has_committed + false, // has_server_redirect + nav_map->at(download_url).at(0)); + VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(2U, referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(initial_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[1]); } // Click on a link with rel="noreferrer" attribute, and start download on the // same page. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, DirectDownloadNoReferrer) { - ClickTestLink("direct_download_noreferrer", 1); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("direct_download_noreferrer", 1, initial_url); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(1), nav_map->size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); + ASSERT_EQ(2U, nav_map->size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); VerifyNavigationEvent(initial_url, // source_url initial_url, // source_main_frame_url download_url, // original_request_url download_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, false, // has_committed false, // has_server_redirect nav_map->at(download_url).at(0)); VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(2U, referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(initial_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[1]); } // Click on a link with rel="noreferrer" attribute, and start download in a // new tab using target=_blank. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, DirectDownloadNoReferrerTargetBlank) { - ClickTestLink("direct_download_noreferrer_target_blank", 1); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("direct_download_noreferrer_target_blank", 1, initial_url); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(1), nav_map->size()); - ASSERT_EQ(std::size_t(2), nav_map->at(download_url).size()); - // The first NavigationEvent was obtained from NOIFICATION_RETARGETING. + ASSERT_EQ(2U, nav_map->size()); + ASSERT_EQ(2U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); + // The next NavigationEvent was obtained from NOIFICATION_RETARGETING. // TODO(jialiul): After https://crbug.com/651895 is fixed, we'll no longer // listen to NOTIFICATION_RETARGETING, hence only one NavigationEvent will // be observed with the true initator URL. This applies to other new tab @@ -279,11 +460,11 @@ initial_url, // source_main_frame_url download_url, // original_request_url download_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, false, // has_committed false, // has_server_redirect nav_map->at(download_url).at(0)); - // The second one is the actual navigation which triggers download. + // This one is the actual navigation which triggers download. VerifyNavigationEvent(GURL(), // source_url GURL(), // source_main_frame_url download_url, // original_request_url @@ -293,28 +474,55 @@ false, // has_server_redirect nav_map->at(download_url).at(1)); VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(2U, referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + true, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(initial_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[1]); } // Click on a link which navigates to a page then redirects to a download using // META HTTP-EQUIV="refresh". All transitions happen in the same tab. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, SingleMetaRefreshRedirect) { - ClickTestLink("single_meta_refresh_redirect", 2); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("single_meta_refresh_redirect", 2, initial_url); GURL redirect_url = embedded_test_server()->GetURL(kRedirectURL); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); // Since unlike server redirects client redirects commit and then generate a // second navigation, our observer records two NavigationEvents for this test. - ASSERT_EQ(std::size_t(2), nav_map->size()); - ASSERT_EQ(std::size_t(1), nav_map->at(redirect_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); + ASSERT_EQ(std::size_t(3), nav_map->size()); + ASSERT_EQ(1U, nav_map->at(redirect_url).size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); VerifyNavigationEvent(initial_url, // source_url initial_url, // source_main_frame_url redirect_url, // original_request_url redirect_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, true, // has_committed false, // has_server_redirect nav_map->at(redirect_url).at(0)); @@ -327,6 +535,30 @@ false, // has_server_redirect nav_map->at(download_url).at(0)); VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(std::size_t(3), referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + redirect_url, // referrer_url + redirect_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(redirect_url, // url + ReferrerChainEntry::CLIENT_REDIRECT, // type + test_server_ip, // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[1]); + VerifyReferrerChainEntry(initial_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[2]); } // https://crbug.com/667784: The test is flaky on Linux. @@ -339,15 +571,25 @@ // META HTTP-EQUIV="refresh". First navigation happens in target blank. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, MAYBE_SingleMetaRefreshRedirectTargetBlank) { - ClickTestLink("single_meta_refresh_redirect_target_blank", 2); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("single_meta_refresh_redirect_target_blank", 2, initial_url); GURL redirect_url = embedded_test_server()->GetURL(kRedirectURL); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(2), nav_map->size()); - ASSERT_EQ(std::size_t(2), nav_map->at(redirect_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); + ASSERT_EQ(std::size_t(3), nav_map->size()); + ASSERT_EQ(2U, nav_map->at(redirect_url).size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); // TODO(jialiul): After https://crbug.com/651895 is fixed, we'll no longer // listen to NOTIFICATION_RETARGETING, hence only two NavigationEvents will // be observed with the true initator URL. @@ -355,7 +597,7 @@ initial_url, // source_main_frame_url redirect_url, // original_request_url redirect_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, false, // has_committed false, // has_server_redirect nav_map->at(redirect_url).at(0)); @@ -376,30 +618,64 @@ false, // has_server_redirect nav_map->at(download_url).at(0)); VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(std::size_t(3), referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + redirect_url, // referrer_url + redirect_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(redirect_url, // url + ReferrerChainEntry::CLIENT_REDIRECT, // type + test_server_ip, // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + true, // is_retargeting + referrer_chain[1]); + VerifyReferrerChainEntry(initial_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[2]); } // Click on a link which redirects twice before reaching download using // META HTTP-EQUIV="refresh". All transitions happen in the same tab. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, MultiMetaRefreshRedirects) { - ClickTestLink("multiple_meta_refresh_redirects", 3); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("multiple_meta_refresh_redirects", 3, initial_url); GURL first_redirect_url = embedded_test_server()->GetURL( "/safe_browsing/download_protection/navigation_observer/" "double_redirect.html"); GURL second_redirect_url = embedded_test_server()->GetURL(kRedirectURL); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(3), nav_map->size()); - ASSERT_EQ(std::size_t(1), nav_map->at(first_redirect_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(second_redirect_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); + ASSERT_EQ(std::size_t(4), nav_map->size()); + ASSERT_EQ(1U, nav_map->at(first_redirect_url).size()); + ASSERT_EQ(1U, nav_map->at(second_redirect_url).size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); VerifyNavigationEvent(initial_url, // source_url initial_url, // source_main_frame_url first_redirect_url, // original_request_url first_redirect_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, true, // has_committed false, // has_server_redirect nav_map->at(first_redirect_url).at(0)); @@ -420,47 +696,115 @@ false, // has_server_redirect nav_map->at(download_url).at(0)); VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(std::size_t(4), referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + second_redirect_url, // referrer_url + second_redirect_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(second_redirect_url, // url + ReferrerChainEntry::CLIENT_REDIRECT, // type + test_server_ip, // ip_address + first_redirect_url, // referrer_url + first_redirect_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[1]); + VerifyReferrerChainEntry(first_redirect_url, // url + ReferrerChainEntry::CLIENT_REDIRECT, // type + test_server_ip, // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[2]); + VerifyReferrerChainEntry(initial_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[3]); } // Click on a link which redirects to download using window.location. // All transitions happen in the same tab. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, WindowLocationRedirect) { - ClickTestLink("window_location_redirection", 1); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("window_location_redirection", 1, initial_url); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(1), nav_map->size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); + ASSERT_EQ(2U, nav_map->size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); VerifyNavigationEvent(initial_url, // source_url initial_url, // source_main_frame_url download_url, // original_request_url download_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, false, // has_committed false, // has_server_redirect nav_map->at(download_url).at(0)); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(2U, referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(initial_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[1]); } // Click on a link which redirects twice until it reaches download using a // mixture of meta refresh and window.location. All transitions happen in the // same tab. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, MixRedirects) { - ClickTestLink("mix_redirects", 2); - GURL redirect_url = embedded_test_server()->GetURL(kRedirectURL); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("mix_redirects", 2, initial_url); + GURL redirect_url = embedded_test_server()->GetURL(kRedirectURL); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(2), nav_map->size()); - ASSERT_EQ(std::size_t(1), nav_map->at(redirect_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); + ASSERT_EQ(std::size_t(3), nav_map->size()); + ASSERT_EQ(1U, nav_map->at(redirect_url).size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); VerifyNavigationEvent(initial_url, // source_url initial_url, // source_main_frame_url redirect_url, // original_request_url redirect_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, true, // has_committed false, // has_server_redirect nav_map->at(redirect_url).at(0)); @@ -473,24 +817,58 @@ false, // has_server_redirect nav_map->at(download_url).at(0)); VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(std::size_t(3), referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + redirect_url, // referrer_url + redirect_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(redirect_url, // url + ReferrerChainEntry::CLIENT_REDIRECT, // type + test_server_ip, // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[1]); + VerifyReferrerChainEntry(initial_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[2]); } // Use javascript to open download in a new tab. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, NewTabDownload) { - ClickTestLink("new_tab_download", 2); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("new_tab_download", 2, initial_url); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); GURL blank_url = GURL(url::kAboutBlankURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(2), nav_map->size()); - ASSERT_EQ(std::size_t(2), nav_map->at(blank_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); + ASSERT_EQ(std::size_t(3), nav_map->size()); + ASSERT_EQ(2U, nav_map->at(blank_url).size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); VerifyNavigationEvent(initial_url, // source_url initial_url, // source_main_frame_url blank_url, // original_request_url blank_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, false, // has_committed false, // has_server_redirect nav_map->at(blank_url).at(0)); @@ -518,26 +896,60 @@ EXPECT_EQ(nav_map->at(download_url).at(0).source_tab_id, nav_map->at(download_url).at(0).target_tab_id); VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(std::size_t(3), referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + blank_url, // referrer_url + blank_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(blank_url, // url + ReferrerChainEntry::CLIENT_REDIRECT, // type + "", // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + true, // is_retargeting + referrer_chain[1]); + VerifyReferrerChainEntry(initial_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[2]); } // Use javascript to open download in a new tab and download has a data url. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, NewTabDownloadWithDataURL) { - ClickTestLink("new_tab_download_with_data_url", 2); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("new_tab_download_with_data_url", 2, initial_url); GURL download_url = GURL(kDownloadDataURL); - GURL blank_url = GURL("about:blank"); + GURL blank_url = GURL(url::kAboutBlankURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(2), nav_map->size()); - ASSERT_EQ(std::size_t(2), nav_map->at(blank_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); + ASSERT_EQ(std::size_t(3), nav_map->size()); + ASSERT_EQ(2U, nav_map->at(blank_url).size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); // The first one comes from NOTIFICATION_RETARGETING. VerifyNavigationEvent(initial_url, // source_url initial_url, // source_main_frame_url blank_url, // original_request_url blank_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, false, // has_committed false, // has_server_redirect nav_map->at(blank_url).at(0)); @@ -564,8 +976,31 @@ nav_map->at(download_url).at(0)); EXPECT_TRUE(nav_map->at(download_url).at(0).source_tab_id == nav_map->at(download_url).at(0).target_tab_id); - // Since data url does does not have IP, host_to_ip_map_ should be empty. - EXPECT_EQ(std::size_t(0), host_to_ip_map()->size()); + VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(std::size_t(3), referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + "", // ip_address + blank_url, // referrer_url + blank_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(blank_url, // url + ReferrerChainEntry::CLIENT_REDIRECT, // type + "", // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + true, // is_retargeting + referrer_chain[1]); + VerifyReferrerChainEntry(initial_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[2]); } // TODO(jialiul): Need to figure out why this test is failing on Windows and @@ -574,25 +1009,52 @@ // Download via html5 file API. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, MAYBE_DownloadViaHTML5FileApi) { - ClickTestLink("html5_file_api", 1); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("html5_file_api", 1, initial_url); std::string download_url_str = base::StringPrintf("filesystem:%stemporary/test.exe", embedded_test_server()->base_url().spec().c_str()); GURL download_url = GURL(download_url_str); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(1), nav_map->size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); + ASSERT_EQ(2U, nav_map->size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); VerifyNavigationEvent(initial_url, // source_url initial_url, // source_main_frame_url download_url, // original_request_url download_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, false, // has_committed false, // has_server_redirect nav_map->at(download_url).at(0)); VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(2U, referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + "", // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(initial_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[1]); } // Click a link in a subframe and start download. @@ -602,23 +1064,33 @@ browser(), embedded_test_server()->GetURL(kMultiFrameTestURL)); std::string test_name = base::StringPrintf("%s', '%s", "iframe1", "iframe_direct_download"); - ClickTestLink(test_name.c_str(), 1); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); GURL multi_frame_test_url = embedded_test_server()->GetURL(kMultiFrameTestURL); GURL iframe_url = embedded_test_server()->GetURL(kIframeDirectDownloadURL); + ClickTestLink(test_name.c_str(), 1, iframe_url); GURL iframe_retargeting_url = embedded_test_server()->GetURL(kIframeRetargetingURL); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(4), nav_map->size()); - ASSERT_EQ(std::size_t(1), nav_map->at(multi_frame_test_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(iframe_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(iframe_retargeting_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); - VerifyNavigationEvent(initial_url, // source_url - initial_url, // source_main_frame_url + ASSERT_EQ(std::size_t(5), nav_map->size()); + ASSERT_EQ(1U, nav_map->at(multi_frame_test_url).size()); + ASSERT_EQ(1U, nav_map->at(iframe_url).size()); + ASSERT_EQ(1U, nav_map->at(iframe_retargeting_url).size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url multi_frame_test_url, // original_request_url multi_frame_test_url, // destination_url true, // is_user_initiated, @@ -645,11 +1117,28 @@ multi_frame_test_url, // source_main_frame_url download_url, // original_request_url download_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, false, // has_committed false, // has_server_redirect nav_map->at(download_url).at(0)); VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(2U, referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + iframe_url, // referrer_url + multi_frame_test_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(iframe_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + multi_frame_test_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[1]); } // Click a link in a subframe and open download in a new tab. @@ -659,25 +1148,35 @@ browser(), embedded_test_server()->GetURL(kMultiFrameTestURL)); std::string test_name = base::StringPrintf("%s', '%s", "iframe2", "iframe_new_tab_download"); - ClickTestLink(test_name.c_str(), 2); GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); GURL multi_frame_test_url = embedded_test_server()->GetURL(kMultiFrameTestURL); GURL iframe_url = embedded_test_server()->GetURL(kIframeDirectDownloadURL); GURL iframe_retargeting_url = embedded_test_server()->GetURL(kIframeRetargetingURL); + ClickTestLink(test_name.c_str(), 2, iframe_retargeting_url); GURL blank_url = GURL(url::kAboutBlankURL); GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(5), nav_map->size()); - ASSERT_EQ(std::size_t(1), nav_map->at(multi_frame_test_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(iframe_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(iframe_retargeting_url).size()); - ASSERT_EQ(std::size_t(2), nav_map->at(blank_url).size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); - VerifyNavigationEvent(initial_url, // source_url - initial_url, // source_main_frame_url + ASSERT_EQ(std::size_t(6), nav_map->size()); + ASSERT_EQ(1U, nav_map->at(multi_frame_test_url).size()); + ASSERT_EQ(1U, nav_map->at(iframe_url).size()); + ASSERT_EQ(1U, nav_map->at(iframe_retargeting_url).size()); + ASSERT_EQ(2U, nav_map->at(blank_url).size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url multi_frame_test_url, // original_request_url multi_frame_test_url, // destination_url true, // is_user_initiated, @@ -704,7 +1203,7 @@ multi_frame_test_url, // source_main_frame_url blank_url, // original_request_url blank_url, // destination_url - false, // is_user_initiated, + true, // is_user_initiated, false, // has_committed false, // has_server_redirect nav_map->at(blank_url).at(0)); @@ -725,6 +1224,207 @@ false, // has_server_redirect nav_map->at(download_url).at(0)); VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + EXPECT_EQ(std::size_t(3), referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + blank_url, // referrer_url + blank_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(blank_url, // url + ReferrerChainEntry::CLIENT_REDIRECT, // type + "", // ip_address + iframe_retargeting_url, // referrer_url + multi_frame_test_url, // referrer_main_frame_url + true, // is_retargeting + referrer_chain[1]); + VerifyReferrerChainEntry(iframe_retargeting_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + GURL(), // referrer_url + multi_frame_test_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[2]); +} + +// Click a link which redirects to the landing page, and then click on the +// landing page to trigger download. +IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, CompleteReferrerChain) { + GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("complete_referrer_chain", 2, initial_url); + GURL redirect_url = embedded_test_server()->GetURL(kRedirectToLandingURL); + GURL landing_url = embedded_test_server()->GetURL(kLandingURL); + ClickTestLink("download_on_landing_page", 1, landing_url); + GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); + auto nav_map = navigation_map(); + ASSERT_TRUE(nav_map); + ASSERT_EQ(std::size_t(4), nav_map->size()); + ASSERT_EQ(1U, nav_map->at(redirect_url).size()); + ASSERT_EQ(1U, nav_map->at(landing_url).size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); + VerifyNavigationEvent(initial_url, // source_url + initial_url, // source_main_frame_url + redirect_url, // original_request_url + redirect_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(redirect_url).at(0)); + VerifyNavigationEvent(redirect_url, // source_url + redirect_url, // source_main_frame_url + landing_url, // original_request_url + landing_url, // destination_url + false, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(landing_url).at(0)); + VerifyNavigationEvent(landing_url, // source_url + landing_url, // source_main_frame_url + download_url, // original_request_url + download_url, // destination_url + true, // is_user_initiated, + false, // has_committed + false, // has_server_redirect + nav_map->at(download_url).at(0)); + VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + EXPECT_EQ(std::size_t(4), referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + landing_url, // referrer_url + landing_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(landing_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + redirect_url, // referrer_url + redirect_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[1]); + VerifyReferrerChainEntry(redirect_url, // url + ReferrerChainEntry::CLIENT_REDIRECT, // type + test_server_ip, // ip_address + initial_url, // referrer_url + initial_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[2]); + VerifyReferrerChainEntry( + initial_url, // url + ReferrerChainEntry::LANDING_REFERRER, // type + test_server_ip, // ip_address + GURL(), // referrer_url is empty since this beyonds 2 clicks. + GURL(), // referrer_main_frame_url is empty for the same reason. + false, // is_retargeting + referrer_chain[3]); +} + +// Click three links before reaching download. +IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, + ReferrerAttributionWithinTwoUserGestures) { + GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); + ClickTestLink("attribution_within_two_user_gestures", 1, initial_url); + GURL page_before_landing_referrer_url = + embedded_test_server()->GetURL(kPageBeforeLandingReferrerURL); + ClickTestLink("link_to_landing_referrer", 1, + page_before_landing_referrer_url); + GURL landing_referrer_url = + embedded_test_server()->GetURL(kLandingReferrerURL); + ClickTestLink("link_to_landing", 1, landing_referrer_url); + GURL landing_url = embedded_test_server()->GetURL(kLandingURL); + ClickTestLink("download_on_landing_page", 1, landing_url); + GURL download_url = embedded_test_server()->GetURL(kDownloadItemURL); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); + auto nav_map = navigation_map(); + ASSERT_TRUE(nav_map); + ASSERT_EQ(std::size_t(5), nav_map->size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + ASSERT_EQ(1U, nav_map->at(page_before_landing_referrer_url).size()); + ASSERT_EQ(1U, nav_map->at(landing_referrer_url).size()); + ASSERT_EQ(1U, nav_map->at(landing_url).size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); + VerifyNavigationEvent(initial_url, // source_url + initial_url, // source_main_frame_url + page_before_landing_referrer_url, // original_request + page_before_landing_referrer_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(page_before_landing_referrer_url).at(0)); + VerifyNavigationEvent(page_before_landing_referrer_url, // source_url + page_before_landing_referrer_url, // source_main_frame + landing_referrer_url, // original_request_url + landing_referrer_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(landing_referrer_url).at(0)); + VerifyNavigationEvent(landing_referrer_url, // source_url + landing_referrer_url, // source_main_frame + landing_url, // original_request_url + landing_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(landing_url).at(0)); + VerifyNavigationEvent(landing_url, // source_url + landing_url, // source_main_frame_url + download_url, // original_request_url + download_url, // destination_url + true, // is_user_initiated, + false, // has_committed + false, // has_server_redirect + nav_map->at(download_url).at(0)); + VerifyHostToIpMap(); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + EXPECT_EQ(std::size_t(3), referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + landing_url, // referrer_url + landing_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); + VerifyReferrerChainEntry(landing_url, // url + ReferrerChainEntry::LANDING_PAGE, // type + test_server_ip, // ip_address + landing_referrer_url, // referrer_url + landing_referrer_url, // referrer_main_frame_url + false, // is_retargeting + referrer_chain[1]); + VerifyReferrerChainEntry( + landing_referrer_url, // url + ReferrerChainEntry::LANDING_REFERRER, // type + test_server_ip, // ip_address + GURL(), // referrer_url is empty since this beyonds 2 clicks. + GURL(), // referrer_main_frame_url is empty for the same reason. + false, // is_retargeting + referrer_chain[2]); + // page_before_landing_referrer_url is not in referrer chain. } // Server-side redirect. @@ -734,37 +1434,60 @@ GURL request_url = embedded_test_server()->GetURL("/server-redirect?" + download_url.spec()); ui_test_utils::NavigateToURL(browser(), request_url); - CancelDownloads(); + std::string test_server_ip(embedded_test_server()->host_port_pair().host()); auto nav_map = navigation_map(); ASSERT_TRUE(nav_map); - ASSERT_EQ(std::size_t(1), nav_map->size()); - ASSERT_EQ(std::size_t(1), nav_map->at(download_url).size()); - VerifyNavigationEvent(initial_url, // source_url - initial_url, // source_main_frame_url + ASSERT_EQ(2U, nav_map->size()); + ASSERT_EQ(1U, nav_map->at(download_url).size()); + ASSERT_EQ(1U, nav_map->at(initial_url).size()); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url + initial_url, // original_request_url + initial_url, // destination_url + true, // is_user_initiated, + true, // has_committed + false, // has_server_redirect + nav_map->at(initial_url).at(0)); + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url request_url, // original_request_url download_url, // destination_url true, // is_user_initiated, false, // has_committed true, // has_server_redirect nav_map->at(download_url).at(0)); + + auto referrer_chain = IdentifyReferrerChain(GetDownload()); + ASSERT_EQ(1U, referrer_chain.size()); + VerifyReferrerChainEntry(download_url, // url + ReferrerChainEntry::DOWNLOAD_URL, // type + test_server_ip, // ip_address + GURL(), // referrer_url + GURL(), // referrer_main_frame_url + false, // is_retargeting + referrer_chain[0]); } // host_to_ip_map_ size should increase by one after a new navigation. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, AddIPMapping) { + GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); auto ip_map = host_to_ip_map(); std::string test_server_host(embedded_test_server()->base_url().host()); + ip_map->clear(); ip_map->insert( std::make_pair(test_server_host, std::vector<ResolvedIPAddress>())); ASSERT_EQ(std::size_t(0), ip_map->at(test_server_host).size()); - ClickTestLink("direct_download", 1); - EXPECT_EQ(std::size_t(1), ip_map->at(test_server_host).size()); + ClickTestLink("direct_download", 1, initial_url); + EXPECT_EQ(1U, ip_map->at(test_server_host).size()); EXPECT_EQ(embedded_test_server()->host_port_pair().host(), ip_map->at(test_server_host).back().ip); } // If we have already seen an IP associated with a host, update its timestamp. IN_PROC_BROWSER_TEST_F(SBNavigationObserverBrowserTest, IPListDedup) { + GURL initial_url = embedded_test_server()->GetURL(kSingleFrameTestURL); auto ip_map = host_to_ip_map(); + ip_map->clear(); std::string test_server_host(embedded_test_server()->base_url().host()); ip_map->insert( std::make_pair(test_server_host, std::vector<ResolvedIPAddress>())); @@ -772,9 +1495,9 @@ ip_map->at(test_server_host) .push_back(ResolvedIPAddress( yesterday, embedded_test_server()->host_port_pair().host())); - ASSERT_EQ(std::size_t(1), ip_map->at(test_server_host).size()); - ClickTestLink("direct_download", 1); - EXPECT_EQ(std::size_t(1), ip_map->at(test_server_host).size()); + ASSERT_EQ(1U, ip_map->at(test_server_host).size()); + ClickTestLink("direct_download", 1, initial_url); + EXPECT_EQ(1U, ip_map->at(test_server_host).size()); EXPECT_EQ(embedded_test_server()->host_port_pair().host(), ip_map->at(test_server_host).back().ip); EXPECT_NE(yesterday, ip_map->at(test_server_host).front().timestamp);
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc index 14fdb02a..989f7d61 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
@@ -5,7 +5,10 @@ #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h" #include "base/memory/ptr_util.h" +#include "base/metrics/histogram_macros.h" +#include "base/strings/stringprintf.h" #include "base/time/time.h" +#include "base/timer/timer.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer.h" #include "chrome/browser/sessions/session_tab_helper.h" @@ -21,20 +24,36 @@ namespace safe_browsing { +namespace { + +// Given when an event happened and its TTL, determine if it is already expired. +// Note, if for some reason this event's timestamp is in the future, this +// event's timestamp is invalid, hence we treat it as expired. +bool IsEventExpired(const base::Time& event_time, double ttl_in_second) { + double current_time_in_second = base::Time::Now().ToDoubleT(); + double event_time_in_second = event_time.ToDoubleT(); + if (current_time_in_second <= event_time_in_second) + return true; + return current_time_in_second - event_time_in_second > ttl_in_second; +} + +} // namespace + // The expiration period of a user gesture. Any user gesture that happened 1.0 -// second ago will be considered as expired and not relevant to upcoming -// navigation events. +// second ago is considered as expired and not relevant to upcoming navigation +// events. static const double kUserGestureTTLInSecond = 1.0; +// The expiration period of navigation events and resolved IP addresses. Any +// navigation related records that happened 2 minutes ago are considered as +// expired. So we clean up these navigation footprints every 2 minutes. +static const double kNavigationFootprintTTLInSecond = 120.0; +// The number of user gestures we trace back for download attribution. +static const int kDownloadAttributionUserGestureLimit = 2; // static bool SafeBrowsingNavigationObserverManager::IsUserGestureExpired( const base::Time& timestamp) { - double now = base::Time::Now().ToDoubleT(); - double timestamp_in_double = timestamp.ToDoubleT(); - - if (now <= timestamp_in_double) - return true; - return (now - timestamp_in_double) > kUserGestureTTLInSecond; + return IsEventExpired(timestamp, kUserGestureTTLInSecond); } // static @@ -50,6 +69,9 @@ SafeBrowsingNavigationObserverManager::SafeBrowsingNavigationObserverManager() { registrar_.Add(this, chrome::NOTIFICATION_RETARGETING, content::NotificationService::AllSources()); + + // TODO(jialiul): call ScheduleNextCleanUpAfterInterval() when this class is + // ready to be hooked into SafeBrowsingService. } void SafeBrowsingNavigationObserverManager::RecordNavigationEvent( @@ -104,7 +126,109 @@ void SafeBrowsingNavigationObserverManager::OnWebContentDestroyed( content::WebContents* web_contents) { user_gesture_map_.erase(web_contents); - // TODO (jialiul): Will add other clean up tasks shortly. +} + +void SafeBrowsingNavigationObserverManager::CleanUpStaleNavigationFootprints() { + CleanUpNavigationEvents(); + CleanUpUserGestures(); + CleanUpIpAddresses(); + ScheduleNextCleanUpAfterInterval( + base::TimeDelta::FromSecondsD(kNavigationFootprintTTLInSecond)); +} + +SafeBrowsingNavigationObserverManager::AttributionResult +SafeBrowsingNavigationObserverManager::IdentifyReferrerChain( + const GURL& target_url, + int target_tab_id, + int user_gesture_count_limit, + std::vector<ReferrerChainEntry>* out_referrer_chain) { + if (!target_url.is_valid()) + return INVALID_URL; + + NavigationEvent* nav_event = FindNavigationEvent(target_url, target_tab_id); + if (!nav_event) { + // We cannot find a single navigation event related to this download. + return NAVIGATION_EVENT_NOT_FOUND; + } + + AddToReferrerChain(out_referrer_chain, nav_event, + ReferrerChainEntry::DOWNLOAD_URL); + AttributionResult result = SUCCESS; + int user_gesture_count = 0; + while (user_gesture_count < user_gesture_count_limit) { + // Back trace to the next nav_event that was initiated by the user. + while (!nav_event->is_user_initiated) { + nav_event = + FindNavigationEvent(nav_event->source_url, nav_event->source_tab_id); + if (!nav_event) + return result; + AddToReferrerChain(out_referrer_chain, nav_event, + nav_event->has_server_redirect + ? ReferrerChainEntry::SERVER_REDIRECT + : ReferrerChainEntry::CLIENT_REDIRECT); + } + + user_gesture_count++; + + // If the source_url and source_main_frame_url of current navigation event + // are empty, and is_user_initiated is true, this is a browser initiated + // navigation (e.g. trigged by typing in address bar, clicking on bookmark, + // etc). We reached the end of the referrer chain. + if (nav_event->source_url.is_empty() && + nav_event->source_main_frame_url.is_empty()) { + DCHECK(nav_event->is_user_initiated); + return result; + } + + nav_event = + FindNavigationEvent(nav_event->source_url, nav_event->source_tab_id); + if (!nav_event) + return result; + + // Landing page of a download refers to the page user directly interacts + // with to trigger this download (e.g. clicking on download button). Landing + // referrer page is the one user interacts with right before navigating to + // the landing page. + // Since we are tracing navigations backwards, if we've encountered 1 user + // gesture before this navigation event, this is a navigation leading to the + // landing page. If we've encountered 2 user gestures, it leads to landing + // referrer page. + if (user_gesture_count == 1) { + AddToReferrerChain(out_referrer_chain, nav_event, + ReferrerChainEntry::LANDING_PAGE); + result = SUCCESS_LANDING_PAGE; + } else if (user_gesture_count == 2) { + AddToReferrerChain(out_referrer_chain, nav_event, + ReferrerChainEntry::LANDING_REFERRER); + result = SUCCESS_LANDING_REFERRER; + } else { + NOTREACHED(); + } + } + return result; +} + +void SafeBrowsingNavigationObserverManager:: + AddReferrerChainToClientDownloadRequest( + const GURL& download_url, + content::WebContents* source_contents, + ClientDownloadRequest* out_request) { + int download_tab_id = SessionTabHelper::IdForTab(source_contents); + UMA_HISTOGRAM_BOOLEAN( + "SafeBrowsing.ReferrerHasInvalidTabID.DownloadAttribution", + download_tab_id == -1); + std::vector<ReferrerChainEntry> attribution_chain; + AttributionResult result = IdentifyReferrerChain( + download_url, download_tab_id, kDownloadAttributionUserGestureLimit, + &attribution_chain); + UMA_HISTOGRAM_COUNTS_100( + "SafeBrowsing.ReferrerURLChainSize.DownloadAttribution", + attribution_chain.size()); + UMA_HISTOGRAM_ENUMERATION( + "SafeBrowsing.ReferrerAttributionResult.DownloadAttribution", result, + SafeBrowsingNavigationObserverManager::ATTRIBUTION_FAILURE_TYPE_MAX); + for (auto entry : attribution_chain) + *out_request->add_referrer_chain() = entry; } SafeBrowsingNavigationObserverManager:: @@ -166,4 +290,115 @@ insertion_result.first->second.push_back(std::move(nav_event)); } +void SafeBrowsingNavigationObserverManager::CleanUpNavigationEvents() { + // Remove any stale NavigationEnvent, if it is older than + // kNavigationFootprintTTLInSecond. + for (auto it = navigation_map_.begin(); it != navigation_map_.end();) { + it->second.erase(std::remove_if(it->second.begin(), it->second.end(), + [](const NavigationEvent& nav_event) { + return IsEventExpired( + nav_event.last_updated, + kNavigationFootprintTTLInSecond); + }), + it->second.end()); + if (it->second.size() == 0) + it = navigation_map_.erase(it); + else + ++it; + } +} + +void SafeBrowsingNavigationObserverManager::CleanUpUserGestures() { + for (auto it = user_gesture_map_.begin(); it != user_gesture_map_.end();) { + if (IsEventExpired(it->second, kUserGestureTTLInSecond)) + it = user_gesture_map_.erase(it); + else + ++it; + } +} + +void SafeBrowsingNavigationObserverManager::CleanUpIpAddresses() { + for (auto it = host_to_ip_map_.begin(); it != host_to_ip_map_.end();) { + it->second.erase(std::remove_if(it->second.begin(), it->second.end(), + [](const ResolvedIPAddress& resolved_ip) { + return IsEventExpired( + resolved_ip.timestamp, + kNavigationFootprintTTLInSecond); + }), + it->second.end()); + if (it->second.size() == 0) + it = host_to_ip_map_.erase(it); + else + ++it; + } +} + +bool SafeBrowsingNavigationObserverManager::IsCleanUpScheduled() const { + return cleanup_timer_.IsRunning(); +} + +void SafeBrowsingNavigationObserverManager::ScheduleNextCleanUpAfterInterval( + base::TimeDelta interval) { + DCHECK_GT(interval, base::TimeDelta()); + cleanup_timer_.Stop(); + cleanup_timer_.Start( + FROM_HERE, interval, this, + &SafeBrowsingNavigationObserverManager::CleanUpStaleNavigationFootprints); +} + +NavigationEvent* SafeBrowsingNavigationObserverManager::FindNavigationEvent( + const GURL& target_url, + int target_tab_id) { + auto it = navigation_map_.find(target_url); + if (it == navigation_map_.end()) { + return nullptr; + } + // Since navigation events are recorded in chronological order, we traverse + // the vector in reverse order to get the latest match. + for (auto rit = it->second.rbegin(); rit != it->second.rend(); ++rit) { + // If tab id is not valid, we only compare url, otherwise we compare both. + if (rit->destination_url == target_url && + (target_tab_id == -1 || rit->target_tab_id == target_tab_id)) { + // If both source_url and source_main_frame_url are empty, and this + // navigation is not triggered by user, a retargeting navigation probably + // causes this navigation. In this case, we skip this navigation event and + // looks for the retargeting navigation event. + if (rit->source_url.is_empty() && rit->source_main_frame_url.is_empty() && + !rit->is_user_initiated) { + continue; + } else { + return &*rit; + } + } + } + return nullptr; +} + +void SafeBrowsingNavigationObserverManager::AddToReferrerChain( + std::vector<ReferrerChainEntry>* referrer_chain, + NavigationEvent* nav_event, + ReferrerChainEntry::URLType type) { + ReferrerChainEntry referrer_chain_entry; + referrer_chain_entry.set_url(nav_event->destination_url.spec()); + referrer_chain_entry.set_type(type); + auto ip_it = host_to_ip_map_.find(nav_event->destination_url.host()); + if (ip_it != host_to_ip_map_.end()) { + for (ResolvedIPAddress entry : ip_it->second) { + referrer_chain_entry.add_ip_addresses(entry.ip); + } + } + // Since we only track navigation to landing referrer, we will not log the + // referrer of the landing referrer page. + if (type != ReferrerChainEntry::LANDING_REFERRER) { + referrer_chain_entry.set_referrer_url(nav_event->source_url.spec()); + referrer_chain_entry.set_referrer_main_frame_url( + nav_event->source_main_frame_url.spec()); + } + referrer_chain_entry.set_is_retargeting(nav_event->source_tab_id != + nav_event->target_tab_id); + referrer_chain_entry.set_navigation_time_msec( + nav_event->last_updated.ToJavaTime()); + referrer_chain->push_back(referrer_chain_entry); +} + } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h index f66172fe..7a47da8 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_NAVIGATION_OBSERVER_MANAGER_H_ #define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_NAVIGATION_OBSERVER_MANAGER_H_ +#include "chrome/common/safe_browsing/csd.pb.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/web_contents_observer.h" @@ -17,7 +18,7 @@ struct ResolvedIPAddress; // Manager class for SafeBrowsingNavigationObserver, which is in charge of -// cleaning up stale navigation events, and identifing landing page/landing +// cleaning up stale navigation events, and identifying landing page/landing // referrer for a specific download. // TODO(jialiul): For now, SafeBrowsingNavigationObserverManager also listens to // NOTIFICATION_RETARGETING as a way to detect cross frame/tab navigation. @@ -27,6 +28,18 @@ : public content::NotificationObserver, public base::RefCountedThreadSafe<SafeBrowsingNavigationObserverManager> { public: + // For UMA histogram counting. Do NOT change order. + enum AttributionResult { + SUCCESS = 1, // Identified referrer chain is not empty. + SUCCESS_LANDING_PAGE = 2, // Successfully identified landing page. + SUCCESS_LANDING_REFERRER = 3, // Successfully identified landing referrer. + INVALID_URL = 4, + NAVIGATION_EVENT_NOT_FOUND = 5, + + // Always at the end. + ATTRIBUTION_FAILURE_TYPE_MAX + }; + // Helper function to check if user gesture is older than // kUserGestureTTLInSecond. static bool IsUserGestureExpired(const base::Time& timestamp); @@ -47,10 +60,34 @@ void OnUserGestureConsumed(content::WebContents* web_contents, const base::Time& timestamp); void RecordHostToIpMapping(const std::string& host, const std::string& ip); + // Clean-ups need to be done when a WebContents gets destroyed. void OnWebContentDestroyed(content::WebContents* web_contents); - // TODO(jialiul): more functions are coming for managing navigation_map_. + // Remove all the observed NavigationEvents, user gestures, and resolved IP + // addresses that are older than kNavigationFootprintTTLInSecond. + void CleanUpStaleNavigationFootprints(); + + // Based on the |target_url| and |target_tab_id|, trace back the observed + // NavigationEvents in navigation_map_ to identify the sequence of navigations + // leading to the target, with the coverage limited to + // |user_gesture_count_limit| number of user gestures. Then convert these + // identified NavigationEvents into ReferrerChainEntrys and append them to + // |out_referrer_chain|. + AttributionResult IdentifyReferrerChain( + const GURL& target_url, + int target_tab_id, // -1 if tab id is not valid + int user_gesture_count_limit, + std::vector<ReferrerChainEntry>* out_referrer_chain); + + // Identify and add referrer chain info of a download to ClientDownloadRequest + // proto. This function also record UMA stats of download attribution result. + // TODO(jialiul): This function will be moved to DownloadProtectionService + // class shortly. + void AddReferrerChainToClientDownloadRequest( + const GURL& download_url, + content::WebContents* source_contents, + ClientDownloadRequest* out_request); private: friend class base::RefCountedThreadSafe< @@ -84,6 +121,45 @@ HostToIpMap* host_to_ip_map() { return &host_to_ip_map_; } + // Remove stale entries from navigation_map_ if they are older than + // kNavigationFootprintTTLInSecond (2 minutes). + void CleanUpNavigationEvents(); + + // Remove stale entries from user_gesture_map_ if they are older than + // kUserGestureTTLInSecond (1 sec). + void CleanUpUserGestures(); + + // Remove stale entries from host_to_ip_map_ if they are older than + // kNavigationFootprintTTLInSecond (2 minutes). + void CleanUpIpAddresses(); + + bool IsCleanUpScheduled() const; + + void ScheduleNextCleanUpAfterInterval(base::TimeDelta interval); + + // Find the most recent navigation event that navigated to |target_url| in the + // tab with ID |target_tab_id|. If |target_tab_id| is not available (-1), we + // look for all tabs for the most recent navigation to |target_url|. + // For some cases, the most recent navigation to |target_url| may not be + // relevant. + // For example, url1 in window A opens url2 in window B, url1 then opens an + // about:blank page window C and injects script code in it to trigger a + // delayed download in Window D. Before the download occurs, url2 in window B + // opens a different about:blank page in window C. + // A ---- C - D + // \ / + // B + // In this case, FindNavigationEvent() will think url2 in Window B is the + // referrer of about::blank in Window C since this navigation is more recent. + // However, it does not prevent us to attribute url1 in Window A as the cause + // of all these navigations. + NavigationEvent* FindNavigationEvent(const GURL& target_url, + int target_tab_id); + + void AddToReferrerChain(std::vector<ReferrerChainEntry>* referrer_chain, + NavigationEvent* nav_event, + ReferrerChainEntry::URLType type); + // navigation_map_ keeps track of all the observed navigations. This map is // keyed on the resolved request url. In other words, in case of server // redirects, its key is the last server redirect url, otherwise, it is the @@ -108,6 +184,8 @@ content::NotificationRegistrar registrar_; + base::OneShotTimer cleanup_timer_; + DISALLOW_COPY_AND_ASSIGN(SafeBrowsingNavigationObserverManager); }; } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_unittest.cc index 3c4fde5..f38dcf8e 100644 --- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_unittest.cc
@@ -56,6 +56,34 @@ return navigation_observer_manager_->navigation_map(); } + SafeBrowsingNavigationObserverManager::UserGestureMap* user_gesture_map() { + return &navigation_observer_manager_->user_gesture_map_; + } + + SafeBrowsingNavigationObserverManager::HostToIpMap* host_to_ip_map() { + return &navigation_observer_manager_->host_to_ip_map_; + } + + NavigationEvent CreateNavigationEvent(const GURL& destination_url, + const base::Time& timestamp) { + NavigationEvent nav_event; + nav_event.destination_url = destination_url; + nav_event.last_updated = timestamp; + return nav_event; + } + + void CleanUpNavigationEvents() { + navigation_observer_manager_->CleanUpNavigationEvents(); + } + + void CleanUpIpAddresses() { + navigation_observer_manager_->CleanUpIpAddresses(); + } + + void CleanUpUserGestures() { + navigation_observer_manager_->CleanUpUserGestures(); + } + protected: SafeBrowsingNavigationObserverManager* navigation_observer_manager_; SafeBrowsingNavigationObserver* navigation_observer_; @@ -77,8 +105,8 @@ auto nav_map = navigation_map(); ASSERT_EQ(std::size_t(1), nav_map->size()); ASSERT_EQ(std::size_t(1), nav_map->at(GURL("http://foo/1")).size()); - VerifyNavigationEvent(GURL("http://foo/0"), // source_url - GURL("http://foo/0"), // source_main_frame_url + VerifyNavigationEvent(GURL(), // source_url + GURL(), // source_main_frame_url GURL("http://foo/1"), // original_request_url GURL("http://foo/1"), // destination_url tab_id, // source_tab_id @@ -114,4 +142,105 @@ nav_map->at(GURL("http://redirect/1")).at(0)); } +TEST_F(SBNavigationObserverTest, TestCleanUpStaleNavigationEvents) { + // Sets up navigation_map() such that it includes fresh, stale and invalid + // navigation events. + base::Time now = base::Time::Now(); // Fresh + base::Time one_hour_ago = + base::Time::FromDoubleT(now.ToDoubleT() - 60.0 * 60.0); // Stale + base::Time one_minute_ago = + base::Time::FromDoubleT(now.ToDoubleT() - 60.0); // Fresh + base::Time in_an_hour = + base::Time::FromDoubleT(now.ToDoubleT() + 60.0 * 60.0); // Invalid + GURL url_0("http://foo/0"); + GURL url_1("http://foo/1"); + navigation_map()->insert( + std::make_pair(url_0, std::vector<NavigationEvent>())); + navigation_map()->at(url_0).push_back( + CreateNavigationEvent(url_0, one_hour_ago)); + navigation_map()->at(url_0).push_back(CreateNavigationEvent(url_0, now)); + navigation_map()->at(url_0).push_back( + CreateNavigationEvent(url_0, one_minute_ago)); + navigation_map()->at(url_0).push_back( + CreateNavigationEvent(url_0, in_an_hour)); + navigation_map()->insert( + std::make_pair(url_1, std::vector<NavigationEvent>())); + navigation_map()->at(url_1).push_back( + CreateNavigationEvent(url_0, one_hour_ago)); + navigation_map()->at(url_1).push_back( + CreateNavigationEvent(url_0, one_hour_ago)); + ASSERT_EQ(std::size_t(2), navigation_map()->size()); + ASSERT_EQ(std::size_t(4), navigation_map()->at(url_0).size()); + ASSERT_EQ(std::size_t(2), navigation_map()->at(url_1).size()); + + // Cleans up navigation events. + CleanUpNavigationEvents(); + + // Verifies all stale and invalid navigation events are removed. + ASSERT_EQ(std::size_t(1), navigation_map()->size()); + EXPECT_EQ(navigation_map()->end(), navigation_map()->find(url_1)); + EXPECT_EQ(std::size_t(2), navigation_map()->at(url_0).size()); +} + +TEST_F(SBNavigationObserverTest, TestCleanUpStaleUserGestures) { + // Sets up user_gesture_map() such that it includes fresh, stale and invalid + // user gestures. + base::Time now = base::Time::Now(); // Fresh + base::Time one_minute_ago = + base::Time::FromDoubleT(now.ToDoubleT() - 60.0); // Stale + base::Time in_an_hour = + base::Time::FromDoubleT(now.ToDoubleT() + 60.0 * 60.0); // Invalid + AddTab(browser(), GURL("http://foo/1")); + AddTab(browser(), GURL("http://foo/2")); + content::WebContents* content0 = + browser()->tab_strip_model()->GetWebContentsAt(0); + content::WebContents* content1 = + browser()->tab_strip_model()->GetWebContentsAt(1); + content::WebContents* content2 = + browser()->tab_strip_model()->GetWebContentsAt(2); + user_gesture_map()->insert(std::make_pair(content0, now)); + user_gesture_map()->insert(std::make_pair(content1, one_minute_ago)); + user_gesture_map()->insert(std::make_pair(content2, in_an_hour)); + ASSERT_EQ(std::size_t(3), user_gesture_map()->size()); + + // Cleans up user_gesture_map() + CleanUpUserGestures(); + + // Verifies all stale and invalid user gestures are removed. + ASSERT_EQ(std::size_t(1), user_gesture_map()->size()); + EXPECT_NE(user_gesture_map()->end(), user_gesture_map()->find(content0)); + EXPECT_EQ(now, user_gesture_map()->at(content0)); +} + +TEST_F(SBNavigationObserverTest, TestCleanUpStaleIPAddresses) { + // Sets up host_to_ip_map() such that it includes fresh, stale and invalid + // user gestures. + base::Time now = base::Time::Now(); // Fresh + base::Time one_hour_ago = + base::Time::FromDoubleT(now.ToDoubleT() - 60.0 * 60.0); // Stale + base::Time in_an_hour = + base::Time::FromDoubleT(now.ToDoubleT() + 60.0 * 60.0); // Invalid + std::string host_0 = GURL("http://foo/0").host(); + std::string host_1 = GURL("http://bar/1").host(); + host_to_ip_map()->insert( + std::make_pair(host_0, std::vector<ResolvedIPAddress>())); + host_to_ip_map()->at(host_0).push_back(ResolvedIPAddress(now, "1.1.1.1")); + host_to_ip_map()->at(host_0).push_back( + ResolvedIPAddress(one_hour_ago, "2.2.2.2")); + host_to_ip_map()->insert( + std::make_pair(host_1, std::vector<ResolvedIPAddress>())); + host_to_ip_map()->at(host_1).push_back( + ResolvedIPAddress(in_an_hour, "3.3.3.3")); + ASSERT_EQ(std::size_t(2), host_to_ip_map()->size()); + + // Cleans up host_to_ip_map() + CleanUpIpAddresses(); + + // Verifies all stale and invalid IP addresses are removed. + ASSERT_EQ(std::size_t(1), host_to_ip_map()->size()); + EXPECT_EQ(host_to_ip_map()->end(), host_to_ip_map()->find(host_1)); + ASSERT_EQ(std::size_t(1), host_to_ip_map()->at(host_0).size()); + EXPECT_EQ(now, host_to_ip_map()->at(host_0).front().timestamp); +} + } // namespace safe_browsing
diff --git a/chrome/browser/sync_file_system/local/canned_syncable_file_system.cc b/chrome/browser/sync_file_system/local/canned_syncable_file_system.cc index 73d9b608..cbac4c7 100644 --- a/chrome/browser/sync_file_system/local/canned_syncable_file_system.cc +++ b/chrome/browser/sync_file_system/local/canned_syncable_file_system.cc
@@ -242,7 +242,8 @@ if (quota_mode == QUOTA_ENABLED) { quota_manager_ = new QuotaManager( false /* is_incognito */, data_dir_.GetPath(), io_task_runner_.get(), - base::ThreadTaskRunnerHandle::Get().get(), storage_policy.get()); + base::ThreadTaskRunnerHandle::Get().get(), storage_policy.get(), + storage::GetQuotaSettingsFunc()); } std::vector<std::string> additional_allowed_schemes;
diff --git a/chrome/browser/ui/views/critical_notification_bubble_view.cc b/chrome/browser/ui/views/critical_notification_bubble_view.cc index cbaf22be..2e26666 100644 --- a/chrome/browser/ui/views/critical_notification_bubble_view.cc +++ b/chrome/browser/ui/views/critical_notification_bubble_view.cc
@@ -88,15 +88,6 @@ IDS_CRITICAL_NOTIFICATION_HEADLINE_ALTERNATE); } -gfx::ImageSkia CriticalNotificationBubbleView::GetWindowIcon() { - return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( - IDR_UPDATE_MENU_SEVERITY_HIGH); -} - -bool CriticalNotificationBubbleView::ShouldShowWindowIcon() const { - return true; -} - void CriticalNotificationBubbleView::WindowClosing() { refresh_timer_.Stop(); }
diff --git a/chrome/browser/ui/views/critical_notification_bubble_view.h b/chrome/browser/ui/views/critical_notification_bubble_view.h index 3cd0cc2..badc0cf 100644 --- a/chrome/browser/ui/views/critical_notification_bubble_view.h +++ b/chrome/browser/ui/views/critical_notification_bubble_view.h
@@ -16,8 +16,6 @@ // views::BubbleDialogDelegateView overrides: base::string16 GetWindowTitle() const override; - gfx::ImageSkia GetWindowIcon() override; - bool ShouldShowWindowIcon() const override; void WindowClosing() override; bool Cancel() override; bool Accept() override;
diff --git a/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc b/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc index 1df5677..e32de0d 100644 --- a/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc +++ b/chrome/browser/ui/views/outdated_upgrade_bubble_view.cc
@@ -13,13 +13,11 @@ #include "chrome/common/pref_names.h" #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" -#include "chrome/grit/theme_resources.h" #include "components/prefs/pref_service.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/page_navigator.h" #include "content/public/browser/user_metrics.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" #include "ui/views/controls/label.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/layout/layout_constants.h" @@ -100,15 +98,6 @@ return l10n_util::GetStringUTF16(IDS_UPGRADE_BUBBLE_TITLE); } -gfx::ImageSkia OutdatedUpgradeBubbleView::GetWindowIcon() { - return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( - IDR_UPDATE_MENU_SEVERITY_HIGH); -} - -bool OutdatedUpgradeBubbleView::ShouldShowWindowIcon() const { - return true; -} - bool OutdatedUpgradeBubbleView::Cancel() { content::RecordAction(base::UserMetricsAction("OutdatedUpgradeBubble.Later")); return true;
diff --git a/chrome/browser/ui/views/outdated_upgrade_bubble_view.h b/chrome/browser/ui/views/outdated_upgrade_bubble_view.h index dcfc9c9..915e4e7 100644 --- a/chrome/browser/ui/views/outdated_upgrade_bubble_view.h +++ b/chrome/browser/ui/views/outdated_upgrade_bubble_view.h
@@ -31,8 +31,6 @@ // views::BubbleDialogDelegateView methods. void WindowClosing() override; base::string16 GetWindowTitle() const override; - gfx::ImageSkia GetWindowIcon() override; - bool ShouldShowWindowIcon() const override; bool Cancel() override; bool Accept() override; void UpdateButton(views::LabelButton* button, ui::DialogButton type) override;
diff --git a/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.cc b/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.cc index 11decea0..2e88070bc 100644 --- a/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.cc +++ b/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.cc
@@ -32,19 +32,12 @@ return; } quota_manager_ = quota_manager; - { - // crbug.com/349708 - TRACE_EVENT0("io", "QuotaInternalsProxy::RequestInfo"); - quota_manager_->GetAvailableSpace( - base::Bind(&QuotaInternalsProxy::DidGetAvailableSpace, - weak_factory_.GetWeakPtr())); - } + quota_manager_->GetQuotaSettings(base::Bind( + &QuotaInternalsProxy::DidGetSettings, weak_factory_.GetWeakPtr())); - quota_manager_->GetTemporaryGlobalQuota( - base::Bind(&QuotaInternalsProxy::DidGetGlobalQuota, - weak_factory_.GetWeakPtr(), - storage::kStorageTypeTemporary)); + quota_manager_->GetStorageCapacity(base::Bind( + &QuotaInternalsProxy::DidGetCapacity, weak_factory_.GetWeakPtr())); quota_manager_->GetGlobalUsage( storage::kStorageTypeTemporary, @@ -101,23 +94,18 @@ #undef RELAY_TO_HANDLER -void QuotaInternalsProxy::DidGetAvailableSpace(storage::QuotaStatusCode status, - int64_t space) { - // crbug.com/349708 - TRACE_EVENT0("io", "QuotaInternalsProxy::DidGetAvailableSpace"); - - if (status == storage::kQuotaStatusOk) - ReportAvailableSpace(space); +void QuotaInternalsProxy::DidGetSettings( + const storage::QuotaSettings& settings) { + // TODO(michaeln): also report the other config fields + GlobalStorageInfo info(storage::kStorageTypeTemporary); + info.set_quota(settings.pool_size); + ReportGlobalInfo(info); } -void QuotaInternalsProxy::DidGetGlobalQuota(storage::StorageType type, - storage::QuotaStatusCode status, - int64_t quota) { - if (status == storage::kQuotaStatusOk) { - GlobalStorageInfo info(type); - info.set_quota(quota); - ReportGlobalInfo(info); - } +void QuotaInternalsProxy::DidGetCapacity(int64_t total_space, + int64_t available_space) { + // TODO(michaeln): also report total_space + ReportAvailableSpace(available_space); } void QuotaInternalsProxy::DidGetGlobalUsage(storage::StorageType type,
diff --git a/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.h b/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.h index b3e3d661..c8e750f 100644 --- a/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.h +++ b/chrome/browser/ui/webui/quota_internals/quota_internals_proxy.h
@@ -58,10 +58,8 @@ void ReportStatistics(const Statistics& stats); // Called on IO Thread by QuotaManager as callback. - void DidGetAvailableSpace(storage::QuotaStatusCode status, int64_t space); - void DidGetGlobalQuota(storage::StorageType type, - storage::QuotaStatusCode status, - int64_t quota); + void DidGetSettings(const storage::QuotaSettings& settings); + void DidGetCapacity(int64_t total_space, int64_t available_space); void DidGetGlobalUsage(storage::StorageType type, int64_t usage, int64_t unlimited_usage);
diff --git a/chrome/browser/webshare/OWNERS b/chrome/browser/webshare/OWNERS new file mode 100644 index 0000000..bba345d --- /dev/null +++ b/chrome/browser/webshare/OWNERS
@@ -0,0 +1,2 @@ +mgiuca@chromium.com +sammc@chromium.com
diff --git a/chrome/browser/webshare/share_service_impl.cc b/chrome/browser/webshare/share_service_impl.cc new file mode 100644 index 0000000..9f8bb0b --- /dev/null +++ b/chrome/browser/webshare/share_service_impl.cc
@@ -0,0 +1,22 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/webshare/share_service_impl.h" + +#include "mojo/public/cpp/bindings/strong_binding.h" + +// static +void ShareServiceImpl::Create(blink::mojom::ShareServiceRequest request) { + mojo::MakeStrongBinding(base::MakeUnique<ShareServiceImpl>(), + std::move(request)); +} + +void ShareServiceImpl::Share(const std::string& title, + const std::string& text, + const GURL& url, + const ShareCallback& callback) { + // TODO(constantina): Implement Web Share Target here. + NOTIMPLEMENTED(); + callback.Run(base::Optional<std::string>("Not implemented: navigator.share")); +}
diff --git a/chrome/browser/webshare/share_service_impl.h b/chrome/browser/webshare/share_service_impl.h new file mode 100644 index 0000000..83de10f --- /dev/null +++ b/chrome/browser/webshare/share_service_impl.h
@@ -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. + +#ifndef CHROME_BROWSER_WEBSHARE_SHARE_SERVICE_IMPL_H_ +#define CHROME_BROWSER_WEBSHARE_SHARE_SERVICE_IMPL_H_ + +#include <string> + +#include "mojo/public/cpp/bindings/interface_request.h" +#include "third_party/WebKit/public/platform/modules/webshare/webshare.mojom.h" + +class GURL; + +// Desktop implementation of the ShareService Mojo service. +class ShareServiceImpl : public blink::mojom::ShareService { + public: + ShareServiceImpl() = default; + ~ShareServiceImpl() override = default; + + static void Create(mojo::InterfaceRequest<ShareService> request); + + void Share(const std::string& title, + const std::string& text, + const GURL& url, + const ShareCallback& callback) override; + + private: + DISALLOW_COPY_AND_ASSIGN(ShareServiceImpl); +}; + +#endif // CHROME_BROWSER_WEBSHARE_SHARE_SERVICE_IMPL_H_
diff --git a/chrome/browser/webshare/share_service_impl_unittest.cc b/chrome/browser/webshare/share_service_impl_unittest.cc new file mode 100644 index 0000000..fe0e1c7 --- /dev/null +++ b/chrome/browser/webshare/share_service_impl_unittest.cc
@@ -0,0 +1,56 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/bind.h" +#include "base/callback.h" +#include "base/run_loop.h" +#include "chrome/browser/webshare/share_service_impl.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "mojo/public/cpp/bindings/interface_request.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +class ShareServiceTest : public ChromeRenderViewHostTestHarness { + public: + ShareServiceTest() = default; + ~ShareServiceTest() override = default; + + void SetUp() override { + ChromeRenderViewHostTestHarness::SetUp(); + + ShareServiceImpl::Create(mojo::GetProxy(&share_service_)); + } + + void TearDown() override { + ChromeRenderViewHostTestHarness::TearDown(); + } + + void DidShare(const base::Optional<std::string>& expected, + const base::Optional<std::string>& str) { + EXPECT_EQ(expected, str); + + if (!on_callback_.is_null()) + on_callback_.Run(); + } + + blink::mojom::ShareServicePtr share_service_; + base::Closure on_callback_; +}; + +// Basic test to check the Share method calls the callback with the expected +// parameters. +TEST_F(ShareServiceTest, ShareCallbackParams) { + const GURL url("https://www.google.com"); + + base::RunLoop run_loop; + on_callback_ = run_loop.QuitClosure(); + + base::Callback<void(const base::Optional<std::string>&)> callback = + base::Bind( + &ShareServiceTest::DidShare, base::Unretained(this), + base::Optional<std::string>("Not implemented: navigator.share")); + share_service_->Share("title", "text", url, callback); + + run_loop.Run(); +}
diff --git a/chrome/common/safe_browsing/csd.proto b/chrome/common/safe_browsing/csd.proto index ce779cae..c98152a 100644 --- a/chrome/common/safe_browsing/csd.proto +++ b/chrome/common/safe_browsing/csd.proto
@@ -382,46 +382,42 @@ // the leading extension separator. repeated string alternate_extensions = 35; - message URLChainEntry { - enum URLType { - DOWNLOAD_URL = 1; - DOWNLOAD_REFERRER = 2; - LANDING_PAGE = 3; - LANDING_REFERRER = 4; - CLIENT_REDIRECT = 5; - SERVER_REDIRECT = 6; - } - - // [required] The url of this Entry. - optional string url = 1; - - // Type of URLs, such as download url, download referrer, etc. - optional URLType type = 2; - - // IP address corresponding to url. - optional string ip_address = 3; - - // Referrer url of this entry. - optional string referrer = 4; - - // Main frame URL of referrer. - optional string main_frame_referrer = 5; - - // If this URL loads in a different tab/frame from previous one. - optional bool is_retargeting = 6; - - // If there is a user gesture attached to this transition. - optional bool is_user_initiated = 7; - - optional double timestamp_in_millisec = 8; - } // End of URLChainEntry - // URLs transitions from landing referrer to download in reverse chronological // order, i.e. download url comes first in this list, and landing referrer // comes last. - repeated URLChainEntry url_chain = 36; + repeated ReferrerChainEntry referrer_chain = 36; } +message ReferrerChainEntry { + enum URLType { + DOWNLOAD_URL = 1; + LANDING_PAGE = 2; + LANDING_REFERRER = 3; + CLIENT_REDIRECT = 4; + SERVER_REDIRECT = 5; + } + + // [required] The url of this Entry. + optional string url = 1; + + // Type of URLs, such as download url, download referrer, etc. + optional URLType type = 2; + + // IP addresses corresponding to this host. + repeated string ip_addresses = 3; + + // Referrer url of this entry. + optional string referrer_url = 4; + + // Main frame URL of referrer. + optional string referrer_main_frame_url = 5; + + // If this URL loads in a different tab/frame from previous one. + optional bool is_retargeting = 6; + + optional double navigation_time_msec = 7; +} // End of URLChainEntry + message ClientDownloadResponse { enum Verdict { // Download is considered safe.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 068d9351..066be1a 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3122,7 +3122,6 @@ "../browser/download/download_target_determiner_unittest.cc", "../browser/download/download_ui_controller_unittest.cc", "../browser/engagement/important_sites_util_unittest.cc", - "../browser/engagement/site_engagement_eviction_policy_unittest.cc", "../browser/engagement/site_engagement_helper_unittest.cc", "../browser/engagement/site_engagement_score_unittest.cc", "../browser/engagement/site_engagement_service_unittest.cc", @@ -3334,6 +3333,7 @@ "../browser/ui/webui/local_state/local_state_ui_unittest.cc", "../browser/ui/webui/log_web_ui_url_unittest.cc", "../browser/update_client/chrome_update_query_params_delegate_unittest.cc", + "../browser/webshare/share_service_impl_unittest.cc", "../browser/win/chrome_elf_init_unittest.cc", "../browser/win/enumerate_modules_model_unittest.cc", "../common/chrome_content_client_unittest.cc",
diff --git a/chrome/test/DEPS b/chrome/test/DEPS index a975b8f..c65a276 100644 --- a/chrome/test/DEPS +++ b/chrome/test/DEPS
@@ -13,6 +13,8 @@ "+mojo", "+rlz/features", "+services", + "+storage/browser", + "+storage/common", # Tests under chrome/ shouldn't need to access the internals of content/ and # as such are allowed only content/public. If you find yourself wanting to
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc index 2f8ecb4..48ac9eea 100644 --- a/chrome/test/base/in_process_browser_test.cc +++ b/chrome/test/base/in_process_browser_test.cc
@@ -22,6 +22,7 @@ #include "build/build_config.h" #include "chrome/browser/after_startup_task_utils.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/chrome_content_browser_client.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/devtools/devtools_window.h" #include "chrome/browser/lifetime/application_lifetime.h" @@ -248,6 +249,12 @@ google_util::SetMockLinkDoctorBaseURLForTesting(); + // Use hardcoded quota settings to have a consistent testing environment. + const int kQuota = 5 * 1024 * 1024; + quota_settings_ = storage::QuotaSettings(kQuota * 5, kQuota, 0); + ChromeContentBrowserClient::SetDefaultQuotaSettingsForTesting( + "a_settings_); + BrowserTestBase::SetUp(); } @@ -357,6 +364,7 @@ #endif BrowserTestBase::TearDown(); OSCryptMocker::TearDown(); + ChromeContentBrowserClient::SetDefaultQuotaSettingsForTesting(nullptr); } void InProcessBrowserTest::CloseBrowserSynchronously(Browser* browser) {
diff --git a/chrome/test/base/in_process_browser_test.h b/chrome/test/base/in_process_browser_test.h index c66260e..5dd5428 100644 --- a/chrome/test/base/in_process_browser_test.h +++ b/chrome/test/base/in_process_browser_test.h
@@ -14,6 +14,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_base.h" +#include "storage/browser/quota/quota_settings.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/base/page_transition_types.h" @@ -260,6 +261,9 @@ // This is reset for every test case. bool run_accessibility_checks_for_test_case_; + // We use hardcoded quota settings to have a consistent testing environment. + storage::QuotaSettings quota_settings_; + #if defined(OS_MACOSX) base::mac::ScopedNSAutoreleasePool* autorelease_pool_; std::unique_ptr<ScopedBundleSwizzlerMac> bundle_swizzler_;
diff --git a/chrome/test/data/safe_browsing/download_protection/navigation_observer/landing.html b/chrome/test/data/safe_browsing/download_protection/navigation_observer/landing.html new file mode 100644 index 0000000..f4bd7d5 --- /dev/null +++ b/chrome/test/data/safe_browsing/download_protection/navigation_observer/landing.html
@@ -0,0 +1,19 @@ +<html> + <head> + <script> + // Click on a link by id to start a test case. + function clickLink(linkId) { + var node = document.getElementById(linkId); + if (node != null) { + // Click and open link in the same tab. + node.click(); + } + } + </script> + </head> + <body> + <a id="download_on_landing_page" href="../signed.exe"> + Direct download from landing page + </a><br> + </body> +</html>
diff --git a/chrome/test/data/safe_browsing/download_protection/navigation_observer/landing_referrer.html b/chrome/test/data/safe_browsing/download_protection/navigation_observer/landing_referrer.html new file mode 100644 index 0000000..d7f29275 --- /dev/null +++ b/chrome/test/data/safe_browsing/download_protection/navigation_observer/landing_referrer.html
@@ -0,0 +1,17 @@ +<html> + <head> + <script> + // Click on a link by id to start a test case. + function clickLink(linkId) { + var node = document.getElementById(linkId); + // Click and open link in the same tab. + node.click(); + } + </script> + </head> + <body> + <a id="link_to_landing" href="landing.html"> + Link to landing + </a><br> + </body> +</html>
diff --git a/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html b/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html index ba37365..0868814 100644 --- a/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html +++ b/chrome/test/data/safe_browsing/download_protection/navigation_observer/navigation_observer_tests.html
@@ -26,7 +26,7 @@ tab.document.write('<META HTTP-EQUIV="refresh" content="0; url=../signed.exe">'); tab.document.close(); } - + // Trigger download in a new tab and the download is from a data url. function downloadInNewTabWithDataURL() { var tab = window.open(''); @@ -34,7 +34,7 @@ tab.document.write('<META HTTP-EQUIV="refresh" content="0; url=data:application/octet-stream;base64,a2poYWxrc2hkbGtoYXNka2xoYXNsa2RoYWxraGtoYWxza2hka2xzamFoZGxramhhc2xka2hhc2xrZGgKYXNrZGpoa2FzZGpoYWtzaGRrYXNoZGtoYXNrZGhhc2tkaGthc2hka2Foc2RraGFrc2hka2FzaGRraGFzCmFza2pkaGFrc2hkbSxjbmtzamFoZGtoYXNrZGhhc2tka2hrYXNkCjg3MzQ2ODEyNzQ2OGtqc2hka2FoZHNrZGhraApha3NqZGthc2Roa3NkaGthc2hka2FzaGtkaAohISomXkAqJl4qYWhpZGFzeWRpeWlhc1xcb1wKa2Fqc2Roa2FzaGRrYXNoZGsKYWtzamRoc2tkaAplbmQK">'); tab.document.close(); } - + // Create a data blob and save it as a test.exe file in filesystem's // space with use URL filesystem:http://test_host/temporary/test.exe // to download it. @@ -117,6 +117,14 @@ <a id="html5_file_api" href="" onclick="downloadViaFileApi()"> Download via HTML5 file system API - </a> + </a><br> + + <a id="complete_referrer_chain" href="redirect_to_landing.html"> + Click on landing referrer and landing page then reach download + </a><br> + + <a id="attribution_within_two_user_gestures" href="page_before_landing_referrer.html"> + Attribution should not trace back more than 2 user gestures. + </a><br> </body> </html>
diff --git a/chrome/test/data/safe_browsing/download_protection/navigation_observer/page_before_landing_referrer.html b/chrome/test/data/safe_browsing/download_protection/navigation_observer/page_before_landing_referrer.html new file mode 100644 index 0000000..1c898f7 --- /dev/null +++ b/chrome/test/data/safe_browsing/download_protection/navigation_observer/page_before_landing_referrer.html
@@ -0,0 +1,19 @@ +<html> + <head> + <script> + // Click on a link by id to start a test case. + function clickLink(linkId) { + var node = document.getElementById(linkId); + if (node != null) { + // Click and open link in the same tab. + node.click(); + } + } + </script> + </head> + <body> + <a id="link_to_landing_referrer" href="landing_referrer.html"> + Link to landing referrer + </a><br> + </body> +</html>
diff --git a/chrome/test/data/safe_browsing/download_protection/navigation_observer/redirect_to_landing.html b/chrome/test/data/safe_browsing/download_protection/navigation_observer/redirect_to_landing.html new file mode 100644 index 0000000..b32b795 --- /dev/null +++ b/chrome/test/data/safe_browsing/download_protection/navigation_observer/redirect_to_landing.html
@@ -0,0 +1,8 @@ +<html> + <head> + <META HTTP-EQUIV="refresh" content="0; url=landing.html"> + </head> + <body> + Redirecting to landing.html. + </body> +</html>
diff --git a/chrome/test/data/webui/settings/advanced_page_browsertest.js b/chrome/test/data/webui/settings/advanced_page_browsertest.js index 5a10142..e8652d37 100644 --- a/chrome/test/data/webui/settings/advanced_page_browsertest.js +++ b/chrome/test/data/webui/settings/advanced_page_browsertest.js
@@ -41,14 +41,14 @@ }); test('advanced pages', function() { - var page = self.getPage('advanced'); + var page = self.getPage('basic'); var sections = ['privacy', 'passwordsAndForms', 'languages', 'downloads', 'reset']; if (cr.isChromeOS) sections = sections.concat(['dateTime', 'bluetooth', 'a11y']); for (var i = 0; i < sections.length; i++) { - var section = self.getSection(page, sections[i]); + var section = self.getSection(page, sections[i], true /* advanced */); expectTrue(!!section); self.verifySubpagesHidden(section); }
diff --git a/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js b/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js index 9bc4ec64..3f7f6ffa3 100644 --- a/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js +++ b/chrome/test/data/webui/settings/bluetooth_page_browsertest_chromeos.js
@@ -60,9 +60,9 @@ var self = this; self.toggleAdvanced(); - var advanced = self.getPage('advanced'); - assertTrue(!!advanced); - advanced.set('pageVisibility.bluetooth', true); + var page = self.getPage('basic'); + assertTrue(!!page); + page.set('pageVisibility.bluetooth', true); Polymer.dom.flush(); /** @type {!Array<!chrome.bluetooth.Device>} */ var fakeDevices_ = [ @@ -94,7 +94,7 @@ suite('SettingsBluetoothPage', function() { test('enable', function() { assertFalse(self.bluetoothApi_.adapterState.powered); - var bluetoothSection = self.getSection(advanced, 'bluetooth'); + var bluetoothSection = self.getSection(page, 'bluetooth'); assertTrue(!!bluetoothSection); var bluetooth = bluetoothSection.querySelector('settings-bluetooth-page'); @@ -119,7 +119,7 @@ }); test('device list', function() { - var bluetoothSection = self.getSection(advanced, 'bluetooth'); + var bluetoothSection = self.getSection(page, 'bluetooth'); var bluetooth = bluetoothSection.querySelector('settings-bluetooth-page'); assertTrue(!!bluetooth); @@ -153,7 +153,7 @@ }); test('device dialog', function() { - var bluetoothSection = self.getSection(advanced, 'bluetooth'); + var bluetoothSection = self.getSection(page, 'bluetooth'); var bluetooth = bluetoothSection.querySelector('settings-bluetooth-page'); assertTrue(!!bluetooth);
diff --git a/chrome/test/data/webui/settings/languages_page_browsertest.js b/chrome/test/data/webui/settings/languages_page_browsertest.js index 8a64216e..fe801319 100644 --- a/chrome/test/data/webui/settings/languages_page_browsertest.js +++ b/chrome/test/data/webui/settings/languages_page_browsertest.js
@@ -47,7 +47,7 @@ testing.Test.disableAnimationsAndTransitions(); this.toggleAdvanced(); - var advanced = this.getPage('advanced'); + var page = this.getPage('basic'); var languagesSection; var languagesPage; @@ -81,10 +81,10 @@ } suiteSetup(function() { - advanced.set('pageVisibility.languages', true); + page.set('pageVisibility.languages', true); Polymer.dom.flush(); - languagesSection = assert(this.getSection(advanced, 'languages')); + languagesSection = assert(this.getSection(page, 'languages')); languagesPage = assert( languagesSection.querySelector('settings-languages-page')); languagesCollapse = languagesPage.$.languagesCollapse;
diff --git a/chrome/test/data/webui/settings/settings_main_test.js b/chrome/test/data/webui/settings/settings_main_test.js index 177581b8..dc271511 100644 --- a/chrome/test/data/webui/settings/settings_main_test.js +++ b/chrome/test/data/webui/settings/settings_main_test.js
@@ -104,20 +104,40 @@ }); }); + /** @return {!HTMLElement} */ + function getToggleContainer() { + var page = settingsMain.$$('settings-basic-page'); + assertTrue(!!page); + var toggleContainer = page.$$('#toggleContainer'); + assertTrue(!!toggleContainer); + return toggleContainer; + } + + /** + * Asserts that the Advanced toggle container exists in the combined + * settings page and asserts whether it should be visible. + * @param {boolean} expectedVisible + */ + function assertToggleContainerVisible(expectedVisible) { + var toggleContainer = getToggleContainer(); + if (expectedVisible) + assertNotEquals('none', toggleContainer.style.display); + else + assertEquals('none', toggleContainer.style.display); + } + test('no results page shows and hides', function() { Polymer.dom.flush(); var noSearchResults = settingsMain.$.noSearchResults; assertTrue(!!noSearchResults); assertTrue(noSearchResults.hidden); - var toggleContainer = settingsMain.$$('#toggleContainer'); - assertTrue(!!toggleContainer); - assertNotEquals('none', toggleContainer.style.display); + assertToggleContainerVisible(true); searchManager.setMatchesFound(false); return settingsMain.searchContents('Query1').then(function() { assertFalse(noSearchResults.hidden); - assertEquals('none', toggleContainer.style.display); + assertToggleContainerVisible(false); searchManager.setMatchesFound(true); return settingsMain.searchContents('Query2'); @@ -134,20 +154,37 @@ assertTrue(!!noSearchResults); assertTrue(noSearchResults.hidden); - var toggleContainer = settingsMain.$$('#toggleContainer'); - assertTrue(!!toggleContainer); - assertNotEquals('none', toggleContainer.style.display); + assertToggleContainerVisible(true); searchManager.setMatchesFound(false); // Clearing the search box is effectively a search for the empty string. return settingsMain.searchContents('').then(function() { Polymer.dom.flush(); assertTrue(noSearchResults.hidden); - assertNotEquals('none', toggleContainer.style.display); + assertToggleContainerVisible(true); }); }); /** + * Asserts the visibility of the basic and advanced pages. + * @param {string} Expected 'display' value for the basic page. + * @param {string} Expected 'display' value for the advanced page. + */ + function assertPageVisibility(expectedBasic, expectedAdvanced) { + Polymer.dom.flush(); + var page = settingsMain.$$('settings-basic-page'); + assertEquals( + expectedBasic, page.$$('#basicPage').style.display); + assertEquals( + expectedAdvanced, page.$$('#advancedPage').style.display); + } + + // TODO(michaelpg): It would be better not to drill into + // settings-basic-page. If search should indeed only work in Settings + // (as opposed to Advanced), perhaps some of this logic should be + // delegated to settings-basic-page now instead of settings-main. + + /** * Asserts the visibility of the basic and advanced pages after exiting * search mode. * @param {string} Expected 'display' value for the basic page. @@ -161,13 +198,7 @@ searchManager.setMatchesFound(false); return settingsMain.searchContents(''); }).then(function() { - Polymer.dom.flush(); - assertEquals( - expectedBasic, - settingsMain.$$('settings-basic-page').style.display); - assertEquals( - expectedAdvanced, - settingsMain.$$('settings-advanced-page').style.display); + assertPageVisibility(expectedBasic, expectedAdvanced); }); } @@ -202,39 +233,36 @@ Polymer.dom.flush(); // Simulate clicking the left arrow to go back to the search results. - settingsMain.currentRouteChanged(settings.Route.BASIC); - Polymer.dom.flush(); - assertEquals( - '', settingsMain.$$('settings-basic-page').style.display); - assertEquals( - '', settingsMain.$$('settings-advanced-page').style.display); + settings.navigateTo(settings.Route.BASIC); + assertPageVisibility('', ''); }); }); + // TODO(michaelpg): Move these to a new test for settings-basic-page. test('can collapse advanced on advanced section route', function() { settings.navigateTo(settings.Route.PRIVACY); Polymer.dom.flush(); - var advancedToggle = settingsMain.$$('#advancedToggle'); + var advancedToggle = + getToggleContainer().querySelector('#advancedToggle'); assertTrue(!!advancedToggle); MockInteractions.tap(advancedToggle); Polymer.dom.flush(); - assertFalse(settingsMain.showPages_.advanced); + assertPageVisibility('', 'none'); }); test('navigating to a basic page does not collapse advanced', function() { settings.navigateTo(settings.Route.PRIVACY); Polymer.dom.flush(); - var advancedToggle = settingsMain.$$('#advancedToggle'); - assertTrue(!!advancedToggle); + assertToggleContainerVisible(true); settings.navigateTo(settings.Route.PEOPLE); Polymer.dom.flush(); - assertTrue(settingsMain.showPages_.advanced); + assertPageVisibility('', ''); }); }); }
diff --git a/chrome/test/data/webui/settings/settings_page_browsertest.js b/chrome/test/data/webui/settings/settings_page_browsertest.js index 62e9550..a1c5ef5 100644 --- a/chrome/test/data/webui/settings/settings_page_browsertest.js +++ b/chrome/test/data/webui/settings/settings_page_browsertest.js
@@ -46,12 +46,12 @@ toggleAdvanced: function() { var settingsMain = document.querySelector('* /deep/ settings-main'); assert(!!settingsMain); - settingsMain.toggleAdvancedPage_(); + settingsMain.advancedToggleExpanded = !settingsMain.advancedToggleExpanded; Polymer.dom.flush(); }, /** - * @param {string} type The settings page type, e.g. 'advanced' or 'basic'. + * @param {string} type The settings page type, e.g. 'about' or 'basic'. * @return {!PolymerElement} The PolymerElement for the page. */ getPage: function(type) {
diff --git a/chrome/test/data/webui/settings/settings_subpage_browsertest.js b/chrome/test/data/webui/settings/settings_subpage_browsertest.js index d71eb4b..1e0e804 100644 --- a/chrome/test/data/webui/settings/settings_subpage_browsertest.js +++ b/chrome/test/data/webui/settings/settings_subpage_browsertest.js
@@ -13,15 +13,15 @@ * @constructor * @extends {SettingsPageBrowserTest} * - * @param {string} pageId 'basic' or 'advanced'. - * @param {!Array<string>} subPages + * @param {string} pageId Just 'basic'. TODO(michaelpg): Add 'about' if we want + * to, but that requires wrapping its sole <settings-section> in a dom-if. */ -function SettingsSubPageBrowserTest(pageId, subPages) { +function SettingsSubPageBrowserTest(pageId) { /** @type {string} */ this.pageId = pageId; /** @type {!Array<string>} */ - this.subPages = subPages; + this.subPages = []; } SettingsSubPageBrowserTest.prototype = { @@ -39,25 +39,19 @@ /** @override */ setUp: function() { SettingsPageBrowserTest.prototype.setUp.call(this); - // Explicitly hide all of the pages (not strictly required but is more - // clear than relying on undefined -> hidden). - this.toggleAdvanced(); - this.hideSubPages_(); + this.verifySubPagesHidden_(); }, /* - * This will hide all subpages in |this.subPages|. Note: any existing subpages - * not listed in |this.subPages| will be shown. + * Checks all subpages are hidden first. + * @private */ - hideSubPages_: function() { + verifySubPagesHidden_: function() { var page = this.getPage(this.pageId); - var visibility = {}; - this.subPages.forEach(function(subPage) { - visibility[subPage] = false; - }); assertEquals(0, Object.keys(page.pageVisibility).length); - page.pageVisibility = visibility; - // Ensure all pages are hidden. + + // Ensure all pages are still hidden after the dom-ifs compute their |if|. + Polymer.dom.flush(); var sections = page.shadowRoot.querySelectorAll('settings-section'); assertTrue(!!sections); assertEquals(0, sections.length); @@ -70,7 +64,7 @@ * @param {Node} page * @param {string} subpage */ - testPage: function(page, subPage) { + testSubPage: function(page, subPage) { Polymer.dom.flush(); expectFalse(!!this.getSection(page, subPage)); var startTime = window.performance.now(); @@ -85,39 +79,28 @@ }, testSubPages: function() { - Polymer.dom.flush(); var page = this.getPage(this.pageId); this.subPages.forEach(function(subPage) { - if (this.includePage(subPage)) - test(subPage, this.testPage.bind(this, page, subPage)); + test(subPage, this.testSubPage.bind(this, page, subPage)); }.bind(this)); }, - - /** - * @param {string} id - * @return {boolean} - */ - includePage: function(id) { - if (cr.isChromeOS) - return id != 'people' && id != 'defaultBrowser'; - return id != 'internet' && id != 'users' && id != 'device' && - id != 'dateTime' && id != 'bluetooth' && id != 'a11y'; - }, }; /** @constructor @extends {SettingsSubPageBrowserTest} */ function SettingsBasicSubPageBrowserTest() { - var subPages = [ + SettingsSubPageBrowserTest.call(this, 'basic'); + + /** @override */ + this.subPages = [ 'people', - 'internet', 'appearance', 'onStartup', 'search', - 'defaultBrowser', - 'device' ]; - - SettingsSubPageBrowserTest.call(this, 'basic', subPages); + if (cr.isChromeOS) + this.subPages.push('device', 'internet'); + else + this.subPages.push('defaultBrowser'); } SettingsBasicSubPageBrowserTest.prototype = { @@ -131,22 +114,33 @@ /** @constructor @extends {SettingsSubPageBrowserTest} */ function SettingsAdvancedSubPageBrowserTest() { - var subPages = [ - 'dateTime', + // "Advanced" sections live in the settings-basic-page. + SettingsSubPageBrowserTest.call(this, 'basic'); + + /** @override */ + this.subPages = [ 'privacy', - 'bluetooth', 'passwordsAndForms', 'languages', 'downloads', + 'printing', + 'a11y', 'reset', - 'a11y' ]; - - SettingsSubPageBrowserTest.call(this, 'advanced', subPages); + if (cr.isChromeOS) + this.subPages.push('dateTime', 'bluetooth'); + else + this.subPages.push('system'); }; SettingsAdvancedSubPageBrowserTest.prototype = { __proto__: SettingsSubPageBrowserTest.prototype, + + /** @override */ + setUp: function() { + this.toggleAdvanced(); + SettingsSubPageBrowserTest.prototype.setUp.call(this); + }, }; TEST_F('SettingsAdvancedSubPageBrowserTest', 'SubPages', function() {
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc index 7d9e4a3..071298b5 100644 --- a/chromecast/browser/cast_content_browser_client.cc +++ b/chromecast/browser/cast_content_browser_client.cc
@@ -47,6 +47,7 @@ #include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/resource_dispatcher_host.h" +#include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_descriptors.h" #include "content/public/common/content_switches.h" @@ -322,6 +323,16 @@ return new CastQuotaPermissionContext(); } +void CastContentBrowserClient::GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + content::BrowserThread::PostTaskAndReplyWithResult( + content::BrowserThread::FILE, FROM_HERE, + base::Bind(&storage::CalculateNominalDynamicSettings, + partition->GetPath(), context->IsOffTheRecord()), + callback); +} void CastContentBrowserClient::AllowCertificateError( content::WebContents* web_contents, int cert_error,
diff --git a/chromecast/browser/cast_content_browser_client.h b/chromecast/browser/cast_content_browser_client.h index 0ed31c1..cc07dcb 100644 --- a/chromecast/browser/cast_content_browser_client.h +++ b/chromecast/browser/cast_content_browser_client.h
@@ -117,6 +117,10 @@ void ResourceDispatcherHostCreated() override; std::string GetApplicationLocale() override; content::QuotaPermissionContext* CreateQuotaPermissionContext() override; + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override; void AllowCertificateError( content::WebContents* web_contents, int cert_error,
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index e7b891e6..1872e6aa 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -190,6 +190,8 @@ "$target_gen_dir/devtools/protocol/storage.h", "$target_gen_dir/devtools/protocol/system_info.cc", "$target_gen_dir/devtools/protocol/system_info.h", + "$target_gen_dir/devtools/protocol/target.cc", + "$target_gen_dir/devtools/protocol/target.h", "$target_gen_dir/devtools/protocol/tethering.cc", "$target_gen_dir/devtools/protocol/tethering.h", "$target_gen_dir/devtools/protocol/tracing.cc", @@ -936,6 +938,8 @@ "memory/memory_monitor_win.h", "memory/memory_pressure_controller_impl.cc", "memory/memory_pressure_controller_impl.h", + "memory/memory_state_updater.cc", + "memory/memory_state_updater.h", "message_port_message_filter.cc", "message_port_message_filter.h", "message_port_provider.cc",
diff --git a/content/browser/appcache/appcache_host_unittest.cc b/content/browser/appcache/appcache_host_unittest.cc index 1e19f24..221afb21 100644 --- a/content/browser/appcache/appcache_host_unittest.cc +++ b/content/browser/appcache/appcache_host_unittest.cc
@@ -110,7 +110,7 @@ void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner, const GURL& origin, storage::StorageType type, - const GetUsageAndQuotaCallback& callback) override {} + const UsageAndQuotaCallback& callback) override {} void NotifyOriginInUse(const GURL& origin) override { inuse_[origin] += 1; }
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc index b754546..d1ed641 100644 --- a/content/browser/appcache/appcache_storage_impl_unittest.cc +++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -277,12 +277,13 @@ base::FilePath(), io_thread->task_runner().get(), db_thread->task_runner().get(), - NULL), + nullptr, + storage::GetQuotaSettingsFunc()), async_(false) {} void GetUsageAndQuota(const GURL& origin, storage::StorageType type, - const GetUsageAndQuotaCallback& callback) override { + const UsageAndQuotaCallback& callback) override { EXPECT_EQ(storage::kStorageTypeTemporary, type); if (async_) { base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -293,7 +294,7 @@ CallCallback(callback); } - void CallCallback(const GetUsageAndQuotaCallback& callback) { + void CallCallback(const UsageAndQuotaCallback& callback) { callback.Run(storage::kQuotaStatusOk, 0, kMockQuota); } @@ -345,7 +346,7 @@ void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner, const GURL& origin, storage::StorageType type, - const GetUsageAndQuotaCallback& callback) override {} + const UsageAndQuotaCallback& callback) override {} int notify_storage_accessed_count_; int notify_storage_modified_count_;
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc index 3127778..7219d1f 100644 --- a/content/browser/background_sync/background_sync_manager_unittest.cc +++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -136,9 +136,7 @@ // Create a StoragePartition with the correct BrowserContext so that the // BackgroundSyncManager can find the BrowserContext through it. storage_partition_impl_.reset(new StoragePartitionImpl( - helper_->browser_context(), base::FilePath(), nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr)); + helper_->browser_context(), base::FilePath(), nullptr)); helper_->context_wrapper()->set_storage_partition( storage_partition_impl_.get());
diff --git a/content/browser/background_sync/background_sync_service_impl_unittest.cc b/content/browser/background_sync/background_sync_service_impl_unittest.cc index 457d8ab..158c518 100644 --- a/content/browser/background_sync/background_sync_service_impl_unittest.cc +++ b/content/browser/background_sync/background_sync_service_impl_unittest.cc
@@ -133,9 +133,7 @@ // Creates a StoragePartition so that the BackgroundSyncManager can // use it to access the BrowserContext. storage_partition_impl_.reset(new StoragePartitionImpl( - embedded_worker_helper_->browser_context(), base::FilePath(), nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr)); + embedded_worker_helper_->browser_context(), base::FilePath(), nullptr)); embedded_worker_helper_->context_wrapper()->set_storage_partition( storage_partition_impl_.get()); }
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index ff0c374..2d71994 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc
@@ -93,7 +93,7 @@ #include "device/time_zone_monitor/time_zone_monitor.h" #include "media/base/media.h" #include "media/base/user_input_monitor.h" -#include "media/midi/midi_manager.h" +#include "media/midi/midi_service.h" #include "mojo/edk/embedder/embedder.h" #include "mojo/edk/embedder/scoped_ipc_support.h" #include "net/base/network_change_notifier.h" @@ -1140,9 +1140,9 @@ resource_dispatcher_host_->Shutdown(); } // Request shutdown to clean up allocated resources on the IO thread. - if (midi_manager_) { - TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:MidiManager"); - midi_manager_->Shutdown(); + if (midi_service_) { + TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:MidiService"); + midi_service_->Shutdown(); } memory_pressure_monitor_.reset(); @@ -1405,8 +1405,8 @@ } { - TRACE_EVENT0("startup", "BrowserThreadsStarted::Subsystem:MidiManager"); - midi_manager_.reset(midi::MidiManager::Create()); + TRACE_EVENT0("startup", "BrowserThreadsStarted::Subsystem:MidiService"); + midi_service_.reset(new midi::MidiService); } #if defined(OS_WIN)
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h index 77c98c5..856a67b6 100644 --- a/content/browser/browser_main_loop.h +++ b/content/browser/browser_main_loop.h
@@ -52,7 +52,7 @@ } // namespace media namespace midi { -class MidiManager; +class MidiService; } // namespace midi namespace mojo { @@ -145,7 +145,7 @@ device::TimeZoneMonitor* time_zone_monitor() const { return time_zone_monitor_.get(); } - midi::MidiManager* midi_manager() const { return midi_manager_.get(); } + midi::MidiService* midi_service() const { return midi_service_.get(); } base::Thread* indexed_db_thread() const { return indexed_db_thread_.get(); } bool is_tracing_startup_for_duration() const { @@ -291,7 +291,7 @@ std::unique_ptr<AudioManagerThread> audio_thread_; media::ScopedAudioManagerPtr audio_manager_; - std::unique_ptr<midi::MidiManager> midi_manager_; + std::unique_ptr<midi::MidiService> midi_service_; #if defined(OS_WIN) std::unique_ptr<media::SystemMessageWindowWin> system_message_window_;
diff --git a/content/browser/browsing_data/clear_site_data_throttle_browsertest.cc b/content/browser/browsing_data/clear_site_data_throttle_browsertest.cc index f5e4364..f8ae1b6d 100644 --- a/content/browser/browsing_data/clear_site_data_throttle_browsertest.cc +++ b/content/browser/browsing_data/clear_site_data_throttle_browsertest.cc
@@ -21,6 +21,7 @@ #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" +#include "storage/browser/quota/quota_settings.h" #include "testing/gmock/include/gmock/gmock.h" #include "url/origin.h" #include "url/url_constants.h" @@ -40,6 +41,13 @@ bool remove_storage, bool remove_cache, const base::Closure& callback)); + + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override { + callback.Run(storage::GetHardCodedSettings(100 * 1024 * 1024)); + } }; class TestContentBrowserClient : public MockContentBrowserClient {
diff --git a/content/browser/database_tracker_unittest.cc b/content/browser/database_tracker_unittest.cc index c1ec078..f3eea24 100644 --- a/content/browser/database_tracker_unittest.cc +++ b/content/browser/database_tracker_unittest.cc
@@ -140,7 +140,7 @@ void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner, const GURL& origin, storage::StorageType type, - const GetUsageAndQuotaCallback& callback) override {} + const UsageAndQuotaCallback& callback) override {} void SimulateQuotaManagerDestroyed() { if (registered_client_) {
diff --git a/content/browser/devtools/BUILD.gn b/content/browser/devtools/BUILD.gn index ddda5baf..dc026ba 100644 --- a/content/browser/devtools/BUILD.gn +++ b/content/browser/devtools/BUILD.gn
@@ -82,6 +82,8 @@ "protocol/storage.h", "protocol/system_info.cc", "protocol/system_info.h", + "protocol/target.cc", + "protocol/target.h", "protocol/tethering.cc", "protocol/tethering.h", "protocol/tracing.cc",
diff --git a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py index 60178dd..34e0970b 100755 --- a/content/browser/devtools/protocol/devtools_protocol_handler_generator.py +++ b/content/browser/devtools/protocol/devtools_protocol_handler_generator.py
@@ -643,7 +643,7 @@ includes = [] fields_init = [] -browser_domains_list = ["Target", "Input"] +browser_domains_list = ["Input"] browser_commands_list = [] async_commands_list = [ "Input.synthesizePinchGesture",
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc index 254a4ac..78778f4 100644 --- a/content/browser/devtools/protocol/target_handler.cc +++ b/content/browser/devtools/protocol/target_handler.cc
@@ -11,10 +11,7 @@ #include "content/browser/frame_host/render_frame_host_impl.h" namespace content { -namespace devtools { -namespace target { - -using Response = DevToolsProtocolClient::Response; +namespace protocol { namespace { @@ -84,12 +81,13 @@ return result; } -scoped_refptr<TargetInfo> CreateInfo(DevToolsAgentHost* host) { - return TargetInfo::Create() - ->set_target_id(host->GetId()) - ->set_title(host->GetTitle()) - ->set_url(host->GetURL().spec()) - ->set_type(host->GetType()); +std::unique_ptr<Target::TargetInfo> CreateInfo(DevToolsAgentHost* host) { + return Target::TargetInfo::Create() + .SetTargetId(host->GetId()) + .SetTitle(host->GetTitle()) + .SetUrl(host->GetURL().spec()) + .SetType(host->GetType()) + .Build(); } } // namespace @@ -103,7 +101,11 @@ } TargetHandler::~TargetHandler() { - Detached(); +} + +void TargetHandler::Wire(UberDispatcher* dispatcher) { + frontend_.reset(new Target::Frontend(dispatcher->channel())); + Target::Dispatcher::wire(dispatcher, this); } void TargetHandler::SetRenderFrameHost(RenderFrameHostImpl* render_frame_host) { @@ -111,16 +113,13 @@ UpdateFrames(); } -void TargetHandler::SetClient(std::unique_ptr<Client> client) { - client_.swap(client); -} - -void TargetHandler::Detached() { +Response TargetHandler::Disable() { SetAutoAttach(false, false); SetDiscoverTargets(false); for (const auto& id_host : attached_hosts_) id_host.second->DetachClient(this); attached_hosts_.clear(); + return Response::OK(); } void TargetHandler::UpdateServiceWorkers() { @@ -198,8 +197,7 @@ void TargetHandler::TargetCreatedInternal(DevToolsAgentHost* host) { if (reported_hosts_.find(host->GetId()) != reported_hosts_.end()) return; - client_->TargetCreated( - TargetCreatedParams::Create()->set_target_info(CreateInfo(host))); + frontend_->TargetCreated(CreateInfo(host)); reported_hosts_[host->GetId()] = host; } @@ -208,8 +206,7 @@ auto it = reported_hosts_.find(host->GetId()); if (it == reported_hosts_.end()) return; - client_->TargetDestroyed(TargetDestroyedParams::Create() - ->set_target_id(host->GetId())); + frontend_->TargetDestroyed(host->GetId()); reported_hosts_.erase(it); } @@ -218,9 +215,7 @@ if (!host->AttachClient(this)) return false; attached_hosts_[host->GetId()] = host; - client_->AttachedToTarget(AttachedToTargetParams::Create() - ->set_target_info(CreateInfo(host)) - ->set_waiting_for_debugger(waiting_for_debugger)); + frontend_->AttachedToTarget(CreateInfo(host), waiting_for_debugger); return true; } @@ -229,8 +224,7 @@ if (it == attached_hosts_.end()) return; host->DetachClient(this); - client_->DetachedFromTarget(DetachedFromTargetParams::Create()-> - set_target_id(host->GetId())); + frontend_->DetachedFromTarget(host->GetId()); attached_hosts_.erase(it); } @@ -284,8 +278,8 @@ } Response TargetHandler::SetRemoteLocations( - const std::vector<std::unique_ptr<base::DictionaryValue>>& locations) { - return Response::ServerError("Not supported"); + std::unique_ptr<protocol::Array<Target::RemoteLocation>>) { + return Response::Error("Not supported"); } Response TargetHandler::AttachToTarget(const std::string& target_id, @@ -294,7 +288,7 @@ scoped_refptr<DevToolsAgentHost> agent_host = DevToolsAgentHost::GetForId(target_id); if (!agent_host) - return Response::ServerError("No target with given id found"); + return Response::InvalidParams("No target with given id found"); *out_success = AttachToTargetInternal(agent_host.get(), false); return Response::OK(); } @@ -302,7 +296,7 @@ Response TargetHandler::DetachFromTarget(const std::string& target_id) { auto it = attached_hosts_.find(target_id); if (it == attached_hosts_.end()) - return Response::InternalError("Not attached to the target"); + return Response::Error("Not attached to the target"); DevToolsAgentHost* agent_host = it->second.get(); DetachFromTargetInternal(agent_host); return Response::OK(); @@ -320,7 +314,7 @@ Response TargetHandler::GetTargetInfo( const std::string& target_id, - scoped_refptr<TargetInfo>* target_info) { + std::unique_ptr<Target::TargetInfo>* target_info) { // TODO(dgozman): only allow reported hosts. scoped_refptr<DevToolsAgentHost> agent_host( DevToolsAgentHost::GetForId(target_id)); @@ -345,41 +339,42 @@ scoped_refptr<DevToolsAgentHost> agent_host = DevToolsAgentHost::GetForId(target_id); if (!agent_host) - return Response::ServerError("No target with given id found"); + return Response::InvalidParams("No target with given id found"); *out_success = agent_host->Close(); return Response::OK(); } Response TargetHandler::CreateBrowserContext(std::string* out_context_id) { - return Response::ServerError("Not supported"); + return Response::Error("Not supported"); } Response TargetHandler::DisposeBrowserContext(const std::string& context_id, bool* out_success) { - return Response::ServerError("Not supported"); + return Response::Error("Not supported"); } Response TargetHandler::CreateTarget(const std::string& url, - const int* width, - const int* height, - const std::string* context_id, + Maybe<int> width, + Maybe<int> height, + Maybe<std::string> context_id, std::string* out_target_id) { DevToolsManagerDelegate* delegate = DevToolsManager::GetInstance()->delegate(); if (!delegate) - return Response::ServerError("Not supported"); + return Response::Error("Not supported"); scoped_refptr<content::DevToolsAgentHost> agent_host = delegate->CreateNewTarget(GURL(url)); if (!agent_host) - return Response::ServerError("Not supported"); + return Response::Error("Not supported"); *out_target_id = agent_host->GetId(); return Response::OK(); } Response TargetHandler::GetTargets( - std::vector<scoped_refptr<TargetInfo>>* target_infos) { + std::unique_ptr<protocol::Array<Target::TargetInfo>>* target_infos) { + *target_infos = protocol::Array<Target::TargetInfo>::create(); for (const auto& host : DevToolsAgentHost::GetOrCreateAll()) - target_infos->push_back(CreateInfo(host.get())); + (*target_infos)->addItem(CreateInfo(host.get())); return Response::OK(); } @@ -392,17 +387,13 @@ if (it == attached_hosts_.end()) return; // Already disconnected. - client_->ReceivedMessageFromTarget( - ReceivedMessageFromTargetParams::Create()-> - set_target_id(host->GetId())-> - set_message(message)); + frontend_->ReceivedMessageFromTarget(host->GetId(), message); } void TargetHandler::AgentHostClosed( DevToolsAgentHost* host, bool replaced_with_another_client) { - client_->DetachedFromTarget(DetachedFromTargetParams::Create()-> - set_target_id(host->GetId())); + frontend_->DetachedFromTarget(host->GetId()); attached_hosts_.erase(host->GetId()); } @@ -462,6 +453,5 @@ UpdateServiceWorkers(); } -} // namespace target -} // namespace devtools +} // namespace protocol } // namespace content
diff --git a/content/browser/devtools/protocol/target_handler.h b/content/browser/devtools/protocol/target_handler.h index c37c602..0b31029 100644 --- a/content/browser/devtools/protocol/target_handler.h +++ b/content/browser/devtools/protocol/target_handler.h
@@ -8,7 +8,7 @@ #include <map> #include <set> -#include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h" +#include "content/browser/devtools/protocol/target.h" #include "content/browser/devtools/service_worker_devtools_manager.h" #include "content/public/browser/devtools_agent_host_client.h" #include "content/public/browser/devtools_agent_host_observer.h" @@ -17,48 +17,52 @@ class RenderFrameHostImpl; -namespace devtools { -namespace target { +namespace protocol { -class TargetHandler : public DevToolsAgentHostClient, +class TargetHandler : public Target::Backend, + public DevToolsAgentHostClient, public ServiceWorkerDevToolsManager::Observer, public DevToolsAgentHostObserver { public: - using Response = DevToolsProtocolClient::Response; - TargetHandler(); ~TargetHandler() override; + void Wire(UberDispatcher*); void SetRenderFrameHost(RenderFrameHostImpl* render_frame_host); - void SetClient(std::unique_ptr<Client> client); - void Detached(); + Response Disable() override; void UpdateServiceWorkers(); void UpdateFrames(); // Domain implementation. - Response SetDiscoverTargets(bool discover); - Response SetAutoAttach(bool auto_attach, bool wait_for_debugger_on_start); - Response SetAttachToFrames(bool value); + Response SetDiscoverTargets(bool discover) override; + Response SetAutoAttach(bool auto_attach, + bool wait_for_debugger_on_start) override; + Response SetAttachToFrames(bool value) override; Response SetRemoteLocations( - const std::vector<std::unique_ptr<base::DictionaryValue>>&); - Response AttachToTarget(const std::string& target_id, bool* out_success); - Response DetachFromTarget(const std::string& target_id); + std::unique_ptr<protocol::Array<Target::RemoteLocation>>) override; + Response AttachToTarget(const std::string& target_id, + bool* out_success) override; + Response DetachFromTarget(const std::string& target_id) override; Response SendMessageToTarget(const std::string& target_id, - const std::string& message); - Response GetTargetInfo(const std::string& target_id, - scoped_refptr<TargetInfo>* target_info); - Response ActivateTarget(const std::string& target_id); - Response CloseTarget(const std::string& target_id, bool* out_success); - Response CreateBrowserContext(std::string* out_context_id); + const std::string& message) override; + Response GetTargetInfo( + const std::string& target_id, + std::unique_ptr<Target::TargetInfo>* target_info) override; + Response ActivateTarget(const std::string& target_id) override; + Response CloseTarget(const std::string& target_id, + bool* out_success) override; + Response CreateBrowserContext(std::string* out_context_id) override; Response DisposeBrowserContext(const std::string& context_id, - bool* out_success); + bool* out_success) override; Response CreateTarget(const std::string& url, - const int* width, - const int* height, - const std::string* context_id, - std::string* out_target_id); - Response GetTargets(std::vector<scoped_refptr<TargetInfo>>* target_infos); + Maybe<int> width, + Maybe<int> height, + Maybe<std::string> context_id, + std::string* out_target_id) override; + Response GetTargets( + std::unique_ptr<protocol::Array<Target::TargetInfo>>* target_infos) + override; private: using HostsMap = std::map<std::string, scoped_refptr<DevToolsAgentHost>>; @@ -92,7 +96,7 @@ void AgentHostClosed(DevToolsAgentHost* agent_host, bool replaced_with_another_client) override; - std::unique_ptr<Client> client_; + std::unique_ptr<Target::Frontend> frontend_; bool discover_; bool auto_attach_; bool wait_for_debugger_on_start_; @@ -105,8 +109,7 @@ DISALLOW_COPY_AND_ASSIGN(TargetHandler); }; -} // namespace target -} // namespace devtools +} // namespace protocol } // namespace content #endif // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_TARGET_HANDLER_H_
diff --git a/content/browser/devtools/protocol_config.json b/content/browser/devtools/protocol_config.json index d1f1d2c..3e4180b 100644 --- a/content/browser/devtools/protocol_config.json +++ b/content/browser/devtools/protocol_config.json
@@ -62,6 +62,9 @@ "async": ["getInfo"] }, { + "domain": "Target" + }, + { "domain": "Tethering", "async": ["bind", "unbind"] },
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc index ad707efe..76b3866 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.cc +++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -395,7 +395,6 @@ RenderFrameHostImpl* host) : DevToolsAgentHostImpl(base::GenerateGUID()), input_handler_(new devtools::input::InputHandler()), - target_handler_(new devtools::target::TargetHandler()), frame_trace_recorder_(nullptr), protocol_handler_(new DevToolsProtocolHandler(this)), handlers_frame_host_(nullptr), @@ -404,7 +403,6 @@ frame_tree_node_(host->frame_tree_node()) { DevToolsProtocolDispatcher* dispatcher = protocol_handler_->dispatcher(); dispatcher->SetInputHandler(input_handler_.get()); - dispatcher->SetTargetHandler(target_handler_.get()); SetPending(host); CommitPending(); @@ -514,6 +512,10 @@ storage_handler_->Wire(session()->dispatcher()); storage_handler_->SetRenderFrameHost(handlers_frame_host_); + target_handler_.reset(new protocol::TargetHandler()); + target_handler_->Wire(session()->dispatcher()); + target_handler_->SetRenderFrameHost(handlers_frame_host_); + tracing_handler_.reset(new protocol::TracingHandler( protocol::TracingHandler::Renderer, frame_tree_node_->frame_tree_node_id(), @@ -554,6 +556,8 @@ service_worker_handler_.reset(); storage_handler_->Disable(); storage_handler_.reset(); + target_handler_->Disable(); + target_handler_.reset(); tracing_handler_->Disable(); tracing_handler_.reset(); @@ -618,7 +622,6 @@ #if defined(OS_ANDROID) power_save_blocker_.reset(); #endif - target_handler_->Detached(); frame_trace_recorder_.reset(); in_navigation_protocol_message_buffer_.clear(); } @@ -692,7 +695,7 @@ DispatchBufferedProtocolMessagesIfNecessary(); DCHECK(CheckConsistency()); - if (navigation_handle->HasCommitted()) + if (target_handler_ && navigation_handle->HasCommitted()) target_handler_->UpdateServiceWorkers(); } @@ -738,7 +741,8 @@ // CommitPending may destruct |this|. scoped_refptr<RenderFrameDevToolsAgentHost> protect(this); - target_handler_->UpdateFrames(); + if (target_handler_) + target_handler_->UpdateFrames(); if (IsBrowserSideNavigationEnabled()) return; @@ -905,7 +909,8 @@ if (pending_ && pending_->host() == render_frame_host) CommitPending(); DCHECK(CheckConsistency()); - target_handler_->UpdateServiceWorkers(); + if (target_handler_) + target_handler_->UpdateServiceWorkers(); } void RenderFrameDevToolsAgentHost::DidFailProvisionalLoad( @@ -972,7 +977,8 @@ security_handler_->SetRenderFrameHost(host); if (storage_handler_) storage_handler_->SetRenderFrameHost(host); - target_handler_->SetRenderFrameHost(host); + if (target_handler_) + target_handler_->SetRenderFrameHost(host); } void RenderFrameDevToolsAgentHost::DisconnectWebContents() {
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h index e4fa63e8..9a3bd65 100644 --- a/content/browser/devtools/render_frame_devtools_agent_host.h +++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -41,7 +41,6 @@ namespace devtools { namespace input { class InputHandler; } -namespace target { class TargetHandler; } } namespace protocol { @@ -55,6 +54,7 @@ class SecurityHandler; class ServiceWorkerHandler; class StorageHandler; +class TargetHandler; class TracingHandler; } // namespace protocol @@ -193,7 +193,7 @@ std::unique_ptr<protocol::SecurityHandler> security_handler_; std::unique_ptr<protocol::ServiceWorkerHandler> service_worker_handler_; std::unique_ptr<protocol::StorageHandler> storage_handler_; - std::unique_ptr<devtools::target::TargetHandler> target_handler_; + std::unique_ptr<protocol::TargetHandler> target_handler_; std::unique_ptr<protocol::TracingHandler> tracing_handler_; std::unique_ptr<protocol::EmulationHandler> emulation_handler_; std::unique_ptr<DevToolsFrameTraceRecorder> frame_trace_recorder_;
diff --git a/content/browser/fileapi/file_system_browsertest.cc b/content/browser/fileapi/file_system_browsertest.cc index 1bc55e74..ed7fa379 100644 --- a/content/browser/fileapi/file_system_browsertest.cc +++ b/content/browser/fileapi/file_system_browsertest.cc
@@ -55,29 +55,27 @@ class FileSystemBrowserTestWithLowQuota : public FileSystemBrowserTest { public: void SetUpOnMainThread() override { - const int kInitialQuotaKilobytes = 5000; - const int kTemporaryStorageQuotaMaxSize = - kInitialQuotaKilobytes * 1024 * QuotaManager::kPerHostTemporaryPortion; - SetTempQuota( - kTemporaryStorageQuotaMaxSize, - BrowserContext::GetDefaultStoragePartition( - shell()->web_contents()->GetBrowserContext())->GetQuotaManager()); + SetLowQuota(BrowserContext::GetDefaultStoragePartition( + shell()->web_contents()->GetBrowserContext()) + ->GetQuotaManager()); } - static void SetTempQuota(int64_t bytes, scoped_refptr<QuotaManager> qm) { + static void SetLowQuota(scoped_refptr<QuotaManager> qm) { if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, - base::Bind(&FileSystemBrowserTestWithLowQuota::SetTempQuota, bytes, - qm)); + base::Bind(&FileSystemBrowserTestWithLowQuota::SetLowQuota, qm)); return; } DCHECK_CURRENTLY_ON(BrowserThread::IO); - qm->SetTemporaryGlobalOverrideQuota(bytes, storage::QuotaCallback()); - // Don't return until the quota has been set. - scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper( - BrowserThread::GetTaskRunnerForThread(BrowserThread::DB).get())); - ASSERT_TRUE(helper->Run()); + // These sizes must correspond with expectations in html and js. + const int kMeg = 1000 * 1024; + storage::QuotaSettings settings; + settings.pool_size = 25 * kMeg; + settings.per_host_quota = 5 * kMeg; + settings.must_remain_available = 100 * kMeg; + settings.refresh_interval = base::TimeDelta::Max(); + qm->SetQuotaSettings(settings); } };
diff --git a/content/browser/fileapi/obfuscated_file_util_unittest.cc b/content/browser/fileapi/obfuscated_file_util_unittest.cc index 9eb3d5fa..8086c6bc 100644 --- a/content/browser/fileapi/obfuscated_file_util_unittest.cc +++ b/content/browser/fileapi/obfuscated_file_util_unittest.cc
@@ -167,7 +167,14 @@ quota_manager_ = new storage::QuotaManager( false /* is_incognito */, data_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get(), - base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get()); + base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get(), + storage::GetQuotaSettingsFunc()); + storage::QuotaSettings settings; + settings.per_host_quota = 25 * 1024 * 1024; + settings.pool_size = settings.per_host_quota * 5; + settings.must_remain_available = 10 * 1024 * 1024; + settings.refresh_interval = base::TimeDelta::Max(); + quota_manager_->SetQuotaSettings(settings); // Every time we create a new sandbox_file_system helper, // it creates another context, which creates another path manager,
diff --git a/content/browser/indexed_db/indexed_db_browsertest.cc b/content/browser/indexed_db/indexed_db_browsertest.cc index 8c151a35..f4e7668c 100644 --- a/content/browser/indexed_db/indexed_db_browsertest.cc +++ b/content/browser/indexed_db/indexed_db_browsertest.cc
@@ -122,27 +122,25 @@ return static_cast<IndexedDBContextImpl*>(partition->GetIndexedDBContext()); } - void SetQuota(int quota_kilobytes) { - const int kTemporaryStorageQuotaSize = - quota_kilobytes * 1024 * QuotaManager::kPerHostTemporaryPortion; - SetTempQuota(kTemporaryStorageQuotaSize, - BrowserContext::GetDefaultStoragePartition( - shell()->web_contents()->GetBrowserContext())->GetQuotaManager()); + void SetQuota(int per_host_quota_kilobytes) { + SetTempQuota(per_host_quota_kilobytes, + BrowserContext::GetDefaultStoragePartition( + shell()->web_contents()->GetBrowserContext()) + ->GetQuotaManager()); } - static void SetTempQuota(int64_t bytes, scoped_refptr<QuotaManager> qm) { + static void SetTempQuota(int per_host_quota_kilobytes, + scoped_refptr<QuotaManager> qm) { if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&IndexedDBBrowserTest::SetTempQuota, bytes, qm)); + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&IndexedDBBrowserTest::SetTempQuota, + per_host_quota_kilobytes, qm)); return; } DCHECK_CURRENTLY_ON(BrowserThread::IO); - qm->SetTemporaryGlobalOverrideQuota(bytes, storage::QuotaCallback()); - // Don't return until the quota has been set. - scoped_refptr<base::ThreadTestHelper> helper(new base::ThreadTestHelper( - BrowserThread::GetTaskRunnerForThread(BrowserThread::DB))); - ASSERT_TRUE(helper->Run()); + const int KB = 1024; + qm->SetQuotaSettings( + storage::GetHardCodedSettings(per_host_quota_kilobytes * KB)); } virtual int64_t RequestDiskUsage() {
diff --git a/content/browser/loader/reload_cache_control_browsertest.cc b/content/browser/loader/reload_cache_control_browsertest.cc index 93288ac..7d7a6818 100644 --- a/content/browser/loader/reload_cache_control_browsertest.cc +++ b/content/browser/loader/reload_cache_control_browsertest.cc
@@ -8,10 +8,9 @@ #include "base/bind.h" #include "base/bind_helpers.h" -#include "base/command_line.h" #include "base/macros.h" #include "base/synchronization/lock.h" -#include "content/public/common/content_switches.h" +#include "content/public/common/browser_side_navigation_policy.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" #include "content/shell/browser/shell.h" @@ -189,8 +188,7 @@ // TODO(crbug.com/671545): This test does not work correctly if browser-side // navigation is enabled. - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableBrowserSideNavigation)) + if (IsBrowserSideNavigationEnabled()) return; // The second navigation is the same page navigation. This should be handled
diff --git a/content/browser/media/midi_host.cc b/content/browser/media/midi_host.cc index ed01c71..d85dc7d9a 100644 --- a/content/browser/media/midi_host.cc +++ b/content/browser/media/midi_host.cc
@@ -15,8 +15,8 @@ #include "content/public/browser/content_browser_client.h" #include "content/public/browser/user_metrics.h" #include "media/midi/message_util.h" -#include "media/midi/midi_manager.h" #include "media/midi/midi_message_queue.h" +#include "media/midi/midi_service.h" namespace content { namespace { @@ -42,30 +42,29 @@ using midi::mojom::PortState; using midi::mojom::Result; -MidiHost::MidiHost(int renderer_process_id, - midi::MidiManager* midi_manager) +MidiHost::MidiHost(int renderer_process_id, midi::MidiService* midi_service) : BrowserMessageFilter(MidiMsgStart), renderer_process_id_(renderer_process_id), has_sys_ex_permission_(false), is_session_requested_(false), - midi_manager_(midi_manager), + midi_service_(midi_service), sent_bytes_in_flight_(0), bytes_sent_since_last_acknowledgement_(0), output_port_count_(0) { - DCHECK(midi_manager_); + DCHECK(midi_service_); } MidiHost::~MidiHost() = default; void MidiHost::OnChannelClosing() { - // If we get here the MidiHost is going to be destroyed soon. Prevent any - // subsequent calls from MidiManager by closing our session. + // If we get here the MidiHost is going to be destroyed soon. Prevent any + // subsequent calls from MidiService by closing our session. // If Send() is called from a different thread (e.g. a separate thread owned - // by the MidiManager implementation), it will get posted to the IO thread. + // by the MidiService implementation), it will get posted to the IO thread. // There is a race condition here if our refcount is 0 and we're about to or // have already entered OnDestruct(). - if (is_session_requested_ && midi_manager_) { - midi_manager_->EndSession(this); + if (is_session_requested_ && midi_service_) { + midi_service_->EndSession(this); is_session_requested_ = false; } } @@ -89,8 +88,8 @@ void MidiHost::OnStartSession() { is_session_requested_ = true; - if (midi_manager_) - midi_manager_->StartSession(this); + if (midi_service_) + midi_service_->StartSession(this); } void MidiHost::OnSendData(uint32_t port, @@ -128,14 +127,14 @@ return; sent_bytes_in_flight_ += data.size(); } - if (midi_manager_) - midi_manager_->DispatchSendMidiData(this, port, data, timestamp); + if (midi_service_) + midi_service_->DispatchSendMidiData(this, port, data, timestamp); } void MidiHost::OnEndSession() { is_session_requested_ = false; - if (midi_manager_) - midi_manager_->EndSession(this); + if (midi_service_) + midi_service_->EndSession(this); } void MidiHost::CompleteStartSession(Result result) { @@ -222,7 +221,7 @@ } void MidiHost::Detach() { - midi_manager_ = nullptr; + midi_service_ = nullptr; } } // namespace content
diff --git a/content/browser/media/midi_host.h b/content/browser/media/midi_host.h index 95e69031f..bc6fd39 100644 --- a/content/browser/media/midi_host.h +++ b/content/browser/media/midi_host.h
@@ -24,7 +24,7 @@ #include "media/midi/midi_service.mojom.h" namespace midi { -class MidiManager; +class MidiService; class MidiMessageQueue; } // namespace midi @@ -34,7 +34,7 @@ public midi::MidiManagerClient { public: // Called from UI thread from the owner of this object. - MidiHost(int renderer_process_id, midi::MidiManager* midi_manager); + MidiHost(int renderer_process_id, midi::MidiService* midi_service); // BrowserMessageFilter implementation. void OnChannelClosing() override; @@ -80,12 +80,9 @@ // Represents if a session is requested to start. bool is_session_requested_; - // |midi_manager_| talks to the platform-specific MIDI APIs. - // It can be NULL if the platform (or our current implementation) - // does not support MIDI. If not supported then a call to - // OnRequestAccess() will always refuse access and a call to - // OnSendData() will do nothing. - midi::MidiManager* midi_manager_; + // |midi_service_| manages a MidiManager instance that talks to + // platform-specific MIDI APIs. It can be nullptr after detached. + midi::MidiService* midi_service_; // Buffers where data sent from each MIDI input port is stored. ScopedVector<midi::MidiMessageQueue> received_messages_queues_;
diff --git a/content/browser/media/midi_host_unittest.cc b/content/browser/media/midi_host_unittest.cc index 866d4469..8fea9a56 100644 --- a/content/browser/media/midi_host_unittest.cc +++ b/content/browser/media/midi_host_unittest.cc
@@ -8,12 +8,14 @@ #include <stdint.h> #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" #include "content/common/media/midi_messages.h" #include "content/public/test/test_browser_thread.h" #include "media/midi/midi_manager.h" +#include "media/midi/midi_service.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { @@ -60,9 +62,8 @@ class MidiHostForTesting : public MidiHost { public: - MidiHostForTesting(int renderer_process_id, - midi::MidiManager* midi_manager) - : MidiHost(renderer_process_id, midi_manager) {} + MidiHostForTesting(int renderer_process_id, midi::MidiService* midi_service) + : MidiHost(renderer_process_id, midi_service) {} private: ~MidiHostForTesting() override {} @@ -78,11 +79,14 @@ public: MidiHostTest() : io_browser_thread_(BrowserThread::IO, &message_loop_), - host_(new MidiHostForTesting(kRenderProcessId, &manager_)), data_(kNoteOn, kNoteOn + arraysize(kNoteOn)), - port_id_(0) {} + port_id_(0) { + manager_ = new FakeMidiManager; + service_.reset(new midi::MidiService(base::WrapUnique(manager_))); + host_ = new MidiHostForTesting(kRenderProcessId, service_.get()); + } ~MidiHostTest() override { - manager_.Shutdown(); + service_->Shutdown(); RunLoopUntilIdle(); } @@ -104,15 +108,13 @@ host_->OnMessageReceived(*message.get()); } - size_t GetEventSize() const { - return manager_.events_.size(); - } + size_t GetEventSize() const { return manager_->events_.size(); } void CheckSendEventAt(size_t at, uint32_t port) { - EXPECT_EQ(DISPATCH_SEND_MIDI_DATA, manager_.events_[at].type); - EXPECT_EQ(port, manager_.events_[at].port_index); - EXPECT_EQ(data_, manager_.events_[at].data); - EXPECT_EQ(0.0, manager_.events_[at].timestamp); + EXPECT_EQ(DISPATCH_SEND_MIDI_DATA, manager_->events_[at].type); + EXPECT_EQ(port, manager_->events_[at].port_index); + EXPECT_EQ(data_, manager_->events_[at].data); + EXPECT_EQ(0.0, manager_->events_[at].timestamp); } void RunLoopUntilIdle() { @@ -124,10 +126,11 @@ base::MessageLoop message_loop_; TestBrowserThread io_browser_thread_; - FakeMidiManager manager_; - scoped_refptr<MidiHostForTesting> host_; std::vector<uint8_t> data_; int32_t port_id_; + FakeMidiManager* manager_; // Raw pointer for testing, owned by |service_|. + std::unique_ptr<midi::MidiService> service_; + scoped_refptr<MidiHostForTesting> host_; DISALLOW_COPY_AND_ASSIGN(MidiHostTest); };
diff --git a/content/browser/memory/memory_coordinator_impl.cc b/content/browser/memory/memory_coordinator_impl.cc index ca18cba..5a24676 100644 --- a/content/browser/memory/memory_coordinator_impl.cc +++ b/content/browser/memory/memory_coordinator_impl.cc
@@ -9,8 +9,8 @@ #include "base/strings/string_number_conversions.h" #include "base/threading/thread_task_runner_handle.h" #include "base/trace_event/trace_event.h" -#include "components/variations/variations_associated_data.h" #include "content/browser/memory/memory_monitor.h" +#include "content/browser/memory/memory_state_updater.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" @@ -21,24 +21,6 @@ namespace { -// A expected renderer size. These values come from the median of appropriate -// UMA stats. -#if defined(OS_ANDROID) || defined(OS_IOS) -const int kDefaultExpectedRendererSizeMB = 40; -#elif defined(OS_WIN) -const int kDefaultExpectedRendererSizeMB = 70; -#else // Mac, Linux, and ChromeOS -const int kDefaultExpectedRendererSizeMB = 120; -#endif - -// Default values for parameters to determine the global state. -const int kDefaultNewRenderersUntilThrottled = 4; -const int kDefaultNewRenderersUntilSuspended = 2; -const int kDefaultNewRenderersBackToNormal = 5; -const int kDefaultNewRenderersBackToThrottled = 3; -const int kDefaultMinimumTransitionPeriodSeconds = 30; -const int kDefaultMonitoringIntervalSeconds = 5; - mojom::MemoryState ToMojomMemoryState(base::MemoryState state) { switch (state) { case base::MemoryState::UNKNOWN: @@ -111,33 +93,6 @@ #undef RECORD_METRICS } -void SetIntVariationParameter(const std::map<std::string, std::string> params, - const char* name, - int* target) { - const auto& iter = params.find(name); - if (iter == params.end()) - return; - int value; - if (!iter->second.empty() && base::StringToInt(iter->second, &value)) { - DCHECK(value > 0); - *target = value; - } -} - -void SetSecondsVariationParameter( - const std::map<std::string, std::string> params, - const char* name, - base::TimeDelta* target) { - const auto& iter = params.find(name); - if (iter == params.end()) - return; - int value; - if (!iter->second.empty() && base::StringToInt(iter->second, &value)) { - DCHECK(value > 0); - *target = base::TimeDelta::FromSeconds(value); - } -} - } // namespace // SingletonTraits for MemoryCoordinator. Returns MemoryCoordinatorImpl @@ -161,11 +116,9 @@ MemoryCoordinatorImpl::MemoryCoordinatorImpl( scoped_refptr<base::SingleThreadTaskRunner> task_runner, std::unique_ptr<MemoryMonitor> memory_monitor) - : task_runner_(task_runner), - memory_monitor_(std::move(memory_monitor)), - weak_ptr_factory_(this) { + : memory_monitor_(std::move(memory_monitor)), + state_updater_(base::MakeUnique<MemoryStateUpdater>(this, task_runner)) { DCHECK(memory_monitor_.get()); - InitializeParameters(); } MemoryCoordinatorImpl::~MemoryCoordinatorImpl() {} @@ -173,13 +126,12 @@ void MemoryCoordinatorImpl::Start() { DCHECK(CalledOnValidThread()); DCHECK(last_state_change_.is_null()); - DCHECK(ValidateParameters()); notification_registrar_.Add( this, NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, NotificationService::AllBrowserContextsAndSources()); last_state_change_ = base::TimeTicks::Now(); - ScheduleUpdateState(base::TimeDelta()); + state_updater_->ScheduleUpdateState(base::TimeDelta()); } void MemoryCoordinatorImpl::OnChildAdded(int render_process_id) { @@ -211,7 +163,7 @@ base::TimeDelta duration) { DCHECK(new_state != MemoryState::UNKNOWN); ChangeStateIfNeeded(current_state_, new_state); - ScheduleUpdateState(duration); + state_updater_->ScheduleUpdateState(duration); } void MemoryCoordinatorImpl::Observe(int type, @@ -232,6 +184,7 @@ bool MemoryCoordinatorImpl::ChangeStateIfNeeded(base::MemoryState prev_state, base::MemoryState next_state) { + DCHECK(CalledOnValidThread()); if (prev_state == next_state) return false; @@ -249,57 +202,6 @@ return true; } -base::MemoryState MemoryCoordinatorImpl::CalculateNextState() { - using MemoryState = base::MemoryState; - - int available = memory_monitor_->GetFreeMemoryUntilCriticalMB(); - - // TODO(chrisha): Move this histogram recording to a better place when - // https://codereview.chromium.org/2479673002/ is landed. - UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Coordinator.FreeMemoryUntilCritical", - available); - - if (available <= 0) - return MemoryState::SUSPENDED; - - int expected_renderer_count = available / expected_renderer_size_; - - switch (current_state_) { - case MemoryState::NORMAL: - if (expected_renderer_count <= new_renderers_until_suspended_) - return MemoryState::SUSPENDED; - if (expected_renderer_count <= new_renderers_until_throttled_) - return MemoryState::THROTTLED; - return MemoryState::NORMAL; - case MemoryState::THROTTLED: - if (expected_renderer_count <= new_renderers_until_suspended_) - return MemoryState::SUSPENDED; - if (expected_renderer_count >= new_renderers_back_to_normal_) - return MemoryState::NORMAL; - return MemoryState::THROTTLED; - case MemoryState::SUSPENDED: - if (expected_renderer_count >= new_renderers_back_to_normal_) - return MemoryState::NORMAL; - if (expected_renderer_count >= new_renderers_back_to_throttled_) - return MemoryState::THROTTLED; - return MemoryState::SUSPENDED; - case MemoryState::UNKNOWN: - // Fall through - default: - NOTREACHED(); - return MemoryState::UNKNOWN; - } -} - -void MemoryCoordinatorImpl::UpdateState() { - MemoryState next_state = CalculateNextState(); - if (ChangeStateIfNeeded(current_state_, next_state)) { - ScheduleUpdateState(minimum_transition_period_); - } else { - ScheduleUpdateState(monitoring_interval_); - } -} - void MemoryCoordinatorImpl::NotifyStateToClients() { auto state = GetCurrentMemoryState(); base::MemoryCoordinatorClientRegistry::GetInstance()->Notify(state); @@ -342,49 +244,4 @@ total_private_kb / 1024); } -void MemoryCoordinatorImpl::ScheduleUpdateState(base::TimeDelta delta) { - update_state_closure_.Reset(base::Bind(&MemoryCoordinatorImpl::UpdateState, - weak_ptr_factory_.GetWeakPtr())); - task_runner_->PostDelayedTask(FROM_HERE, update_state_closure_.callback(), - delta); -} - -void MemoryCoordinatorImpl::InitializeParameters() { - expected_renderer_size_ = kDefaultExpectedRendererSizeMB; - new_renderers_until_throttled_ = kDefaultNewRenderersUntilThrottled; - new_renderers_until_suspended_ = kDefaultNewRenderersUntilSuspended; - new_renderers_back_to_normal_ = kDefaultNewRenderersBackToNormal; - new_renderers_back_to_throttled_ = kDefaultNewRenderersBackToThrottled; - minimum_transition_period_ = - base::TimeDelta::FromSeconds(kDefaultMinimumTransitionPeriodSeconds); - monitoring_interval_ = - base::TimeDelta::FromSeconds(kDefaultMonitoringIntervalSeconds); - - // Override default parameters with variations. - static constexpr char kMemoryCoordinatorV0Trial[] = "MemoryCoordinatorV0"; - std::map<std::string, std::string> params; - variations::GetVariationParams(kMemoryCoordinatorV0Trial, ¶ms); - SetIntVariationParameter(params, "expected_renderer_size", - &expected_renderer_size_); - SetIntVariationParameter(params, "new_renderers_until_throttled", - &new_renderers_until_throttled_); - SetIntVariationParameter(params, "new_renderers_until_suspended", - &new_renderers_until_suspended_); - SetIntVariationParameter(params, "new_renderers_back_to_normal", - &new_renderers_back_to_normal_); - SetIntVariationParameter(params, "new_renderers_back_to_throttled", - &new_renderers_back_to_throttled_); - SetSecondsVariationParameter(params, "minimum_transition_period", - &minimum_transition_period_); - SetSecondsVariationParameter(params, "monitoring_interval", - &monitoring_interval_); -} - -bool MemoryCoordinatorImpl::ValidateParameters() { - return (new_renderers_until_throttled_ > new_renderers_until_suspended_) && - (new_renderers_back_to_normal_ > new_renderers_back_to_throttled_) && - (new_renderers_back_to_normal_ > new_renderers_until_throttled_) && - (new_renderers_back_to_throttled_ > new_renderers_until_suspended_); -} - } // namespace content
diff --git a/content/browser/memory/memory_coordinator_impl.h b/content/browser/memory/memory_coordinator_impl.h index 95c2a2c..014bb528 100644 --- a/content/browser/memory/memory_coordinator_impl.h +++ b/content/browser/memory/memory_coordinator_impl.h
@@ -7,7 +7,6 @@ #include "base/callback.h" #include "base/memory/singleton.h" -#include "base/memory/weak_ptr.h" #include "base/single_thread_task_runner.h" #include "base/threading/non_thread_safe.h" #include "base/time/time.h" @@ -19,40 +18,32 @@ class MemoryMonitor; class MemoryCoordinatorImplTest; +class MemoryStateUpdater; struct MemoryCoordinatorSingletonTraits; -// MemoryCoordinatorImpl is an internal implementation of MemoryCoordinator -// which uses a heuristic to determine a single global memory state. -// In the current implementation browser process and renderer processes share -// the global state; the memory coordinator will notify the global state to -// all background renderers if the state has changed. -// -// State calculation: -// MemoryCoordinatorImpl uses followings to determine the global state: -// * Compute "number of renderers which can be created until the system will -// be in a critical state". Call this N. -// (See memory_monitor.h for the definition of "critical") -// * Covert N to a memory state using some thresholds/hysteresis for each state. -// Once a state is changed to a limited state, larger N will be needed to go -// back to a relaxed state. (e.g. THROTTLED -> NORMAL) -// * Once a state is changed, it remains the same for a certain period of time. +// MemoryCoordinatorImpl is an implementation of MemoryCoordinator. +// The current implementation uses MemoryStateUpdater to update the global +// memory state. See comments in MemoryStateUpdater for details. class CONTENT_EXPORT MemoryCoordinatorImpl : public MemoryCoordinator, public NotificationObserver, public base::NonThreadSafe { public: + using MemoryState = base::MemoryState; + MemoryCoordinatorImpl(scoped_refptr<base::SingleThreadTaskRunner> task_runner, std::unique_ptr<MemoryMonitor> monitor); ~MemoryCoordinatorImpl() override; + MemoryMonitor* memory_monitor() { return memory_monitor_.get(); } + MemoryStateUpdater* state_updater() { return state_updater_.get(); } + // MemoryCoordinator implementations: void Start() override; void OnChildAdded(int render_process_id) override; - MemoryMonitor* memory_monitor() { return memory_monitor_.get(); } - - base::MemoryState GetGlobalMemoryState() const override; - base::MemoryState GetCurrentMemoryState() const override; - void SetCurrentMemoryStateForTesting(base::MemoryState memory_state) override; + MemoryState GetGlobalMemoryState() const override; + MemoryState GetCurrentMemoryState() const override; + void SetCurrentMemoryStateForTesting(MemoryState memory_state) override; // NotificationObserver implementation: void Observe(int type, @@ -65,6 +56,11 @@ void ForceSetGlobalState(base::MemoryState new_state, base::TimeDelta duration); + // Changes the global state and notifies state changes to clients (lives in + // the browser) and child processes (renderers) if needed. Returns true when + // the state is actually changed. + bool ChangeStateIfNeeded(MemoryState prev_state, MemoryState next_state); + private: FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplTest, CalculateNextState); FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplTest, UpdateState); @@ -73,20 +69,6 @@ friend struct MemoryCoordinatorSingletonTraits; - using MemoryState = base::MemoryState; - - // Changes the global state and notifies state changes to clients (lives in - // the browser) and child processes (renderers) if needed. Returns true when - // the state is actually changed. - bool ChangeStateIfNeeded(MemoryState prev_state, MemoryState next_state); - - // Calculates the next global state from the amount of free memory using - // a heuristic. - MemoryState CalculateNextState(); - - // Periodically called to update the global state. - void UpdateState(); - // Notifies a state change to in-process clients. void NotifyStateToClients(); @@ -98,52 +80,12 @@ MemoryState next_state, base::TimeDelta duration); - // Schedules a task to update the global state. The task will be executed - // after |delay| has passed. - void ScheduleUpdateState(base::TimeDelta delay); - - scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - NotificationRegistrar notification_registrar_; std::unique_ptr<MemoryMonitor> memory_monitor_; - base::CancelableClosure update_state_closure_; - base::MemoryState current_state_ = MemoryState::NORMAL; + NotificationRegistrar notification_registrar_; + std::unique_ptr<MemoryStateUpdater> state_updater_; + MemoryState current_state_ = MemoryState::NORMAL; base::TimeTicks last_state_change_; - // Sets up parameters for the heuristic. - void InitializeParameters(); - - // Validates parameters defined below. - bool ValidateParameters(); - - // Parameters to control the heuristic. - - // The median size of a renderer on the current platform. This is used to - // convert the amount of free memory to an expected number of new renderers - // that could be started before hitting critical memory pressure. - int expected_renderer_size_; - // When in a NORMAL state and the potential number of new renderers drops - // below this level, the coordinator will transition to a THROTTLED state. - int new_renderers_until_throttled_; - // When in a NORMAL/THROTTLED state and the potential number of new renderers - // drops below this level, the coordinator will transition to a SUSPENDED - // state. - int new_renderers_until_suspended_; - // When in a THROTTLED/SUSPENDED state and the potential number of new - // renderers rises above this level, the coordinator will transition to a - // NORMAL state. - int new_renderers_back_to_normal_; - // When in a SUSPENDED state and the potential number of new renderers rises - // above this level, the coordinator will transition to a SUSPENDED state. - int new_renderers_back_to_throttled_; - // The memory coordinator stays in the same state at least this duration even - // when there are considerable changes in the amount of free memory to prevent - // thrashing. - base::TimeDelta minimum_transition_period_; - // The interval of checking the amount of free memory. - base::TimeDelta monitoring_interval_; - - base::WeakPtrFactory<MemoryCoordinatorImpl> weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(MemoryCoordinatorImpl); };
diff --git a/content/browser/memory/memory_coordinator_impl_unittest.cc b/content/browser/memory/memory_coordinator_impl_unittest.cc index 785de04..b2d8530 100644 --- a/content/browser/memory/memory_coordinator_impl_unittest.cc +++ b/content/browser/memory/memory_coordinator_impl_unittest.cc
@@ -9,6 +9,7 @@ #include "base/test/scoped_feature_list.h" #include "base/test/test_mock_time_task_runner.h" #include "content/browser/memory/memory_monitor.h" +#include "content/browser/memory/memory_state_updater.h" #include "content/public/common/content_features.h" #include "testing/gtest/include/gtest/gtest.h" @@ -82,12 +83,13 @@ }; TEST_F(MemoryCoordinatorImplTest, CalculateNextState) { - coordinator_->expected_renderer_size_ = 10; - coordinator_->new_renderers_until_throttled_ = 4; - coordinator_->new_renderers_until_suspended_ = 2; - coordinator_->new_renderers_back_to_normal_ = 5; - coordinator_->new_renderers_back_to_throttled_ = 3; - DCHECK(coordinator_->ValidateParameters()); + auto* state_updater = coordinator_->state_updater_.get(); + state_updater->expected_renderer_size_ = 10; + state_updater->new_renderers_until_throttled_ = 4; + state_updater->new_renderers_until_suspended_ = 2; + state_updater->new_renderers_back_to_normal_ = 5; + state_updater->new_renderers_back_to_throttled_ = 3; + DCHECK(state_updater->ValidateParameters()); // The default state is NORMAL. EXPECT_EQ(base::MemoryState::NORMAL, coordinator_->GetCurrentMemoryState()); @@ -103,11 +105,11 @@ GetCurrentMemoryState()); GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(50); - EXPECT_EQ(base::MemoryState::NORMAL, coordinator_->CalculateNextState()); + EXPECT_EQ(base::MemoryState::NORMAL, state_updater->CalculateNextState()); GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(40); - EXPECT_EQ(base::MemoryState::THROTTLED, coordinator_->CalculateNextState()); + EXPECT_EQ(base::MemoryState::THROTTLED, state_updater->CalculateNextState()); GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(20); - EXPECT_EQ(base::MemoryState::SUSPENDED, coordinator_->CalculateNextState()); + EXPECT_EQ(base::MemoryState::SUSPENDED, state_updater->CalculateNextState()); // Transitions from THROTTLED coordinator_->current_state_ = base::MemoryState::THROTTLED; @@ -118,11 +120,11 @@ GetCurrentMemoryState()); GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(40); - EXPECT_EQ(base::MemoryState::THROTTLED, coordinator_->CalculateNextState()); + EXPECT_EQ(base::MemoryState::THROTTLED, state_updater->CalculateNextState()); GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(50); - EXPECT_EQ(base::MemoryState::NORMAL, coordinator_->CalculateNextState()); + EXPECT_EQ(base::MemoryState::NORMAL, state_updater->CalculateNextState()); GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(20); - EXPECT_EQ(base::MemoryState::SUSPENDED, coordinator_->CalculateNextState()); + EXPECT_EQ(base::MemoryState::SUSPENDED, state_updater->CalculateNextState()); // Transitions from SUSPENDED coordinator_->current_state_ = base::MemoryState::SUSPENDED; @@ -135,20 +137,21 @@ GetCurrentMemoryState()); GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(20); - EXPECT_EQ(base::MemoryState::SUSPENDED, coordinator_->CalculateNextState()); + EXPECT_EQ(base::MemoryState::SUSPENDED, state_updater->CalculateNextState()); GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(30); - EXPECT_EQ(base::MemoryState::THROTTLED, coordinator_->CalculateNextState()); + EXPECT_EQ(base::MemoryState::THROTTLED, state_updater->CalculateNextState()); GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(50); - EXPECT_EQ(base::MemoryState::NORMAL, coordinator_->CalculateNextState()); + EXPECT_EQ(base::MemoryState::NORMAL, state_updater->CalculateNextState()); } TEST_F(MemoryCoordinatorImplTest, UpdateState) { - coordinator_->expected_renderer_size_ = 10; - coordinator_->new_renderers_until_throttled_ = 4; - coordinator_->new_renderers_until_suspended_ = 2; - coordinator_->new_renderers_back_to_normal_ = 5; - coordinator_->new_renderers_back_to_throttled_ = 3; - DCHECK(coordinator_->ValidateParameters()); + auto* state_updater = coordinator_->state_updater_.get(); + state_updater->expected_renderer_size_ = 10; + state_updater->new_renderers_until_throttled_ = 4; + state_updater->new_renderers_until_suspended_ = 2; + state_updater->new_renderers_back_to_normal_ = 5; + state_updater->new_renderers_back_to_throttled_ = 3; + DCHECK(state_updater->ValidateParameters()); { // Transition happens (NORMAL -> THROTTLED). @@ -156,7 +159,7 @@ base::MemoryCoordinatorClientRegistry::GetInstance()->Register(&client); coordinator_->current_state_ = base::MemoryState::NORMAL; GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(40); - coordinator_->UpdateState(); + state_updater->UpdateState(); base::RunLoop loop; loop.RunUntilIdle(); EXPECT_TRUE(client.is_called()); @@ -170,7 +173,7 @@ base::MemoryCoordinatorClientRegistry::GetInstance()->Register(&client); coordinator_->current_state_ = base::MemoryState::NORMAL; GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(50); - coordinator_->UpdateState(); + state_updater->UpdateState(); base::RunLoop loop; loop.RunUntilIdle(); EXPECT_FALSE(client.is_called()); @@ -180,12 +183,13 @@ } TEST_F(MemoryCoordinatorImplTest, SetMemoryStateForTesting) { - coordinator_->expected_renderer_size_ = 10; - coordinator_->new_renderers_until_throttled_ = 4; - coordinator_->new_renderers_until_suspended_ = 2; - coordinator_->new_renderers_back_to_normal_ = 5; - coordinator_->new_renderers_back_to_throttled_ = 3; - DCHECK(coordinator_->ValidateParameters()); + auto* state_updater = coordinator_->state_updater_.get(); + state_updater->expected_renderer_size_ = 10; + state_updater->new_renderers_until_throttled_ = 4; + state_updater->new_renderers_until_suspended_ = 2; + state_updater->new_renderers_back_to_normal_ = 5; + state_updater->new_renderers_back_to_throttled_ = 3; + DCHECK(state_updater->ValidateParameters()); MockMemoryCoordinatorClient client; base::MemoryCoordinatorClientRegistry::GetInstance()->Register(&client); @@ -220,18 +224,19 @@ } TEST_F(MemoryCoordinatorImplTest, ForceSetGlobalState) { - coordinator_->expected_renderer_size_ = 10; - coordinator_->new_renderers_until_throttled_ = 4; - coordinator_->new_renderers_until_suspended_ = 2; - coordinator_->new_renderers_back_to_normal_ = 5; - coordinator_->new_renderers_back_to_throttled_ = 3; - DCHECK(coordinator_->ValidateParameters()); + auto* state_updater = coordinator_->state_updater_.get(); + state_updater->expected_renderer_size_ = 10; + state_updater->new_renderers_until_throttled_ = 4; + state_updater->new_renderers_until_suspended_ = 2; + state_updater->new_renderers_back_to_normal_ = 5; + state_updater->new_renderers_back_to_throttled_ = 3; + DCHECK(state_updater->ValidateParameters()); GetMockMemoryMonitor()->SetFreeMemoryUntilCriticalMB(50); base::TimeDelta interval = base::TimeDelta::FromSeconds(5); base::TimeDelta minimum_transition = base::TimeDelta::FromSeconds(30); - coordinator_->monitoring_interval_ = interval; - coordinator_->minimum_transition_period_ = minimum_transition; + state_updater->monitoring_interval_ = interval; + state_updater->minimum_transition_period_ = minimum_transition; // Starts updating states. The initial state should be NORMAL with above // configuration.
diff --git a/content/browser/memory/memory_state_updater.cc b/content/browser/memory/memory_state_updater.cc new file mode 100644 index 0000000..fb75dbd2 --- /dev/null +++ b/content/browser/memory/memory_state_updater.cc
@@ -0,0 +1,173 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/memory/memory_state_updater.h" + +#include "base/metrics/histogram_macros.h" +#include "base/strings/string_number_conversions.h" +#include "components/variations/variations_associated_data.h" +#include "content/browser/memory/memory_monitor.h" + +namespace content { + +namespace { + +// A expected renderer size. These values come from the median of appropriate +// UMA stats. +#if defined(OS_ANDROID) || defined(OS_IOS) +const int kDefaultExpectedRendererSizeMB = 40; +#elif defined(OS_WIN) +const int kDefaultExpectedRendererSizeMB = 70; +#else // Mac, Linux, and ChromeOS +const int kDefaultExpectedRendererSizeMB = 120; +#endif + +// Default values for parameters to determine the global state. +const int kDefaultNewRenderersUntilThrottled = 4; +const int kDefaultNewRenderersUntilSuspended = 2; +const int kDefaultNewRenderersBackToNormal = 5; +const int kDefaultNewRenderersBackToThrottled = 3; +const int kDefaultMinimumTransitionPeriodSeconds = 30; +const int kDefaultMonitoringIntervalSeconds = 5; + +void SetIntVariationParameter(const std::map<std::string, std::string> params, + const char* name, + int* target) { + const auto& iter = params.find(name); + if (iter == params.end()) + return; + int value; + if (!iter->second.empty() && base::StringToInt(iter->second, &value)) { + DCHECK(value > 0); + *target = value; + } +} + +void SetSecondsVariationParameter( + const std::map<std::string, std::string> params, + const char* name, + base::TimeDelta* target) { + const auto& iter = params.find(name); + if (iter == params.end()) + return; + int value; + if (!iter->second.empty() && base::StringToInt(iter->second, &value)) { + DCHECK(value > 0); + *target = base::TimeDelta::FromSeconds(value); + } +} + +} // namespace + +MemoryStateUpdater::MemoryStateUpdater( + MemoryCoordinatorImpl* coordinator, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : coordinator_(coordinator), task_runner_(task_runner) { + DCHECK(coordinator_); + InitializeParameters(); + DCHECK(ValidateParameters()); +} + +MemoryStateUpdater::~MemoryStateUpdater() {} + +base::MemoryState MemoryStateUpdater::CalculateNextState() { + using MemoryState = base::MemoryState; + + int available = + coordinator_->memory_monitor()->GetFreeMemoryUntilCriticalMB(); + + // TODO(chrisha): Move this histogram recording to a better place when + // https://codereview.chromium.org/2479673002/ is landed. + UMA_HISTOGRAM_MEMORY_LARGE_MB("Memory.Coordinator.FreeMemoryUntilCritical", + available); + + if (available <= 0) + return MemoryState::SUSPENDED; + + auto current_state = coordinator_->GetGlobalMemoryState(); + int expected_renderer_count = available / expected_renderer_size_; + + switch (current_state) { + case MemoryState::NORMAL: + if (expected_renderer_count <= new_renderers_until_suspended_) + return MemoryState::SUSPENDED; + if (expected_renderer_count <= new_renderers_until_throttled_) + return MemoryState::THROTTLED; + return MemoryState::NORMAL; + case MemoryState::THROTTLED: + if (expected_renderer_count <= new_renderers_until_suspended_) + return MemoryState::SUSPENDED; + if (expected_renderer_count >= new_renderers_back_to_normal_) + return MemoryState::NORMAL; + return MemoryState::THROTTLED; + case MemoryState::SUSPENDED: + if (expected_renderer_count >= new_renderers_back_to_normal_) + return MemoryState::NORMAL; + if (expected_renderer_count >= new_renderers_back_to_throttled_) + return MemoryState::THROTTLED; + return MemoryState::SUSPENDED; + case MemoryState::UNKNOWN: + // Fall through + default: + NOTREACHED(); + return MemoryState::UNKNOWN; + } +} + +void MemoryStateUpdater::UpdateState() { + auto current_state = coordinator_->GetGlobalMemoryState(); + auto next_state = CalculateNextState(); + if (coordinator_->ChangeStateIfNeeded(current_state, next_state)) { + ScheduleUpdateState(minimum_transition_period_); + } else { + ScheduleUpdateState(monitoring_interval_); + } +} + +void MemoryStateUpdater::ScheduleUpdateState(base::TimeDelta delta) { + update_state_closure_.Reset(base::Bind(&MemoryStateUpdater::UpdateState, + base::Unretained(this))); + task_runner_->PostDelayedTask(FROM_HERE, update_state_closure_.callback(), + delta); +} + +void MemoryStateUpdater::InitializeParameters() { + expected_renderer_size_ = kDefaultExpectedRendererSizeMB; + new_renderers_until_throttled_ = kDefaultNewRenderersUntilThrottled; + new_renderers_until_suspended_ = kDefaultNewRenderersUntilSuspended; + new_renderers_back_to_normal_ = kDefaultNewRenderersBackToNormal; + new_renderers_back_to_throttled_ = kDefaultNewRenderersBackToThrottled; + minimum_transition_period_ = + base::TimeDelta::FromSeconds(kDefaultMinimumTransitionPeriodSeconds); + monitoring_interval_ = + base::TimeDelta::FromSeconds(kDefaultMonitoringIntervalSeconds); + + // Override default parameters with variations. + static constexpr char kMemoryCoordinatorV0Trial[] = "MemoryCoordinatorV0"; + std::map<std::string, std::string> params; + variations::GetVariationParams(kMemoryCoordinatorV0Trial, ¶ms); + SetIntVariationParameter(params, "expected_renderer_size", + &expected_renderer_size_); + SetIntVariationParameter(params, "new_renderers_until_throttled", + &new_renderers_until_throttled_); + SetIntVariationParameter(params, "new_renderers_until_suspended", + &new_renderers_until_suspended_); + SetIntVariationParameter(params, "new_renderers_back_to_normal", + &new_renderers_back_to_normal_); + SetIntVariationParameter(params, "new_renderers_back_to_throttled", + &new_renderers_back_to_throttled_); + SetSecondsVariationParameter(params, "minimum_transition_period", + &minimum_transition_period_); + SetSecondsVariationParameter(params, "monitoring_interval", + &monitoring_interval_); +} + +bool MemoryStateUpdater::ValidateParameters() { + return (new_renderers_until_throttled_ > new_renderers_until_suspended_) && + (new_renderers_back_to_normal_ > new_renderers_back_to_throttled_) && + (new_renderers_back_to_normal_ > new_renderers_until_throttled_) && + (new_renderers_back_to_throttled_ > new_renderers_until_suspended_); +} + +} // namespace content
diff --git a/content/browser/memory/memory_state_updater.h b/content/browser/memory/memory_state_updater.h new file mode 100644 index 0000000..2c8998a8 --- /dev/null +++ b/content/browser/memory/memory_state_updater.h
@@ -0,0 +1,97 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MEMORY_MEMORY_STATE_UPDATER_H_ +#define CONTENT_BROWSER_MEMORY_MEMORY_STATE_UPDATER_H_ + +#include "base/cancelable_callback.h" +#include "base/single_thread_task_runner.h" +#include "base/time/time.h" +#include "content/browser/memory/memory_coordinator_impl.h" +#include "content/common/content_export.h" + +namespace content { + +// MemoryStateUpdater is an internal implementation of MemoryCoordinator +// which uses a heuristic to determine a single global memory state. +// In the current implementation browser process and renderer processes share +// the global state; the memory coordinator will notify the global state to +// all background renderers if the state has changed. +// +// State calculation: +// MemoryStateUpdater uses followings to determine the global state: +// * Compute "number of renderers which can be created until the system will +// be in a critical state". Call this N. +// (See memory_monitor.h for the definition of "critical") +// * Covert N to a memory state using some thresholds/hysteresis for each state. +// Once a state is changed to a limited state, larger N will be needed to go +// back to a relaxed state. (e.g. THROTTLED -> NORMAL) +// * Once a state is changed, it remains the same for a certain period of time. +class CONTENT_EXPORT MemoryStateUpdater { + public: + // |coordinator| must outlive than this instance. + MemoryStateUpdater(MemoryCoordinatorImpl* coordinator, + scoped_refptr<base::SingleThreadTaskRunner> task_runner); + ~MemoryStateUpdater(); + + // Calculates the next global state from the amount of free memory using + // a heuristic. + base::MemoryState CalculateNextState(); + + // Schedules a task to update the global state. The task will be executed + // after |delay| has passed. + void ScheduleUpdateState(base::TimeDelta delay); + + private: + FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplTest, CalculateNextState); + FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplTest, UpdateState); + FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplTest, SetMemoryStateForTesting); + FRIEND_TEST_ALL_PREFIXES(MemoryCoordinatorImplTest, ForceSetGlobalState); + + // Periodically called to update the global state. + void UpdateState(); + + MemoryCoordinatorImpl* coordinator_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + base::CancelableClosure update_state_closure_; + + // Sets up parameters for the heuristic. + void InitializeParameters(); + + // Validates parameters defined below. + bool ValidateParameters(); + + // Parameters to control the heuristic. + + // The median size of a renderer on the current platform. This is used to + // convert the amount of free memory to an expected number of new renderers + // that could be started before hitting critical memory pressure. + int expected_renderer_size_; + // When in a NORMAL state and the potential number of new renderers drops + // below this level, the coordinator will transition to a THROTTLED state. + int new_renderers_until_throttled_; + // When in a NORMAL/THROTTLED state and the potential number of new renderers + // drops below this level, the coordinator will transition to a SUSPENDED + // state. + int new_renderers_until_suspended_; + // When in a THROTTLED/SUSPENDED state and the potential number of new + // renderers rises above this level, the coordinator will transition to a + // NORMAL state. + int new_renderers_back_to_normal_; + // When in a SUSPENDED state and the potential number of new renderers rises + // above this level, the coordinator will transition to a SUSPENDED state. + int new_renderers_back_to_throttled_; + // The memory coordinator stays in the same state at least this duration even + // when there are considerable changes in the amount of free memory to prevent + // thrashing. + base::TimeDelta minimum_transition_period_; + // The interval of checking the amount of free memory. + base::TimeDelta monitoring_interval_; + + DISALLOW_COPY_AND_ASSIGN(MemoryStateUpdater); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_MEMORY_MEMORY_STATE_UPDATER_H_
diff --git a/content/browser/payments/payment_app_manager_unittest.cc b/content/browser/payments/payment_app_manager_unittest.cc index e67b57c..ccd8c6a 100644 --- a/content/browser/payments/payment_app_manager_unittest.cc +++ b/content/browser/payments/payment_app_manager_unittest.cc
@@ -59,9 +59,8 @@ new TestBrowserThreadBundle(TestBrowserThreadBundle::IO_MAINLOOP)), embedded_worker_helper_(new EmbeddedWorkerTestHelper(base::FilePath())), storage_partition_impl_(new StoragePartitionImpl( - embedded_worker_helper_->browser_context(), base::FilePath(), - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { + embedded_worker_helper_->browser_context(), + base::FilePath(), nullptr)) { embedded_worker_helper_->context_wrapper()->set_storage_partition( storage_partition_impl_.get());
diff --git a/content/browser/quota/mock_quota_manager.cc b/content/browser/quota/mock_quota_manager.cc index 7340797..65e197a 100644 --- a/content/browser/quota/mock_quota_manager.cc +++ b/content/browser/quota/mock_quota_manager.cc
@@ -44,14 +44,13 @@ profile_path, io_thread, db_thread, - special_storage_policy), - weak_factory_(this) { -} + special_storage_policy, + storage::GetQuotaSettingsFunc()), + weak_factory_(this) {} -void MockQuotaManager::GetUsageAndQuota( - const GURL& origin, - storage::StorageType type, - const GetUsageAndQuotaCallback& callback) { +void MockQuotaManager::GetUsageAndQuota(const GURL& origin, + storage::StorageType type, + const UsageAndQuotaCallback& callback) { StorageInfo& info = usage_and_quota_map_[std::make_pair(origin, type)]; callback.Run(storage::kQuotaStatusOk, info.usage, info.quota); }
diff --git a/content/browser/quota/mock_quota_manager.h b/content/browser/quota/mock_quota_manager.h index 172b7e92..6289f319 100644 --- a/content/browser/quota/mock_quota_manager.h +++ b/content/browser/quota/mock_quota_manager.h
@@ -56,7 +56,7 @@ // a helper method MockQuotaManagerProxy::SetQuota(). void GetUsageAndQuota(const GURL& origin, storage::StorageType type, - const GetUsageAndQuotaCallback& callback) override; + const UsageAndQuotaCallback& callback) override; // Overrides QuotaManager's implementation with a canned implementation that // allows clients to set up the origin database that should be queried. This
diff --git a/content/browser/quota/mock_quota_manager_proxy.cc b/content/browser/quota/mock_quota_manager_proxy.cc index 697577b..8ca0293 100644 --- a/content/browser/quota/mock_quota_manager_proxy.cc +++ b/content/browser/quota/mock_quota_manager_proxy.cc
@@ -40,7 +40,7 @@ base::SequencedTaskRunner* original_task_runner, const GURL& origin, StorageType type, - const QuotaManager::GetUsageAndQuotaCallback& callback) { + const QuotaManager::UsageAndQuotaCallback& callback) { if (mock_manager()) { mock_manager()->GetUsageAndQuota(origin, type, callback); }
diff --git a/content/browser/quota/mock_quota_manager_proxy.h b/content/browser/quota/mock_quota_manager_proxy.h index e550a9d9..3f9ddab 100644 --- a/content/browser/quota/mock_quota_manager_proxy.h +++ b/content/browser/quota/mock_quota_manager_proxy.h
@@ -41,7 +41,7 @@ base::SequencedTaskRunner* original_task_runner, const GURL& origin, StorageType type, - const QuotaManager::GetUsageAndQuotaCallback& callback) override; + const QuotaManager::UsageAndQuotaCallback& callback) override; // Validates the |client_id| and updates the internal access count // which can be accessed via notify_storage_accessed_count().
diff --git a/content/browser/quota/quota_backend_impl_unittest.cc b/content/browser/quota/quota_backend_impl_unittest.cc index 12e76e6..6054e32 100644 --- a/content/browser/quota/quota_backend_impl_unittest.cc +++ b/content/browser/quota/quota_backend_impl_unittest.cc
@@ -70,7 +70,7 @@ void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner, const GURL& origin, storage::StorageType type, - const GetUsageAndQuotaCallback& callback) override { + const UsageAndQuotaCallback& callback) override { callback.Run(storage::kQuotaStatusOk, usage_, quota_); }
diff --git a/content/browser/quota/quota_manager_unittest.cc b/content/browser/quota/quota_manager_unittest.cc index 580d68e..3613ec8 100644 --- a/content/browser/quota/quota_manager_unittest.cc +++ b/content/browser/quota/quota_manager_unittest.cc
@@ -44,7 +44,6 @@ using storage::QuotaManager; using storage::QuotaStatusCode; using storage::StorageType; -using storage::UsageAndQuota; using storage::UsageInfo; using storage::UsageInfoEntries; @@ -59,42 +58,26 @@ const int kAllClients = QuotaClient::kAllClientsMask; +// Values in bytes. const int64_t kAvailableSpaceForApp = 13377331U; - -const int64_t kMinimumPreserveForSystem = - QuotaManager::kMinimumPreserveForSystem; -const int kPerHostTemporaryPortion = QuotaManager::kPerHostTemporaryPortion; +const int64_t kMustRemainAvailableForSystem = kAvailableSpaceForApp / 2; +const int64_t kDefaultPoolSize = 1000; +const int64_t kDefaultPerHostQuota = 200; const GURL kTestEvictionOrigin = GURL("http://test.eviction.policy/result"); // Returns a deterministic value for the amount of available disk space. int64_t GetAvailableDiskSpaceForTest() { - return kAvailableSpaceForApp + kMinimumPreserveForSystem; + return kAvailableSpaceForApp + kMustRemainAvailableForSystem; } -bool GetVolumeInfoForTests(const base::FilePath&, - uint64_t* available, uint64_t* total) { - *available = static_cast<uint64_t>(GetAvailableDiskSpaceForTest()); - *total = *available * 2; - return true; +std::pair<int64_t, int64_t> GetVolumeInfoForTests( + const base::FilePath& unused) { + int64_t available = static_cast<uint64_t>(GetAvailableDiskSpaceForTest()); + int64_t total = available * 2; + return std::make_pair(total, available); } -class TestEvictionPolicy : public storage::QuotaEvictionPolicy { - public: - TestEvictionPolicy() {} - ~TestEvictionPolicy() override {} - - // Overridden from storage::QuotaEvictionPolicy: - void GetEvictionOrigin(const scoped_refptr<storage::SpecialStoragePolicy>& - special_storage_policy, - const std::set<GURL>& exceptions, - const std::map<GURL, int64_t>& usage_map, - int64_t global_quota, - const storage::GetOriginCallback& callback) override { - callback.Run(kTestEvictionOrigin); - } -}; - } // namespace class QuotaManagerTest : public testing::Test { @@ -126,7 +109,11 @@ quota_manager_ = new QuotaManager(is_incognito, data_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get(), base::ThreadTaskRunnerHandle::Get().get(), - mock_special_storage_policy_.get()); + mock_special_storage_policy_.get(), + storage::GetQuotaSettingsFunc()); + SetQuotaSettings(kDefaultPoolSize, kDefaultPerHostQuota, + is_incognito ? INT64_C(0) : kMustRemainAvailableForSystem); + // Don't (automatically) start the eviction for testing. quota_manager_->eviction_disabled_ = true; // Don't query the hard disk for remaining capacity. @@ -173,21 +160,15 @@ weak_factory_.GetWeakPtr())); } - void GetTemporaryGlobalQuota() { - quota_status_ = kQuotaStatusUnknown; - quota_ = -1; - quota_manager_->GetTemporaryGlobalQuota( - base::Bind(&QuotaManagerTest::DidGetQuota, - weak_factory_.GetWeakPtr())); - } - - void SetTemporaryGlobalQuota(int64_t new_quota) { - quota_status_ = kQuotaStatusUnknown; - quota_ = -1; - quota_manager_->SetTemporaryGlobalOverrideQuota( - new_quota, - base::Bind(&QuotaManagerTest::DidGetQuota, - weak_factory_.GetWeakPtr())); + void SetQuotaSettings(int64_t pool_size, + int64_t per_host_quota, + int64_t must_remain_available) { + storage::QuotaSettings settings; + settings.pool_size = pool_size; + settings.per_host_quota = per_host_quota; + settings.must_remain_available = must_remain_available; + settings.refresh_interval = base::TimeDelta::Max(); + quota_manager_->SetQuotaSettings(settings); } void GetPersistentHostQuota(const std::string& host) { @@ -272,22 +253,21 @@ weak_factory_.GetWeakPtr())); } - void GetAvailableSpace() { - quota_status_ = kQuotaStatusUnknown; + void GetStorageCapacity() { available_space_ = -1; - quota_manager_->GetAvailableSpace( - base::Bind(&QuotaManagerTest::DidGetAvailableSpace, - weak_factory_.GetWeakPtr())); + total_space_ = -1; + quota_manager_->GetStorageCapacity(base::Bind( + &QuotaManagerTest::DidGetStorageCapacity, weak_factory_.GetWeakPtr())); } - void GetUsageAndQuotaForEviction() { + void GetEvictionRoundInfo() { quota_status_ = kQuotaStatusUnknown; - usage_ = -1; - unlimited_usage_ = -1; - quota_ = -1; + settings_ = storage::QuotaSettings(); available_space_ = -1; - quota_manager_->GetUsageAndQuotaForEviction( - base::Bind(&QuotaManagerTest::DidGetUsageAndQuotaForEviction, + total_space_ = -1; + usage_ = -1; + quota_manager_->GetEvictionRoundInfo( + base::Bind(&QuotaManagerTest::DidGetEvictionRoundInfo, weak_factory_.GetWeakPtr())); } @@ -297,12 +277,6 @@ quota_manager_->GetCachedOrigins(type, origins); } - bool GetVolumeInfo(const base::FilePath& path, - uint64_t* available_space, - uint64_t* total_size) { - return QuotaManager::GetVolumeInfo(path, available_space, total_size); - } - void NotifyStorageAccessed(QuotaClient* client, const GURL& origin, StorageType type) { @@ -373,8 +347,8 @@ quota_ = quota; } - void DidGetAvailableSpace(QuotaStatusCode status, int64_t available_space) { - quota_status_ = status; + void DidGetStorageCapacity(int64_t total_space, int64_t available_space) { + total_space_ = total_space; available_space_ = available_space; } @@ -395,12 +369,17 @@ quota_status_ = status; } - void DidGetUsageAndQuotaForEviction(QuotaStatusCode status, - const UsageAndQuota& usage_and_quota) { + void DidGetEvictionRoundInfo(QuotaStatusCode status, + const storage::QuotaSettings& settings, + int64_t available_space, + int64_t total_space, + int64_t global_usage, + bool global_usage_is_complete) { quota_status_ = status; - limited_usage_ = usage_and_quota.global_limited_usage; - quota_ = usage_and_quota.quota; - available_space_ = usage_and_quota.available_disk_space; + settings_ = settings; + available_space_ = available_space; + total_space_ = total_space; + usage_ = global_usage; } void DidGetEvictionOrigin(const GURL& origin) { @@ -445,6 +424,7 @@ int64_t limited_usage() const { return limited_usage_; } int64_t unlimited_usage() const { return unlimited_usage_; } int64_t quota() const { return quota_; } + int64_t total_space() const { return total_space_; } int64_t available_space() const { return available_space_; } const GURL& eviction_origin() const { return eviction_origin_; } const std::set<GURL>& modified_origins() const { return modified_origins_; } @@ -453,6 +433,7 @@ const OriginInfoTableEntries& origin_info_entries() const { return origin_info_entries_; } + const storage::QuotaSettings& settings() const { return settings_; } base::FilePath profile_path() const { return data_dir_.GetPath(); } int status_callback_count() const { return status_callback_count_; } void reset_status_callback_count() { status_callback_count_ = 0; } @@ -475,12 +456,14 @@ int64_t limited_usage_; int64_t unlimited_usage_; int64_t quota_; + int64_t total_space_; int64_t available_space_; GURL eviction_origin_; std::set<GURL> modified_origins_; StorageType modified_origins_type_; QuotaTableEntries quota_entries_; OriginInfoTableEntries origin_info_entries_; + storage::QuotaSettings settings_; int status_callback_count_; int additional_callback_count_; @@ -633,20 +616,17 @@ QuotaClient::kFileSystem)); // This time explicitly sets a temporary global quota. - SetTemporaryGlobalQuota(100); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(kQuotaStatusOk, status()); - EXPECT_EQ(100, quota()); + const int kPoolSize = 100; + const int kPerHostQuota = 20; + SetQuotaSettings(kPoolSize, kPerHostQuota, kMustRemainAvailableForSystem); GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kTemp); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(10 + 20, usage()); - const int kPerHostQuota = 100 / kPerHostTemporaryPortion; - // The host's quota should be its full portion of the global quota - // since global usage is under the global quota. + // since there's plenty of diskspace. EXPECT_EQ(kPerHostQuota, quota()); GetUsageAndQuotaForWebApps(GURL("http://bar.com/"), kTemp); @@ -662,39 +642,39 @@ { "http://bar.com/", kTemp, 2 }, { "http://bar.com/", kPerm, 4 }, { "http://unlimited/", kPerm, 8 }, - { "http://installed/", kPerm, 16 }, }; static const MockOriginData kData2[] = { { "https://foo.com/", kTemp, 128 }, { "http://example.com/", kPerm, 256 }, { "http://unlimited/", kTemp, 512 }, - { "http://installed/", kTemp, 1024 }, }; mock_special_storage_policy()->AddUnlimited(GURL("http://unlimited/")); - mock_special_storage_policy()->GrantQueryDiskSize(GURL("http://installed/")); RegisterClient(CreateClient(kData1, arraysize(kData1), QuotaClient::kFileSystem)); RegisterClient(CreateClient(kData2, arraysize(kData2), QuotaClient::kDatabase)); - const int64_t kTempQuotaBase = - GetAvailableDiskSpaceForTest() / kPerHostTemporaryPortion; + const int64_t kPoolSize = GetAvailableDiskSpaceForTest(); + const int64_t kPerHostQuota = kPoolSize / 5; + SetQuotaSettings(kPoolSize, kPerHostQuota, kMustRemainAvailableForSystem); GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kTemp); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(1 + 128, usage()); + EXPECT_EQ(kPerHostQuota, quota()); GetUsageAndQuotaForWebApps(GURL("http://bar.com/"), kPerm); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(4, usage()); + EXPECT_EQ(0, quota()); GetUsageAndQuotaForWebApps(GURL("http://unlimited/"), kTemp); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(512, usage()); - EXPECT_EQ(std::min(kAvailableSpaceForApp, kTempQuotaBase) + usage(), quota()); + EXPECT_EQ(kAvailableSpaceForApp + usage(), quota()); GetUsageAndQuotaForWebApps(GURL("http://unlimited/"), kPerm); base::RunLoop().RunUntilIdle(); @@ -702,33 +682,16 @@ EXPECT_EQ(8, usage()); EXPECT_EQ(kAvailableSpaceForApp + usage(), quota()); - GetAvailableSpace(); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(kQuotaStatusOk, status()); - EXPECT_LE(0, available_space()); - - GetUsageAndQuotaForWebApps(GURL("http://installed/"), kTemp); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(kQuotaStatusOk, status()); - EXPECT_EQ(1024, usage()); - EXPECT_EQ(std::min(kAvailableSpaceForApp, kTempQuotaBase) + usage(), quota()); - - GetUsageAndQuotaForWebApps(GURL("http://installed/"), kPerm); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(kQuotaStatusOk, status()); - EXPECT_EQ(16, usage()); - EXPECT_EQ(usage(), quota()); // Over-budget case. - GetGlobalUsage(kTemp); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); - EXPECT_EQ(1 + 2 + 128 + 512 + 1024, usage()); + EXPECT_EQ(1 + 2 + 128 + 512, usage()); EXPECT_EQ(512, unlimited_usage()); GetGlobalUsage(kPerm); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); - EXPECT_EQ(4 + 8 + 16 + 256, usage()); + EXPECT_EQ(4 + 8 + 256, usage()); EXPECT_EQ(8, unlimited_usage()); } @@ -781,10 +744,10 @@ }; RegisterClient(CreateClient(kData, arraysize(kData), QuotaClient::kFileSystem)); - SetTemporaryGlobalQuota(100); - base::RunLoop().RunUntilIdle(); - const int kPerHostQuota = 100 / QuotaManager::kPerHostTemporaryPortion; + const int kPoolSize = 100; + const int kPerHostQuota = 20; + SetQuotaSettings(kPoolSize, kPerHostQuota, kMustRemainAvailableForSystem); GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kTemp); GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kTemp); @@ -815,8 +778,9 @@ }; RegisterClient(CreateClient(kData, arraysize(kData), QuotaClient::kFileSystem)); - SetTemporaryGlobalQuota(100); - base::RunLoop().RunUntilIdle(); + const int kPoolSize = 100; + const int kPerHostQuota = 20; + SetQuotaSettings(kPoolSize, kPerHostQuota, kMustRemainAvailableForSystem); set_additional_callback_count(0); GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kTemp); @@ -842,22 +806,28 @@ }; RegisterClient(CreateClient(kData, arraysize(kData), QuotaClient::kFileSystem)); - SetTemporaryGlobalQuota(100); - base::RunLoop().RunUntilIdle(); + const int kPoolSize = 100; + const int kPerHostQuota = 20; + SetQuotaSettings(kPoolSize, kPerHostQuota, kMustRemainAvailableForSystem); - const int kPerHostQuota = 100 / QuotaManager::kPerHostTemporaryPortion; + // Provided diskspace is not tight, global usage does not affect the + // quota calculations for an individual origin, so despite global usage + // in excess of our poolsize, we still get the nominal quota value. + GetStorageCapacity(); + base::RunLoop().RunUntilIdle(); + EXPECT_LE(kMustRemainAvailableForSystem, available_space()); GetUsageAndQuotaForWebApps(GURL("http://usage1/"), kTemp); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(1, usage()); - EXPECT_EQ(1, quota()); // should be clamped to our current usage + EXPECT_EQ(kPerHostQuota, quota()); GetUsageAndQuotaForWebApps(GURL("http://usage10/"), kTemp); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(10, usage()); - EXPECT_EQ(10, quota()); + EXPECT_EQ(kPerHostQuota, quota()); GetUsageAndQuotaForWebApps(GURL("http://usage200/"), kTemp); base::RunLoop().RunUntilIdle(); @@ -878,17 +848,14 @@ RegisterClient(client); // Test when not overbugdet. - SetTemporaryGlobalQuota(1000); - base::RunLoop().RunUntilIdle(); + const int kPerHostQuotaFor1000 = 200; + SetQuotaSettings(1000, kPerHostQuotaFor1000, kMustRemainAvailableForSystem); GetGlobalUsage(kTemp); base::RunLoop().RunUntilIdle(); EXPECT_EQ(10 + 50 + 4000, usage()); EXPECT_EQ(4000, unlimited_usage()); - const int kPerHostQuotaFor1000 = - 1000 / QuotaManager::kPerHostTemporaryPortion; - GetUsageAndQuotaForWebApps(GURL("http://usage10/"), kTemp); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); @@ -914,11 +881,8 @@ EXPECT_EQ(QuotaManager::kNoLimit, quota()); // Test when overbugdet. - SetTemporaryGlobalQuota(100); - base::RunLoop().RunUntilIdle(); - - const int kPerHostQuotaFor100 = - 100 / QuotaManager::kPerHostTemporaryPortion; + const int kPerHostQuotaFor100 = 20; + SetQuotaSettings(100, kPerHostQuotaFor100, kMustRemainAvailableForSystem); GetUsageAndQuotaForWebApps(GURL("http://usage10/"), kTemp); base::RunLoop().RunUntilIdle(); @@ -957,7 +921,7 @@ base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(10, usage()); - EXPECT_EQ(10, quota()); // should be clamped to our current usage + EXPECT_EQ(kPerHostQuotaFor100, quota()); GetUsageAndQuotaForWebApps(GURL("http://usage50/"), kTemp); base::RunLoop().RunUntilIdle(); @@ -1043,14 +1007,7 @@ EXPECT_EQ(0, usage()); EXPECT_EQ(100, quota()); - // For installed app GetUsageAndQuotaForWebApps returns the capped quota. - mock_special_storage_policy()->GrantQueryDiskSize(GURL("http://installed/")); - SetPersistentHostQuota("installed", kAvailableSpaceForApp + 100); - GetUsageAndQuotaForWebApps(GURL("http://installed/"), kPerm); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(kAvailableSpaceForApp, quota()); - - // Ditto for unlimited apps. + // The actual space avaialble is given to 'unlimited' origins as their quota. mock_special_storage_policy()->AddUnlimited(GURL("http://unlimited/")); GetUsageAndQuotaForWebApps(GURL("http://unlimited/"), kPerm); base::RunLoop().RunUntilIdle(); @@ -1072,22 +1029,14 @@ EXPECT_LE(kAvailableSpaceForApp, QuotaManager::kSyncableStorageDefaultHostQuota); - // For installed apps the quota manager should return + // For unlimited origins the quota manager should return // kAvailableSpaceForApp as syncable quota (because of the pre-condition). - mock_special_storage_policy()->GrantQueryDiskSize(GURL("http://installed/")); - GetUsageAndQuotaForWebApps(GURL("http://installed/"), kSync); + mock_special_storage_policy()->AddUnlimited(GURL("http://unlimited/")); + GetUsageAndQuotaForWebApps(GURL("http://unlimited/"), kSync); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(0, usage()); EXPECT_EQ(kAvailableSpaceForApp, quota()); - - // If it's not installed (which shouldn't happen in real case) it - // should just return the default host quota for syncable. - GetUsageAndQuotaForWebApps(GURL("http://foo/"), kSync); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(kQuotaStatusOk, status()); - EXPECT_EQ(0, usage()); - EXPECT_EQ(QuotaManager::kSyncableStorageDefaultHostQuota, quota()); } TEST_F(QuotaManagerTest, GetPersistentUsageAndQuota_MultiOrigins) { @@ -1294,22 +1243,13 @@ EXPECT_EQ(predelete_host_pers, usage()); } -TEST_F(QuotaManagerTest, GetAvailableSpaceTest) { - GetAvailableSpace(); +TEST_F(QuotaManagerTest, GetStorageCapacity) { + GetStorageCapacity(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(kQuotaStatusOk, status()); + EXPECT_LE(0, total_space()); EXPECT_LE(0, available_space()); } -TEST_F(QuotaManagerTest, SetTemporaryStorageEvictionPolicy) { - quota_manager()->SetTemporaryStorageEvictionPolicy( - base::WrapUnique(new TestEvictionPolicy)); - - GetEvictionOrigin(kTemp); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(kTestEvictionOrigin, eviction_origin()); -} - TEST_F(QuotaManagerTest, EvictOriginData) { static const MockOriginData kData1[] = { { "http://foo.com/", kTemp, 1 }, @@ -1528,7 +1468,7 @@ EXPECT_EQ(predelete_host_pers, usage()); } -TEST_F(QuotaManagerTest, GetUsageAndQuotaForEviction) { +TEST_F(QuotaManagerTest, GetEvictionRoundInfo) { static const MockOriginData kData[] = { { "http://foo.com/", kTemp, 1 }, { "http://foo.com:1/", kTemp, 20 }, @@ -1541,14 +1481,15 @@ QuotaClient::kFileSystem); RegisterClient(client); - SetTemporaryGlobalQuota(10000000); - base::RunLoop().RunUntilIdle(); + const int kPoolSize = 10000000; + const int kPerHostQuota = kPoolSize / 5; + SetQuotaSettings(kPoolSize, kPerHostQuota, kMustRemainAvailableForSystem); - GetUsageAndQuotaForEviction(); + GetEvictionRoundInfo(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); - EXPECT_EQ(21, limited_usage()); - EXPECT_EQ(10000000, quota()); + EXPECT_EQ(21, usage()); + EXPECT_EQ(kPoolSize, settings().pool_size); EXPECT_LE(0, available_space()); } @@ -1801,16 +1742,19 @@ GetCachedOrigins(kTemp, &origins); EXPECT_TRUE(origins.empty()); - // No matter how we make queries the quota manager tries to cache all - // the origins at startup. GetHostUsage("a.com", kTemp); base::RunLoop().RunUntilIdle(); GetCachedOrigins(kTemp, &origins); - EXPECT_EQ(3U, origins.size()); + EXPECT_EQ(2U, origins.size()); GetHostUsage("b.com", kTemp); base::RunLoop().RunUntilIdle(); GetCachedOrigins(kTemp, &origins); + EXPECT_EQ(2U, origins.size()); + + GetHostUsage("c.com", kTemp); + base::RunLoop().RunUntilIdle(); + GetCachedOrigins(kTemp, &origins); EXPECT_EQ(3U, origins.size()); GetCachedOrigins(kPerm, &origins); @@ -2267,44 +2211,44 @@ RegisterClient(CreateClient(kData, arraysize(kData), QuotaClient::kFileSystem)); + // Query global usage to warmup the usage tracker caching. + GetGlobalUsage(kTemp); + GetGlobalUsage(kPerm); + base::RunLoop().RunUntilIdle(); + GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kPerm); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(80, usage()); EXPECT_EQ(0, quota()); - SetTemporaryGlobalQuota(100); + const int kPoolSize = 1000; + const int kPerHostQuota = kPoolSize / 5; + SetQuotaSettings(kPoolSize, kPerHostQuota, INT64_C(0)); + + GetStorageCapacity(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(kPoolSize, total_space()); + EXPECT_EQ(kPoolSize - 80 - 10, available_space()); + GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kTemp); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(10, usage()); - EXPECT_LE(std::min(static_cast<int64_t>(100 / kPerHostTemporaryPortion), - QuotaManager::kIncognitoDefaultQuotaLimit), - quota()); + EXPECT_LE(kPerHostQuota, quota()); mock_special_storage_policy()->AddUnlimited(GURL("http://foo.com/")); GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kPerm); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(80, usage()); - EXPECT_EQ(QuotaManager::kIncognitoDefaultQuotaLimit, quota()); + EXPECT_EQ(available_space() + usage(), quota()); GetUsageAndQuotaForWebApps(GURL("http://foo.com/"), kTemp); base::RunLoop().RunUntilIdle(); EXPECT_EQ(kQuotaStatusOk, status()); EXPECT_EQ(10, usage()); - EXPECT_EQ(QuotaManager::kIncognitoDefaultQuotaLimit, quota()); -} - -TEST_F(QuotaManagerTest, GetVolumeInfo) { - // We aren't actually testing that it's correct, just that it's sane. - base::FilePath tmp_dir; - ASSERT_TRUE(base::GetTempDir(&tmp_dir)); - uint64_t available_space = 0; - uint64_t total_size = 0; - EXPECT_TRUE(GetVolumeInfo(tmp_dir, &available_space, &total_size)); - EXPECT_GT(available_space, 0u) << tmp_dir.value(); - EXPECT_GT(total_size, 0u) << tmp_dir.value(); + EXPECT_EQ(available_space() + usage(), quota()); } } // namespace content
diff --git a/content/browser/quota/quota_temporary_storage_evictor_unittest.cc b/content/browser/quota/quota_temporary_storage_evictor_unittest.cc index 989c63d..ef417c708 100644 --- a/content/browser/quota/quota_temporary_storage_evictor_unittest.cc +++ b/content/browser/quota/quota_temporary_storage_evictor_unittest.cc
@@ -21,7 +21,6 @@ using storage::QuotaTemporaryStorageEvictor; using storage::StorageType; -using storage::UsageAndQuota; namespace content { @@ -31,15 +30,14 @@ class MockQuotaEvictionHandler : public storage::QuotaEvictionHandler { public: - explicit MockQuotaEvictionHandler(QuotaTemporaryStorageEvictorTest *test) - : quota_(0), - available_space_(0), + explicit MockQuotaEvictionHandler(QuotaTemporaryStorageEvictorTest* test) + : available_space_(0), error_on_evict_origin_data_(false), error_on_get_usage_and_quota_(false) {} void EvictOriginData(const GURL& origin, StorageType type, - const EvictOriginDataCallback& callback) override { + const storage::StatusCallback& callback) override { if (error_on_evict_origin_data_) { callback.Run(storage::kQuotaErrorInvalidModification); return; @@ -50,22 +48,17 @@ callback.Run(storage::kQuotaStatusOk); } - void AsyncGetVolumeInfo(const VolumeInfoCallback& callback) override { - uint64_t available = static_cast<uint64_t>(available_space_); - uint64_t total = (1024 * 1024 * 1024) + (2 * available); // 1G plus some. - callback.Run(true, available, total); - } - - void GetUsageAndQuotaForEviction( - const UsageAndQuotaCallback& callback) override { + void GetEvictionRoundInfo( + const EvictionRoundInfoCallback& callback) override { if (error_on_get_usage_and_quota_) { - callback.Run(storage::kQuotaErrorInvalidAccess, UsageAndQuota()); + callback.Run(storage::kQuotaErrorAbort, storage::QuotaSettings(), 0, 0, 0, + false); return; } if (!task_for_get_usage_and_quota_.is_null()) task_for_get_usage_and_quota_.Run(); - UsageAndQuota quota_and_usage(-1, GetUsage(), quota_, available_space_); - callback.Run(storage::kQuotaStatusOk, quota_and_usage); + callback.Run(storage::kQuotaStatusOk, settings_, available_space_, + available_space_ * 2, GetUsage(), true); } void GetEvictionOrigin(StorageType type, @@ -86,7 +79,13 @@ return total_usage; } - void set_quota(int64_t quota) { quota_ = quota; } + const storage::QuotaSettings& settings() const { return settings_; } + void SetPoolSize(int64_t pool_size) { + settings_.pool_size = pool_size; + settings_.per_host_quota = pool_size / 5; + settings_.must_remain_available = pool_size / 5; + settings_.refresh_interval = base::TimeDelta::Max(); + } void set_available_space(int64_t available_space) { available_space_ = available_space; } @@ -130,7 +129,7 @@ return origin_usage; } - int64_t quota_; + storage::QuotaSettings settings_; int64_t available_space_; std::list<GURL> origin_order_; std::map<GURL, int64_t> origins_; @@ -169,20 +168,20 @@ int expected_usage_after_second) { EXPECT_GE(4, num_get_usage_and_quota_for_eviction_); switch (num_get_usage_and_quota_for_eviction_) { - case 2: - EXPECT_EQ(expected_usage_after_first, - quota_eviction_handler()->GetUsage()); - if (!origin_to_be_added.first.is_empty()) - quota_eviction_handler()->AddOrigin(origin_to_be_added.first, - origin_to_be_added.second); - if (!origin_to_be_accessed.is_empty()) - quota_eviction_handler()->AccessOrigin(origin_to_be_accessed); - break; - case 3: - EXPECT_EQ(expected_usage_after_second, - quota_eviction_handler()->GetUsage()); - temporary_storage_evictor()->set_repeated_eviction(false); - break; + case 2: + EXPECT_EQ(expected_usage_after_first, + quota_eviction_handler()->GetUsage()); + if (!origin_to_be_added.first.is_empty()) + quota_eviction_handler()->AddOrigin(origin_to_be_added.first, + origin_to_be_added.second); + if (!origin_to_be_accessed.is_empty()) + quota_eviction_handler()->AccessOrigin(origin_to_be_accessed); + break; + case 3: + EXPECT_EQ(expected_usage_after_second, + quota_eviction_handler()->GetUsage()); + temporary_storage_evictor()->timer_disabled_for_testing_ = true; + break; } ++num_get_usage_and_quota_for_eviction_; } @@ -201,36 +200,19 @@ return temporary_storage_evictor()->statistics_; } - void set_repeated_eviction(bool repeated_eviction) const { - return temporary_storage_evictor_->set_repeated_eviction(repeated_eviction); + void disable_timer_for_testing() const { + temporary_storage_evictor_->timer_disabled_for_testing_ = true; } int num_get_usage_and_quota_for_eviction() const { return num_get_usage_and_quota_for_eviction_; } - int64_t default_min_available_disk_space_to_start_eviction() const { - return 1000 * 1000 * 500; - } - - void set_min_available_disk_space_to_start_eviction(int64_t value) const { - temporary_storage_evictor_->set_min_available_disk_space_to_start_eviction( - value); - } - - void reset_min_available_disk_space_to_start_eviction() const { - temporary_storage_evictor_-> - reset_min_available_disk_space_to_start_eviction(); - } - base::MessageLoop message_loop_; std::unique_ptr<MockQuotaEvictionHandler> quota_eviction_handler_; std::unique_ptr<QuotaTemporaryStorageEvictor> temporary_storage_evictor_; - int num_get_usage_and_quota_for_eviction_; - base::WeakPtrFactory<QuotaTemporaryStorageEvictorTest> weak_factory_; - DISALLOW_COPY_AND_ASSIGN(QuotaTemporaryStorageEvictorTest); }; @@ -238,10 +220,10 @@ quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 3000); quota_eviction_handler()->AddOrigin(GURL("http://www.y.com"), 200); quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 500); - quota_eviction_handler()->set_quota(4000); + quota_eviction_handler()->SetPoolSize(4000); quota_eviction_handler()->set_available_space(1000000000); EXPECT_EQ(3000 + 200 + 500, quota_eviction_handler()->GetUsage()); - set_repeated_eviction(false); + disable_timer_for_testing(); temporary_storage_evictor()->Start(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(200 + 500, quota_eviction_handler()->GetUsage()); @@ -258,10 +240,10 @@ quota_eviction_handler()->AddOrigin(GURL("http://www.y.com"), 2900); quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 450); quota_eviction_handler()->AddOrigin(GURL("http://www.w.com"), 400); - quota_eviction_handler()->set_quota(4000); + quota_eviction_handler()->SetPoolSize(4000); quota_eviction_handler()->set_available_space(1000000000); EXPECT_EQ(20 + 2900 + 450 + 400, quota_eviction_handler()->GetUsage()); - set_repeated_eviction(false); + disable_timer_for_testing(); temporary_storage_evictor()->Start(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(450 + 400, quota_eviction_handler()->GetUsage()); @@ -285,7 +267,7 @@ quota_eviction_handler()->AddOrigin(GURL("http://www.c.com"), c_size); quota_eviction_handler()->AddOrigin(GURL("http://www.b.com"), b_size); quota_eviction_handler()->AddOrigin(GURL("http://www.a.com"), a_size); - quota_eviction_handler()->set_quota(1000); + quota_eviction_handler()->SetPoolSize(1000); quota_eviction_handler()->set_available_space(1000000000); quota_eviction_handler()->set_task_for_get_usage_and_quota( base::Bind(&QuotaTemporaryStorageEvictorTest::TaskForRepeatedEvictionTest, @@ -318,14 +300,14 @@ quota_eviction_handler()->AddOrigin(GURL("http://www.c.com"), c_size); quota_eviction_handler()->AddOrigin(GURL("http://www.b.com"), b_size); quota_eviction_handler()->AddOrigin(GURL("http://www.a.com"), a_size); - quota_eviction_handler()->set_quota(1000); + quota_eviction_handler()->SetPoolSize(1000); quota_eviction_handler()->set_available_space(1000000000); quota_eviction_handler()->set_task_for_get_usage_and_quota( base::Bind(&QuotaTemporaryStorageEvictorTest::TaskForRepeatedEvictionTest, weak_factory_.GetWeakPtr(), std::make_pair(GURL(), 0), GURL(), initial_total_size - d_size, initial_total_size - d_size)); EXPECT_EQ(initial_total_size, quota_eviction_handler()->GetUsage()); - set_repeated_eviction(true); + // disable_timer_for_testing(); temporary_storage_evictor()->Start(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(initial_total_size - d_size, quota_eviction_handler()->GetUsage()); @@ -350,7 +332,7 @@ quota_eviction_handler()->AddOrigin(GURL("http://www.c.com"), c_size); quota_eviction_handler()->AddOrigin(GURL("http://www.b.com"), b_size); quota_eviction_handler()->AddOrigin(GURL("http://www.a.com"), a_size); - quota_eviction_handler()->set_quota(1000); + quota_eviction_handler()->SetPoolSize(1000); quota_eviction_handler()->set_available_space(1000000000); quota_eviction_handler()->set_task_for_get_usage_and_quota( base::Bind(&QuotaTemporaryStorageEvictorTest::TaskForRepeatedEvictionTest, @@ -374,17 +356,18 @@ } TEST_F(QuotaTemporaryStorageEvictorTest, DiskSpaceNonEvictionTest) { - quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 414); - quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 450); - quota_eviction_handler()->set_quota(10000); + // If we're using so little that evicting all of it wouldn't + // do enough to alleviate a diskspace shortage, we don't evict. + quota_eviction_handler()->AddOrigin(GURL("http://www.z.com"), 10); + quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 20); + quota_eviction_handler()->SetPoolSize(10000); quota_eviction_handler()->set_available_space( - default_min_available_disk_space_to_start_eviction() - 350); - EXPECT_EQ(414 + 450, quota_eviction_handler()->GetUsage()); - reset_min_available_disk_space_to_start_eviction(); - set_repeated_eviction(false); + quota_eviction_handler()->settings().must_remain_available - 350); + EXPECT_EQ(10 + 20, quota_eviction_handler()->GetUsage()); + disable_timer_for_testing(); temporary_storage_evictor()->Start(); base::RunLoop().RunUntilIdle(); - EXPECT_EQ(414 + 450, quota_eviction_handler()->GetUsage()); + EXPECT_EQ(10 + 20, quota_eviction_handler()->GetUsage()); EXPECT_EQ(0, statistics().num_errors_on_evicting_origin); EXPECT_EQ(0, statistics().num_errors_on_getting_usage_and_quota); @@ -398,13 +381,11 @@ quota_eviction_handler()->AddOrigin(GURL("http://www.y.com"), 120); quota_eviction_handler()->AddOrigin(GURL("http://www.x.com"), 150); quota_eviction_handler()->AddOrigin(GURL("http://www.w.com"), 300); - quota_eviction_handler()->set_quota(10000); + quota_eviction_handler()->SetPoolSize(10000); quota_eviction_handler()->set_available_space( - default_min_available_disk_space_to_start_eviction() - 350); + quota_eviction_handler()->settings().must_remain_available - 350); EXPECT_EQ(294 + 120 + 150 + 300, quota_eviction_handler()->GetUsage()); - set_min_available_disk_space_to_start_eviction( - default_min_available_disk_space_to_start_eviction()); - set_repeated_eviction(false); + disable_timer_for_testing(); temporary_storage_evictor()->Start(); base::RunLoop().RunUntilIdle(); EXPECT_EQ(150 + 300, quota_eviction_handler()->GetUsage());
diff --git a/content/browser/quota/storage_monitor_unittest.cc b/content/browser/quota/storage_monitor_unittest.cc index 7cbeb91..12512cf2b 100644 --- a/content/browser/quota/storage_monitor_unittest.cc +++ b/content/browser/quota/storage_monitor_unittest.cc
@@ -68,7 +68,8 @@ base::FilePath(), base::ThreadTaskRunnerHandle::Get().get(), base::ThreadTaskRunnerHandle::Get().get(), - special_storage_policy), + special_storage_policy, + storage::GetQuotaSettingsFunc()), callback_usage_(0), callback_quota_(0), callback_status_(kQuotaStatusOk), @@ -88,7 +89,7 @@ void GetUsageAndQuotaForWebApps( const GURL& origin, StorageType type, - const GetUsageAndQuotaCallback& callback) override { + const UsageAndQuotaCallback& callback) override { if (initialized_) callback.Run(callback_status_, callback_usage_, callback_quota_); else @@ -103,7 +104,7 @@ int64_t callback_quota_; QuotaStatusCode callback_status_; bool initialized_; - GetUsageAndQuotaCallback delayed_callback_; + UsageAndQuotaCallback delayed_callback_; }; } // namespace @@ -649,7 +650,8 @@ storage_policy_ = new MockSpecialStoragePolicy(); quota_manager_ = new QuotaManager( false, data_dir_.GetPath(), base::ThreadTaskRunnerHandle::Get().get(), - base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get()); + base::ThreadTaskRunnerHandle::Get().get(), storage_policy_.get(), + storage::GetQuotaSettingsFunc()); client_ = new MockStorageClient(quota_manager_->proxy(), NULL,
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 9ae4ccf..5948e63c 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1074,7 +1074,7 @@ browser_context->GetResourceContext()->GetMediaDeviceIDSalt()); AddFilter(audio_renderer_host_.get()); AddFilter( - new MidiHost(GetID(), BrowserMainLoop::GetInstance()->midi_manager())); + new MidiHost(GetID(), BrowserMainLoop::GetInstance()->midi_service())); AddFilter(new AppCacheDispatcherHost( storage_partition_impl_->GetAppCacheService(), GetID())); AddFilter(new ClipboardMessageFilter(blob_storage_context));
diff --git a/content/browser/service_worker/service_worker_storage.cc b/content/browser/service_worker/service_worker_storage.cc index adfca9c..b9730196 100644 --- a/content/browser/service_worker/service_worker_storage.cc +++ b/content/browser/service_worker/service_worker_storage.cc
@@ -627,11 +627,14 @@ const GURL& origin, const std::vector<std::pair<std::string, std::string>>& key_value_pairs, const StatusCallback& callback) { - DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_; - if (IsDisabled()) { - RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_ABORT)); + if (!LazyInitialize(base::Bind(&ServiceWorkerStorage::StoreUserData, + weak_factory_.GetWeakPtr(), registration_id, + origin, key_value_pairs, callback))) { + if (state_ != INITIALIZING) + RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_ABORT)); return; } + DCHECK_EQ(INITIALIZED, state_); if (registration_id == kInvalidServiceWorkerRegistrationId || key_value_pairs.empty()) { @@ -657,12 +660,16 @@ void ServiceWorkerStorage::GetUserData(int64_t registration_id, const std::vector<std::string>& keys, const GetUserDataCallback& callback) { - DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_; - if (IsDisabled()) { - RunSoon(FROM_HERE, base::Bind(callback, std::vector<std::string>(), - SERVICE_WORKER_ERROR_ABORT)); + if (!LazyInitialize(base::Bind(&ServiceWorkerStorage::GetUserData, + weak_factory_.GetWeakPtr(), registration_id, + keys, callback))) { + if (state_ != INITIALIZING) { + RunSoon(FROM_HERE, base::Bind(callback, std::vector<std::string>(), + SERVICE_WORKER_ERROR_ABORT)); + } return; } + DCHECK_EQ(INITIALIZED, state_); if (registration_id == kInvalidServiceWorkerRegistrationId || keys.empty()) { RunSoon(FROM_HERE, base::Bind(callback, std::vector<std::string>(), @@ -688,7 +695,15 @@ void ServiceWorkerStorage::ClearUserData(int64_t registration_id, const std::vector<std::string>& keys, const StatusCallback& callback) { - DCHECK(state_ == INITIALIZED || state_ == DISABLED) << state_; + if (!LazyInitialize(base::Bind(&ServiceWorkerStorage::ClearUserData, + weak_factory_.GetWeakPtr(), registration_id, + keys, callback))) { + if (state_ != INITIALIZING) + RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_ABORT)); + return; + } + DCHECK_EQ(INITIALIZED, state_); + if (IsDisabled()) { RunSoon(FROM_HERE, base::Bind(callback, SERVICE_WORKER_ERROR_ABORT)); return;
diff --git a/content/browser/service_worker/service_worker_storage_unittest.cc b/content/browser/service_worker/service_worker_storage_unittest.cc index 97312a5..fb743e9 100644 --- a/content/browser/service_worker/service_worker_storage_unittest.cc +++ b/content/browser/service_worker/service_worker_storage_unittest.cc
@@ -1096,6 +1096,35 @@ GetUserDataForAllRegistrations(std::string(), &data_list_out)); } +// The *_BeforeInitialize tests exercise the API before LazyInitialize() is +// called. +TEST_P(ServiceWorkerStorageTestP, StoreUserData_BeforeInitialize) { + const int kRegistrationId = 0; + EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, + StoreUserData(kRegistrationId, GURL("https://example.com"), + {{"key", "data"}})); +} + +TEST_P(ServiceWorkerStorageTestP, GetUserData_BeforeInitialize) { + const int kRegistrationId = 0; + std::vector<std::string> data_out; + EXPECT_EQ(SERVICE_WORKER_ERROR_NOT_FOUND, + GetUserData(kRegistrationId, {"key"}, &data_out)); +} + +TEST_P(ServiceWorkerStorageTestP, ClearUserData_BeforeInitialize) { + const int kRegistrationId = 0; + EXPECT_EQ(SERVICE_WORKER_OK, ClearUserData(kRegistrationId, {"key"})); +} + +TEST_P(ServiceWorkerStorageTestP, + GetUserDataForAllRegistrations_BeforeInitialize) { + std::vector<std::pair<int64_t, std::string>> data_list_out; + EXPECT_EQ(SERVICE_WORKER_OK, + GetUserDataForAllRegistrations("key", &data_list_out)); + EXPECT_TRUE(data_list_out.empty()); +} + class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTestP { public: void SetUp() override {
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index 9d9b2a6..1562ad45 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc
@@ -22,10 +22,12 @@ #include "content/common/dom_storage/dom_storage_types.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/content_browser_client.h" #include "content/public/browser/dom_storage_context.h" #include "content/public/browser/indexed_db_context.h" #include "content/public/browser/local_storage_usage_info.h" #include "content/public/browser/session_storage_usage_info.h" +#include "content/public/common/content_client.h" #include "net/base/completion_callback.h" #include "net/base/net_errors.h" #include "net/cookies/canonical_cookie.h" @@ -363,36 +365,11 @@ StoragePartitionImpl::StoragePartitionImpl( BrowserContext* browser_context, const base::FilePath& partition_path, - storage::QuotaManager* quota_manager, - ChromeAppCacheService* appcache_service, - storage::FileSystemContext* filesystem_context, - storage::DatabaseTracker* database_tracker, - DOMStorageContextWrapper* dom_storage_context, - IndexedDBContextImpl* indexed_db_context, - CacheStorageContextImpl* cache_storage_context, - ServiceWorkerContextWrapper* service_worker_context, - storage::SpecialStoragePolicy* special_storage_policy, - HostZoomLevelContext* host_zoom_level_context, - PlatformNotificationContextImpl* platform_notification_context, - BackgroundSyncContext* background_sync_context, - PaymentAppContextImpl* payment_app_context, - scoped_refptr<BroadcastChannelProvider> broadcast_channel_provider) + storage::SpecialStoragePolicy* special_storage_policy) : partition_path_(partition_path), - quota_manager_(quota_manager), - appcache_service_(appcache_service), - filesystem_context_(filesystem_context), - database_tracker_(database_tracker), - dom_storage_context_(dom_storage_context), - indexed_db_context_(indexed_db_context), - cache_storage_context_(cache_storage_context), - service_worker_context_(service_worker_context), special_storage_policy_(special_storage_policy), - host_zoom_level_context_(host_zoom_level_context), - platform_notification_context_(platform_notification_context), - background_sync_context_(background_sync_context), - payment_app_context_(payment_app_context), - broadcast_channel_provider_(std::move(broadcast_channel_provider)), - browser_context_(browser_context) {} + browser_context_(browser_context), + weak_factory_(this) {} StoragePartitionImpl::~StoragePartitionImpl() { browser_context_ = nullptr; @@ -440,34 +417,38 @@ base::FilePath partition_path = context->GetPath().Append(relative_partition_path); + std::unique_ptr<StoragePartitionImpl> partition = + base::WrapUnique(new StoragePartitionImpl( + context, partition_path, context->GetSpecialStoragePolicy())); + // All of the clients have to be created and registered with the // QuotaManager prior to the QuotaManger being used. We do them // all together here prior to handing out a reference to anything // that utilizes the QuotaManager. - scoped_refptr<storage::QuotaManager> quota_manager = - new storage::QuotaManager( - in_memory, partition_path, - BrowserThread::GetTaskRunnerForThread(BrowserThread::IO).get(), - BrowserThread::GetTaskRunnerForThread(BrowserThread::DB).get(), - context->GetSpecialStoragePolicy()); + partition->quota_manager_ = new storage::QuotaManager( + in_memory, partition_path, + BrowserThread::GetTaskRunnerForThread(BrowserThread::IO).get(), + BrowserThread::GetTaskRunnerForThread(BrowserThread::DB).get(), + context->GetSpecialStoragePolicy(), + base::Bind(&StoragePartitionImpl::GetQuotaSettings, + partition->weak_factory_.GetWeakPtr())); + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy = + partition->quota_manager_->proxy(); // Each consumer is responsible for registering its QuotaClient during // its construction. - scoped_refptr<storage::FileSystemContext> filesystem_context = - CreateFileSystemContext( - context, partition_path, in_memory, quota_manager->proxy()); + partition->filesystem_context_ = CreateFileSystemContext( + context, partition_path, in_memory, quota_manager_proxy.get()); - scoped_refptr<storage::DatabaseTracker> database_tracker = - new storage::DatabaseTracker( - partition_path, in_memory, context->GetSpecialStoragePolicy(), - quota_manager->proxy(), - BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE).get()); + partition->database_tracker_ = new storage::DatabaseTracker( + partition_path, in_memory, context->GetSpecialStoragePolicy(), + quota_manager_proxy.get(), + BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE).get()); - scoped_refptr<DOMStorageContextWrapper> dom_storage_context = - new DOMStorageContextWrapper( - BrowserContext::GetConnectorFor(context), - in_memory ? base::FilePath() : context->GetPath(), - relative_partition_path, context->GetSpecialStoragePolicy()); + partition->dom_storage_context_ = new DOMStorageContextWrapper( + BrowserContext::GetConnectorFor(context), + in_memory ? base::FilePath() : context->GetPath(), + relative_partition_path, context->GetSpecialStoragePolicy()); // BrowserMainLoop may not be initialized in unit tests. Tests will // need to inject their own task runner into the IndexedDBContext. @@ -481,60 +462,38 @@ : NULL; base::FilePath path = in_memory ? base::FilePath() : partition_path; - scoped_refptr<IndexedDBContextImpl> indexed_db_context = - new IndexedDBContextImpl(path, - context->GetSpecialStoragePolicy(), - quota_manager->proxy(), - idb_task_runner); + partition->indexed_db_context_ = + new IndexedDBContextImpl(path, context->GetSpecialStoragePolicy(), + quota_manager_proxy.get(), idb_task_runner); - scoped_refptr<CacheStorageContextImpl> cache_storage_context = - new CacheStorageContextImpl(context); - cache_storage_context->Init(path, make_scoped_refptr(quota_manager->proxy())); + partition->cache_storage_context_ = new CacheStorageContextImpl(context); + partition->cache_storage_context_->Init(path, quota_manager_proxy); - scoped_refptr<ServiceWorkerContextWrapper> service_worker_context = - new ServiceWorkerContextWrapper(context); - service_worker_context->Init(path, quota_manager->proxy(), - context->GetSpecialStoragePolicy()); + partition->service_worker_context_ = new ServiceWorkerContextWrapper(context); + partition->service_worker_context_->Init(path, quota_manager_proxy.get(), + context->GetSpecialStoragePolicy()); + partition->service_worker_context_->set_storage_partition(partition.get()); - scoped_refptr<ChromeAppCacheService> appcache_service = - new ChromeAppCacheService(quota_manager->proxy()); + partition->appcache_service_ = + new ChromeAppCacheService(quota_manager_proxy.get()); - scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy( - context->GetSpecialStoragePolicy()); + partition->host_zoom_level_context_ = new HostZoomLevelContext( + context->CreateZoomLevelDelegate(partition_path)); - scoped_refptr<HostZoomLevelContext> host_zoom_level_context( - new HostZoomLevelContext( - context->CreateZoomLevelDelegate(partition_path))); - - scoped_refptr<PlatformNotificationContextImpl> platform_notification_context = + partition->platform_notification_context_ = new PlatformNotificationContextImpl(path, context, - service_worker_context); - platform_notification_context->Initialize(); + partition->service_worker_context_); + partition->platform_notification_context_->Initialize(); - scoped_refptr<BackgroundSyncContext> background_sync_context = - new BackgroundSyncContext(); - background_sync_context->Init(service_worker_context); + partition->background_sync_context_ = new BackgroundSyncContext(); + partition->background_sync_context_->Init(partition->service_worker_context_); - scoped_refptr<PaymentAppContextImpl> payment_app_context = - new PaymentAppContextImpl(service_worker_context); + partition->payment_app_context_ = new PaymentAppContextImpl( + partition->service_worker_context_); - scoped_refptr<BroadcastChannelProvider> - broadcast_channel_provider = new BroadcastChannelProvider(); + partition->broadcast_channel_provider_ = new BroadcastChannelProvider(); - std::unique_ptr<StoragePartitionImpl> storage_partition( - new StoragePartitionImpl( - context, partition_path, quota_manager.get(), appcache_service.get(), - filesystem_context.get(), database_tracker.get(), - dom_storage_context.get(), indexed_db_context.get(), - cache_storage_context.get(), service_worker_context.get(), - special_storage_policy.get(), host_zoom_level_context.get(), - platform_notification_context.get(), background_sync_context.get(), - payment_app_context.get(), - std::move(broadcast_channel_provider))); - - service_worker_context->set_storage_partition(storage_partition.get()); - - return storage_partition; + return partition; } base::FilePath StoragePartitionImpl::GetPath() { @@ -934,4 +893,10 @@ media_url_request_context_ = media_url_request_context; } +void StoragePartitionImpl::GetQuotaSettings( + const storage::OptionalQuotaSettingsCallback& callback) { + GetContentClient()->browser()->GetQuotaSettings(browser_context_, this, + callback); +} + } // namespace content
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h index f00d02f..e3822dab 100644 --- a/content/browser/storage_partition_impl.h +++ b/content/browser/storage_partition_impl.h
@@ -14,6 +14,7 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" #include "content/browser/appcache/chrome_appcache_service.h" #include "content/browser/background_sync/background_sync_context.h" #include "content/browser/broadcast_channel/broadcast_channel_provider.h" @@ -165,23 +166,9 @@ bool in_memory, const base::FilePath& relative_partition_path); - StoragePartitionImpl( - BrowserContext* browser_context, - const base::FilePath& partition_path, - storage::QuotaManager* quota_manager, - ChromeAppCacheService* appcache_service, - storage::FileSystemContext* filesystem_context, - storage::DatabaseTracker* database_tracker, - DOMStorageContextWrapper* dom_storage_context, - IndexedDBContextImpl* indexed_db_context, - CacheStorageContextImpl* cache_storage_context, - ServiceWorkerContextWrapper* service_worker_context, - storage::SpecialStoragePolicy* special_storage_policy, - HostZoomLevelContext* host_zoom_level_context, - PlatformNotificationContextImpl* platform_notification_context, - BackgroundSyncContext* background_sync_context, - PaymentAppContextImpl* payment_app_context, - scoped_refptr<BroadcastChannelProvider>broadcast_channel_provider); + StoragePartitionImpl(BrowserContext* browser_context, + const base::FilePath& partition_path, + storage::SpecialStoragePolicy* special_storage_policy); // We will never have both remove_origin be populated and a cookie_matcher. void ClearDataImpl(uint32_t remove_mask, @@ -211,6 +198,10 @@ void SetMediaURLRequestContext( net::URLRequestContextGetter* media_url_request_context); + // Function used by the quota system to ask the embedder for the + // storage configuration info. + void GetQuotaSettings(const storage::OptionalQuotaSettingsCallback& callback); + base::FilePath partition_path_; scoped_refptr<net::URLRequestContextGetter> url_request_context_; scoped_refptr<net::URLRequestContextGetter> media_url_request_context_; @@ -236,6 +227,8 @@ // BrowserContext is destroyed, |this| will be destroyed too. BrowserContext* browser_context_; + base::WeakPtrFactory<StoragePartitionImpl> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(StoragePartitionImpl); };
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc index 0e85d8a6..3e65c39d 100644 --- a/content/browser/storage_partition_impl_map.cc +++ b/content/browser/storage_partition_impl_map.cc
@@ -399,10 +399,6 @@ StoragePartitionImpl* partition = partition_ptr.get(); partitions_[partition_config] = std::move(partition_ptr); - partition->GetQuotaManager()->SetTemporaryStorageEvictionPolicy( - GetContentClient()->browser()->GetTemporaryStorageEvictionPolicy( - browser_context_)); - ChromeBlobStorageContext* blob_storage_context = ChromeBlobStorageContext::GetFor(browser_context_); StreamContext* stream_context = StreamContext::GetFor(browser_context_);
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc index 89a604d..bdabb9f8 100644 --- a/content/child/resource_dispatcher.cc +++ b/content/child/resource_dispatcher.cc
@@ -95,7 +95,7 @@ mojom::DownloadedTempFilePtr downloaded_file) override { has_received_response_ = true; if (body_consumer_) - body_consumer_->Start(task_runner_.get()); + body_consumer_->Start(); downloaded_file_ = std::move(downloaded_file); resource_dispatcher_->OnMessageReceived( ResourceMsg_ReceivedResponse(request_id_, response_head)); @@ -120,7 +120,7 @@ body_consumer_ = new URLResponseBodyConsumer( request_id_, resource_dispatcher_, std::move(body), task_runner_); if (has_received_response_) - body_consumer_->Start(task_runner_.get()); + body_consumer_->Start(); } void OnComplete(const ResourceRequestCompletionStatus& status) override {
diff --git a/content/child/url_response_body_consumer.cc b/content/child/url_response_body_consumer.cc index 101aee6..9d5c017 100644 --- a/content/child/url_response_body_consumer.cc +++ b/content/child/url_response_body_consumer.cc
@@ -4,6 +4,7 @@ #include "content/child/url_response_body_consumer.h" +#include "base/auto_reset.h" #include "base/bind.h" #include "base/macros.h" #include "base/memory/ptr_util.h" @@ -45,17 +46,18 @@ resource_dispatcher_(resource_dispatcher), handle_(std::move(handle)), handle_watcher_(task_runner), + task_runner_(task_runner), has_seen_end_of_data_(!handle_.is_valid()) {} URLResponseBodyConsumer::~URLResponseBodyConsumer() {} -void URLResponseBodyConsumer::Start(base::SingleThreadTaskRunner* task_runner) { +void URLResponseBodyConsumer::Start() { if (has_been_cancelled_) return; handle_watcher_.Start( handle_.get(), MOJO_HANDLE_SIGNAL_READABLE, base::Bind(&URLResponseBodyConsumer::OnReadable, base::Unretained(this))); - task_runner->PostTask( + task_runner_->PostTask( FROM_HERE, base::Bind(&URLResponseBodyConsumer::OnReadable, AsWeakPtr(), MOJO_RESULT_OK)); } @@ -77,14 +79,24 @@ void URLResponseBodyConsumer::Reclaim(uint32_t size) { MojoResult result = mojo::EndReadDataRaw(handle_.get(), size); DCHECK_EQ(MOJO_RESULT_OK, result); + + if (is_in_on_readable_) + return; + + task_runner_->PostTask( + FROM_HERE, base::Bind(&URLResponseBodyConsumer::OnReadable, AsWeakPtr(), + MOJO_RESULT_OK)); } void URLResponseBodyConsumer::OnReadable(MojoResult unused) { + DCHECK(!is_in_on_readable_); + if (has_been_cancelled_ || has_seen_end_of_data_) return; // Protect |this| as RequestPeer::OnReceivedData may call deref. scoped_refptr<URLResponseBodyConsumer> protect(this); + base::AutoReset<bool> is_in_on_readable(&is_in_on_readable_, true); // TODO(yhirano): Suppress notification when deferred. while (!has_been_cancelled_) { @@ -92,7 +104,7 @@ uint32_t available = 0; MojoResult result = mojo::BeginReadDataRaw( handle_.get(), &buffer, &available, MOJO_READ_DATA_FLAG_NONE); - if (result == MOJO_RESULT_SHOULD_WAIT) + if (result == MOJO_RESULT_SHOULD_WAIT || result == MOJO_RESULT_BUSY) return; if (result == MOJO_RESULT_FAILED_PRECONDITION) { has_seen_end_of_data_ = true;
diff --git a/content/child/url_response_body_consumer.h b/content/child/url_response_body_consumer.h index 13e122d2..09a988bdd 100644 --- a/content/child/url_response_body_consumer.h +++ b/content/child/url_response_body_consumer.h
@@ -38,7 +38,7 @@ scoped_refptr<base::SingleThreadTaskRunner> task_runner); // Starts watching the handle. - void Start(base::SingleThreadTaskRunner* task_runner); + void Start(); // Sets the completion status. The completion status is dispatched to the // ResourceDispatcher when the both following conditions hold: @@ -66,10 +66,12 @@ mojo::ScopedDataPipeConsumerHandle handle_; mojo::Watcher handle_watcher_; ResourceRequestCompletionStatus completion_status_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; bool has_received_completion_ = false; bool has_been_cancelled_ = false; bool has_seen_end_of_data_; + bool is_in_on_readable_ = false; DISALLOW_COPY_AND_ASSIGN(URLResponseBodyConsumer); };
diff --git a/content/child/url_response_body_consumer_unittest.cc b/content/child/url_response_body_consumer_unittest.cc index 8bf435c..3496b4e4 100644 --- a/content/child/url_response_body_consumer_unittest.cc +++ b/content/child/url_response_body_consumer_unittest.cc
@@ -29,7 +29,9 @@ class TestRequestPeer : public RequestPeer { public: struct Context; - explicit TestRequestPeer(Context* context) : context_(context) {} + TestRequestPeer(Context* context, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) + : context_(context), task_runner_(std::move(task_runner)) {} void OnUploadProgress(uint64_t position, uint64_t size) override { ADD_FAILURE() << "OnUploadProgress should not be called."; @@ -52,6 +54,8 @@ void OnReceivedData(std::unique_ptr<ReceivedData> data) override { EXPECT_FALSE(context_->complete); context_->data.append(data->payload(), data->length()); + if (context_->release_data_asynchronously) + task_runner_->DeleteSoon(FROM_HERE, data.release()); context_->run_loop_quit_closure.Run(); } @@ -75,10 +79,12 @@ bool complete = false; base::Closure run_loop_quit_closure; int error_code = net::OK; + bool release_data_asynchronously = false; }; private: Context* context_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; DISALLOW_COPY_AND_ASSIGN(TestRequestPeer); }; @@ -130,7 +136,7 @@ TestRequestPeer::Context* context) { return dispatcher_->StartAsync( std::move(request), 0, nullptr, url::Origin(), - base::MakeUnique<TestRequestPeer>(context), + base::MakeUnique<TestRequestPeer>(context, message_loop_.task_runner()), blink::WebURLRequest::LoadingIPCType::ChromeIPC, nullptr, nullptr); } @@ -154,7 +160,7 @@ scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer( request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle), message_loop_.task_runner())); - consumer->Start(message_loop_.task_runner().get()); + consumer->Start(); mojo::ScopedDataPipeProducerHandle writer = std::move(data_pipe.producer_handle); @@ -180,7 +186,43 @@ scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer( request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle), message_loop_.task_runner())); - consumer->Start(message_loop_.task_runner().get()); + consumer->Start(); + + consumer->OnComplete(ResourceRequestCompletionStatus()); + mojo::ScopedDataPipeProducerHandle writer = + std::move(data_pipe.producer_handle); + std::string buffer = "hello"; + uint32_t size = buffer.size(); + MojoResult result = + mojo::WriteDataRaw(writer.get(), buffer.c_str(), &size, kNone); + ASSERT_EQ(MOJO_RESULT_OK, result); + ASSERT_EQ(buffer.size(), size); + + Run(&context); + + writer.reset(); + EXPECT_FALSE(context.complete); + EXPECT_EQ("hello", context.data); + + Run(&context); + + EXPECT_TRUE(context.complete); + EXPECT_EQ("hello", context.data); +} + +// Release the received data asynchronously. This leads to MOJO_RESULT_BUSY +// from the BeginReadDataRaw call in OnReadable. +TEST_F(URLResponseBodyConsumerTest, OnCompleteThenCloseWithAsyncRelease) { + TestRequestPeer::Context context; + context.release_data_asynchronously = true; + std::unique_ptr<ResourceRequest> request(CreateResourceRequest()); + int request_id = SetUpRequestPeer(std::move(request), &context); + mojo::DataPipe data_pipe(CreateDataPipeOptions()); + + scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer( + request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle), + message_loop_.task_runner())); + consumer->Start(); consumer->OnComplete(ResourceRequestCompletionStatus()); mojo::ScopedDataPipeProducerHandle writer = @@ -213,7 +255,7 @@ scoped_refptr<URLResponseBodyConsumer> consumer(new URLResponseBodyConsumer( request_id, dispatcher_.get(), std::move(data_pipe.consumer_handle), message_loop_.task_runner())); - consumer->Start(message_loop_.task_runner().get()); + consumer->Start(); ResourceRequestCompletionStatus status; status.error_code = net::ERR_FAILED;
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn index 18ad2f7..021e8f5 100644 --- a/content/public/browser/BUILD.gn +++ b/content/public/browser/BUILD.gn
@@ -299,6 +299,9 @@ # We expose skia headers in the public API. "//skia", + + # We expose storage headers for quota in the public API. + "//storage/browser", "//third_party/WebKit/public:mojo_bindings", ] deps = [ @@ -311,7 +314,6 @@ "//media", "//net", "//ppapi/c", - "//storage/browser", "//ui/accessibility", "//ui/base", "//ui/events",
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index f6c8cdb..6d8fb21d 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc
@@ -6,6 +6,7 @@ #include "base/files/file_path.h" #include "base/guid.h" +#include "base/logging.h" #include "build/build_config.h" #include "content/public/browser/client_certificate_delegate.h" #include "content/public/browser/memory_coordinator_delegate.h" @@ -232,10 +233,12 @@ return nullptr; } -std::unique_ptr<storage::QuotaEvictionPolicy> -ContentBrowserClient::GetTemporaryStorageEvictionPolicy( - content::BrowserContext* context) { - return std::unique_ptr<storage::QuotaEvictionPolicy>(); +void ContentBrowserClient::GetQuotaSettings( + BrowserContext* context, + StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + // By default, no quota is provided, embedders should override. + callback.Run(storage::GetNoQuotaSettings()); } void ContentBrowserClient::SelectClientCertificate(
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 39316c3..437ca897 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h
@@ -32,6 +32,7 @@ #include "net/base/mime_util.h" #include "net/cookies/canonical_cookie.h" #include "storage/browser/fileapi/file_system_context.h" +#include "storage/browser/quota/quota_manager.h" #include "third_party/WebKit/public/platform/WebPageVisibilityState.h" #include "ui/base/page_transition_types.h" #include "ui/base/window_open_disposition.h" @@ -100,7 +101,6 @@ namespace storage { class FileSystemBackend; -class QuotaEvictionPolicy; } namespace content { @@ -127,6 +127,7 @@ class ResourceContext; class SiteInstance; class SpeechRecognitionManagerDelegate; +class StoragePartition; class TracingDelegate; class VpnServiceProxy; class WebContents; @@ -462,10 +463,13 @@ // Create and return a new quota permission context. virtual QuotaPermissionContext* CreateQuotaPermissionContext(); - // Gives the embedder a chance to register a custom QuotaEvictionPolicy for - // temporary storage. - virtual std::unique_ptr<storage::QuotaEvictionPolicy> - GetTemporaryStorageEvictionPolicy(BrowserContext* context); + // Allows the embedder to provide settings that determine the amount + // of disk space that may be used by content facing storage apis like + // IndexedDatabase and ServiceWorker::CacheStorage and others. + virtual void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback); // Informs the embedder that a certificate error has occured. If // |overridable| is true and if |strict_enforcement| is false, the user
diff --git a/content/public/test/mock_special_storage_policy.cc b/content/public/test/mock_special_storage_policy.cc index f3b3c02..0226b98e 100644 --- a/content/public/test/mock_special_storage_policy.cc +++ b/content/public/test/mock_special_storage_policy.cc
@@ -26,10 +26,6 @@ return base::ContainsKey(session_only_, origin); } -bool MockSpecialStoragePolicy::CanQueryDiskSize(const GURL& origin) { - return base::ContainsKey(can_query_disk_size_, origin); -} - bool MockSpecialStoragePolicy::HasIsolatedStorage(const GURL& origin) { return base::ContainsKey(isolated_, origin); }
diff --git a/content/public/test/mock_special_storage_policy.h b/content/public/test/mock_special_storage_policy.h index 96003e8c..b4a2a6c 100644 --- a/content/public/test/mock_special_storage_policy.h +++ b/content/public/test/mock_special_storage_policy.h
@@ -22,7 +22,6 @@ bool IsStorageProtected(const GURL& origin) override; bool IsStorageUnlimited(const GURL& origin) override; bool IsStorageSessionOnly(const GURL& origin) override; - bool CanQueryDiskSize(const GURL& origin) override; bool HasIsolatedStorage(const GURL& origin) override; bool HasSessionOnlyOrigins() override; bool IsStorageDurable(const GURL& origin) override; @@ -43,10 +42,6 @@ session_only_.insert(origin); } - void GrantQueryDiskSize(const GURL& origin) { - can_query_disk_size_.insert(origin); - } - void AddIsolated(const GURL& origin) { isolated_.insert(origin); } @@ -67,7 +62,6 @@ protected_.clear(); unlimited_.clear(); session_only_.clear(); - can_query_disk_size_.clear(); file_handlers_.clear(); isolated_.clear(); all_unlimited_ = false; @@ -92,7 +86,6 @@ std::set<GURL> protected_; std::set<GURL> unlimited_; std::set<GURL> session_only_; - std::set<GURL> can_query_disk_size_; std::set<GURL> isolated_; std::set<GURL> durable_; std::set<std::string> file_handlers_;
diff --git a/content/shell/browser/layout_test/layout_test_browser_main_parts.cc b/content/shell/browser/layout_test/layout_test_browser_main_parts.cc index acb5e2a4..7f01424a 100644 --- a/content/shell/browser/layout_test/layout_test_browser_main_parts.cc +++ b/content/shell/browser/layout_test/layout_test_browser_main_parts.cc
@@ -27,7 +27,6 @@ #include "net/base/net_module.h" #include "net/grit/net_resources.h" #include "ppapi/features/features.h" -#include "storage/browser/quota/quota_manager.h" #include "ui/base/resource/resource_bundle.h" #include "url/gurl.h" @@ -51,13 +50,6 @@ namespace content { -namespace { - -// Default quota for each origin is 5MB. -const int kDefaultLayoutTestQuotaBytes = 5 * 1024 * 1024; - -} // namespace - LayoutTestBrowserMainParts::LayoutTestBrowserMainParts( const MainFunctionParams& parameters) : ShellBrowserMainParts(parameters) { @@ -72,18 +64,6 @@ } void LayoutTestBrowserMainParts::InitializeMessageLoopContext() { - storage::QuotaManager* quota_manager = - BrowserContext::GetDefaultStoragePartition(browser_context()) - ->GetQuotaManager(); - BrowserThread::PostTask( - BrowserThread::IO, - FROM_HERE, - base::Bind(&storage::QuotaManager::SetTemporaryGlobalOverrideQuota, - quota_manager, - kDefaultLayoutTestQuotaBytes * - storage::QuotaManager::kPerHostTemporaryPortion, - storage::QuotaCallback())); - #if BUILDFLAG(ENABLE_PLUGINS) PluginService* plugin_service = PluginService::GetInstance(); plugin_service_filter_.reset(new ShellPluginServiceFilter);
diff --git a/content/shell/browser/layout_test/layout_test_content_browser_client.cc b/content/shell/browser/layout_test/layout_test_content_browser_client.cc index 3b25ecd..f913fdb 100644 --- a/content/shell/browser/layout_test/layout_test_content_browser_client.cc +++ b/content/shell/browser/layout_test/layout_test_content_browser_client.cc
@@ -128,6 +128,13 @@ return shell_browser_main_parts(); } +void LayoutTestContentBrowserClient::GetQuotaSettings( + BrowserContext* context, + StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + callback.Run(storage::GetHardCodedSettings(5 * 1024 * 1024)); +} + PlatformNotificationService* LayoutTestContentBrowserClient::GetPlatformNotificationService() { return layout_test_notification_manager_.get();
diff --git a/content/shell/browser/layout_test/layout_test_content_browser_client.h b/content/shell/browser/layout_test/layout_test_content_browser_client.h index e3fe22f..f2091ea 100644 --- a/content/shell/browser/layout_test/layout_test_content_browser_client.h +++ b/content/shell/browser/layout_test/layout_test_content_browser_client.h
@@ -37,6 +37,10 @@ int child_process_id) override; BrowserMainParts* CreateBrowserMainParts( const MainFunctionParams& parameters) override; + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override; PlatformNotificationService* GetPlatformNotificationService() override;
diff --git a/content/shell/browser/layout_test/layout_test_message_filter.cc b/content/shell/browser/layout_test/layout_test_message_filter.cc index 248f3e1..fe7ddf46 100644 --- a/content/shell/browser/layout_test/layout_test_message_filter.cc +++ b/content/shell/browser/layout_test/layout_test_message_filter.cc
@@ -119,9 +119,7 @@ } void LayoutTestMessageFilter::OnSetDatabaseQuota(int quota) { - quota_manager_->SetTemporaryGlobalOverrideQuota( - quota * storage::QuotaManager::kPerHostTemporaryPortion, - storage::QuotaCallback()); + quota_manager_->SetQuotaSettings(storage::GetHardCodedSettings(quota)); } void LayoutTestMessageFilter::OnSimulateWebNotificationClick(
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc index 2b44625..cb70799 100644 --- a/content/shell/browser/shell_content_browser_client.cc +++ b/content/shell/browser/shell_content_browser_client.cc
@@ -39,6 +39,7 @@ #include "content/shell/common/shell_switches.h" #include "grit/shell_resources.h" #include "net/url_request/url_request_context_getter.h" +#include "storage/browser/quota/quota_settings.h" #include "ui/base/resource/resource_bundle.h" #include "url/gurl.h" #include "url/origin.h" @@ -292,6 +293,13 @@ return new ShellQuotaPermissionContext(); } +void ShellContentBrowserClient::GetQuotaSettings( + BrowserContext* context, + StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + callback.Run(storage::GetHardCodedSettings(100 * 1024 * 1024)); +} + void ShellContentBrowserClient::SelectClientCertificate( WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info,
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h index d1937bfb..84365ef 100644 --- a/content/shell/browser/shell_content_browser_client.h +++ b/content/shell/browser/shell_content_browser_client.h
@@ -47,6 +47,10 @@ WebContentsViewDelegate* GetWebContentsViewDelegate( WebContents* web_contents) override; QuotaPermissionContext* CreateQuotaPermissionContext() override; + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override; void SelectClientCertificate( WebContents* web_contents, net::SSLCertRequestInfo* cert_request_info,
diff --git a/content/test/test_content_browser_client.cc b/content/test/test_content_browser_client.cc index b766e537..52a7ba6 100644 --- a/content/test/test_content_browser_client.cc +++ b/content/test/test_content_browser_client.cc
@@ -6,6 +6,7 @@ #include "base/files/file_path.h" #include "base/logging.h" +#include "storage/browser/quota/quota_settings.h" namespace content { @@ -23,4 +24,11 @@ return download_dir_.GetPath(); } +void TestContentBrowserClient::GetQuotaSettings( + BrowserContext* context, + StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + callback.Run(storage::GetHardCodedSettings(100 * 1024 * 1024)); +} + } // namespace content
diff --git a/content/test/test_content_browser_client.h b/content/test/test_content_browser_client.h index 5945806..6511df27 100644 --- a/content/test/test_content_browser_client.h +++ b/content/test/test_content_browser_client.h
@@ -20,6 +20,10 @@ TestContentBrowserClient(); ~TestContentBrowserClient() override; base::FilePath GetDefaultDownloadDirectory() override; + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override; private: // Temporary directory for GetDefaultDownloadDirectory.
diff --git a/extensions/shell/browser/shell_content_browser_client.cc b/extensions/shell/browser/shell_content_browser_client.cc index e9ee2ab..584f29c7 100644 --- a/extensions/shell/browser/shell_content_browser_client.cc +++ b/extensions/shell/browser/shell_content_browser_client.cc
@@ -37,6 +37,7 @@ #include "extensions/shell/browser/shell_extension_system.h" #include "extensions/shell/browser/shell_navigation_ui_data.h" #include "extensions/shell/browser/shell_speech_recognition_manager_delegate.h" +#include "storage/browser/quota/quota_settings.h" #include "url/gurl.h" #if !defined(DISABLE_NACL) @@ -120,6 +121,17 @@ return true; } +void ShellContentBrowserClient::GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + content::BrowserThread::PostTaskAndReplyWithResult( + content::BrowserThread::FILE, FROM_HERE, + base::Bind(&storage::CalculateNominalDynamicSettings, + partition->GetPath(), context->IsOffTheRecord()), + callback); +} + bool ShellContentBrowserClient::IsHandledURL(const GURL& url) { if (!url.is_valid()) return false;
diff --git a/extensions/shell/browser/shell_content_browser_client.h b/extensions/shell/browser/shell_content_browser_client.h index f3621dc..d626afa 100644 --- a/extensions/shell/browser/shell_content_browser_client.h +++ b/extensions/shell/browser/shell_content_browser_client.h
@@ -43,7 +43,10 @@ void RenderProcessWillLaunch(content::RenderProcessHost* host) override; bool ShouldUseProcessPerSite(content::BrowserContext* browser_context, const GURL& effective_url) override; - // TODO(jamescook): Quota management? + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override; bool IsHandledURL(const GURL& url) override; void SiteInstanceGotProcess(content::SiteInstance* site_instance) override; void SiteInstanceDeleting(content::SiteInstance* site_instance) override;
diff --git a/extensions/shell/browser/shell_special_storage_policy.cc b/extensions/shell/browser/shell_special_storage_policy.cc index d43c71b..26b9dc2 100644 --- a/extensions/shell/browser/shell_special_storage_policy.cc +++ b/extensions/shell/browser/shell_special_storage_policy.cc
@@ -30,10 +30,6 @@ return false; } -bool ShellSpecialStoragePolicy::CanQueryDiskSize(const GURL& origin) { - return true; -} - bool ShellSpecialStoragePolicy::HasSessionOnlyOrigins() { return false; }
diff --git a/extensions/shell/browser/shell_special_storage_policy.h b/extensions/shell/browser/shell_special_storage_policy.h index dc78154..0973c3a 100644 --- a/extensions/shell/browser/shell_special_storage_policy.h +++ b/extensions/shell/browser/shell_special_storage_policy.h
@@ -20,7 +20,6 @@ bool IsStorageUnlimited(const GURL& origin) override; bool IsStorageDurable(const GURL& origin) override; bool IsStorageSessionOnly(const GURL& origin) override; - bool CanQueryDiskSize(const GURL& origin) override; bool HasIsolatedStorage(const GURL& origin) override; bool HasSessionOnlyOrigins() override;
diff --git a/headless/lib/browser/DEPS b/headless/lib/browser/DEPS index 1704e22e..0df32e1 100644 --- a/headless/lib/browser/DEPS +++ b/headless/lib/browser/DEPS
@@ -1,4 +1,5 @@ include_rules = [ "+components/security_state", + "+storage/browser/quota", "+ui/aura", ]
diff --git a/headless/lib/browser/headless_content_browser_client.cc b/headless/lib/browser/headless_content_browser_client.cc index 1bfe88ff..e81f084 100644 --- a/headless/lib/browser/headless_content_browser_client.cc +++ b/headless/lib/browser/headless_content_browser_client.cc
@@ -14,12 +14,14 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" +#include "content/public/browser/storage_partition.h" #include "content/public/common/service_names.mojom.h" #include "headless/grit/headless_lib_resources.h" #include "headless/lib/browser/headless_browser_context_impl.h" #include "headless/lib/browser/headless_browser_impl.h" #include "headless/lib/browser/headless_browser_main_parts.h" #include "headless/lib/browser/headless_devtools_manager_delegate.h" +#include "storage/browser/quota/quota_settings.h" #include "ui/base/resource/resource_bundle.h" namespace headless { @@ -86,4 +88,15 @@ return manifest; } +void HeadlessContentBrowserClient::GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + content::BrowserThread::PostTaskAndReplyWithResult( + content::BrowserThread::FILE, FROM_HERE, + base::Bind(&storage::CalculateNominalDynamicSettings, + partition->GetPath(), context->IsOffTheRecord()), + callback); +} + } // namespace headless
diff --git a/headless/lib/browser/headless_content_browser_client.h b/headless/lib/browser/headless_content_browser_client.h index 511083bf..82c5d9e7 100644 --- a/headless/lib/browser/headless_content_browser_client.h +++ b/headless/lib/browser/headless_content_browser_client.h
@@ -24,6 +24,10 @@ content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override; std::unique_ptr<base::Value> GetServiceManifestOverlay( const std::string& name) override; + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override; private: HeadlessBrowserImpl* browser_; // Not owned.
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index 03b11fb..79c6966 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -1933,22 +1933,40 @@ DCHECK(main_task_runner_->BelongsToCurrentThread()); const PipelineStatistics stats = pipeline_.GetStatistics(); + const int64_t data_source_memory_usage = + data_source_ ? data_source_->GetMemoryUsage() : 0; const int64_t current_memory_usage = stats.audio_memory_usage + stats.video_memory_usage + - (data_source_ ? data_source_->GetMemoryUsage() : 0) + - demuxer_memory_usage; + data_source_memory_usage + demuxer_memory_usage; // Note, this isn't entirely accurate, there may be VideoFrames held by the // compositor or other resources that we're unaware of. DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage - << ", Video: " << stats.video_memory_usage << ", DataSource: " - << (data_source_ ? data_source_->GetMemoryUsage() : 0) + << ", Video: " << stats.video_memory_usage + << ", DataSource: " << data_source_memory_usage << ", Demuxer: " << demuxer_memory_usage; const int64_t delta = current_memory_usage - last_reported_memory_usage_; last_reported_memory_usage_ = current_memory_usage; adjust_allocated_memory_cb_.Run(delta); + + if (hasAudio()) { + UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Audio", + stats.audio_memory_usage / 1024); + } + if (hasVideo()) { + UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Video", + stats.video_memory_usage / 1024); + } + if (data_source_) { + UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.DataSource", + data_source_memory_usage / 1024); + } + if (demuxer_) { + UMA_HISTOGRAM_MEMORY_KB("Media.WebMediaPlayerImpl.Memory.Demuxer", + demuxer_memory_usage / 1024); + } } void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
diff --git a/media/midi/BUILD.gn b/media/midi/BUILD.gn index 38100e1..0dc5ed3 100644 --- a/media/midi/BUILD.gn +++ b/media/midi/BUILD.gn
@@ -88,6 +88,8 @@ "midi_port_info.h", "midi_scheduler.cc", "midi_scheduler.h", + "midi_service.cc", + "midi_service.h", "midi_switches.cc", "midi_switches.h", ]
diff --git a/media/midi/midi_manager.h b/media/midi/midi_manager.h index f90a55b..27e24f9 100644 --- a/media/midi/midi_manager.h +++ b/media/midi/midi_manager.h
@@ -28,6 +28,7 @@ // A MidiManagerClient registers with the MidiManager to receive MIDI data. // See MidiManager::RequestAccess() and MidiManager::ReleaseAccess() // for details. +// TODO(toyoshim): Consider to have a MidiServiceClient interface. class MIDI_EXPORT MidiManagerClient { public: virtual ~MidiManagerClient() {}
diff --git a/media/midi/midi_service.cc b/media/midi/midi_service.cc new file mode 100644 index 0000000..0d01124 --- /dev/null +++ b/media/midi/midi_service.cc
@@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/midi/midi_service.h" + +#include "media/midi/midi_manager.h" + +namespace midi { + +MidiService::MidiService(std::unique_ptr<MidiManager> manager) { + base::AutoLock lock(lock_); + if (manager.get()) + manager_ = std::move(manager); + else + manager_.reset(MidiManager::Create()); +} + +MidiService::~MidiService() { + base::AutoLock lock(lock_); + manager_.reset(); +} + +void MidiService::Shutdown() { + base::AutoLock lock(lock_); + manager_->Shutdown(); +} + +void MidiService::StartSession(MidiManagerClient* client) { + base::AutoLock lock(lock_); + manager_->StartSession(client); +} + +void MidiService::EndSession(MidiManagerClient* client) { + base::AutoLock lock(lock_); + manager_->EndSession(client); +} + +void MidiService::DispatchSendMidiData(MidiManagerClient* client, + uint32_t port_index, + const std::vector<uint8_t>& data, + double timestamp) { + base::AutoLock lock(lock_); + manager_->DispatchSendMidiData(client, port_index, data, timestamp); +} + +} // namespace midi
diff --git a/media/midi/midi_service.h b/media/midi/midi_service.h new file mode 100644 index 0000000..5b870d6c --- /dev/null +++ b/media/midi/midi_service.h
@@ -0,0 +1,53 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_MIDI_MIDI_SERVICE_H_ +#define MEDIA_MIDI_MIDI_SERVICE_H_ + +#include <stdint.h> + +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "base/synchronization/lock.h" +#include "media/midi/midi_export.h" +#include "media/midi/midi_manager.h" + +namespace midi { + +// Manages MidiManager backends. This class expects to be constructed and +// destructed on the browser main thread, but methods can be called on both +// the main thread and the I/O thread. +class MIDI_EXPORT MidiService final { + public: + // |MidiManager| can be explicitly specified in the constructor for testing. + explicit MidiService(std::unique_ptr<MidiManager> manager = nullptr); + ~MidiService(); + + // Called on the browser main thread to notify the I/O thread will stop and + // the instance will be destructed on the main thread soon. + void Shutdown(); + + // A client calls StartSession() to receive and send MIDI data. + void StartSession(MidiManagerClient* client); + + // A client calls EndSession() to stop receiving MIDI data. + void EndSession(MidiManagerClient* client); + + // A client calls DispatchSendMidiData() to send MIDI data. + virtual void DispatchSendMidiData(MidiManagerClient* client, + uint32_t port_index, + const std::vector<uint8_t>& data, + double timestamp); + + std::unique_ptr<MidiManager> manager_; + base::Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(MidiService); +}; + +} // namespace midi + +#endif // MEDIA_MIDI_MIDI_SERVICE_H_
diff --git a/services/ui/ws/window_manager_client_unittest.cc b/services/ui/ws/window_manager_client_unittest.cc index d94a800..7f712dcf 100644 --- a/services/ui/ws/window_manager_client_unittest.cc +++ b/services/ui/ws/window_manager_client_unittest.cc
@@ -652,7 +652,8 @@ // Verify change from embedded makes it to parent. const gfx::Insets insets(1, 2, 3, 4); - embed_result->window_tree_host->SetClientArea(insets); + embed_result->window_tree_host->SetClientArea(insets, + std::vector<gfx::Rect>()); std::unique_ptr<ClientAreaChange> client_area_change = WaitForClientAreaToChange(); ASSERT_TRUE(client_area_change);
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn index 8e91590..d701ae0 100644 --- a/storage/browser/BUILD.gn +++ b/storage/browser/BUILD.gn
@@ -166,6 +166,8 @@ "quota/quota_manager.h", "quota/quota_manager_proxy.cc", "quota/quota_manager_proxy.h", + "quota/quota_settings.cc", + "quota/quota_settings.h", "quota/quota_task.cc", "quota/quota_task.h", "quota/quota_temporary_storage_evictor.cc",
diff --git a/storage/browser/quota/client_usage_tracker.cc b/storage/browser/quota/client_usage_tracker.cc index c9c46f6d1..c5a17a5 100644 --- a/storage/browser/quota/client_usage_tracker.cc +++ b/storage/browser/quota/client_usage_tracker.cc
@@ -165,6 +165,15 @@ AsWeakPtr(), origin)); } +int64_t ClientUsageTracker::GetCachedUsage() const { + int64_t usage = 0; + for (const auto& host_and_usage_map : cached_usage_by_host_) { + for (const auto& origin_and_usage : host_and_usage_map.second) + usage += origin_and_usage.second; + } + return usage; +} + void ClientUsageTracker::GetCachedHostsUsage( std::map<std::string, int64_t>* host_usage) const { DCHECK(host_usage);
diff --git a/storage/browser/quota/client_usage_tracker.h b/storage/browser/quota/client_usage_tracker.h index 5b5a84b..2fbe765 100644 --- a/storage/browser/quota/client_usage_tracker.h +++ b/storage/browser/quota/client_usage_tracker.h
@@ -52,6 +52,7 @@ void GetGlobalUsage(const GlobalUsageCallback& callback); void GetHostUsage(const std::string& host, const UsageCallback& callback); void UpdateUsageCache(const GURL& origin, int64_t delta); + int64_t GetCachedUsage() const; void GetCachedHostsUsage(std::map<std::string, int64_t>* host_usage) const; void GetCachedOriginsUsage(std::map<GURL, int64_t>* origin_usage) const; void GetCachedOrigins(std::set<GURL>* origins) const;
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc index 44ba5f1..b0bef465 100644 --- a/storage/browser/quota/quota_manager.cc +++ b/storage/browser/quota/quota_manager.cc
@@ -13,6 +13,7 @@ #include <memory> #include <utility> +#include "base/barrier_closure.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" @@ -26,6 +27,7 @@ #include "base/strings/string_number_conversions.h" #include "base/sys_info.h" #include "base/task_runner_util.h" +#include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "net/base/url_util.h" @@ -36,49 +38,36 @@ #include "storage/browser/quota/usage_tracker.h" #include "storage/common/quota/quota_types.h" -#define UMA_HISTOGRAM_MBYTES(name, sample) \ - UMA_HISTOGRAM_CUSTOM_COUNTS( \ - (name), static_cast<int>((sample) / kMBytes), \ - 1, 10 * 1024 * 1024 /* 10TB */, 100) - namespace storage { namespace { const int64_t kMBytes = 1024 * 1024; const int kMinutesInMilliSeconds = 60 * 1000; - const int64_t kReportHistogramInterval = 60 * 60 * 1000; // 1 hour -const double kTemporaryQuotaRatioToAvail = 1.0 / 3.0; // 33% + +#define UMA_HISTOGRAM_MBYTES(name, sample) \ + UMA_HISTOGRAM_CUSTOM_COUNTS((name), static_cast<int>((sample) / kMBytes), 1, \ + 10 * 1024 * 1024 /* 10TB */, 100) } // namespace -// Arbitrary for now, but must be reasonably small so that -// in-memory databases can fit. -// TODO(kinuko): Refer SysInfo::AmountOfPhysicalMemory() to determine this. -const int64_t QuotaManager::kIncognitoDefaultQuotaLimit = 100 * kMBytes; - const int64_t QuotaManager::kNoLimit = INT64_MAX; -const int QuotaManager::kPerHostTemporaryPortion = 5; // 20% - // Cap size for per-host persistent quota determined by the histogram. // This is a bit lax value because the histogram says nothing about per-host // persistent storage usage and we determined by global persistent storage // usage that is less than 10GB for almost all users. const int64_t QuotaManager::kPerHostPersistentQuotaLimit = 10 * 1024 * kMBytes; +// Heuristics: assuming average cloud server allows a few Gigs storage +// on the server side and the storage needs to be shared for user data +// and by multiple apps. +int64_t QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes; + const char QuotaManager::kDatabaseName[] = "QuotaManager"; const int QuotaManager::kThresholdOfErrorsToBeBlacklisted = 3; - -// Preserve kMinimumPreserveForSystem disk space for system book-keeping -// when returning the quota to unlimited apps/extensions. -// TODO(kinuko): This should be like 10% of the actual disk space. -// For now we simply use a constant as getting the disk size needs -// platform-dependent code. (http://crbug.com/178976) -int64_t QuotaManager::kMinimumPreserveForSystem = 1024 * kMBytes; - const int QuotaManager::kEvictionIntervalInMilliSeconds = 30 * kMinutesInMilliSeconds; @@ -89,13 +78,17 @@ const char QuotaManager::kEvictedOriginTimeSinceAccessHistogram[] = "Quota.EvictedOriginTimeSinceAccess"; -// Heuristics: assuming average cloud server allows a few Gigs storage -// on the server side and the storage needs to be shared for user data -// and by multiple apps. -int64_t QuotaManager::kSyncableStorageDefaultHostQuota = 500 * kMBytes; - namespace { +bool IsSupportedType(StorageType type) { + return type != kStorageTypeTemporary || type != kStorageTypePersistent || + type != kStorageTypeSyncable; +} + +bool IsSupportedIncognitoType(StorageType type) { + return type != kStorageTypeTemporary || type != kStorageTypePersistent; +} + void CountOriginType(const std::set<GURL>& origins, SpecialStoragePolicy* policy, size_t* protected_origins, @@ -116,17 +109,6 @@ } } -bool SetTemporaryGlobalOverrideQuotaOnDBThread(int64_t* new_quota, - QuotaDatabase* database) { - DCHECK(database); - if (!database->SetQuotaConfigValue( - QuotaDatabase::kTemporaryQuotaOverrideKey, *new_quota)) { - *new_quota = -1; - return false; - } - return true; -} - bool GetPersistentHostQuotaOnDBThread(const std::string& host, int64_t* quota, QuotaDatabase* database) { @@ -145,17 +127,6 @@ return false; } -bool InitializeOnDBThread(int64_t* temporary_quota_override, - int64_t* desired_available_space, - QuotaDatabase* database) { - DCHECK(database); - database->GetQuotaConfigValue(QuotaDatabase::kTemporaryQuotaOverrideKey, - temporary_quota_override); - database->GetQuotaConfigValue(QuotaDatabase::kDesiredAvailableSpaceKey, - desired_available_space); - return true; -} - bool GetLRUOriginOnDBThread(StorageType type, const std::set<GURL>& exceptions, SpecialStoragePolicy* policy, @@ -204,8 +175,8 @@ return database->SetOriginLastEvictionTime(origin, type, now); } -bool InitializeTemporaryOriginsInfoOnDBThread(const std::set<GURL>* origins, - QuotaDatabase* database) { +bool BootstrapDatabaseOnDBThread(const std::set<GURL>* origins, + QuotaDatabase* database) { DCHECK(database); if (database->IsOriginDatabaseBootstrapped()) return true; @@ -234,277 +205,222 @@ return database->SetOriginLastModifiedTime(origin, type, modified_time); } -int64_t CalculateTemporaryGlobalQuota(int64_t global_limited_usage, - int64_t available_space) { - DCHECK_GE(global_limited_usage, 0); - int64_t avail_space = available_space; - if (avail_space < - std::numeric_limits<int64_t>::max() - global_limited_usage) { - // We basically calculate the temporary quota by - // [available_space + space_used_for_temp] * kTempQuotaRatio, - // but make sure we'll have no overflow. - avail_space += global_limited_usage; - } - int64_t pool_size = avail_space * kTemporaryQuotaRatioToAvail; - UMA_HISTOGRAM_MBYTES("Quota.GlobalTemporaryPoolSize", pool_size); - return pool_size; -} - -void DispatchTemporaryGlobalQuotaCallback( - const QuotaCallback& callback, - QuotaStatusCode status, - const UsageAndQuota& usage_and_quota) { - if (status != kQuotaStatusOk) { - callback.Run(status, 0); - return; - } - - callback.Run(status, CalculateTemporaryGlobalQuota( - usage_and_quota.global_limited_usage, - usage_and_quota.available_disk_space)); -} - -int64_t CalculateQuotaWithDiskSpace(int64_t available_disk_space, - int64_t usage, - int64_t quota) { - if (available_disk_space < QuotaManager::kMinimumPreserveForSystem) { - LOG(WARNING) - << "Running out of disk space for profile." - << " QuotaManager starts forbidding further quota consumption."; - return usage; - } - - if (quota < usage) { - // No more space; cap the quota to the current usage. - return usage; - } - - available_disk_space -= QuotaManager::kMinimumPreserveForSystem; - if (available_disk_space < quota - usage) - return available_disk_space + usage; - - return quota; -} - -int64_t CalculateTemporaryHostQuota(int64_t host_usage, - int64_t global_quota, - int64_t global_limited_usage) { - DCHECK_GE(global_limited_usage, 0); - int64_t host_quota = global_quota / QuotaManager::kPerHostTemporaryPortion; - if (global_limited_usage > global_quota) - host_quota = std::min(host_quota, host_usage); - return host_quota; -} - -void DispatchUsageAndQuotaForWebApps( - StorageType type, - bool is_incognito, - bool is_unlimited, - bool can_query_disk_size, - const QuotaManager::GetUsageAndQuotaCallback& callback, - QuotaStatusCode status, - const UsageAndQuota& usage_and_quota) { - if (status != kQuotaStatusOk) { - callback.Run(status, 0, 0); - return; - } - - int64_t usage = usage_and_quota.usage; - int64_t quota = usage_and_quota.quota; - - if (type == kStorageTypeTemporary && !is_unlimited) { - quota = CalculateTemporaryHostQuota( - usage, quota, usage_and_quota.global_limited_usage); - } - - if (is_incognito) { - quota = std::min(quota, QuotaManager::kIncognitoDefaultQuotaLimit); - callback.Run(status, usage, quota); - return; - } - - // For apps with unlimited permission or can_query_disk_size is true (and not - // in incognito mode). - // We assume we can expose the actual disk size for them and cap the quota by - // the available disk space. - if (is_unlimited || can_query_disk_size) { - quota = CalculateQuotaWithDiskSpace( - usage_and_quota.available_disk_space, - usage, quota); - } - - callback.Run(status, usage, quota); - - if (type == kStorageTypeTemporary && !is_unlimited) - UMA_HISTOGRAM_MBYTES("Quota.QuotaForOrigin", quota); -} - } // namespace -UsageAndQuota::UsageAndQuota() - : usage(0), - global_limited_usage(0), - quota(0), - available_disk_space(0) { -} - -UsageAndQuota::UsageAndQuota(int64_t usage, - int64_t global_limited_usage, - int64_t quota, - int64_t available_disk_space) - : usage(usage), - global_limited_usage(global_limited_usage), - quota(quota), - available_disk_space(available_disk_space) {} - -class UsageAndQuotaCallbackDispatcher - : public QuotaTask, - public base::SupportsWeakPtr<UsageAndQuotaCallbackDispatcher> { +class QuotaManager::UsageAndQuotaHelper : public QuotaTask { public: - explicit UsageAndQuotaCallbackDispatcher(QuotaManager* manager) + UsageAndQuotaHelper(QuotaManager* manager, + const GURL& origin, + StorageType type, + bool is_unlimited, + bool is_incognito, + const UsageAndQuotaCallback& callback) : QuotaTask(manager), - has_usage_(false), - has_global_limited_usage_(false), - has_quota_(false), - has_available_disk_space_(false), - status_(kQuotaStatusUnknown), - usage_and_quota_(-1, -1, -1, -1), - waiting_callbacks_(1) {} + origin_(origin), + callback_(callback), + type_(type), + is_unlimited_(is_unlimited), + is_incognito_(is_incognito), + weak_factory_(this) {} - ~UsageAndQuotaCallbackDispatcher() override {} - - void WaitForResults(const QuotaManager::UsageAndQuotaCallback& callback) { - callback_ = callback; - Start(); - } - - void set_usage(int64_t usage) { - usage_and_quota_.usage = usage; - has_usage_ = true; - } - - void set_global_limited_usage(int64_t global_limited_usage) { - usage_and_quota_.global_limited_usage = global_limited_usage; - has_global_limited_usage_ = true; - } - - void set_quota(int64_t quota) { - usage_and_quota_.quota = quota; - has_quota_ = true; - } - - void set_available_disk_space(int64_t available_disk_space) { - usage_and_quota_.available_disk_space = available_disk_space; - has_available_disk_space_ = true; - } - - UsageCallback GetHostUsageCallback() { - ++waiting_callbacks_; - has_usage_ = true; - return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetHostUsage, - AsWeakPtr()); - } - - UsageCallback GetGlobalLimitedUsageCallback() { - ++waiting_callbacks_; - has_global_limited_usage_ = true; - return base::Bind( - &UsageAndQuotaCallbackDispatcher::DidGetGlobalLimitedUsage, - AsWeakPtr()); - } - - QuotaCallback GetQuotaCallback() { - ++waiting_callbacks_; - has_quota_ = true; - return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetQuota, - AsWeakPtr()); - } - - QuotaCallback GetAvailableSpaceCallback() { - ++waiting_callbacks_; - has_available_disk_space_ = true; - return base::Bind(&UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace, - AsWeakPtr()); - } - - private: - void DidGetHostUsage(int64_t usage) { - if (status_ == kQuotaStatusUnknown) - status_ = kQuotaStatusOk; - usage_and_quota_.usage = usage; - CheckCompleted(); - } - - void DidGetGlobalLimitedUsage(int64_t limited_usage) { - if (status_ == kQuotaStatusUnknown) - status_ = kQuotaStatusOk; - usage_and_quota_.global_limited_usage = limited_usage; - CheckCompleted(); - } - - void DidGetQuota(QuotaStatusCode status, int64_t quota) { - if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk) - status_ = status; - usage_and_quota_.quota = quota; - CheckCompleted(); - } - - void DidGetAvailableSpace(QuotaStatusCode status, int64_t space) { - // crbug.com/349708 - TRACE_EVENT0( - "io", "UsageAndQuotaCallbackDispatcher::DidGetAvailableSpace"); - - DCHECK_GE(space, 0); - if (status_ == kQuotaStatusUnknown || status_ == kQuotaStatusOk) - status_ = status; - usage_and_quota_.available_disk_space = space; - CheckCompleted(); - } - + protected: void Run() override { - // We initialize waiting_callbacks to 1 so that we won't run - // the completion callback until here even some of the callbacks - // are dispatched synchronously. - CheckCompleted(); + // Start the async process of gathering the info we need. + // Gather 4 pieces of info before computing an answer: + // settings, device_storage_capacity, host_usage, and host_quota. + base::Closure barrier = base::BarrierClosure( + 4, base::Bind(&UsageAndQuotaHelper::OnBarrierComplete, + weak_factory_.GetWeakPtr())); + + std::string host = net::GetHostOrSpecFromURL(origin_); + + manager()->GetQuotaSettings(base::Bind(&UsageAndQuotaHelper::OnGotSettings, + weak_factory_.GetWeakPtr(), + barrier)); + manager()->GetStorageCapacity( + base::Bind(&UsageAndQuotaHelper::OnGotCapacity, + weak_factory_.GetWeakPtr(), barrier)); + manager()->GetHostUsage(host, type_, + base::Bind(&UsageAndQuotaHelper::OnGotHostUsage, + weak_factory_.GetWeakPtr(), barrier)); + + // Determine host_quota differently depending on type. + if (is_unlimited_) { + SetDesiredHostQuota(barrier, kQuotaStatusOk, kNoLimit); + } else if (type_ == kStorageTypeSyncable) { + SetDesiredHostQuota(barrier, kQuotaStatusOk, + kSyncableStorageDefaultHostQuota); + } else if (type_ == kStorageTypePersistent) { + manager()->GetPersistentHostQuota( + host, base::Bind(&UsageAndQuotaHelper::SetDesiredHostQuota, + weak_factory_.GetWeakPtr(), barrier)); + } else { + DCHECK_EQ(kStorageTypeTemporary, type_); + // For temporary storge, OnGotSettings will set the host quota. + } } void Aborted() override { - callback_.Run(kQuotaErrorAbort, UsageAndQuota()); + weak_factory_.InvalidateWeakPtrs(); + callback_.Run(kQuotaErrorAbort, 0, 0); DeleteSoon(); } void Completed() override { - // crbug.com/349708 - TRACE_EVENT0("io", "UsageAndQuotaCallbackDispatcher::Completed"); + weak_factory_.InvalidateWeakPtrs(); - DCHECK(!has_usage_ || usage_and_quota_.usage >= 0); - DCHECK(!has_global_limited_usage_ || - usage_and_quota_.global_limited_usage >= 0); - DCHECK(!has_quota_ || usage_and_quota_.quota >= 0); - DCHECK(!has_available_disk_space_ || - usage_and_quota_.available_disk_space >= 0); - - callback_.Run(status_, usage_and_quota_); + // Constrain the desired |host_quota| to something that fits. + // If available space is too low, cap usage at current levels. + // If it's close to being too low, cap growth to avoid it getting too low. + int64_t host_quota = + std::min(desired_host_quota_, + host_usage_ + + std::max(INT64_C(0), available_space_ - + settings_.must_remain_available)); + callback_.Run(kQuotaStatusOk, host_usage_, host_quota); + if (type_ == kStorageTypeTemporary && !is_incognito_ && !is_unlimited_) + UMA_HISTOGRAM_MBYTES("Quota.QuotaForOrigin", host_quota); DeleteSoon(); } - void CheckCompleted() { - if (--waiting_callbacks_ <= 0) - CallCompleted(); + private: + QuotaManager* manager() const { + return static_cast<QuotaManager*>(observer()); } - // For sanity checks, they're checked only when DCHECK is on. - bool has_usage_; - bool has_global_limited_usage_; - bool has_quota_; - bool has_available_disk_space_; + void OnGotSettings(const base::Closure& barrier_closure, + const QuotaSettings& settings) { + settings_ = settings; + barrier_closure.Run(); + if (type_ == kStorageTypeTemporary && !is_unlimited_) { + SetDesiredHostQuota(barrier_closure, kQuotaStatusOk, + settings.per_host_quota); + } + } - QuotaStatusCode status_; - UsageAndQuota usage_and_quota_; + void OnGotCapacity(const base::Closure& barrier_closure, + int64_t total_space, + int64_t available_space) { + total_space_ = total_space; + available_space_ = available_space; + barrier_closure.Run(); + } + + void OnGotHostUsage(const base::Closure& barrier_closure, int64_t usage) { + host_usage_ = usage; + barrier_closure.Run(); + } + + void SetDesiredHostQuota(const base::Closure& barrier_closure, + QuotaStatusCode status, + int64_t quota) { + desired_host_quota_ = quota; + barrier_closure.Run(); + } + + void OnBarrierComplete() { CallCompleted(); } + + GURL origin_; QuotaManager::UsageAndQuotaCallback callback_; - int waiting_callbacks_; + StorageType type_; + bool is_unlimited_; + bool is_incognito_; + int64_t available_space_ = 0; + int64_t total_space_ = 0; + int64_t desired_host_quota_ = 0; + int64_t host_usage_ = 0; + QuotaSettings settings_; + base::WeakPtrFactory<UsageAndQuotaHelper> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaHelper); +}; - DISALLOW_COPY_AND_ASSIGN(UsageAndQuotaCallbackDispatcher); +// Helper to asychronously gather information needed at the start of an +// eviction round. +class QuotaManager::EvictionRoundInfoHelper : public QuotaTask { + public: + EvictionRoundInfoHelper(QuotaManager* manager, + const EvictionRoundInfoCallback& callback) + : QuotaTask(manager), callback_(callback), weak_factory_(this) {} + + protected: + void Run() override { + // Gather 2 pieces of info before deciding if we need to get GlobalUsage: + // settings and device_storage_capacity. + base::Closure barrier = base::BarrierClosure( + 2, base::Bind(&EvictionRoundInfoHelper::OnBarrierComplete, + weak_factory_.GetWeakPtr())); + + manager()->GetQuotaSettings( + base::Bind(&EvictionRoundInfoHelper::OnGotSettings, + weak_factory_.GetWeakPtr(), barrier)); + manager()->GetStorageCapacity( + base::Bind(&EvictionRoundInfoHelper::OnGotCapacity, + weak_factory_.GetWeakPtr(), barrier)); + } + + void Aborted() override { + weak_factory_.InvalidateWeakPtrs(); + callback_.Run(kQuotaErrorAbort, QuotaSettings(), 0, 0, 0, false); + DeleteSoon(); + } + + void Completed() override { + weak_factory_.InvalidateWeakPtrs(); + callback_.Run(kQuotaStatusOk, settings_, available_space_, total_space_, + global_usage_, global_usage_is_complete_); + DeleteSoon(); + } + + private: + QuotaManager* manager() const { + return static_cast<QuotaManager*>(observer()); + } + + void OnGotSettings(const base::Closure& barrier_closure, + const QuotaSettings& settings) { + settings_ = settings; + barrier_closure.Run(); + } + + void OnGotCapacity(const base::Closure& barrier_closure, + int64_t total_space, + int64_t available_space) { + total_space_ = total_space; + available_space_ = available_space; + barrier_closure.Run(); + } + + void OnBarrierComplete() { + // Avoid computing the full current_usage when there's no pressure. + int64_t consumed_space = total_space_ - available_space_; + if (consumed_space < settings_.pool_size && + available_space_ > settings_.must_remain_available) { + DCHECK(!global_usage_is_complete_); + global_usage_ = + manager()->GetUsageTracker(kStorageTypeTemporary)->GetCachedUsage(); + CallCompleted(); + return; + } + manager()->GetGlobalUsage( + kStorageTypeTemporary, + base::Bind(&EvictionRoundInfoHelper::OnGotGlobalUsage, + weak_factory_.GetWeakPtr())); + } + + void OnGotGlobalUsage(int64_t usage, int64_t unlimited_usage) { + global_usage_ = std::max(INT64_C(0), usage - unlimited_usage); + global_usage_is_complete_ = true; + CallCompleted(); + } + + EvictionRoundInfoCallback callback_; + QuotaSettings settings_; + int64_t available_space_ = 0; + int64_t total_space_ = 0; + int64_t global_usage_ = 0; + bool global_usage_is_complete_ = false; + base::WeakPtrFactory<EvictionRoundInfoHelper> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(EvictionRoundInfoHelper); }; class QuotaManager::GetUsageInfoTask : public QuotaTask { @@ -866,7 +782,8 @@ const base::FilePath& profile_path, const scoped_refptr<base::SingleThreadTaskRunner>& io_thread, const scoped_refptr<base::SequencedTaskRunner>& db_thread, - const scoped_refptr<SpecialStoragePolicy>& special_storage_policy) + const scoped_refptr<SpecialStoragePolicy>& special_storage_policy, + const GetQuotaSettingsFunc& get_settings_function) : is_incognito_(is_incognito), profile_path_(profile_path), proxy_(new QuotaManagerProxy(this, io_thread)), @@ -874,13 +791,25 @@ eviction_disabled_(false), io_thread_(io_thread), db_thread_(db_thread), + get_settings_function_(get_settings_function), is_getting_eviction_origin_(false), - temporary_quota_initialized_(false), - temporary_quota_override_(-1), special_storage_policy_(special_storage_policy), get_volume_info_fn_(&QuotaManager::GetVolumeInfo), storage_monitor_(new StorageMonitor(this)), - weak_factory_(this) {} + weak_factory_(this) { + DCHECK_EQ(settings_.refresh_interval, base::TimeDelta::Max()); + if (!get_settings_function.is_null()) { + // Reset the interval to ensure we use the get_settings_function + // the first times settings_ is needed. + settings_.refresh_interval = base::TimeDelta(); + get_settings_task_runner_ = base::ThreadTaskRunnerHandle::Get(); + } +} + +void QuotaManager::SetQuotaSettings(const QuotaSettings& settings) { + settings_ = settings; + settings_timestamp_ = base::TimeTicks::Now(); +} void QuotaManager::GetUsageInfo(const GetUsageInfoCallback& callback) { LazyInitialize(); @@ -891,61 +820,28 @@ void QuotaManager::GetUsageAndQuotaForWebApps( const GURL& origin, StorageType type, - const GetUsageAndQuotaCallback& callback) { - // TODO(pkasting): Remove ScopedTracker below once crbug.com/477117 is fixed. - tracked_objects::ScopedTracker tracking_profile( - FROM_HERE_WITH_EXPLICIT_FUNCTION( - "477117 QuotaManager::GetUsageAndQuotaForWebApps")); - if (type != kStorageTypeTemporary && - type != kStorageTypePersistent && - type != kStorageTypeSyncable) { + const UsageAndQuotaCallback& callback) { + DCHECK(origin == origin.GetOrigin()); + if (!IsSupportedType(type) || + (is_incognito_ && !IsSupportedIncognitoType(type))) { callback.Run(kQuotaErrorNotSupported, 0, 0); return; } - - DCHECK(origin == origin.GetOrigin()); LazyInitialize(); - - bool unlimited = IsStorageUnlimited(origin, type); - bool can_query_disk_size = CanQueryDiskSize(origin); - - UsageAndQuotaCallbackDispatcher* dispatcher = - new UsageAndQuotaCallbackDispatcher(this); - - if (unlimited) { - dispatcher->set_quota(kNoLimit); - } else { - if (type == kStorageTypeTemporary) { - GetUsageTracker(type)->GetGlobalLimitedUsage( - dispatcher->GetGlobalLimitedUsageCallback()); - GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback()); - } else if (type == kStorageTypePersistent) { - GetPersistentHostQuota(net::GetHostOrSpecFromURL(origin), - dispatcher->GetQuotaCallback()); - } else { - dispatcher->set_quota(kSyncableStorageDefaultHostQuota); - } - } - - DCHECK(GetUsageTracker(type)); - GetUsageTracker(type)->GetHostUsage(net::GetHostOrSpecFromURL(origin), - dispatcher->GetHostUsageCallback()); - - if (!is_incognito_ && (unlimited || can_query_disk_size)) - GetAvailableSpace(dispatcher->GetAvailableSpaceCallback()); - - dispatcher->WaitForResults(base::Bind( - &DispatchUsageAndQuotaForWebApps, - type, is_incognito_, unlimited, can_query_disk_size, - callback)); + UsageAndQuotaHelper* helper = new UsageAndQuotaHelper( + this, origin, type, IsStorageUnlimited(origin, type), is_incognito_, + callback); + helper->Start(); } -void QuotaManager::GetUsageAndQuota( - const GURL& origin, StorageType type, - const GetUsageAndQuotaCallback& callback) { +void QuotaManager::GetUsageAndQuota(const GURL& origin, + StorageType type, + const UsageAndQuotaCallback& callback) { DCHECK(origin == origin.GetOrigin()); if (IsStorageUnlimited(origin, type)) { + // TODO(michaeln): This seems like a non-obvious odd behavior, probably for + // apps/extensions, but it would be good to elimiate this special case. callback.Run(kQuotaStatusOk, 0, kNoLimit); return; } @@ -991,11 +887,6 @@ GetUsageTracker(type)->SetUsageCacheEnabled(client_id, origin, enabled); } -void QuotaManager::SetTemporaryStorageEvictionPolicy( - std::unique_ptr<QuotaEvictionPolicy> policy) { - temporary_storage_eviction_policy_ = std::move(policy); -} - void QuotaManager::DeleteOriginData(const GURL& origin, StorageType type, int quota_client_mask, @@ -1008,7 +899,6 @@ int quota_client_mask, const StatusCallback& callback) { LazyInitialize(); - if (host.empty() || clients_.empty()) { callback.Run(kQuotaStatusOk); return; @@ -1019,72 +909,6 @@ deleter->Start(); } -void QuotaManager::GetAvailableSpace(const AvailableSpaceCallback& callback) { - if (!available_space_callbacks_.Add(callback)) - return; - // crbug.com/349708 - TRACE_EVENT0("io", "QuotaManager::GetAvailableSpace"); - - PostTaskAndReplyWithResult( - db_thread_.get(), - FROM_HERE, - base::Bind(&QuotaManager::CallGetAmountOfFreeDiskSpace, - get_volume_info_fn_, profile_path_), - base::Bind(&QuotaManager::DidGetAvailableSpace, - weak_factory_.GetWeakPtr())); -} - -void QuotaManager::GetTemporaryGlobalQuota(const QuotaCallback& callback) { - LazyInitialize(); - if (!temporary_quota_initialized_) { - db_initialization_callbacks_.Add(base::Bind( - &QuotaManager::GetTemporaryGlobalQuota, - weak_factory_.GetWeakPtr(), callback)); - return; - } - - if (temporary_quota_override_ > 0) { - callback.Run(kQuotaStatusOk, temporary_quota_override_); - return; - } - - UsageAndQuotaCallbackDispatcher* dispatcher = - new UsageAndQuotaCallbackDispatcher(this); - GetUsageTracker(kStorageTypeTemporary)-> - GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback()); - GetAvailableSpace(dispatcher->GetAvailableSpaceCallback()); - dispatcher->WaitForResults( - base::Bind(&DispatchTemporaryGlobalQuotaCallback, callback)); -} - -void QuotaManager::SetTemporaryGlobalOverrideQuota( - int64_t new_quota, - const QuotaCallback& callback) { - LazyInitialize(); - - if (new_quota < 0) { - if (!callback.is_null()) - callback.Run(kQuotaErrorInvalidModification, -1); - return; - } - - if (db_disabled_) { - if (!callback.is_null()) - callback.Run(kQuotaErrorInvalidAccess, -1); - return; - } - - int64_t* new_quota_ptr = new int64_t(new_quota); - PostTaskAndReplyWithResultForDBThread( - FROM_HERE, - base::Bind(&SetTemporaryGlobalOverrideQuotaOnDBThread, - base::Unretained(new_quota_ptr)), - base::Bind(&QuotaManager::DidSetTemporaryGlobalOverrideQuota, - weak_factory_.GetWeakPtr(), - callback, - base::Owned(new_quota_ptr))); -} - void QuotaManager::GetPersistentHostQuota(const std::string& host, const QuotaCallback& callback) { LazyInitialize(); @@ -1126,10 +950,8 @@ return; } - if (kPerHostPersistentQuotaLimit < new_quota) { - // Cap the requested size at the per-host quota limit. - new_quota = kPerHostPersistentQuotaLimit; - } + // Cap the requested size at the per-host quota limit. + new_quota = std::min(new_quota, kPerHostPersistentQuotaLimit); if (db_disabled_) { callback.Run(kQuotaErrorInvalidAccess, -1); @@ -1289,7 +1111,7 @@ void QuotaManager::LazyInitialize() { DCHECK(io_thread_->BelongsToCurrentThread()); if (database_) { - // Initialization seems to be done already. + // Already initialized. return; } @@ -1307,17 +1129,45 @@ clients_, kStorageTypeSyncable, special_storage_policy_.get(), storage_monitor_.get())); - int64_t* temporary_quota_override = new int64_t(-1); - int64_t* desired_available_space = new int64_t(-1); + if (!is_incognito_) { + histogram_timer_.Start( + FROM_HERE, base::TimeDelta::FromMilliseconds(kReportHistogramInterval), + this, &QuotaManager::ReportHistogram); + } + + base::PostTaskAndReplyWithResult( + db_thread_.get(), FROM_HERE, + base::Bind(&QuotaDatabase::IsOriginDatabaseBootstrapped, + base::Unretained(database_.get())), + base::Bind(&QuotaManager::FinishLazyInitialize, + weak_factory_.GetWeakPtr())); +} + +void QuotaManager::FinishLazyInitialize(bool is_database_bootstrapped) { + is_database_bootstrapped_ = is_database_bootstrapped; + StartEviction(); +} + +void QuotaManager::BootstrapDatabaseForEviction( + const GetOriginCallback& did_get_origin_callback, + int64_t usage, + int64_t unlimited_usage) { + // The usage cache should be fully populated now so we can + // seed the database with origins we know about. + std::set<GURL>* origins = new std::set<GURL>; + temporary_usage_tracker_->GetCachedOrigins(origins); PostTaskAndReplyWithResultForDBThread( - FROM_HERE, - base::Bind(&InitializeOnDBThread, - base::Unretained(temporary_quota_override), - base::Unretained(desired_available_space)), - base::Bind(&QuotaManager::DidInitialize, - weak_factory_.GetWeakPtr(), - base::Owned(temporary_quota_override), - base::Owned(desired_available_space))); + FROM_HERE, base::Bind(&BootstrapDatabaseOnDBThread, base::Owned(origins)), + base::Bind(&QuotaManager::DidBootstrapDatabase, + weak_factory_.GetWeakPtr(), did_get_origin_callback)); +} + +void QuotaManager::DidBootstrapDatabase( + const GetOriginCallback& did_get_origin_callback, + bool success) { + is_database_bootstrapped_ = success; + DidDatabaseWork(success); + GetLRUOrigin(kStorageTypeTemporary, did_get_origin_callback); } void QuotaManager::RegisterClient(QuotaClient* client) { @@ -1412,11 +1262,10 @@ void QuotaManager::StartEviction() { DCHECK(!temporary_storage_evictor_.get()); + if (eviction_disabled_) + return; temporary_storage_evictor_.reset(new QuotaTemporaryStorageEvictor( this, kEvictionIntervalInMilliSeconds)); - if (desired_available_space_ >= 0) - temporary_storage_evictor_->set_min_available_disk_space_to_start_eviction( - desired_available_space_); temporary_storage_evictor_->Start(); } @@ -1602,26 +1451,21 @@ base::Bind(&QuotaManager::DidGetEvictionOrigin, weak_factory_.GetWeakPtr(), callback); - if (type == kStorageTypeTemporary && temporary_storage_eviction_policy_) { - std::map<GURL, int64_t> usage_map; - // The cached origins are populated by the prior call to - // GetUsageAndQuotaForEviction(). - GetUsageTracker(kStorageTypeTemporary)->GetCachedOriginsUsage(&usage_map); - - temporary_storage_eviction_policy_->GetEvictionOrigin( - special_storage_policy_, GetEvictionOriginExceptions(extra_exceptions), - usage_map, global_quota, did_get_origin_callback); - + if (!is_database_bootstrapped_ && !eviction_disabled_) { + // Once bootstrapped, GetLRUOrigin will be called. + GetGlobalUsage( + kStorageTypeTemporary, + base::Bind(&QuotaManager::BootstrapDatabaseForEviction, + weak_factory_.GetWeakPtr(), did_get_origin_callback)); return; } - // TODO(calamity): convert LRU origin retrieval into a QuotaEvictionPolicy. GetLRUOrigin(type, did_get_origin_callback); } void QuotaManager::EvictOriginData(const GURL& origin, StorageType type, - const EvictOriginDataCallback& callback) { + const StatusCallback& callback) { DCHECK(io_thread_->BelongsToCurrentThread()); DCHECK_EQ(type, kStorageTypeTemporary); @@ -1634,47 +1478,12 @@ weak_factory_.GetWeakPtr())); } -void QuotaManager::GetUsageAndQuotaForEviction( - const UsageAndQuotaCallback& callback) { - // crbug.com/349708 - TRACE_EVENT0("io", "QuotaManager::GetUsageAndQuotaForEviction"); - +void QuotaManager::GetEvictionRoundInfo( + const EvictionRoundInfoCallback& callback) { DCHECK(io_thread_->BelongsToCurrentThread()); LazyInitialize(); - - UsageAndQuotaCallbackDispatcher* dispatcher = - new UsageAndQuotaCallbackDispatcher(this); - GetUsageTracker(kStorageTypeTemporary) - ->GetGlobalLimitedUsage(dispatcher->GetGlobalLimitedUsageCallback()); - GetTemporaryGlobalQuota(dispatcher->GetQuotaCallback()); - GetAvailableSpace(dispatcher->GetAvailableSpaceCallback()); - dispatcher->WaitForResults(callback); -} - -void QuotaManager::AsyncGetVolumeInfo( - const VolumeInfoCallback& callback) { - DCHECK(io_thread_->BelongsToCurrentThread()); - uint64_t* available_space = new uint64_t(0); - uint64_t* total_space = new uint64_t(0); - PostTaskAndReplyWithResult( - db_thread_.get(), - FROM_HERE, - base::Bind(get_volume_info_fn_, - profile_path_, - base::Unretained(available_space), - base::Unretained(total_space)), - base::Bind(&QuotaManager::DidGetVolumeInfo, - weak_factory_.GetWeakPtr(), - callback, - base::Owned(available_space), - base::Owned(total_space))); -} - -void QuotaManager::DidGetVolumeInfo( - const VolumeInfoCallback& callback, - uint64_t* available_space, uint64_t* total_space, bool success) { - DCHECK(io_thread_->BelongsToCurrentThread()); - callback.Run(success, *available_space, *total_space); + EvictionRoundInfoHelper* helper = new EvictionRoundInfoHelper(this, callback); + helper->Start(); } void QuotaManager::GetLRUOrigin(StorageType type, @@ -1699,28 +1508,12 @@ base::Owned(url))); } -void QuotaManager::DidSetTemporaryGlobalOverrideQuota( - const QuotaCallback& callback, - const int64_t* new_quota, - bool success) { - QuotaStatusCode status = kQuotaErrorInvalidAccess; - DidDatabaseWork(success); - if (success) { - temporary_quota_override_ = *new_quota; - status = kQuotaStatusOk; - } - - if (callback.is_null()) - return; - - callback.Run(status, *new_quota); -} - void QuotaManager::DidGetPersistentHostQuota(const std::string& host, const int64_t* quota, bool success) { DidDatabaseWork(success); - persistent_host_quota_callbacks_.Run(host, kQuotaStatusOk, *quota); + persistent_host_quota_callbacks_.Run( + host, kQuotaStatusOk, std::min(*quota, kPerHostPersistentQuotaLimit)); } void QuotaManager::DidSetPersistentHostQuota(const std::string& host, @@ -1731,27 +1524,6 @@ callback.Run(success ? kQuotaStatusOk : kQuotaErrorInvalidAccess, *new_quota); } -void QuotaManager::DidInitialize(int64_t* temporary_quota_override, - int64_t* desired_available_space, - bool success) { - temporary_quota_override_ = *temporary_quota_override; - desired_available_space_ = *desired_available_space; - temporary_quota_initialized_ = true; - DidDatabaseWork(success); - - if (!is_incognito_) { - histogram_timer_.Start(FROM_HERE, - base::TimeDelta::FromMilliseconds( - kReportHistogramInterval), - this, &QuotaManager::ReportHistogram); - } - - db_initialization_callbacks_.Run(); - GetTemporaryGlobalQuota( - base::Bind(&QuotaManager::DidGetInitialTemporaryGlobalQuota, - weak_factory_.GetWeakPtr(), base::TimeTicks::Now())); -} - void QuotaManager::DidGetLRUOrigin(const GURL* origin, bool success) { DidDatabaseWork(success); @@ -1760,41 +1532,83 @@ lru_origin_callback_.Reset(); } -void QuotaManager::DidGetInitialTemporaryGlobalQuota( - base::TimeTicks start_ticks, - QuotaStatusCode status, - int64_t quota_unused) { - UMA_HISTOGRAM_LONG_TIMES( - "Quota.TimeToInitializeGlobalQuota", - base::TimeTicks::Now() - start_ticks); +namespace { +void DidGetSettingsThreadAdapter(base::TaskRunner* task_runner, + const OptionalQuotaSettingsCallback& callback, + base::Optional<QuotaSettings> settings) { + task_runner->PostTask(FROM_HERE, base::Bind(callback, std::move(settings))); +} +} // namespace - if (eviction_disabled_) +void QuotaManager::GetQuotaSettings(const QuotaSettingsCallback& callback) { + if (base::TimeTicks::Now() - settings_timestamp_ < + settings_.refresh_interval) { + callback.Run(settings_); + return; + } + + if (!settings_callbacks_.Add(callback)) return; - std::set<GURL>* origins = new std::set<GURL>; - temporary_usage_tracker_->GetCachedOrigins(origins); - // This will call the StartEviction() when initial origin registration - // is completed. - PostTaskAndReplyWithResultForDBThread( + // We invoke our clients GetQuotaSettingsFunc on the + // UI thread and plumb the resulting value back to this thread. + get_settings_task_runner_->PostTask( FROM_HERE, - base::Bind(&InitializeTemporaryOriginsInfoOnDBThread, - base::Owned(origins)), - base::Bind(&QuotaManager::DidInitializeTemporaryOriginsInfo, + base::Bind( + get_settings_function_, + base::Bind( + &DidGetSettingsThreadAdapter, + base::RetainedRef(base::ThreadTaskRunnerHandle::Get()), + base::Bind(&QuotaManager::DidGetSettings, + weak_factory_.GetWeakPtr(), base::TimeTicks::Now())))); +} + +void QuotaManager::DidGetSettings(base::TimeTicks start_ticks, + base::Optional<QuotaSettings> settings) { + if (!settings) { + settings = settings_; + settings->refresh_interval = base::TimeDelta::FromMinutes(1); + } + SetQuotaSettings(*settings); + settings_callbacks_.Run(*settings); + UMA_HISTOGRAM_MBYTES("Quota.GlobalTemporaryPoolSize", settings->pool_size); + UMA_HISTOGRAM_LONG_TIMES("Quota.TimeToGetSettings", + base::TimeTicks::Now() - start_ticks); + LOG_IF(WARNING, settings->pool_size == 0) + << "No storage quota provided in QuotaSettings."; +} + +void QuotaManager::GetStorageCapacity(const StorageCapacityCallback& callback) { + if (!storage_capacity_callbacks_.Add(callback)) + return; + if (is_incognito_) { + GetQuotaSettings( + base::Bind(&QuotaManager::ContinueIncognitoGetStorageCapacity, + weak_factory_.GetWeakPtr())); + return; + } + base::PostTaskAndReplyWithResult( + db_thread_.get(), FROM_HERE, + base::Bind(&QuotaManager::CallGetVolumeInfo, get_volume_info_fn_, + profile_path_), + base::Bind(&QuotaManager::DidGetStorageCapacity, weak_factory_.GetWeakPtr())); } -void QuotaManager::DidInitializeTemporaryOriginsInfo(bool success) { - DidDatabaseWork(success); - if (success) - StartEviction(); +void QuotaManager::ContinueIncognitoGetStorageCapacity( + const QuotaSettings& settings) { + int64_t current_usage = + GetUsageTracker(kStorageTypeTemporary)->GetCachedUsage(); + current_usage += GetUsageTracker(kStorageTypePersistent)->GetCachedUsage(); + int64_t available_space = + std::max(INT64_C(0), settings.pool_size - current_usage); + DidGetStorageCapacity(std::make_pair(settings.pool_size, available_space)); } -void QuotaManager::DidGetAvailableSpace(int64_t space) { - // crbug.com/349708 - TRACE_EVENT1("io", "QuotaManager::DidGetAvailableSpace", - "n_callbacks", available_space_callbacks_.size()); - - available_space_callbacks_.Run(kQuotaStatusOk, space); +void QuotaManager::DidGetStorageCapacity( + const std::pair<int64_t, int64_t>& total_and_available) { + storage_capacity_callbacks_.Run(total_and_available.first, + total_and_available.second); } void QuotaManager::DidDatabaseWork(bool success) { @@ -1824,41 +1638,30 @@ } // static -int64_t QuotaManager::CallGetAmountOfFreeDiskSpace( +std::pair<int64_t, int64_t> QuotaManager::CallGetVolumeInfo( GetVolumeInfoFn get_volume_info_fn, - const base::FilePath& profile_path) { + const base::FilePath& path) { // crbug.com/349708 - TRACE_EVENT0("io", "CallSystemGetAmountOfFreeDiskSpace"); - if (!base::CreateDirectory(profile_path)) { - LOG(WARNING) << "Create directory failed for path" << profile_path.value(); - return 0; + TRACE_EVENT0("io", "CallGetVolumeInfo"); + if (!base::CreateDirectory(path)) { + LOG(WARNING) << "Create directory failed for path" << path.value(); + return std::make_pair<int64_t, int64_t>(0, 0); } - uint64_t available, total; - if (!get_volume_info_fn(profile_path, &available, &total)) { - return 0; + std::pair<int64_t, int64_t> total_and_available = get_volume_info_fn(path); + if (total_and_available.first < 0 || total_and_available.second < 0) { + LOG(WARNING) << "Unable to get volume info: " << path.value(); + return std::make_pair<int64_t, int64_t>(0, 0); } - UMA_HISTOGRAM_MBYTES("Quota.AvailableDiskSpace", available); - UMA_HISTOGRAM_MBYTES("Quota.TotalDiskSpace", total); - return static_cast<int64_t>(available); + UMA_HISTOGRAM_MBYTES("Quota.TotalDiskSpace", total_and_available.first); + UMA_HISTOGRAM_MBYTES("Quota.AvailableDiskSpace", total_and_available.second); + return total_and_available; } -//static -bool QuotaManager::GetVolumeInfo(const base::FilePath& path, - uint64_t* available_space, - uint64_t* total_size) { - // Inspired by similar code in the base::SysInfo class. - base::ThreadRestrictions::AssertIOAllowed(); - - int64_t available = base::SysInfo::AmountOfFreeDiskSpace(path); - if (available < 0) - return false; - int64_t total = base::SysInfo::AmountOfTotalDiskSpace(path); - if (total < 0) - return false; - - *available_space = static_cast<uint64_t>(available); - *total_size = static_cast<uint64_t>(total); - return true; +// static +std::pair<int64_t, int64_t> QuotaManager::GetVolumeInfo( + const base::FilePath& path) { + return std::make_pair(base::SysInfo::AmountOfTotalDiskSpace(path), + base::SysInfo::AmountOfFreeDiskSpace(path)); } } // namespace storage
diff --git a/storage/browser/quota/quota_manager.h b/storage/browser/quota/quota_manager.h index a1ef11d..ded960e2 100644 --- a/storage/browser/quota/quota_manager.h +++ b/storage/browser/quota/quota_manager.h
@@ -21,17 +21,17 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "base/optional.h" #include "base/sequenced_task_runner_helpers.h" #include "storage/browser/quota/quota_callbacks.h" #include "storage/browser/quota/quota_client.h" #include "storage/browser/quota/quota_database.h" +#include "storage/browser/quota/quota_settings.h" #include "storage/browser/quota/quota_task.h" #include "storage/browser/quota/special_storage_policy.h" #include "storage/browser/quota/storage_observer.h" #include "storage/browser/storage_browser_export.h" -class SiteEngagementEvictionPolicyWithQuotaManagerTest; - namespace base { class FilePath; class SequencedTaskRunner; @@ -60,44 +60,21 @@ struct QuotaManagerDeleter; -struct STORAGE_EXPORT UsageAndQuota { - int64_t usage; - int64_t global_limited_usage; - int64_t quota; - int64_t available_disk_space; - - UsageAndQuota(); - UsageAndQuota(int64_t usage, - int64_t global_limited_usage, - int64_t quota, - int64_t available_disk_space); -}; - -// TODO(calamity): Use this in the temporary storage eviction path. -// An interface for deciding which origin's storage should be evicted when the -// quota is exceeded. -class STORAGE_EXPORT QuotaEvictionPolicy { - public: - virtual ~QuotaEvictionPolicy() {} - - // Returns the next origin to evict. It might return an empty GURL when there - // are no evictable origins. - virtual void GetEvictionOrigin( - const scoped_refptr<SpecialStoragePolicy>& special_storage_policy, - const std::set<GURL>& exceptions, - const std::map<GURL, int64_t>& usage_map, - int64_t global_quota, - const GetOriginCallback& callback) = 0; -}; - // An interface called by QuotaTemporaryStorageEvictor. class STORAGE_EXPORT QuotaEvictionHandler { public: - using EvictOriginDataCallback = StatusCallback; - using UsageAndQuotaCallback = base::Callback< - void(QuotaStatusCode status, const UsageAndQuota& usage_and_quota)>; - using VolumeInfoCallback = base::Callback< - void(bool success, uint64_t available_space, uint64_t total_space)>; + using EvictionRoundInfoCallback = + base::Callback<void(QuotaStatusCode status, + const QuotaSettings& settings, + int64_t available_space, + int64_t total_space, + int64_t global_usage, + bool global_usage_is_complete)>; + + // Called at the beginning of an eviction round to gather the info about + // the current settings, capacity, and usage. + virtual void GetEvictionRoundInfo( + const EvictionRoundInfoCallback& callback) = 0; // Returns next origin to evict. It might return an empty GURL when there are // no evictable origins. @@ -106,14 +83,10 @@ int64_t global_quota, const GetOriginCallback& callback) = 0; - virtual void EvictOriginData( - const GURL& origin, - StorageType type, - const EvictOriginDataCallback& callback) = 0; - - virtual void AsyncGetVolumeInfo(const VolumeInfoCallback& callback) = 0; - virtual void GetUsageAndQuotaForEviction( - const UsageAndQuotaCallback& callback) = 0; + // Called to evict an origin. + virtual void EvictOriginData(const GURL& origin, + StorageType type, + const StatusCallback& callback) = 0; protected: virtual ~QuotaEvictionHandler() {} @@ -135,11 +108,10 @@ public QuotaEvictionHandler, public base::RefCountedThreadSafe<QuotaManager, QuotaManagerDeleter> { public: - typedef base::Callback<void(QuotaStatusCode, - int64_t /* usage */, - int64_t /* quota */)> GetUsageAndQuotaCallback; + typedef base::Callback< + void(QuotaStatusCode, int64_t /* usage */, int64_t /* quota */)> + UsageAndQuotaCallback; - static const int64_t kIncognitoDefaultQuotaLimit; static const int64_t kNoLimit; QuotaManager( @@ -147,7 +119,11 @@ const base::FilePath& profile_path, const scoped_refptr<base::SingleThreadTaskRunner>& io_thread, const scoped_refptr<base::SequencedTaskRunner>& db_thread, - const scoped_refptr<SpecialStoragePolicy>& special_storage_policy); + const scoped_refptr<SpecialStoragePolicy>& special_storage_policy, + const GetQuotaSettingsFunc& get_settings_function); + + const QuotaSettings& settings() const { return settings_; } + void SetQuotaSettings(const QuotaSettings& settings); // Returns a proxy object that can be used on any thread. QuotaManagerProxy* proxy() { return proxy_.get(); } @@ -160,7 +136,7 @@ virtual void GetUsageAndQuotaForWebApps( const GURL& origin, StorageType type, - const GetUsageAndQuotaCallback& callback); + const UsageAndQuotaCallback& callback); // Called by StorageClients. // This method is declared as virtual to allow test code to override it. @@ -168,10 +144,9 @@ // For UnlimitedStorage origins, this version skips usage and quota handling // to avoid extra query cost. // Do not call this method for apps/user-facing code. - virtual void GetUsageAndQuota( - const GURL& origin, - StorageType type, - const GetUsageAndQuotaCallback& callback); + virtual void GetUsageAndQuota(const GURL& origin, + StorageType type, + const UsageAndQuotaCallback& callback); // Called by clients via proxy. // Client storage should call this method when storage is accessed. @@ -202,10 +177,6 @@ StorageType type, bool enabled); - // Set the eviction policy to use when choosing an origin to evict. - void SetTemporaryStorageEvictionPolicy( - std::unique_ptr<QuotaEvictionPolicy> policy); - // DeleteOriginData and DeleteHostData (surprisingly enough) delete data of a // particular StorageType associated with either a specific origin or set of // origins. Each method additionally requires a |quota_client_mask| which @@ -223,13 +194,6 @@ const StatusCallback& callback); // Called by UI and internal modules. - void GetAvailableSpace(const AvailableSpaceCallback& callback); - void GetTemporaryGlobalQuota(const QuotaCallback& callback); - - // Ok to call with NULL callback. - void SetTemporaryGlobalOverrideQuota(int64_t new_quota, - const QuotaCallback& callback); - void GetPersistentHostQuota(const std::string& host, const QuotaCallback& callback); void SetPersistentHostQuota(const std::string& host, @@ -248,11 +212,6 @@ bool IsStorageUnlimited(const GURL& origin, StorageType type) const; - bool CanQueryDiskSize(const GURL& origin) const { - return special_storage_policy_.get() && - special_storage_policy_->CanQueryDiskSize(origin); - } - virtual void GetOriginsModifiedSince(StorageType type, base::Time modified_since, const GetOriginsCallback& callback); @@ -266,26 +225,17 @@ void RemoveStorageObserverForFilter(StorageObserver* observer, const StorageObserver::Filter& filter); - // Determines the portion of the temp pool that can be - // utilized by a single host (ie. 5 for 20%). - static const int kPerHostTemporaryPortion; - static const int64_t kPerHostPersistentQuotaLimit; - static const char kDatabaseName[]; - static const int kThresholdOfErrorsToBeBlacklisted; - static const int kEvictionIntervalInMilliSeconds; - static const char kTimeBetweenRepeatedOriginEvictionsHistogram[]; static const char kEvictedOriginAccessedCountHistogram[]; static const char kEvictedOriginTimeSinceAccessHistogram[]; - // These are kept non-const so that test code can change the value. + // Kept non-const so that test code can change the value. // TODO(kinuko): Make this a real const value and add a proper way to set // the quota for syncable storage. (http://crbug.com/155488) - static int64_t kMinimumPreserveForSystem; static int64_t kSyncableStorageDefaultHostQuota; protected: @@ -302,13 +252,12 @@ friend class QuotaManagerProxy; friend class QuotaTemporaryStorageEvictor; friend struct QuotaManagerDeleter; - friend class ::SiteEngagementEvictionPolicyWithQuotaManagerTest; + class EvictionRoundInfoHelper; + class UsageAndQuotaHelper; class GetUsageInfoTask; - class OriginDataDeleter; class HostDataDeleter; - class GetModifiedSinceHelper; class DumpQuotaTableHelper; class DumpOriginInfoTableHelper; @@ -318,10 +267,13 @@ typedef std::vector<QuotaTableEntry> QuotaTableEntries; typedef std::vector<OriginInfoTableEntry> OriginInfoTableEntries; + using QuotaSettingsCallback = base::Callback<void(const QuotaSettings&)>; + // Function pointer type used to store the function which returns // information about the volume containing the given FilePath. - using GetVolumeInfoFn = bool(*)(const base::FilePath&, - uint64_t* available, uint64_t* total); + // The value returned is std::pair<total_space, available_space>. + using GetVolumeInfoFn = + std::pair<int64_t, int64_t> (*)(const base::FilePath&); typedef base::Callback<void(const QuotaTableEntries&)> DumpQuotaTableCallback; @@ -329,28 +281,36 @@ DumpOriginInfoTableCallback; typedef CallbackQueue<base::Closure> ClosureQueue; - typedef CallbackQueue<AvailableSpaceCallback, QuotaStatusCode, int64_t> - AvailableSpaceCallbackQueue; typedef CallbackQueueMap<QuotaCallback, std::string, QuotaStatusCode, int64_t> HostQuotaCallbackMap; + using QuotaSettingsCallbackQueue = + CallbackQueue<QuotaSettingsCallback, const QuotaSettings&>; + + // The values returned total_space, available_space. + using StorageCapacityCallback = base::Callback<void(int64_t, int64_t)>; + using StorageCapacityCallbackQueue = + CallbackQueue<StorageCapacityCallback, int64_t, int64_t>; struct EvictionContext { EvictionContext(); - virtual ~EvictionContext(); + ~EvictionContext(); GURL evicted_origin; StorageType evicted_type; - - EvictOriginDataCallback evict_origin_data_callback; + StatusCallback evict_origin_data_callback; }; - typedef QuotaEvictionHandler::UsageAndQuotaCallback - UsageAndQuotaDispatcherCallback; - // This initialization method is lazily called on the IO thread // when the first quota manager API is called. // Initialize must be called after all quota clients are added to the // manager by RegisterStorage. void LazyInitialize(); + void FinishLazyInitialize(bool is_database_bootstraped); + void BootstrapDatabaseForEviction( + const GetOriginCallback& did_get_origin_callback, + int64_t unused_usage, + int64_t unused_unlimited_usage); + void DidBootstrapDatabase(const GetOriginCallback& did_get_origin_callback, + bool success); // Called by clients via proxy. // Registers a quota client to the manager. @@ -412,20 +372,11 @@ const GetOriginCallback& callback) override; void EvictOriginData(const GURL& origin, StorageType type, - const EvictOriginDataCallback& callback) override; - void GetUsageAndQuotaForEviction( - const UsageAndQuotaCallback& callback) override; - void AsyncGetVolumeInfo(const VolumeInfoCallback& callback) override; - - void DidGetVolumeInfo( - const VolumeInfoCallback& callback, - uint64_t* available_space, uint64_t* total_space, bool success); + const StatusCallback& callback) override; + void GetEvictionRoundInfo(const EvictionRoundInfoCallback& callback) override; void GetLRUOrigin(StorageType type, const GetOriginCallback& callback); - void DidSetTemporaryGlobalOverrideQuota(const QuotaCallback& callback, - const int64_t* new_quota, - bool success); void DidGetPersistentHostQuota(const std::string& host, const int64_t* quota, bool success); @@ -433,16 +384,16 @@ const QuotaCallback& callback, const int64_t* new_quota, bool success); - void DidInitialize(int64_t* temporary_quota_override, - int64_t* desired_available_space, - bool success); void DidGetLRUOrigin(const GURL* origin, bool success); - void DidGetInitialTemporaryGlobalQuota(base::TimeTicks start_ticks, - QuotaStatusCode status, - int64_t quota_unused); - void DidInitializeTemporaryOriginsInfo(bool success); - void DidGetAvailableSpace(int64_t space); + void GetQuotaSettings(const QuotaSettingsCallback& callback); + void DidGetSettings(base::TimeTicks start_ticks, + base::Optional<QuotaSettings> settings); + void GetStorageCapacity(const StorageCapacityCallback& callback); + void ContinueIncognitoGetStorageCapacity(const QuotaSettings& settings); + void DidGetStorageCapacity( + const std::pair<int64_t, int64_t>& total_and_available); + void DidDatabaseWork(bool success); void DeleteOnCorrectThread() const; @@ -452,12 +403,10 @@ const base::Callback<bool(QuotaDatabase*)>& task, const base::Callback<void(bool)>& reply); - static int64_t CallGetAmountOfFreeDiskSpace( - GetVolumeInfoFn get_vol_info_fn, - const base::FilePath& profile_path); - static bool GetVolumeInfo(const base::FilePath& path, - uint64_t* available_space, - uint64_t* total_size); + static std::pair<int64_t, int64_t> CallGetVolumeInfo( + GetVolumeInfoFn get_volume_info_fn, + const base::FilePath& path); + static std::pair<int64_t, int64_t> GetVolumeInfo(const base::FilePath& path); const bool is_incognito_; const base::FilePath profile_path_; @@ -468,6 +417,14 @@ scoped_refptr<base::SingleThreadTaskRunner> io_thread_; scoped_refptr<base::SequencedTaskRunner> db_thread_; mutable std::unique_ptr<QuotaDatabase> database_; + bool is_database_bootstrapped_ = false; + + GetQuotaSettingsFunc get_settings_function_; + scoped_refptr<base::TaskRunner> get_settings_task_runner_; + QuotaSettings settings_; + base::TimeTicks settings_timestamp_; + QuotaSettingsCallbackQueue settings_callbacks_; + StorageCapacityCallbackQueue storage_capacity_callbacks_; GetOriginCallback lru_origin_callback_; std::set<GURL> access_notified_origins_; @@ -482,17 +439,10 @@ std::unique_ptr<QuotaTemporaryStorageEvictor> temporary_storage_evictor_; EvictionContext eviction_context_; - std::unique_ptr<QuotaEvictionPolicy> temporary_storage_eviction_policy_; bool is_getting_eviction_origin_; - ClosureQueue db_initialization_callbacks_; - AvailableSpaceCallbackQueue available_space_callbacks_; HostQuotaCallbackMap persistent_host_quota_callbacks_; - bool temporary_quota_initialized_; - int64_t temporary_quota_override_; - int64_t desired_available_space_; - // Map from origin to count. std::map<GURL, int> origins_in_use_; // Map from origin to error count.
diff --git a/storage/browser/quota/quota_manager_proxy.cc b/storage/browser/quota/quota_manager_proxy.cc index 0c1ad0a..b67cfb9c 100644 --- a/storage/browser/quota/quota_manager_proxy.cc +++ b/storage/browser/quota/quota_manager_proxy.cc
@@ -20,7 +20,7 @@ void DidGetUsageAndQuota( base::SequencedTaskRunner* original_task_runner, - const QuotaManagerProxy::GetUsageAndQuotaCallback& callback, + const QuotaManagerProxy::UsageAndQuotaCallback& callback, QuotaStatusCode status, int64_t usage, int64_t quota) { @@ -130,7 +130,7 @@ base::SequencedTaskRunner* original_task_runner, const GURL& origin, StorageType type, - const GetUsageAndQuotaCallback& callback) { + const UsageAndQuotaCallback& callback) { if (!io_thread_->BelongsToCurrentThread()) { io_thread_->PostTask( FROM_HERE, base::Bind(&QuotaManagerProxy::GetUsageAndQuota, this,
diff --git a/storage/browser/quota/quota_manager_proxy.h b/storage/browser/quota/quota_manager_proxy.h index 19a1f89d..7125a6a 100644 --- a/storage/browser/quota/quota_manager_proxy.h +++ b/storage/browser/quota/quota_manager_proxy.h
@@ -34,8 +34,7 @@ class STORAGE_EXPORT QuotaManagerProxy : public base::RefCountedThreadSafe<QuotaManagerProxy> { public: - typedef QuotaManager::GetUsageAndQuotaCallback - GetUsageAndQuotaCallback; + typedef QuotaManager::UsageAndQuotaCallback UsageAndQuotaCallback; virtual void RegisterClient(QuotaClient* client); virtual void NotifyStorageAccessed(QuotaClient::ID client_id, @@ -52,11 +51,10 @@ const GURL& origin, StorageType type, bool enabled); - virtual void GetUsageAndQuota( - base::SequencedTaskRunner* original_task_runner, - const GURL& origin, - StorageType type, - const GetUsageAndQuotaCallback& callback); + virtual void GetUsageAndQuota(base::SequencedTaskRunner* original_task_runner, + const GURL& origin, + StorageType type, + const UsageAndQuotaCallback& callback); // This method may only be called on the IO thread. // It may return NULL if the manager has already been deleted.
diff --git a/storage/browser/quota/quota_settings.cc b/storage/browser/quota/quota_settings.cc new file mode 100644 index 0000000..2b737098 --- /dev/null +++ b/storage/browser/quota/quota_settings.cc
@@ -0,0 +1,83 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "storage/browser/quota/quota_settings.h" + +#include <algorithm> + +#include "base/metrics/histogram_macros.h" +#include "base/sys_info.h" + +#define UMA_HISTOGRAM_MBYTES(name, sample) \ + UMA_HISTOGRAM_CUSTOM_COUNTS((name), static_cast<int>((sample) / kMBytes), 1, \ + 10 * 1024 * 1024 /* 10TB */, 100) + +namespace storage { + +base::Optional<storage::QuotaSettings> CalculateNominalDynamicSettings( + const base::FilePath& partition_path, + bool is_incognito) { + const int64_t kMBytes = 1024 * 1024; + + if (is_incognito) { + storage::QuotaSettings settings; + settings.pool_size = + std::min(300 * kMBytes, base::SysInfo::AmountOfPhysicalMemory() / 10); + settings.per_host_quota = settings.pool_size / 3; + settings.refresh_interval = base::TimeDelta::Max(); + return settings; + } + + // The fraction of the device's storage the browser is willing to + // use for temporary storage, this is applied after adjusting the + // total to take os_accomodation into account. + const double kTemporaryPoolSizeRatio = 1.0 / 3.0; // 33% + + // The fraction of the device's storage the browser attempts to + // keep free. + const double kMustRemainAvailableRatio = 0.1; + + // Determines the portion of the temp pool that can be + // utilized by a single host (ie. 5 for 20%). + const int kPerHostTemporaryPortion = 5; + + // os_accomodation is an estimate of how much storage is needed for + // the os and essential application code outside of the browser. + const int64_t kDefaultOSAccomodation = +#if defined(OS_ANDROID) + 1000 * kMBytes; +#elif defined(OS_CHROMEOS) + 1000 * kMBytes; +#elif defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX) + 10000 * kMBytes; +#else +#error "Port: Need to define an OS accomodation value for unknown OS." +#endif + + storage::QuotaSettings settings; + + int64_t total = base::SysInfo::AmountOfTotalDiskSpace(partition_path); + if (total == -1) { + LOG(ERROR) << "Unable to compute QuotaSettings."; + return base::nullopt; + } + + // If our hardcoded OS accomodation is too large for the volume size, define + // the value as a fraction of the total volume size instead. + int64_t os_accomodation = + std::min(kDefaultOSAccomodation, static_cast<int64_t>(total * 0.8)); + UMA_HISTOGRAM_MBYTES("Quota.OSAccomodationDelta", + kDefaultOSAccomodation - os_accomodation); + + int64_t adjusted_total = total - os_accomodation; + int64_t pool_size = adjusted_total * kTemporaryPoolSizeRatio; + + settings.pool_size = pool_size; + settings.must_remain_available = total * kMustRemainAvailableRatio; + settings.per_host_quota = pool_size / kPerHostTemporaryPortion; + settings.refresh_interval = base::TimeDelta::FromSeconds(60); + return settings; +} + +} // namespace
diff --git a/storage/browser/quota/quota_settings.h b/storage/browser/quota/quota_settings.h new file mode 100644 index 0000000..e05d5530 --- /dev/null +++ b/storage/browser/quota/quota_settings.h
@@ -0,0 +1,82 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef STORAGE_BROWSER_QUOTA_QUOTA_SETTINGS_H_ +#define STORAGE_BROWSER_QUOTA_QUOTA_SETTINGS_H_ + +#include <stdint.h> + +#include "base/callback.h" +#include "base/files/file_path.h" +#include "base/optional.h" +#include "base/time/time.h" +#include "storage/browser/storage_browser_export.h" + +namespace storage { + +// Settings the storage lib embedder must provide to the QuotaManager. +struct QuotaSettings { + QuotaSettings() = default; + QuotaSettings(int64_t pool_size, + int64_t per_host_quota, + int64_t must_remain_available) + : pool_size(pool_size), + per_host_quota(per_host_quota), + must_remain_available(must_remain_available) {} + + // The target size in bytes of the shared pool of disk space the quota + // system allows for use by websites using HTML5 storage apis, for + // example an embedder may use 50% of the total volume size. + int64_t pool_size = 0; + + // The amount in bytes of the pool an individual site may consume. The + // value must be less than or equal to the pool_size. + int64_t per_host_quota = 0; + + // The amount of space that must remain available on the storage + // volume. As the volume approaches this limit, the quota system gets + // more aggressive about evicting data and disallowing new data. + int64_t must_remain_available = 0; + + // The quota system querries the embedder for the QuataSettings, + // but will rate limit the frequency of the querries to no more than once + // per refresh interval. + base::TimeDelta refresh_interval = base::TimeDelta::Max(); +}; + +// Function type used to return the settings in response to a +// GetQuotaSettingsFunc invocation. If the embedder cannot +// produce a settings values, base::nullopt can be returned. +using OptionalQuotaSettingsCallback = + base::Callback<void(base::Optional<QuotaSettings>)>; + +// Function type used to query the embedder about the quota manager settings. +// This function is invoked on the UI thread. +using GetQuotaSettingsFunc = + base::Callback<void(const OptionalQuotaSettingsCallback& callback)>; + +// Returns settings based on the size of the volume containing the storage +// partition and a guestimate of the size required for the OS. The refresh +// interval is 60 seconds to accomodate changes to the size of the volume. +// Except, in the case of incognito, the poolize and quota values are based +// on the amount of physical memory and the rerfresh interval is max'd out. +STORAGE_EXPORT +base::Optional<storage::QuotaSettings> CalculateNominalDynamicSettings( + const base::FilePath& partition_path, + bool is_incognito); + +// Returns settings with a poolsize of zero and no per host quota. +inline QuotaSettings GetNoQuotaSettings() { + return QuotaSettings(); +} + +// Returns settings that provide given |per_host_quota| and a total poolsize of +// five times that. +inline QuotaSettings GetHardCodedSettings(int64_t per_host_quota) { + return QuotaSettings(per_host_quota * 5, per_host_quota, per_host_quota); +} + +} // namespace storage + +#endif // STORAGE_BROWSER_QUOTA_QUOTA_MANAGER_H_
diff --git a/storage/browser/quota/quota_temporary_storage_evictor.cc b/storage/browser/quota/quota_temporary_storage_evictor.cc index 6cce670..1a6c0257 100644 --- a/storage/browser/quota/quota_temporary_storage_evictor.cc +++ b/storage/browser/quota/quota_temporary_storage_evictor.cc
@@ -8,6 +8,7 @@ #include <algorithm> +#include "base/auto_reset.h" #include "base/bind.h" #include "base/metrics/histogram_macros.h" #include "storage/browser/quota/quota_manager.h" @@ -29,16 +30,12 @@ const double kUsageRatioToStartEviction = 0.7; const int kThresholdOfErrorsToStopEviction = 5; const int kHistogramReportIntervalMinutes = 60; -const double kMustRemainAvailableRatio = 0.1; -const int64_t kDefaultMustRemainAvailableSpace = 1024 * kMBytes; + const double kDiskSpaceShortageAllowanceRatio = 0.5; } namespace storage { -const int QuotaTemporaryStorageEvictor:: - kMinAvailableToStartEvictionNotSpecified = -1; - QuotaTemporaryStorageEvictor::EvictionRoundStatistics::EvictionRoundStatistics() : in_round(false), is_initialized(false), @@ -52,11 +49,9 @@ QuotaTemporaryStorageEvictor::QuotaTemporaryStorageEvictor( QuotaEvictionHandler* quota_eviction_handler, int64_t interval_ms) - : min_available_to_start_eviction_( - kMinAvailableToStartEvictionNotSpecified), - quota_eviction_handler_(quota_eviction_handler), + : quota_eviction_handler_(quota_eviction_handler), interval_ms_(interval_ms), - repeated_eviction_(true), + timer_disabled_for_testing_(false), weak_factory_(this) { DCHECK(quota_eviction_handler); } @@ -142,6 +137,8 @@ void QuotaTemporaryStorageEvictor::Start() { DCHECK(CalledOnValidThread()); + + base::AutoReset<bool> auto_reset(&timer_disabled_for_testing_, false); StartEvictionTimerWithDelay(0); if (histogram_timer_.IsRunning()) @@ -153,7 +150,7 @@ } void QuotaTemporaryStorageEvictor::StartEvictionTimerWithDelay(int delay_ms) { - if (eviction_timer_.IsRunning()) + if (eviction_timer_.IsRunning() || timer_disabled_for_testing_) return; eviction_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms), this, &QuotaTemporaryStorageEvictor::ConsiderEviction); @@ -161,66 +158,49 @@ void QuotaTemporaryStorageEvictor::ConsiderEviction() { OnEvictionRoundStarted(); - - if (min_available_to_start_eviction_ == - kMinAvailableToStartEvictionNotSpecified) { - quota_eviction_handler_->AsyncGetVolumeInfo( - base::Bind(&QuotaTemporaryStorageEvictor::OnGotVolumeInfo, - weak_factory_.GetWeakPtr())); - } else { - quota_eviction_handler_->GetUsageAndQuotaForEviction( - base::Bind(&QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction, - weak_factory_.GetWeakPtr(), - min_available_to_start_eviction_)); - } + quota_eviction_handler_->GetEvictionRoundInfo( + base::Bind(&QuotaTemporaryStorageEvictor::OnGotEvictionRoundInfo, + weak_factory_.GetWeakPtr())); } -void QuotaTemporaryStorageEvictor::OnGotVolumeInfo( - bool success, uint64_t available_space, uint64_t total_size) { - // Compute how much to keep free as a function of total disk size. - int64_t must_remain_available_space = success ? - static_cast<int64_t>(total_size * kMustRemainAvailableRatio) : - kDefaultMustRemainAvailableSpace; - - quota_eviction_handler_->GetUsageAndQuotaForEviction( - base::Bind(&QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction, - weak_factory_.GetWeakPtr(), must_remain_available_space)); -} - -void QuotaTemporaryStorageEvictor::OnGotUsageAndQuotaForEviction( - int64_t must_remain_available_space, +void QuotaTemporaryStorageEvictor::OnGotEvictionRoundInfo( QuotaStatusCode status, - const UsageAndQuota& qau) { - DCHECK(CalledOnValidThread()); + const QuotaSettings& settings, + int64_t available_space, + int64_t total_space, + int64_t current_usage, + bool current_usage_is_complete) { + DCHECK_GE(current_usage, 0); - int64_t usage = qau.global_limited_usage; - DCHECK_GE(usage, 0); + // Note: if there is no storage pressure, |current_usage| + // may not be fully calculated and may be 0. if (status != kQuotaStatusOk) ++statistics_.num_errors_on_getting_usage_and_quota; int64_t usage_overage = std::max( static_cast<int64_t>(0), - usage - static_cast<int64_t>(qau.quota * kUsageRatioToStartEviction)); - - int64_t diskspace_shortage = std::max( - static_cast<int64_t>(0), - must_remain_available_space - qau.available_disk_space); + current_usage - static_cast<int64_t>(settings.pool_size * + kUsageRatioToStartEviction)); + int64_t diskspace_shortage = + std::max(static_cast<int64_t>(0), + settings.must_remain_available - available_space); + DCHECK(current_usage_is_complete || diskspace_shortage == 0); // If we're using so little that freeing all of it wouldn't help, // don't let the low space condition cause us to delete it all. - if (usage < static_cast<int64_t>(diskspace_shortage * - kDiskSpaceShortageAllowanceRatio)) { + if (current_usage < static_cast<int64_t>(diskspace_shortage * + kDiskSpaceShortageAllowanceRatio)) { diskspace_shortage = 0; } if (!round_statistics_.is_initialized) { round_statistics_.usage_overage_at_round = usage_overage; round_statistics_.diskspace_shortage_at_round = diskspace_shortage; - round_statistics_.usage_on_beginning_of_round = usage; + round_statistics_.usage_on_beginning_of_round = current_usage; round_statistics_.is_initialized = true; } - round_statistics_.usage_on_end_of_round = usage; + round_statistics_.usage_on_end_of_round = current_usage; int64_t amount_to_evict = std::max(usage_overage, diskspace_shortage); if (status == kQuotaStatusOk && amount_to_evict > 0) { @@ -228,33 +208,31 @@ // TODO(michaeln): if the reason for eviction is low physical disk space, // make 'unlimited' origins subject to eviction too. quota_eviction_handler_->GetEvictionOrigin( - kStorageTypeTemporary, in_progress_eviction_origins_, qau.quota, + kStorageTypeTemporary, in_progress_eviction_origins_, + settings.pool_size, base::Bind(&QuotaTemporaryStorageEvictor::OnGotEvictionOrigin, weak_factory_.GetWeakPtr())); - } else { - if (repeated_eviction_) { - // No action required, sleep for a while and check again later. - if (statistics_.num_errors_on_getting_usage_and_quota < - kThresholdOfErrorsToStopEviction) { - StartEvictionTimerWithDelay(interval_ms_); - } else { - // TODO(dmikurube): Try restarting eviction after a while. - LOG(WARNING) << "Stopped eviction of temporary storage due to errors " - "in GetUsageAndQuotaForEviction."; - } - } - OnEvictionRoundFinished(); + return; } - // TODO(dmikurube): Add error handling for the case status != kQuotaStatusOk. + // No action required, sleep for a while and check again later. + if (statistics_.num_errors_on_getting_usage_and_quota < + kThresholdOfErrorsToStopEviction) { + StartEvictionTimerWithDelay(interval_ms_); + } else { + // TODO(dmikurube): Add error handling for the case status is not OK. + // TODO(dmikurube): Try restarting eviction after a while. + LOG(WARNING) << "Stopped eviction of temporary storage due to errors"; + } + + OnEvictionRoundFinished(); } void QuotaTemporaryStorageEvictor::OnGotEvictionOrigin(const GURL& origin) { DCHECK(CalledOnValidThread()); if (origin.is_empty()) { - if (repeated_eviction_) - StartEvictionTimerWithDelay(interval_ms_); + StartEvictionTimerWithDelay(interval_ms_); OnEvictionRoundFinished(); return; } @@ -284,10 +262,8 @@ ConsiderEviction(); } else { ++statistics_.num_errors_on_evicting_origin; - if (repeated_eviction_) { - // Sleep for a while and retry again until we see too many errors. - StartEvictionTimerWithDelay(interval_ms_); - } + // Sleep for a while and retry again until we see too many errors. + StartEvictionTimerWithDelay(interval_ms_); OnEvictionRoundFinished(); } }
diff --git a/storage/browser/quota/quota_temporary_storage_evictor.h b/storage/browser/quota/quota_temporary_storage_evictor.h index 8039426..187d3396 100644 --- a/storage/browser/quota/quota_temporary_storage_evictor.h +++ b/storage/browser/quota/quota_temporary_storage_evictor.h
@@ -27,7 +27,7 @@ namespace storage { class QuotaEvictionHandler; -struct UsageAndQuota; +struct QuotaSettings; class STORAGE_EXPORT QuotaTemporaryStorageEvictor : public base::NonThreadSafe { public: @@ -78,41 +78,23 @@ void ReportPerHourHistogram(); void Start(); - void reset_min_available_disk_space_to_start_eviction() { - min_available_to_start_eviction_ = - kMinAvailableToStartEvictionNotSpecified; - } - void set_min_available_disk_space_to_start_eviction(int64_t value) { - min_available_to_start_eviction_ = value; - } - private: friend class content::QuotaTemporaryStorageEvictorTest; void StartEvictionTimerWithDelay(int delay_ms); void ConsiderEviction(); - void OnGotVolumeInfo(bool success, - uint64_t available_space, - uint64_t total_size); - void OnGotUsageAndQuotaForEviction( - int64_t must_remain_available_space, - QuotaStatusCode status, - const UsageAndQuota& quota_and_usage); + void OnGotEvictionRoundInfo(QuotaStatusCode status, + const QuotaSettings& settings, + int64_t available_space, + int64_t total_space, + int64_t current_usage, + bool current_usage_is_complete); void OnGotEvictionOrigin(const GURL& origin); void OnEvictionComplete(QuotaStatusCode status); void OnEvictionRoundStarted(); void OnEvictionRoundFinished(); - // This is only used for tests. - void set_repeated_eviction(bool repeated_eviction) { - repeated_eviction_ = repeated_eviction; - } - - static const int kMinAvailableToStartEvictionNotSpecified; - - int64_t min_available_to_start_eviction_; - // Not owned; quota_eviction_handler owns us. QuotaEvictionHandler* quota_eviction_handler_; @@ -124,7 +106,7 @@ std::set<GURL> in_progress_eviction_origins_; int64_t interval_ms_; - bool repeated_eviction_; + bool timer_disabled_for_testing_; base::OneShotTimer eviction_timer_; base::RepeatingTimer histogram_timer_;
diff --git a/storage/browser/quota/special_storage_policy.h b/storage/browser/quota/special_storage_policy.h index 5c97806a..cac9f94 100644 --- a/storage/browser/quota/special_storage_policy.h +++ b/storage/browser/quota/special_storage_policy.h
@@ -51,10 +51,6 @@ // Durable storage is not subject to storage pressure eviction. virtual bool IsStorageDurable(const GURL& origin) = 0; - // Some origins (e.g. installed apps) have access to the size of the remaining - // disk capacity. - virtual bool CanQueryDiskSize(const GURL& origin) = 0; - // Checks if the origin contains per-site isolated storage. virtual bool HasIsolatedStorage(const GURL& origin) = 0;
diff --git a/storage/browser/quota/usage_tracker.cc b/storage/browser/quota/usage_tracker.cc index 041f940..a29004e 100644 --- a/storage/browser/quota/usage_tracker.cc +++ b/storage/browser/quota/usage_tracker.cc
@@ -136,6 +136,13 @@ client_tracker->UpdateUsageCache(origin, delta); } +int64_t UsageTracker::GetCachedUsage() const { + int64_t usage = 0; + for (const auto& client_id_and_tracker : client_tracker_map_) + usage += client_id_and_tracker.second->GetCachedUsage(); + return usage; +} + void UsageTracker::GetCachedHostsUsage( std::map<std::string, int64_t>* host_usage) const { DCHECK(host_usage);
diff --git a/storage/browser/quota/usage_tracker.h b/storage/browser/quota/usage_tracker.h index 074b4f54..343fab6 100644 --- a/storage/browser/quota/usage_tracker.h +++ b/storage/browser/quota/usage_tracker.h
@@ -47,8 +47,9 @@ void UpdateUsageCache(QuotaClient::ID client_id, const GURL& origin, int64_t delta); - void GetCachedOriginsUsage(std::map<GURL, int64_t>* origin_usage) const; + int64_t GetCachedUsage() const; void GetCachedHostsUsage(std::map<std::string, int64_t>* host_usage) const; + void GetCachedOriginsUsage(std::map<GURL, int64_t>* origin_usage) const; void GetCachedOrigins(std::set<GURL>* origins) const; bool IsWorking() const { return global_usage_callbacks_.HasCallbacks() ||
diff --git a/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter b/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter index 34912ff..7cae62b5 100644 --- a/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter +++ b/testing/buildbot/filters/browser-side-navigation.linux.browser_tests.filter
@@ -1,5 +1,11 @@ -ChromeServiceWorkerTest.FallbackMainResourceRequestWhenJSDisabled +# NavigationHandle::IsRendererInitiated some times return differently in +# browser side navigation tests. +-SBNavigationObserverBrowserTest.NewTabDownload +-SBNavigationObserverBrowserTest.NewTabDownloadWithDataURL +-SBNavigationObserverBrowserTest.SubFrameNewTabDownload + # https://crbug.com/652767: NavigationHandle::GetResponseHeaders sometimes # returns null for browser-side navigations -PageLoadMetricsBrowserTest.Ignore204Pages
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index a5e7220..f831891 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1924,7 +1924,6 @@ crbug.com/659917 virtual/mojo-loading/http/tests/xmlhttprequest/workers/xmlhttprequest-response-type-blob-sync.html [ Pass Timeout ] crbug.com/659917 virtual/mojo-loading/http/tests/xmlhttprequest/workers/shared-worker-response-type-blob-sync.html [ Pass Timeout ] -crbug.com/669357 virtual/mojo-loading/http/tests/inspector/network/network-fetch.html [ Failure ] crbug.com/669357 virtual/mojo-loading/http/tests/inspector-protocol/network-data-length.html [ Failure ] crbug.com/669357 virtual/mojo-loading/http/tests/inspector/network/network-datareceived.html [ Failure ] crbug.com/669357 virtual/mojo-loading/http/tests/inspector/tracing/timeline-receive-response-event.html [ Failure ] @@ -2215,4 +2214,4 @@ # Added 2016-12-14 crbug.com/674048 [ Linux ] virtual/mojo-loading/http/tests/navigation/image-load-in-unload-handler.html [ Pass Timeout ] -crbug.com/674123 virtual/threaded/animations/animation-direction-normal.html [ Failure Timeout ] +crbug.com/674396 [ Win ] compositing/reflections/nested-reflection-transition.html [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-normal-expected.html b/third_party/WebKit/LayoutTests/animations/animation-direction-normal-expected.html deleted file mode 100644 index 8db4550..0000000 --- a/third_party/WebKit/LayoutTests/animations/animation-direction-normal-expected.html +++ /dev/null
@@ -1,43 +0,0 @@ -<html lang="en"> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <title>Test of animation-direction</title> - <style type="text/css" media="screen"> - body { - margin: 0; - } - - #box { - position: absolute; - left: 0px; - top: 100px; - height: 100px; - width: 100px; - background-color: red; - margin: 0; - transform: translateX(50px); - } - #safezone { - position: absolute; - top: 100px; - height: 100px; - width: 130px; - left: 30px; - background-color: green; - } - </style> - </script> -</head> -<body> -<!-- This tests the operation of animation-direction. After 1 second the red boxes should be hidden by the green boxes. You should see no red boxes. --> -<div id="box"></div> -<div id="safezone"></div> -<div id="result"> -Warning this test is running in real-time and may be flaky.<br> -PASS - "transform" property for "box" element at 0.5s saw something close to: 1,0,0,1,50,0<br> -PASS - "transform" property for "box" element at 1s saw something close to: 1,0,0,1,100,0<br> -PASS - "transform" property for "box" element at 2.5s saw something close to: 1,0,0,1,50,0 -</div> -</div> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/animations/animation-direction-normal.html b/third_party/WebKit/LayoutTests/animations/animation-direction-normal.html index a1f31bd..feb0adba 100644 --- a/third_party/WebKit/LayoutTests/animations/animation-direction-normal.html +++ b/third_party/WebKit/LayoutTests/animations/animation-direction-normal.html
@@ -1,67 +1,39 @@ -<html lang="en"> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> - <title>Test of animation-direction</title> - <style type="text/css" media="screen"> - body { - margin: 0; - } - - #box { - position: absolute; - left: 0px; - top: 100px; - height: 100px; - width: 100px; - background-color: red; - margin: 0; - animation-duration: 2s; +<!DOCTYPE html> +<title>Test of animation-direction</title> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<style> + #target { animation-direction: normal; + animation-duration: 2s; animation-iteration-count: 2; - animation-timing-function: linear; animation-name: move1; - } - #safezone { + animation-play-state: paused; + animation-timing-function: linear; + background-color: red; + height: 100px; + left: 0px; + margin: 0; position: absolute; top: 100px; - height: 100px; - width: 130px; - left: 30px; - background-color: green; + width: 100px; } @keyframes move1 { - from { transform: translateX(0px); } - to { transform: translateX(200px); } - } - </style> - <script src="resources/animation-test-helpers.js" type="text/javascript" charset="utf-8"></script> - <script type="text/javascript" charset="utf-8"> - const expectedValues = [ - // [time, element-id, property, expected-value, tolerance] - [0.5, "box", "transform", [1,0,0,1, 50,0], 20], - [1.0, "box", "transform", [1,0,0,1,100,0], 20], - [2.5, "box", "transform", [1,0,0,1, 50,0], 20], - ]; - - function pauseAnimation() - { - document.getElementById("box").style.animationPlayState = "paused"; + from { left: 0px; } + to { left: 200px; } } - function setTimers() - { - setTimeout(pauseAnimation, 2500); - } +</style> +<div id="target"></div> +<script> + test(function() { + target.style.animationDelay = '-0.5s'; + assert_equals(getComputedStyle(target).left, '50px'); - runAnimationTest(expectedValues, setTimers, null, true, true); + target.style.animationDelay = '-1s'; + assert_equals(getComputedStyle(target).left, '100px'); - </script> -</head> -<body> -<!-- This tests the operation of animation-direction. After 1 second the red boxes should be hidden by the green boxes. You should see no red boxes. --> -<div id="box"></div> -<div id="safezone"></div> -<div id="result"></div> -</div> -</body> -</html> + target.style.animationDelay = '-2.5s'; + assert_equals(getComputedStyle(target).left, '50px'); + }, "animation-direction normal plays forwards"); +</script>
diff --git a/third_party/WebKit/LayoutTests/animations/transition-zoomed-length.html b/third_party/WebKit/LayoutTests/animations/transition-zoomed-length.html new file mode 100644 index 0000000..6a8e9f4f --- /dev/null +++ b/third_party/WebKit/LayoutTests/animations/transition-zoomed-length.html
@@ -0,0 +1,83 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<style> +#target { + transition: 1s; + border-style: solid; + outline-style: solid; + column-rule-style: solid; +} +</style> +<div id="target"></div> +<script> +var lengthProperties = [ + 'baselineShift', + 'borderBottomWidth', + 'borderLeftWidth', + 'borderRightWidth', + 'borderTopWidth', + 'bottom', + 'cx', + 'cy', + 'flexBasis', + 'height', + 'left', + 'letterSpacing', + 'marginBottom', + 'marginLeft', + 'marginRight', + 'marginTop', + 'maxHeight', + 'maxWidth', + 'minHeight', + 'minWidth', + 'offsetDistance', + 'outlineOffset', + 'outlineWidth', + 'paddingBottom', + 'paddingLeft', + 'paddingRight', + 'paddingTop', + 'perspective', + 'r', + 'right', + 'rx', + 'ry', + 'shapeMargin', + 'strokeDashoffset', + 'strokeWidth', + 'top', + 'verticalAlign', + 'webkitBorderHorizontalSpacing', + 'webkitBorderVerticalSpacing', + 'columnGap', + 'columnRuleWidth', + 'columnWidth', + 'webkitPerspectiveOriginX', + 'webkitPerspectiveOriginY', + 'webkitTransformOriginX', + 'webkitTransformOriginY', + 'webkitTransformOriginZ', + 'width', + 'wordSpacing', + 'x', + 'y', + 'lineHeight', +]; +var expected = {}; + +setup(() => { + for (var property of lengthProperties) { + target.style[property] = '10px'; + expected[property] = getComputedStyle(target)[property]; + } + internals.setZoomFactor(2); +}); + +for (var property of lengthProperties) { + test(() => { + assert_equals(getComputedStyle(target)[property], expected[property]); + }, 'Computed value of transitionable ' + property + ' should not change when zoom changes'); +} +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/independent-inheritance-fast-path.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/independent-inheritance-fast-path.html index f8ad807..f444407 100644 --- a/third_party/WebKit/LayoutTests/fast/css/invalidation/independent-inheritance-fast-path.html +++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/independent-inheritance-fast-path.html
@@ -19,6 +19,7 @@ ["emptyCells", "show", "hide"], ["captionSide", "left", "right"], ["listStylePosition", "outside", "inside"], + ["webkitBoxDirection", "normal", "reverse"], ]; independent_properties.forEach(function(test_data)
diff --git a/third_party/WebKit/LayoutTests/fast/forms/associatedFormControls-leak-nodes-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/associatedFormControls-leak-nodes-expected.txt deleted file mode 100644 index ae3ed3f8..0000000 --- a/third_party/WebKit/LayoutTests/fast/forms/associatedFormControls-leak-nodes-expected.txt +++ /dev/null
@@ -1,5 +0,0 @@ -PASS documentsBefore - 1 is documentsAfter -PASS successfullyParsed is true - -TEST COMPLETE -
diff --git a/third_party/WebKit/LayoutTests/fast/forms/associatedFormControls-leak-nodes.html b/third_party/WebKit/LayoutTests/fast/forms/associatedFormControls-leak-nodes.html deleted file mode 100644 index d1eed450..0000000 --- a/third_party/WebKit/LayoutTests/fast/forms/associatedFormControls-leak-nodes.html +++ /dev/null
@@ -1,40 +0,0 @@ -<!DOCTYPE html> -<html> -<body> -<iframe id="frame"></iframe> - -<script src="../../resources/js-test.js"></script> -<script> -if (!window.internals) { - debug("This test only runs on \"content_shell --run-layout-test\", as it requires existence of window.internals."); -} else { - testRunner.waitUntilDone(); - window.jsTestIsAsync = true; - var documentsBefore; - var documentsAfter; - // FIXME(keishi): Calling asyncGC twice to fix flakiness, crbug.com/674194 - asyncGC(function() { - asyncGC(function() { - documentsBefore = window.internals.numberOfLiveDocuments(); - - var frame = document.getElementById('frame'); - frame.contentDocument.body.innerHTML = '<form></form>'; - document.body.removeChild(frame); - frame = null; - - // FIXME(keishi): crbug.com/674194 - asyncGC(function() { - asyncGC(function() { - documentsAfter = window.internals.numberOfLiveDocuments(); - - // -1 is from removing frame itself. - shouldBe('documentsBefore - 1', 'documentsAfter'); - finishJSTest(); - }); - }); - }); - }); -} -</script> -</body> -</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/cache/location-reload.html b/third_party/WebKit/LayoutTests/http/tests/cache/location-reload.html new file mode 100644 index 0000000..ded56b6 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/cache/location-reload.html
@@ -0,0 +1,40 @@ +<!DOCYUPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script> + +async_test(t => { + let testWindow = null; + let messageCount = 0; + + // Test will run on testWindow that is opened below. + // This page just received messages to confirm if tests run expectedly. + const checkReady = e => { + t.step(() => { + // Will receive "READY" twice because of a reload, then receive "PASS". + assert_equals(e.data, "READY", "received message is " + e.data); + messageCount++; + + if (messageCount == 2) { + window.removeEventListener("message", checkReady, false); + window.addEventListener("message", e => { + assert_equals(e.data, "PASS", "received message is " + e.data); + t.done(); + }, { once: true }); + } + + // Send back "START" message for "READY". + assert_class_string(testWindow, "Window", "testWindow is invalid"); + testWindow.postMessage("START", location.origin); + }); + }; + window.addEventListener("message", checkReady, false); + + // Start a test in a dedicated window because we can not track navigations + // within a test harness. + t.step(() => { + testWindow = open("./resources/location-reload-window.html", "testWindow"); + assert_class_string(testWindow, "Window", "window.open() failed"); + }); +}, "Test location.reload() cache behaviors"); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/cache/resources/location-reload-window.html b/third_party/WebKit/LayoutTests/http/tests/cache/resources/location-reload-window.html new file mode 100644 index 0000000..71b5970 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/cache/resources/location-reload-window.html
@@ -0,0 +1,48 @@ +<!DOCTYPE html> +<html> +<body> +<h1>random</h1> +<script src="./random-cached.cgi"></script> +<script> +const lastRandomNumberKey = "lastRandomNumber"; + +window.addEventListener("message", e => { + if (e.data != "START") { + window.opener.postMessage("FAIL: unknown; " + e.data, location.origin); + } else { + // window.top.randomNumber should be set by random-cached.cgi. + if (window.top === undefined || window.top.randomNumber === undefined) { + window.opener.postMessage("FAIL: randomNumber isn't defined", + location.origin); + return; + } + + // If location.reload() is already triggered, lastRandomNumberKey should be + // stored in the sessionStorage. Otherwise, this is the first load. + const lastRandomNumberString = sessionStorage.getItem(lastRandomNumberKey); + if (lastRandomNumberString !== null) { + // sessionStorage returns DOMString and need to be converted to Number. + const lastRandomNumber = Number(lastRandomNumberString); + + // Because the random-cached.cgi is a sub-resource, and set HTTP headers + // to allow caching, location.reload() should follow the cache-protocol to + // reuse the cached resource. That is to say the randomNumber should not + // be changed on the reload. + window.opener.postMessage(lastRandomNumber == top.randomNumber + ? "PASS" + : "FAIL: randomNumber was changed", + location.origin); + } else { + // Store the first randomNumber to the sessionStorage, and call reload(). + // This window will send "READY" again, then receive "START". + sessionStorage.setItem(lastRandomNumberKey, top.randomNumber); + location.reload(); + } + } +}, false); + +// Send "READY" message first so that parent window can ensure to send messages. +window.opener.postMessage("READY", location.origin); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/network-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/network-test.js index 470d3d7..92ccdd6 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/network-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/network-test.js
@@ -45,7 +45,11 @@ function makeFetch(url, requestInitializer) { - return fetch(url, requestInitializer).catch(e => e); + return fetch(url, requestInitializer).then(res => { + // Call text(). Otherwise the backpressure mechanism may block loading. + res.text(); + return res; + }).catch(e => e); } var initialize_NetworkTest = function() {
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-sync-content-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-sync-content-expected.txt index 1e5de22..65a221a 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-sync-content-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-sync-content-expected.txt
@@ -18,6 +18,10 @@ network code: 'window.foo4 = 4;' fileSystem code: 'window.foo4 = 4;' +Running: resetFileSystemWorkingCopy +network code: 'window.foo3 = 3;' +fileSystem code: 'window.foo3 = 3;' + Running: setNetworkRevision network code: 'window.foo2 = 2;' fileSystem code: 'window.foo2 = 2;'
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-sync-content.html b/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-sync-content.html index fd57e59e..c4aef5d 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-sync-content.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/persistence/persistence-sync-content.html
@@ -46,6 +46,12 @@ fileSystemCode.setWorkingCopy("window.foo4 = 4;"); }, + function resetFileSystemWorkingCopy(next) + { + InspectorTest.addSniffer(Persistence.Persistence.prototype, "_contentSyncedForTest", dumpWorkingCopiesAndNext.bind(null, next)); + fileSystemCode.resetWorkingCopy(); + }, + function setNetworkRevision(next) { InspectorTest.addSniffer(Persistence.Persistence.prototype, "_contentSyncedForTest", dumpWorkingCopiesAndNext.bind(null, next));
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js index 0adef3b..c1ad4c83 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
@@ -410,6 +410,40 @@ InspectorTest.addArray(TimelineModel.InvalidationTracker.invalidationEventsFor(record._event), InspectorTest.InvalidationFormatters, "", comment); } +InspectorTest.dumpFlameChartProvider = function(provider, includeGroups) +{ + var includeGroupsSet = includeGroups && new Set(includeGroups); + var timelineData = provider.timelineData(); + var stackDepth = provider.maxStackDepth(); + var entriesByLevel = new Multimap(); + + for (let i = 0; i < timelineData.entryLevels.length; ++i) + entriesByLevel.set(timelineData.entryLevels[i], i); + + for (let groupIndex = 0; groupIndex < timelineData.groups.length; ++groupIndex) { + const group = timelineData.groups[groupIndex]; + if (includeGroupsSet && !includeGroupsSet.has(group.name)) + continue; + var maxLevel = groupIndex + 1 < timelineData.groups.length ? timelineData.groups[groupIndex + 1].firstLevel : stackDepth; + InspectorTest.addResult(`Group: ${group.name}`); + for (let level = group.startLevel; level < maxLevel; ++level) { + InspectorTest.addResult(`Level ${level - group.startLevel}`); + var entries = entriesByLevel.get(level); + for (const index of entries) { + const title = provider.entryTitle(index); + const color = provider.entryColor(index); + InspectorTest.addResult(`${title} (${color})`); + } + } + } +} + +InspectorTest.dumpTimelineFlameChart = function(includeGroups) { + const provider = UI.panels.timeline._flameChart._dataProvider; + InspectorTest.addResult('Timeline Flame Chart'); + InspectorTest.dumpFlameChartProvider(provider, includeGroups); +} + InspectorTest.FakeFileReader.prototype = { start: function(output) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/tracing/timeline-network-received-data.html b/third_party/WebKit/LayoutTests/http/tests/inspector/tracing/timeline-network-received-data.html index 298ea98d..eb3a42e 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/tracing/timeline-network-received-data.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/tracing/timeline-network-received-data.html
@@ -8,11 +8,13 @@ { var image = new Image(); var imagePromise = new Promise((fulfill) => image.onload = fulfill); - image.src = "resources/anImage.png"; + // Use random urls to avoid caching. + const random = Math.random(); + image.src = "resources/anImage.png?random=" + random; var scriptPromise = new Promise((fulfill) => window.timelineNetworkResourceEvaluated = fulfill); var script = document.createElement("script"); - script.src = "resources/timeline-network-resource.js"; + script.src = "resources/timeline-network-resource.js?randome=" + random; document.body.appendChild(script); return Promise.all([imagePromise, scriptPromise]);
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/tracing/timeline-receive-response-event.html b/third_party/WebKit/LayoutTests/http/tests/inspector/tracing/timeline-receive-response-event.html index c20c40a..7ec1251 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/tracing/timeline-receive-response-event.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/tracing/timeline-receive-response-event.html
@@ -10,13 +10,15 @@ var promise = new Promise((fulfill) => callback = fulfill); var image = new Image(); image.onload = bar; - image.src = "resources/anImage.png"; + // Use random urls to avoid caching. + const random = Math.random(); + image.src = "resources/anImage.png?random=" + random; function bar() { var image = new Image(); image.onload = function(event) { callback(); } // do not pass event argument to the callback. - image.src = "resources/anotherImage.png"; + image.src = "resources/anotherImage.png?random=" + random; } return promise; }
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/css-outline.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/css-outline.html index 1590dd8..91db7b90 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/css-outline.html +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/css-outline.html
@@ -60,17 +60,17 @@ function test() { - function onStyleSheetParsed(rules) + function onRulesParsed(isLastChunk, rules) { for (var i = 0; i < rules.length; ++i) InspectorTest.addObject(rules[i]); - InspectorTest.completeTest(); + if (isLastChunk) + InspectorTest.completeTest(); } function onStyleFetched(result) { - var parser = new SDK.CSSParser(); - parser.parse(result.value, onStyleSheetParsed); + Common.formatterWorkerPool.parseCSS(result.value, onRulesParsed); } InspectorTest.evaluateInPage("getCSS()", onStyleFetched);
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-timeline-api-expected.txt b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-timeline-api-expected.txt index 7bb476b..d920e90 100644 --- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-timeline-api-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-timeline-api-expected.txt
@@ -3,6 +3,7 @@ Started extension. Running tests... RUNNING TEST: extension_testTimeline +TraceProvider: { onRecordingStarted : { addListener : <function> @@ -13,7 +14,21 @@ removeListener : <function> } } +Provider short display name: extension trace provider +Provider long display name: long extension name traceProvider.onRecordingStarted fired. +TracingSession: +{ + complete : <function> +} traceProvider.onRecordingStopped fired. +Timeline Flame Chart +Group: long extension name +Level 0 +Extension record X 1 (hsla(261, 82%, 70%, 0.7)) +Extension record X 2 (hsla(230, 88%, 70%, 0.7)) +Level 1 +Extension record I 1 (hsla(298, 100%, 70%, 0.7)) +Extension record B+E (hsla(292, 100%, 70%, 0.7)) All tests done.
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-timeline-api.html b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-timeline-api.html index 1ed18900..c216f2a 100644 --- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-timeline-api.html +++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-timeline-api.html
@@ -5,33 +5,82 @@ <script src="../../http/tests/inspector/timeline-test.js"></script> <script type="text/javascript"> +function initialize_timelineExtensionTest() +{ + +InspectorTest.enableTimelineExtensionAndStart = function(callback) { + const provider = Extensions.extensionServer.traceProviders().peekLast(); + const timelinePanel = UI.panels.timeline; + const setting = Timeline.TimelinePanel._settingForTraceProvider(provider); + setting.set(true); + InspectorTest.addResult(`Provider short display name: ${provider.shortDisplayName()}`); + InspectorTest.addResult(`Provider long display name: ${provider.longDisplayName()}`); + InspectorTest.startTimeline(callback); +} + +} + function extension_testTimeline(nextTest) { - function onRecordingStarted() + var session; + var sessionTimeOffset; + var startTime; + + function onRecordingStarted(s) { + sessionTimeOffset = (Date.now() - performance.now()) * 1000; + startTime = performance.now(); output("traceProvider.onRecordingStarted fired."); - } - function onRecordingStopped() - { + output("TracingSession:"); + dumpObject(s); + session = s; + } + + function onRecordingStopped() + { output("traceProvider.onRecordingStopped fired."); - nextTest(); + + const endTime = performance.now(); + var pid = 1; + var tid = 1; + var step = (endTime - startTime) * 1000 / 10; + var start = startTime * 1000; + var data = { "traceEvents": [ + {"name": "Extension record X 1", "ts": start, "dur": step * 4, "ph": "X", "args": {}, "tid": tid, "pid": pid, "cat":"" }, + {"name": "Extension record X 2", "ts": start + step * 5, "dur": step * 5, "ph": "X", "args": {}, "tid": tid, "pid": pid, "cat":"" }, + {"name": "Extension record I 1", "ts": start + step * 5.5, "ph": "I", "args": {}, "tid": tid, "pid": pid, "cat":"" }, + {"name": "Extension record B+E", "ts": start + step * 6, "ph": "B", "args": {}, "tid": tid, "pid": pid, "cat":"" }, + {"name": "Extension record B+E", "ts": start + step * 10, "ph": "E", "args": {}, "tid": tid, "pid": pid, "cat":"" } + ]}; + var url = "data:application/json," + escape(JSON.stringify(data)); + session.complete(url, sessionTimeOffset); } - var traceProvider = webInspector.timeline.addTraceProvider("extension trace provider", "tooltip"); + + var traceProvider = webInspector.timeline.addTraceProvider("extension trace provider", "long extension name"); + output("TraceProvider:"); dumpObject(traceProvider); traceProvider.onRecordingStarted.addListener(onRecordingStarted); traceProvider.onRecordingStopped.addListener(onRecordingStopped); - extension_startTimeline(() => extension_stopTimeline(() => {})); + extension_startTimeline( + () => extension_stopTimeline( + () => extension_dumpFlameChart(nextTest))); } function extension_startTimeline(callback) { - evaluateOnFrontend("InspectorTest.startTimeline(reply);", callback); + evaluateOnFrontend("InspectorTest.enableTimelineExtensionAndStart(reply);", callback); } function extension_stopTimeline(callback) { evaluateOnFrontend("InspectorTest.stopTimeline(reply);", callback); } + +function extension_dumpFlameChart(callback) +{ + evaluateOnFrontend("InspectorTest.dumpTimelineFlameChart(['long extension name']); reply()", callback); +} + </script> </head> <body onload="runTest()">
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage.html b/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage.html index 0e2ec1a..a7309171 100644 --- a/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage.html +++ b/third_party/WebKit/LayoutTests/inspector/tracing/buffer-usage.html
@@ -43,13 +43,11 @@ { InspectorTest.addResult("TimelineLifecycleDelegate.loadingComplete"); InspectorTest.completeTest(); - }, - - __proto__: Timeline.TimelineLifecycleDelegate + } }; var controller = new Timeline.TimelineController(SDK.targetManager.mainTarget(), new TestTimelineLifecycleDelegate(), InspectorTest.createTracingModel()); - controller.startRecording(); + controller.startRecording({}, []); } </script>
diff --git a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py index b88d4132..6bda8f46 100755 --- a/third_party/WebKit/Source/build/scripts/make_computed_style_base.py +++ b/third_party/WebKit/Source/build/scripts/make_computed_style_base.py
@@ -88,7 +88,7 @@ self._fields = [] for property in self._properties.values(): if property['keyword_only']: - property_name = property['upper_camel_name'] + property_name = property['name_for_methods'] if property['name_for_methods']: property_name = property['name_for_methods'] property_name_lower = property_name[0].lower() + property_name[1:] @@ -106,7 +106,7 @@ # If the property is independent, add the single-bit sized isInherited flag # to the list of Fields as well. if property['independent']: - field_name_suffix_upper = property['upper_camel_name'] + 'IsInherited' + field_name_suffix_upper = property['name_for_methods'] + 'IsInherited' field_name_suffix_lower = property_name_lower + 'IsInherited' self._fields.append(Field( 'inherited_flag',
diff --git a/third_party/WebKit/Source/core/BUILD.gn b/third_party/WebKit/Source/core/BUILD.gn index e32d036..cbd2e0fb 100644 --- a/third_party/WebKit/Source/core/BUILD.gn +++ b/third_party/WebKit/Source/core/BUILD.gn
@@ -1145,6 +1145,7 @@ "html/HTMLImageElementTest.cpp", "html/HTMLInputElementTest.cpp", "html/HTMLLinkElementSizesAttributeTest.cpp", + "html/HTMLLinkElementTest.cpp", "html/HTMLMediaElementTest.cpp", "html/HTMLOutputElementTest.cpp", "html/HTMLSelectElementTest.cpp",
diff --git a/third_party/WebKit/Source/core/animation/BUILD.gn b/third_party/WebKit/Source/core/animation/BUILD.gn index b72f1034..029004a 100644 --- a/third_party/WebKit/Source/core/animation/BUILD.gn +++ b/third_party/WebKit/Source/core/animation/BUILD.gn
@@ -56,8 +56,8 @@ "CSSLengthPairInterpolationType.h", "CSSNumberInterpolationType.cpp", "CSSNumberInterpolationType.h", - "CSSOffsetRotationInterpolationType.cpp", - "CSSOffsetRotationInterpolationType.h", + "CSSOffsetRotateInterpolationType.cpp", + "CSSOffsetRotateInterpolationType.h", "CSSPaintInterpolationType.cpp", "CSSPaintInterpolationType.h", "CSSPathInterpolationType.cpp",
diff --git a/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp index f67ad6f..7622bb5 100644 --- a/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp +++ b/third_party/WebKit/Source/core/animation/CSSInterpolationTypesMap.cpp
@@ -18,7 +18,7 @@ #include "core/animation/CSSLengthListInterpolationType.h" #include "core/animation/CSSLengthPairInterpolationType.h" #include "core/animation/CSSNumberInterpolationType.h" -#include "core/animation/CSSOffsetRotationInterpolationType.h" +#include "core/animation/CSSOffsetRotateInterpolationType.h" #include "core/animation/CSSPaintInterpolationType.h" #include "core/animation/CSSPathInterpolationType.h" #include "core/animation/CSSPositionAxisListInterpolationType.h" @@ -197,7 +197,7 @@ case CSSPropertyOffsetRotation: case CSSPropertyOffsetRotate: applicableTypes->push_back( - WTF::makeUnique<CSSOffsetRotationInterpolationType>(usedProperty)); + WTF::makeUnique<CSSOffsetRotateInterpolationType>(usedProperty)); break; case CSSPropertyBackgroundPositionX: case CSSPropertyBackgroundPositionY:
diff --git a/third_party/WebKit/Source/core/animation/CSSOffsetRotationInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSOffsetRotateInterpolationType.cpp similarity index 89% rename from third_party/WebKit/Source/core/animation/CSSOffsetRotationInterpolationType.cpp rename to third_party/WebKit/Source/core/animation/CSSOffsetRotateInterpolationType.cpp index 3c76b9db..f1d1d08 100644 --- a/third_party/WebKit/Source/core/animation/CSSOffsetRotationInterpolationType.cpp +++ b/third_party/WebKit/Source/core/animation/CSSOffsetRotateInterpolationType.cpp
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "core/animation/CSSOffsetRotationInterpolationType.h" +#include "core/animation/CSSOffsetRotateInterpolationType.h" #include "core/css/resolver/StyleBuilderConverter.h" #include "core/style/StyleOffsetRotation.h" @@ -90,7 +90,7 @@ } // namespace -InterpolationValue CSSOffsetRotationInterpolationType::maybeConvertNeutral( +InterpolationValue CSSOffsetRotateInterpolationType::maybeConvertNeutral( const InterpolationValue& underlying, ConversionCheckers& conversionCheckers) const { OffsetRotationType underlyingRotationType = @@ -101,13 +101,13 @@ return convertOffsetRotate(StyleOffsetRotation(0, underlyingRotationType)); } -InterpolationValue CSSOffsetRotationInterpolationType::maybeConvertInitial( +InterpolationValue CSSOffsetRotateInterpolationType::maybeConvertInitial( const StyleResolverState&, ConversionCheckers& conversionCheckers) const { return convertOffsetRotate(StyleOffsetRotation(0, OffsetRotationAuto)); } -InterpolationValue CSSOffsetRotationInterpolationType::maybeConvertInherit( +InterpolationValue CSSOffsetRotateInterpolationType::maybeConvertInherit( const StyleResolverState& state, ConversionCheckers& conversionCheckers) const { OffsetRotationType inheritedRotationType = @@ -117,15 +117,14 @@ return convertOffsetRotate(state.parentStyle()->offsetRotation()); } -InterpolationValue CSSOffsetRotationInterpolationType::maybeConvertValue( +InterpolationValue CSSOffsetRotateInterpolationType::maybeConvertValue( const CSSValue& value, const StyleResolverState&, ConversionCheckers&) const { return convertOffsetRotate(StyleBuilderConverter::convertOffsetRotate(value)); } -PairwiseInterpolationValue -CSSOffsetRotationInterpolationType::maybeMergeSingles( +PairwiseInterpolationValue CSSOffsetRotateInterpolationType::maybeMergeSingles( InterpolationValue&& start, InterpolationValue&& end) const { const OffsetRotationType& startType = @@ -142,12 +141,12 @@ } InterpolationValue -CSSOffsetRotationInterpolationType::maybeConvertUnderlyingValue( +CSSOffsetRotateInterpolationType::maybeConvertUnderlyingValue( const InterpolationEnvironment& environment) const { return convertOffsetRotate(environment.state().style()->offsetRotation()); } -void CSSOffsetRotationInterpolationType::composite( +void CSSOffsetRotateInterpolationType::composite( UnderlyingValueOwner& underlyingValueOwner, double underlyingFraction, const InterpolationValue& value, @@ -159,14 +158,15 @@ const OffsetRotationType& rotationType = toCSSOffsetRotationNonInterpolableValue(*value.nonInterpolableValue) .rotationType(); - if (underlyingType == rotationType) + if (underlyingType == rotationType) { underlyingValueOwner.mutableValue().interpolableValue->scaleAndAdd( underlyingFraction, *value.interpolableValue); - else + } else { underlyingValueOwner.set(*this, value); + } } -void CSSOffsetRotationInterpolationType::apply( +void CSSOffsetRotateInterpolationType::apply( const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, InterpolationEnvironment& environment) const {
diff --git a/third_party/WebKit/Source/core/animation/CSSOffsetRotationInterpolationType.h b/third_party/WebKit/Source/core/animation/CSSOffsetRotateInterpolationType.h similarity index 85% rename from third_party/WebKit/Source/core/animation/CSSOffsetRotationInterpolationType.h rename to third_party/WebKit/Source/core/animation/CSSOffsetRotateInterpolationType.h index d83662c1..060b4bd 100644 --- a/third_party/WebKit/Source/core/animation/CSSOffsetRotationInterpolationType.h +++ b/third_party/WebKit/Source/core/animation/CSSOffsetRotateInterpolationType.h
@@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CSSOffsetRotationInterpolationType_h -#define CSSOffsetRotationInterpolationType_h +#ifndef CSSOffsetRotateInterpolationType_h +#define CSSOffsetRotateInterpolationType_h #include "core/animation/CSSInterpolationType.h" namespace blink { -class CSSOffsetRotationInterpolationType : public CSSInterpolationType { +class CSSOffsetRotateInterpolationType : public CSSInterpolationType { public: - CSSOffsetRotationInterpolationType(PropertyHandle property) + CSSOffsetRotateInterpolationType(PropertyHandle property) : CSSInterpolationType(property) { DCHECK(cssProperty() == CSSPropertyOffsetRotate || cssProperty() == CSSPropertyOffsetRotation); @@ -44,4 +44,4 @@ } // namespace blink -#endif // CSSOffsetRotationInterpolationType_h +#endif // CSSOffsetRotateInterpolationType_h
diff --git a/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp b/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp index 8f455bf..57e060c 100644 --- a/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp +++ b/third_party/WebKit/Source/core/animation/css/CSSAnimatableValueFactory.cpp
@@ -31,6 +31,7 @@ #include "core/animation/css/CSSAnimatableValueFactory.h" #include "core/CSSValueKeywords.h" +#include "core/animation/LengthPropertyFunctions.h" #include "core/animation/animatable/AnimatableClipPathOperation.h" #include "core/animation/animatable/AnimatableColor.h" #include "core/animation/animatable/AnimatableDouble.h" @@ -96,6 +97,15 @@ return createFromLengthWithZoom(length, style.effectiveZoom()); } +static PassRefPtr<AnimatableValue> createFromPropertyLength( + CSSPropertyID property, + const ComputedStyle& style) { + Length length; + bool success = LengthPropertyFunctions::getLength(property, style, length); + DCHECK(success); + return createFromLength(length, style); +} + static PassRefPtr<AnimatableValue> createFromUnzoomedLength( const UnzoomedLength& unzoomedLength) { return createFromLengthWithZoom(unzoomedLength.length(), 1); @@ -175,7 +185,7 @@ return AnimatableLengthPoint3D::create( createFromLength(transformOrigin.x(), style), createFromLength(transformOrigin.y(), style), - createFromDouble(transformOrigin.z())); + createFromLength(Length(transformOrigin.z(), Fixed), style)); } inline static PassRefPtr<AnimatableValue> createFromLengthSize( @@ -371,7 +381,7 @@ case CSSPropertyBorderBottomRightRadius: return createFromLengthSize(style.borderBottomRightRadius(), style); case CSSPropertyBorderBottomWidth: - return createFromDouble(style.borderBottomWidth()); + return createFromPropertyLength(property, style); case CSSPropertyBorderImageOutset: return createFromBorderImageLengthBox(style.borderImageOutset(), style); case CSSPropertyBorderImageSlice: @@ -384,11 +394,11 @@ case CSSPropertyBorderLeftColor: return createFromColor(property, style); case CSSPropertyBorderLeftWidth: - return createFromDouble(style.borderLeftWidth()); + return createFromPropertyLength(property, style); case CSSPropertyBorderRightColor: return createFromColor(property, style); case CSSPropertyBorderRightWidth: - return createFromDouble(style.borderRightWidth()); + return createFromPropertyLength(property, style); case CSSPropertyBorderTopColor: return createFromColor(property, style); case CSSPropertyBorderTopLeftRadius: @@ -396,7 +406,7 @@ case CSSPropertyBorderTopRightRadius: return createFromLengthSize(style.borderTopRightRadius(), style); case CSSPropertyBorderTopWidth: - return createFromDouble(style.borderTopWidth()); + return createFromPropertyLength(property, style); case CSSPropertyBottom: return createFromLength(style.bottom(), style); case CSSPropertyBoxShadow: @@ -454,7 +464,7 @@ case CSSPropertyLeft: return createFromLength(style.left(), style); case CSSPropertyLetterSpacing: - return createFromDouble(style.letterSpacing()); + return createFromPropertyLength(property, style); case CSSPropertyLineHeight: return createFromLineHeight(style.specifiedLineHeight(), style); case CSSPropertyMarginBottom: @@ -482,9 +492,9 @@ case CSSPropertyOutlineColor: return createFromColor(property, style); case CSSPropertyOutlineOffset: - return createFromDouble(style.outlineOffset()); + return createFromPropertyLength(property, style); case CSSPropertyOutlineWidth: - return createFromDouble(style.outlineWidth()); + return createFromPropertyLength(property, style); case CSSPropertyPaddingBottom: return createFromLength(style.paddingBottom(), style); case CSSPropertyPaddingLeft: @@ -527,9 +537,9 @@ case CSSPropertyTop: return createFromLength(style.top(), style); case CSSPropertyWebkitBorderHorizontalSpacing: - return createFromDouble(style.horizontalBorderSpacing()); + return createFromPropertyLength(property, style); case CSSPropertyWebkitBorderVerticalSpacing: - return createFromDouble(style.verticalBorderSpacing()); + return createFromPropertyLength(property, style); case CSSPropertyClipPath: if (ClipPathOperation* operation = style.clipPath()) return AnimatableClipPathOperation::create(operation); @@ -539,15 +549,15 @@ return AnimatableUnknown::create(CSSValueAuto); return createFromDouble(style.columnCount()); case CSSPropertyColumnGap: - return createFromDouble(style.columnGap()); + return createFromPropertyLength(property, style); case CSSPropertyColumnRuleColor: return createFromColor(property, style); case CSSPropertyColumnRuleWidth: - return createFromDouble(style.columnRuleWidth()); + return createFromPropertyLength(property, style); case CSSPropertyColumnWidth: if (style.hasAutoColumnWidth()) return AnimatableUnknown::create(CSSValueAuto); - return createFromDouble(style.columnWidth()); + return createFromPropertyLength(property, style); case CSSPropertyFilter: return AnimatableFilterOperations::create(style.filter()); case CSSPropertyBackdropFilter: @@ -578,7 +588,7 @@ return AnimatableUnknown::create( CSSIdentifierValue::create(CSSValueNone)); } - return createFromDouble(style.perspective()); + return createFromPropertyLength(property, style); case CSSPropertyPerspectiveOrigin: return createFromLengthPoint(style.perspectiveOrigin(), style); case CSSPropertyShapeOutside: @@ -636,13 +646,13 @@ case CSSPropertyWebkitTransformOriginY: return createFromLength(style.transformOriginY(), style); case CSSPropertyWebkitTransformOriginZ: - return createFromDouble(style.transformOriginZ()); + return createFromPropertyLength(property, style); case CSSPropertyWidows: return createFromDouble(style.widows()); case CSSPropertyWidth: return createFromLength(style.width(), style); case CSSPropertyWordSpacing: - return createFromDouble(style.wordSpacing()); + return createFromPropertyLength(property, style); case CSSPropertyVerticalAlign: if (style.verticalAlign() == VerticalAlignLength) return createFromLength(style.getVerticalAlignLength(), style);
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.in b/third_party/WebKit/Source/core/css/CSSProperties.in index 195e410d..42bb4f7 100644 --- a/third_party/WebKit/Source/core/css/CSSProperties.in +++ b/third_party/WebKit/Source/core/css/CSSProperties.in
@@ -397,7 +397,7 @@ -webkit-border-vertical-spacing interpolable, inherited, name_for_methods=VerticalBorderSpacing, converter=convertComputedLength<short> -webkit-box-align type_name=EBoxAlignment -webkit-box-decoration-break --webkit-box-direction inherited, keyword_only, keywords=[normal|reverse], initial_keyword=normal +-webkit-box-direction inherited, independent, keyword_only, keywords=[normal|reverse], initial_keyword=normal -webkit-box-flex type_name=float -webkit-box-flex-group type_name=unsigned int -webkit-box-lines
diff --git a/third_party/WebKit/Source/core/css/resolver/AnimatedStyleBuilder.cpp b/third_party/WebKit/Source/core/css/resolver/AnimatedStyleBuilder.cpp index c2b859e..d64c35f 100644 --- a/third_party/WebKit/Source/core/css/resolver/AnimatedStyleBuilder.cpp +++ b/third_party/WebKit/Source/core/css/resolver/AnimatedStyleBuilder.cpp
@@ -102,24 +102,31 @@ return Length(Auto); } -template <typename T> -T animatableValueClampTo(const AnimatableValue* value, - T min = defaultMinimumForClamp<T>(), - T max = defaultMaximumForClamp<T>()) { - static_assert(std::is_integral<T>::value, - "should use integral type T when rounding values"); - return clampTo<T>( - roundForImpreciseConversion<T>(toAnimatableDouble(value)->toDouble()), - min, max); +double animatableValueToPixels(const AnimatableValue* value, + const StyleResolverState& state) { + return toAnimatableLength(value) + ->getLength(state.style()->effectiveZoom(), ValueRangeAll) + .pixels(); } template <typename T> -T animatableLineWidthClamp(const AnimatableValue* value) { - double doubleValue = toAnimatableDouble(value)->toDouble(); +T roundedClampTo(double value) { + static_assert(std::is_integral<T>::value, + "should use integral type T when rounding values"); + return clampTo<T>(roundForImpreciseConversion<T>(value)); +} + +template <typename T> +T animatableValueClampTo(const AnimatableValue* value) { + return roundedClampTo<T>(toAnimatableDouble(value)->toDouble()); +} + +template <typename T> +T animatableLineWidthClamp(const AnimatableValue* value, + const StyleResolverState& state) { + double lineWidth = animatableValueToPixels(value, state); // This matches StyleBuilderConverter::convertLineWidth(). - return (doubleValue > 0 && doubleValue < 1) - ? 1 - : animatableValueClampTo<T>(value); + return (lineWidth > 0 && lineWidth < 1) ? 1 : roundedClampTo<T>(lineWidth); } LengthBox animatableValueToLengthBox(const AnimatableValue* value, @@ -163,8 +170,7 @@ return TransformOrigin( animatableValueToLength(animatableLengthPoint3D->x(), state), animatableValueToLength(animatableLengthPoint3D->y(), state), - clampTo<float>( - toAnimatableDouble(animatableLengthPoint3D->z())->toDouble())); + animatableValueToPixels(animatableLengthPoint3D->z(), state)); } LengthSize animatableValueToLengthSize(const AnimatableValue* value, @@ -352,7 +358,8 @@ animatableValueToLengthSize(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderBottomWidth: - style->setBorderBottomWidth(animatableLineWidthClamp<unsigned>(value)); + style->setBorderBottomWidth( + animatableLineWidthClamp<unsigned>(value, state)); return; case CSSPropertyBorderImageOutset: style->setBorderImageOutset( @@ -379,7 +386,8 @@ toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyBorderLeftWidth: - style->setBorderLeftWidth(animatableLineWidthClamp<unsigned>(value)); + style->setBorderLeftWidth( + animatableLineWidthClamp<unsigned>(value, state)); return; case CSSPropertyBorderRightColor: style->setBorderRightColor(toAnimatableColor(value)->getColor()); @@ -387,7 +395,8 @@ toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyBorderRightWidth: - style->setBorderRightWidth(animatableLineWidthClamp<unsigned>(value)); + style->setBorderRightWidth( + animatableLineWidthClamp<unsigned>(value, state)); return; case CSSPropertyBorderTopColor: style->setBorderTopColor(toAnimatableColor(value)->getColor()); @@ -403,7 +412,8 @@ animatableValueToLengthSize(value, state, ValueRangeNonNegative)); return; case CSSPropertyBorderTopWidth: - style->setBorderTopWidth(animatableLineWidthClamp<unsigned>(value)); + style->setBorderTopWidth( + animatableLineWidthClamp<unsigned>(value, state)); return; case CSSPropertyBottom: style->setBottom(animatableValueToLength(value, state)); @@ -488,7 +498,7 @@ return; case CSSPropertyLetterSpacing: style->setLetterSpacing( - clampTo<float>(toAnimatableDouble(value)->toDouble())); + clampTo<float>(animatableValueToPixels(value, state))); return; case CSSPropertyMarginBottom: style->setMarginBottom(animatableValueToLength(value, state)); @@ -536,10 +546,12 @@ toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyOutlineOffset: - style->setOutlineOffset(animatableValueClampTo<int>(value)); + style->setOutlineOffset( + roundedClampTo<int>(animatableValueToPixels(value, state))); return; case CSSPropertyOutlineWidth: - style->setOutlineWidth(animatableLineWidthClamp<unsigned short>(value)); + style->setOutlineWidth( + animatableLineWidthClamp<unsigned short>(value, state)); return; case CSSPropertyPaddingBottom: style->setPaddingBottom( @@ -612,12 +624,12 @@ style->setTop(animatableValueToLength(value, state)); return; case CSSPropertyWebkitBorderHorizontalSpacing: - style->setHorizontalBorderSpacing( - animatableValueClampTo<unsigned short>(value)); + style->setHorizontalBorderSpacing(roundedClampTo<unsigned short>( + animatableValueToPixels(value, state))); return; case CSSPropertyWebkitBorderVerticalSpacing: - style->setVerticalBorderSpacing( - animatableValueClampTo<unsigned short>(value)); + style->setVerticalBorderSpacing(roundedClampTo<unsigned short>( + animatableValueToPixels(value, state))); return; case CSSPropertyClipPath: style->setClipPath( @@ -628,7 +640,7 @@ round(toAnimatableDouble(value)->toDouble()), 1)); return; case CSSPropertyColumnGap: - style->setColumnGap(clampTo(toAnimatableDouble(value)->toDouble(), 0)); + style->setColumnGap(clampTo(animatableValueToPixels(value, state), 0)); return; case CSSPropertyColumnRuleColor: style->setColumnRuleColor(toAnimatableColor(value)->getColor()); @@ -636,12 +648,12 @@ toAnimatableColor(value)->visitedLinkColor()); return; case CSSPropertyColumnWidth: - style->setColumnWidth(clampTo(toAnimatableDouble(value)->toDouble(), + style->setColumnWidth(clampTo(animatableValueToPixels(value, state), std::numeric_limits<float>::epsilon())); return; case CSSPropertyColumnRuleWidth: style->setColumnRuleWidth( - animatableLineWidthClamp<unsigned short>(value)); + animatableLineWidthClamp<unsigned short>(value, state)); return; case CSSPropertyFilter: style->setFilter(toAnimatableFilterOperations(value)->operations()); @@ -687,8 +699,8 @@ return; case CSSPropertyPerspective: style->setPerspective( - value->isDouble() - ? clampTo<float>(toAnimatableDouble(value)->toDouble()) + value->isLength() + ? clampTo<float>(animatableValueToPixels(value, state)) : 0); return; case CSSPropertyPerspectiveOrigin: @@ -782,7 +794,7 @@ style->setTransformOriginY(animatableValueToLength(value, state)); return; case CSSPropertyWebkitTransformOriginZ: - style->setTransformOriginZ(toAnimatableDouble(value)->toDouble()); + style->setTransformOriginZ(animatableValueToPixels(value, state)); return; case CSSPropertyWidows: style->setWidows( @@ -794,7 +806,7 @@ return; case CSSPropertyWordSpacing: style->setWordSpacing( - clampTo<float>(toAnimatableDouble(value)->toDouble())); + clampTo<float>(animatableValueToPixels(value, state))); return; case CSSPropertyVerticalAlign: style->setVerticalAlignLength(animatableValueToLength(value, state));
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp index a8b6dff..82343bab 100644 --- a/third_party/WebKit/Source/core/editing/Editor.cpp +++ b/third_party/WebKit/Source/core/editing/Editor.cpp
@@ -1665,6 +1665,14 @@ // TODO(tkent): Should we check and move Text node children of <html>? } +void Editor::replaceSelection(const String& text) { + DCHECK(!frame().document()->needsLayoutTreeUpdate()); + bool selectReplacement = behavior().shouldSelectReplacement(); + bool smartReplace = true; + replaceSelectionWithText(text, selectReplacement, smartReplace, + InputEvent::InputType::InsertReplacementText); +} + DEFINE_TRACE(Editor) { visitor->trace(m_frame); visitor->trace(m_lastEditCommand);
diff --git a/third_party/WebKit/Source/core/editing/Editor.h b/third_party/WebKit/Source/core/editing/Editor.h index 41a5b49a..eedc2c7 100644 --- a/third_party/WebKit/Source/core/editing/Editor.h +++ b/third_party/WebKit/Source/core/editing/Editor.h
@@ -261,7 +261,9 @@ bool smartReplace, InputEvent::InputType); - // TODO(xiaochengh): Replace |bool| parameters by |enum|. + // Implementation of WebLocalFrameImpl::replaceSelection. + void replaceSelection(const String&); + void replaceSelectionAfterDragging(DocumentFragment*, InsertMode, DragSourceType);
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp index 94d2d7cc..56fb4484 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.cpp
@@ -1039,14 +1039,6 @@ m_spellCheckRequester->cancelCheck(); } -void SpellChecker::requestTextChecking(const Element& element) { - if (!element.isSpellCheckingEnabled()) - return; - const EphemeralRange rangeToCheck = EphemeralRange::rangeOfContents(element); - m_spellCheckRequester->requestCheckingFor( - SpellCheckRequest::create(rangeToCheck)); -} - DEFINE_TRACE(SpellChecker) { visitor->trace(m_frame); visitor->trace(m_spellCheckRequester);
diff --git a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h index 952fed7..2f1d8eb2 100644 --- a/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h +++ b/third_party/WebKit/Source/core/editing/spellcheck/SpellChecker.h
@@ -83,7 +83,6 @@ void updateMarkersForWordsAffectedByEditing( bool onlyHandleWordsContainingSelection); void cancelCheck(); - void requestTextChecking(const Element&); // Exposed for testing only SpellCheckRequester& spellCheckRequester() const {
diff --git a/third_party/WebKit/Source/core/frame/History.cpp b/third_party/WebKit/Source/core/frame/History.cpp index 470ca160..56494e9 100644 --- a/third_party/WebKit/Source/core/frame/History.cpp +++ b/third_party/WebKit/Source/core/frame/History.cpp
@@ -145,14 +145,19 @@ if (!NavigationDisablerForUnload::isNavigationAllowed()) return; - // We intentionally call reload() for the current frame if delta is zero. - // Otherwise, navigation happens on the root frame. - // This behavior is designed in the following spec. - // https://html.spec.whatwg.org/multipage/browsers.html#dom-history-go - if (delta) + if (delta) { frame()->loader().client()->navigateBackForward(delta); - else - frame()->reload(FrameLoadTypeReload, ClientRedirectPolicy::ClientRedirect); + } else { + // We intentionally call reload() for the current frame if delta is zero. + // Otherwise, navigation happens on the root frame. + // This behavior is designed in the following spec. + // https://html.spec.whatwg.org/multipage/browsers.html#dom-history-go + FrameLoadType reloadType = + RuntimeEnabledFeatures::fasterLocationReloadEnabled() + ? FrameLoadTypeReloadMainResource + : FrameLoadTypeReload; + frame()->reload(reloadType, ClientRedirectPolicy::ClientRedirect); + } } KURL History::urlForState(const String& urlString) {
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp index c5b21581..67220a3 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp +++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -377,7 +377,10 @@ request.setClientRedirect(clientRedirectPolicy); m_loader.load(request, loadType); } else { - DCHECK_EQ(FrameLoadTypeReload, loadType); + if (RuntimeEnabledFeatures::fasterLocationReloadEnabled()) + DCHECK_EQ(FrameLoadTypeReloadMainResource, loadType); + else + DCHECK_EQ(FrameLoadTypeReload, loadType); m_navigationScheduler->scheduleReload(); } }
diff --git a/third_party/WebKit/Source/core/frame/Location.cpp b/third_party/WebKit/Source/core/frame/Location.cpp index dd3626c..37a04e2b 100644 --- a/third_party/WebKit/Source/core/frame/Location.cpp +++ b/third_party/WebKit/Source/core/frame/Location.cpp
@@ -248,7 +248,11 @@ return; if (protocolIsJavaScript(toLocalFrame(m_frame)->document()->url())) return; - m_frame->reload(FrameLoadTypeReload, ClientRedirectPolicy::ClientRedirect); + FrameLoadType reloadType = + RuntimeEnabledFeatures::fasterLocationReloadEnabled() + ? FrameLoadTypeReloadMainResource + : FrameLoadTypeReload; + m_frame->reload(reloadType, ClientRedirectPolicy::ClientRedirect); } void Location::setLocation(const String& url,
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp index e3baf91..ae4f4dd 100644 --- a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
@@ -324,7 +324,10 @@ } KURL HTMLLinkElement::href() const { - return document().completeURL(getAttribute(hrefAttr)); + const String& url = getAttribute(hrefAttr); + if (url.isEmpty()) + return KURL(); + return document().completeURL(url); } const AtomicString& HTMLLinkElement::rel() const {
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElementTest.cpp b/third_party/WebKit/Source/core/html/HTMLLinkElementTest.cpp new file mode 100644 index 0000000..e73be25 --- /dev/null +++ b/third_party/WebKit/Source/core/html/HTMLLinkElementTest.cpp
@@ -0,0 +1,41 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/html/HTMLLinkElement.h" + +#include "core/dom/Document.h" +#include "core/frame/FrameView.h" +#include "core/html/HTMLHeadElement.h" +#include "core/testing/DummyPageHolder.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +class HTMLLinkElementTest : public ::testing::Test { + protected: + void SetUp() override; + Document& document() const { return m_dummyPageHolder->document(); } + + private: + std::unique_ptr<DummyPageHolder> m_dummyPageHolder; +}; + +void HTMLLinkElementTest::SetUp() { + m_dummyPageHolder = DummyPageHolder::create(IntSize(800, 600)); +} + +// This tests that we should ignore empty string value +// in href attribute value of the link element. +TEST_F(HTMLLinkElementTest, EmptyHrefAttribute) { + document().documentElement()->setInnerHTML( + "<head>" + "<link rel=\"icon\" type=\"image/ico\" href=\"\" />" + "</head>"); + HTMLLinkElement* linkElement = + toElement<HTMLLinkElement>(document().head()->firstChild()); + EXPECT_EQ(KURL(), linkElement->href()); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp b/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp index 0abc6a5..a7740dee 100644 --- a/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp +++ b/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp
@@ -271,7 +271,10 @@ request.setClientRedirect(ClientRedirectPolicy::ClientRedirect); maybeLogScheduledNavigationClobber(ScheduledNavigationType::ScheduledReload, frame); - frame->loader().load(request, FrameLoadTypeReload); + if (RuntimeEnabledFeatures::fasterLocationReloadEnabled()) + frame->loader().load(request, FrameLoadTypeReloadMainResource); + else + frame->loader().load(request, FrameLoadTypeReload); } private:
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp b/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp index 85b1f075..f499ed5 100644 --- a/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp +++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerTest.cpp
@@ -3,11 +3,13 @@ // found in the LICENSE file. #include "core/events/MessageEvent.h" +#include "core/inspector/ConsoleMessageStorage.h" #include "core/testing/DummyPageHolder.h" #include "core/workers/DedicatedWorkerGlobalScope.h" #include "core/workers/DedicatedWorkerThread.h" #include "core/workers/InProcessWorkerMessagingProxy.h" #include "core/workers/InProcessWorkerObjectProxy.h" +#include "core/workers/WorkerInspectorProxy.h" #include "core/workers/WorkerThread.h" #include "core/workers/WorkerThreadStartupData.h" #include "core/workers/WorkerThreadTestHelper.h" @@ -52,6 +54,33 @@ std::move(startupData->m_starterOriginPrivilegeData), std::move(startupData->m_workerClients)); } + + // Emulates API use on DedicatedWorkerGlobalScope. + void countFeature(UseCounter::Feature feature) { + EXPECT_TRUE(isCurrentThread()); + globalScope()->countFeature(feature); + workerReportingProxy() + .getParentFrameTaskRunners() + ->get(TaskType::Internal) + ->postTask(BLINK_FROM_HERE, crossThreadBind(&testing::exitRunLoop)); + } + + // Emulates deprecated API use on DedicatedWorkerGlobalScope. + void countDeprecation(UseCounter::Feature feature) { + EXPECT_TRUE(isCurrentThread()); + EXPECT_EQ(0u, consoleMessageStorage()->size()); + globalScope()->countDeprecation(feature); + + // countDeprecation() should add a warning message. + EXPECT_EQ(1u, consoleMessageStorage()->size()); + String consoleMessage = consoleMessageStorage()->at(0)->message(); + EXPECT_TRUE(consoleMessage.contains("deprecated")); + + workerReportingProxy() + .getParentFrameTaskRunners() + ->get(TaskType::Internal) + ->postTask(BLINK_FROM_HERE, crossThreadBind(&testing::exitRunLoop)); + } }; class InProcessWorkerMessagingProxyForTest @@ -71,8 +100,6 @@ m_workerThread = WTF::wrapUnique( new DedicatedWorkerThreadForTest(m_mockWorkerLoaderProxyProvider.get(), workerObjectProxy(), threadHeapMode)); - workerThreadCreated(); - m_mockWorkerThreadLifecycleObserver = new MockWorkerThreadLifecycleObserver( m_workerThread->getWorkerThreadLifecycleContext()); EXPECT_CALL(*m_mockWorkerThreadLifecycleObserver, contextDestroyed()) @@ -85,6 +112,27 @@ m_mockWorkerLoaderProxyProvider.get()); } + void startWithSourceCode(const String& source) { + KURL scriptURL(ParsedURLString, "http://fake.url/"); + m_securityOrigin = SecurityOrigin::create(scriptURL); + std::unique_ptr<Vector<CSPHeaderAndType>> headers = + WTF::makeUnique<Vector<CSPHeaderAndType>>(); + CSPHeaderAndType headerAndType("contentSecurityPolicy", + ContentSecurityPolicyHeaderTypeReport); + headers->append(headerAndType); + workerThread()->start(WorkerThreadStartupData::create( + scriptURL, "fake user agent", source, nullptr /* cachedMetaData */, + DontPauseWorkerGlobalScopeOnStart, headers.get(), + "" /* referrerPolicy */, m_securityOrigin.get(), + nullptr /* workerClients */, WebAddressSpaceLocal, + nullptr /* originTrialTokens */, nullptr /* workerSettings */, + V8CacheOptionsDefault)); + + workerInspectorProxy()->workerThreadCreated( + toDocument(getExecutionContext()), m_workerThread.get(), scriptURL); + workerThreadCreated(); + } + enum class Notification { MessageConfirmed, PendingActivityReported, @@ -145,6 +193,7 @@ m_mockWorkerLoaderProxyProvider; Persistent<MockWorkerThreadLifecycleObserver> m_mockWorkerThreadLifecycleObserver; + RefPtr<SecurityOrigin> m_securityOrigin; WTF::Deque<Notification> m_events; bool m_blocking = false; @@ -162,8 +211,6 @@ m_workerMessagingProxy = WTF::wrapUnique(new InProcessWorkerMessagingProxyForTest( &m_page->document(), m_threadHeapMode)); - m_securityOrigin = - SecurityOrigin::create(KURL(ParsedURLString, "http://fake.url/")); } void TearDown() override { @@ -172,21 +219,6 @@ workerMessagingProxy()->waitForNotification()); } - void startWithSourceCode(const String& source) { - std::unique_ptr<Vector<CSPHeaderAndType>> headers = - WTF::makeUnique<Vector<CSPHeaderAndType>>(); - CSPHeaderAndType headerAndType("contentSecurityPolicy", - ContentSecurityPolicyHeaderTypeReport); - headers->append(headerAndType); - workerThread()->start(WorkerThreadStartupData::create( - KURL(ParsedURLString, "http://fake.url/"), "fake user agent", source, - nullptr /* cachedMetaData */, DontPauseWorkerGlobalScopeOnStart, - headers.get(), "" /* referrerPolicy */, m_securityOrigin.get(), - nullptr /* workerClients */, WebAddressSpaceLocal, - nullptr /* originTrialTokens */, nullptr /* workerSettings */, - V8CacheOptionsDefault)); - } - void dispatchMessageEvent() { workerMessagingProxy()->postMessageToWorkerGlobalScope( nullptr /* message */, nullptr /* channels */); @@ -200,8 +232,9 @@ return m_workerMessagingProxy->workerThread(); } + Document& document() { return m_page->document(); } + private: - RefPtr<SecurityOrigin> m_securityOrigin; std::unique_ptr<DummyPageHolder> m_page; std::unique_ptr<InProcessWorkerMessagingProxyForTest> m_workerMessagingProxy; const BlinkGC::ThreadHeapMode m_threadHeapMode; @@ -217,7 +250,7 @@ TEST_P(DedicatedWorkerTest, PendingActivity_NoActivity) { const String sourceCode = "// Do nothing"; - startWithSourceCode(sourceCode); + workerMessagingProxy()->startWithSourceCode(sourceCode); // Worker initialization should be counted as a pending activity. EXPECT_TRUE(workerMessagingProxy()->hasPendingActivity()); @@ -231,7 +264,7 @@ TEST_P(DedicatedWorkerTest, PendingActivity_SetTimeout) { // Start an oneshot timer on initial script evaluation. const String sourceCode = "setTimeout(function() {}, 0);"; - startWithSourceCode(sourceCode); + workerMessagingProxy()->startWithSourceCode(sourceCode); // Worker initialization should be counted as a pending activity. EXPECT_TRUE(workerMessagingProxy()->hasPendingActivity()); @@ -250,7 +283,7 @@ const String sourceCode = "var id = setInterval(function() {}, 50);" "addEventListener('message', function(event) { clearInterval(id); });"; - startWithSourceCode(sourceCode); + workerMessagingProxy()->startWithSourceCode(sourceCode); // Worker initialization should be counted as a pending activity. EXPECT_TRUE(workerMessagingProxy()->hasPendingActivity()); @@ -276,7 +309,7 @@ "addEventListener('message', function(event) {" " setTimeout(function() {}, 0);" "});"; - startWithSourceCode(sourceCode); + workerMessagingProxy()->startWithSourceCode(sourceCode); // Worker initialization should be counted as a pending activity. EXPECT_TRUE(workerMessagingProxy()->hasPendingActivity()); @@ -314,7 +347,7 @@ " clearInterval(id);" " }" "});"; - startWithSourceCode(sourceCode); + workerMessagingProxy()->startWithSourceCode(sourceCode); // Worker initialization should be counted as a pending activity. EXPECT_TRUE(workerMessagingProxy()->hasPendingActivity()); @@ -354,4 +387,35 @@ EXPECT_FALSE(workerMessagingProxy()->hasPendingActivity()); } +TEST_P(DedicatedWorkerTest, UseCounter) { + const String sourceCode = "// Do nothing"; + workerMessagingProxy()->startWithSourceCode(sourceCode); + + // This feature is randomly selected. + const UseCounter::Feature feature1 = UseCounter::Feature::RequestFileSystem; + + // API use on the DedicatedWorkerGlobalScope should be recorded in UseCounter + // on the Document. + EXPECT_FALSE(UseCounter::isCounted(document(), feature1)); + workerThread()->postTask( + BLINK_FROM_HERE, + createCrossThreadTask(&DedicatedWorkerThreadForTest::countFeature, + crossThreadUnretained(workerThread()), feature1)); + testing::enterRunLoop(); + EXPECT_TRUE(UseCounter::isCounted(document(), feature1)); + + // This feature is randomly selected from Deprecation::deprecationMessage(). + const UseCounter::Feature feature2 = UseCounter::Feature::PrefixedStorageInfo; + + // Deprecated API use on the DedicatedWorkerGlobalScope should be recorded in + // UseCounter on the Document. + EXPECT_FALSE(UseCounter::isCounted(document(), feature2)); + workerThread()->postTask( + BLINK_FROM_HERE, + createCrossThreadTask(&DedicatedWorkerThreadForTest::countDeprecation, + crossThreadUnretained(workerThread()), feature2)); + testing::enterRunLoop(); + EXPECT_TRUE(UseCounter::isCounted(document(), feature2)); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/devtools/.eslintrc.js b/third_party/WebKit/Source/devtools/.eslintrc.js index 1e9bf34..914281a 100644 --- a/third_party/WebKit/Source/devtools/.eslintrc.js +++ b/third_party/WebKit/Source/devtools/.eslintrc.js
@@ -63,6 +63,7 @@ "no-unsafe-negation": 2, "radix": 2, "valid-typeof": 2, + "no-unused-vars": [2, { "args": "none", "vars": "local" }], // es2015 features "require-yield": 2,
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn index b9ea6471..71a4868 100644 --- a/third_party/WebKit/Source/devtools/BUILD.gn +++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -113,7 +113,6 @@ "front_end/sdk/CSSMedia.js", "front_end/sdk/CSSMetadata.js", "front_end/sdk/CSSModel.js", - "front_end/sdk/CSSParser.js", "front_end/sdk/CSSProperty.js", "front_end/sdk/CSSRule.js", "front_end/sdk/CSSStyleDeclaration.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/Tests.js b/third_party/WebKit/Source/devtools/front_end/Tests.js index 62714a8..5e94b31 100644 --- a/third_party/WebKit/Source/devtools/front_end/Tests.js +++ b/third_party/WebKit/Source/devtools/front_end/Tests.js
@@ -302,12 +302,6 @@ TestSuite.prototype.testNoScriptDuplicatesOnPanelSwitch = function() { var test = this; - // There should be two scripts: one for the main page and another - // one which is source of console API(see - // InjectedScript._ensureCommandLineAPIInstalled). - var expectedScriptsCount = 2; - var parsedScripts = []; - function switchToElementsTab() { test.showPanel('elements').then(function() { setTimeout(switchToScriptsTab, 0); @@ -573,7 +567,6 @@ this._waitForTargets(2, callback.bind(this)); function callback() { - var target = SDK.targetManager.targets(SDK.Target.Capability.JS)[0]; InspectorBackendClass.deprecatedRunAfterPendingDispatches(this.releaseControl.bind(this)); } };
diff --git a/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilityNodeView.js b/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilityNodeView.js index 3805398..88396b1 100644 --- a/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilityNodeView.js +++ b/third_party/WebKit/Source/devtools/front_end/accessibility/AccessibilityNodeView.js
@@ -347,8 +347,6 @@ */ appendIDRefValueElement(value) { var relatedNodes = value.relatedNodes; - var numNodes = relatedNodes.length; - var valueElement; var idrefs = value.value.trim().split(/\s+/); if (idrefs.length === 1) { @@ -400,7 +398,6 @@ var nameElement = createElement('span'); var AXValueSourceType = Protocol.Accessibility.AXValueSourceType; var type = source.type; - var name; switch (type) { case AXValueSourceType.Attribute: case AXValueSourceType.Placeholder:
diff --git a/third_party/WebKit/Source/devtools/front_end/animation/AnimationUI.js b/third_party/WebKit/Source/devtools/front_end/animation/AnimationUI.js index 45c161f..816766e3 100644 --- a/third_party/WebKit/Source/devtools/front_end/animation/AnimationUI.js +++ b/third_party/WebKit/Source/devtools/front_end/animation/AnimationUI.js
@@ -203,8 +203,6 @@ } redraw() { - var durationWithDelay = - this._delay() + this._duration() * this._animation.source().iterations() + this._animation.source().endDelay(); var maxWidth = this._timeline.width() - Animation.AnimationUI.Options.AnimationMargin; this._svg.setAttribute('width', (maxWidth + 2 * Animation.AnimationUI.Options.AnimationMargin).toFixed(2));
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js index 8aec3f3..78e2f4df1 100644 --- a/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js +++ b/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js
@@ -84,8 +84,6 @@ */ doRun(target, requests, result, callback, progress) { var totalSavings = 0; - var compressedSize = 0; - var candidateSize = 0; var summary = result.addChild('', true); for (var i = 0, length = requests.length; i < length; ++i) { var request = requests[i]; @@ -93,11 +91,8 @@ continue; // Do not test cached resources. if (this._shouldCompress(request)) { var size = request.resourceSize; - candidateSize += size; - if (this._isCompressed(request)) { - compressedSize += size; + if (this._isCompressed(request)) continue; - } var savings = 2 * size / 3; totalSavings += savings; summary.addFormatted('%r could save ~%s', request.url, Number.bytesToString(savings)); @@ -510,29 +505,30 @@ } run() { - this._parser = new SDK.CSSParser(); this._processNextStyleSheet(); } - _terminateWorker() { - if (this._parser) { - this._parser.dispose(); - delete this._parser; - } - } - - _finish() { - this._terminateWorker(); - this._styleSheetsParsedCallback(this._styleSheets); - } - _processNextStyleSheet() { if (!this._styleSheetHeaders.length) { - this._finish(); + this._styleSheetsParsedCallback(this._styleSheets); return; } this._currentStyleSheetHeader = this._styleSheetHeaders.shift(); - this._parser.fetchAndParse(this._currentStyleSheetHeader, this._onStyleSheetParsed.bind(this)); + + var allRules = []; + this._currentStyleSheetHeader.requestContent().then( + content => Common.formatterWorkerPool.parseCSS(content || '', onRulesParsed.bind(this))); + + /** + * @param {boolean} isLastChunk + * @param {!Array<!Common.FormatterWorkerPool.CSSRule>} rules + * @this {Audits.AuditRules.StyleSheetProcessor} + */ + function onRulesParsed(isLastChunk, rules) { + allRules.push(...rules); + if (isLastChunk) + this._onStyleSheetParsed(allRules); + } } /** @@ -540,7 +536,7 @@ */ _onStyleSheetParsed(rules) { if (this._progress.isCanceled()) { - this._finish(); + this._styleSheetsParsedCallback(this._styleSheets); return; }
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/TempFile.js b/third_party/WebKit/Source/devtools/front_end/bindings/TempFile.js index ed0573d..a402a168 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/TempFile.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/TempFile.js
@@ -463,6 +463,8 @@ this._fileSize = fileSize; } + if (!this._file) + this._file = new Bindings.DeferredTempFile(this._dirName, String(Date.now())); this._file.write(this._strings, didWrite.bind(this, chunk)); this._strings = []; this._stringsLength = 0; @@ -483,7 +485,7 @@ reset() { if (this._file) this._file.remove(); - this._file = new Bindings.DeferredTempFile(this._dirName, String(Date.now())); + this._file = null; /** * @type {!Array.<string>} */ @@ -497,7 +499,8 @@ * @param {!Bindings.OutputStreamDelegate} delegate */ writeToStream(outputStream, delegate) { - this._file.copyToOutputStream(outputStream, delegate); + if (this._file) + this._file.copyToOutputStream(outputStream, delegate); } };
diff --git a/third_party/WebKit/Source/devtools/front_end/common/Object.js b/third_party/WebKit/Source/devtools/front_end/common/Object.js index c25bcda9..cf05394 100644 --- a/third_party/WebKit/Source/devtools/front_end/common/Object.js +++ b/third_party/WebKit/Source/devtools/front_end/common/Object.js
@@ -69,13 +69,6 @@ /** * @override - */ - removeAllListeners() { - delete this._listeners; - } - - /** - * @override * @param {symbol} eventType * @return {boolean} */ @@ -144,8 +137,6 @@ */ removeEventListener(eventType, listener, thisObject) {}, - removeAllListeners() {}, - /** * @param {symbol} eventType * @return {boolean}
diff --git a/third_party/WebKit/Source/devtools/front_end/components/Spectrum.js b/third_party/WebKit/Source/devtools/front_end/components/Spectrum.js index c714b4a8..1978f6c 100644 --- a/third_party/WebKit/Source/devtools/front_end/components/Spectrum.js +++ b/third_party/WebKit/Source/devtools/front_end/components/Spectrum.js
@@ -277,9 +277,6 @@ } this._paletteContainerMutable = palette.mutable; - var numItems = palette.colors.length; - if (palette.mutable) - numItems++; if (palette.mutable) { this._paletteContainer.appendChild(this._addColorToolbar.element); this._paletteContainer.appendChild(this._deleteIconToolbar.element);
diff --git a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js index 437a4ed..8bc8645 100644 --- a/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js +++ b/third_party/WebKit/Source/devtools/front_end/console/ConsoleViewMessage.js
@@ -312,7 +312,7 @@ var contentElement = toggleElement.createChild('div', 'console-message-stack-trace-wrapper'); var messageElement = this._buildMessage(consoleMessage); - var icon = UI.Icon.create('smallicon-triangle-right', 'stack-trace-expand-icon'); + var icon = UI.Icon.create('smallicon-triangle-right'); var clickableElement = contentElement.createChild('div'); clickableElement.appendChild(icon);
diff --git a/third_party/WebKit/Source/devtools/front_end/console/consoleView.css b/third_party/WebKit/Source/devtools/front_end/console/consoleView.css index 6d7e9f8b..106de85 100644 --- a/third_party/WebKit/Source/devtools/front_end/console/consoleView.css +++ b/third_party/WebKit/Source/devtools/front_end/console/consoleView.css
@@ -366,7 +366,3 @@ .console-message-stack-trace-wrapper > * { flex: none; } - -.stack-trace-expand-icon { - background-color: rgb(110, 110, 110); -}
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js index 4b037003..56309c5 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
@@ -478,7 +478,6 @@ populateNodeContextMenu(contextMenu) { // Add free-form node-related actions. - var openTagElement = this._node[this.treeOutline.treeElementSymbol()] || this; var isEditable = this.hasEditableNode(); if (isEditable && !this._editing) contextMenu.appendItem(Common.UIString('Edit as HTML'), this._editAsHTML.bind(this));
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/EventListenersWidget.js b/third_party/WebKit/Source/devtools/front_end/elements/EventListenersWidget.js index bd334a8..c76c16d8 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/EventListenersWidget.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/EventListenersWidget.js
@@ -100,7 +100,6 @@ this._lastRequestedNode = node; var selectedNodeOnly = !this._showForAncestorsSetting.get(); var promises = []; - var listenersView = this._eventListenersView; promises.push(node.resolveToObjectPromise(Elements.EventListenersWidget._objectGroupName)); if (!selectedNodeOnly) { var currentNode = node.parentNode;
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js index dd1b2fb..4d18ad3 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
@@ -1513,7 +1513,6 @@ var oldSelectorRange = rule.selectorRange(); if (!oldSelectorRange) return Promise.resolve(); - var selectedNode = this._parentPane.node(); return rule.setSelectorText(newContent) .then(onSelectorsUpdated.bind(this, /** @type {!SDK.CSSStyleRule} */ (rule), oldSelectorRange)); } @@ -1719,7 +1718,6 @@ var oldRange = rule.key().range; if (!oldRange) return Promise.resolve(); - var selectedNode = this._parentPane.node(); return rule.setKeyText(newContent).then(updateSourceRanges.bind(this)); } @@ -2535,7 +2533,7 @@ var isEditingName = context.isEditingName; // Determine where to move to before making changes - var createNewProperty, moveToPropertyName, moveToSelector; + var createNewProperty, moveToSelector; var isDataPasted = 'originalName' in context; var isDirtyViaPaste = isDataPasted && (this.nameElement.textContent !== context.originalName || this.valueElement.textContent !== context.originalValue); @@ -2546,12 +2544,12 @@ if (moveDirection === 'forward' && (!isEditingName || isPropertySplitPaste) || moveDirection === 'backward' && isEditingName) { moveTo = moveTo._findSibling(moveDirection); - if (moveTo) - moveToPropertyName = moveTo.name; - else if (moveDirection === 'forward' && (!this._newProperty || userInput)) - createNewProperty = true; - else if (moveDirection === 'backward') - moveToSelector = true; + if (!moveTo) { + if (moveDirection === 'forward' && (!this._newProperty || userInput)) + createNewProperty = true; + else if (moveDirection === 'backward') + moveToSelector = true; + } } // Make the Changes and trigger the moveToNextCallback after updating.
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js index 12251be..0fb0077 100644 --- a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js +++ b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionAPI.js
@@ -67,6 +67,7 @@ AddRequestHeaders: 'addRequestHeaders', AddTraceProvider: 'addTraceProvider', ApplyStyleSheet: 'applyStyleSheet', + CompleteTraceSession: 'completeTraceSession', CreatePanel: 'createPanel', CreateSidebarPane: 'createSidebarPane', CreateToolbarButton: 'createToolbarButton', @@ -368,6 +369,7 @@ var PanelWithSidebar = declareInterfaceClass(PanelWithSidebarImpl); var Request = declareInterfaceClass(RequestImpl); var Resource = declareInterfaceClass(ResourceImpl); + var TraceSession = declareInterfaceClass(TraceSessionImpl); /** * @constructor @@ -505,16 +507,43 @@ * @constructor * @param {string} id */ + function TraceSessionImpl(id) { + this._id = id; + } + + TraceSessionImpl.prototype = + { + /** + * @param {string=} url + * @param {number=} timeOffset + */ + complete: function(url, timeOffset) { + var request = {command: commands.CompleteTraceSession, id: this._id, url: url || '', timeOffset: timeOffset || 0}; + extensionServer.sendRequest(request); + } + }; + + /** + * @constructor + * @param {string} id + */ function TraceProvider(id) { - this.onRecordingStarted = new EventSink(events.RecordingStarted + id); + /** + * @this {EventSinkImpl} + */ + function dispatchRecordingStarted(message) { + var sessionId = message.arguments[0]; + this._fire(new TraceSession(sessionId)); + } + + this.onRecordingStarted = new EventSink(events.RecordingStarted + id, dispatchRecordingStarted); this.onRecordingStopped = new EventSink(events.RecordingStopped + id); } /** * @constructor */ - function Audits() { - } + function Audits() {} Audits.prototype = { /**
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js index 1410c0ba..2511fdb2 100644 --- a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js +++ b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionServer.js
@@ -47,12 +47,14 @@ this._lastRequestId = 0; this._registeredExtensions = {}; this._status = new Extensions.ExtensionStatus(); - /** @type {!Array.<!Extensions.ExtensionSidebarPane>} */ + /** @type {!Array<!Extensions.ExtensionSidebarPane>} */ this._sidebarPanes = []; - /** @type {!Array.<!Extensions.ExtensionAuditCategory>} */ + /** @type {!Array<!Extensions.ExtensionAuditCategory>} */ this._auditCategories = []; - /** @type {!Array.<!Extensions.ExtensionTraceProvider>} */ + /** @type {!Array<!Extensions.ExtensionTraceProvider>} */ this._traceProviders = []; + /** @type {!Map<string, !Extensions.TracingSession>} */ + this._traceSessions = new Map(); var commands = Extensions.extensionAPI.Commands; @@ -61,6 +63,7 @@ this._registerHandler(commands.AddRequestHeaders, this._onAddRequestHeaders.bind(this)); this._registerHandler(commands.AddTraceProvider, this._onAddTraceProvider.bind(this)); this._registerHandler(commands.ApplyStyleSheet, this._onApplyStyleSheet.bind(this)); + this._registerHandler(commands.CompleteTraceSession, this._onCompleteTraceSession.bind(this)); this._registerHandler(commands.CreatePanel, this._onCreatePanel.bind(this)); this._registerHandler(commands.CreateSidebarPane, this._onCreateSidebarPane.bind(this)); this._registerHandler(commands.CreateToolbarButton, this._onCreateToolbarButton.bind(this)); @@ -164,17 +167,20 @@ } /** - * @param {string} traceProviderId + * @param {string} providerId + * @param {string} sessionId + * @param {!Extensions.TracingSession} session */ - startTraceRecording(traceProviderId) { - this._postNotification('trace-recording-started-' + traceProviderId); + startTraceRecording(providerId, sessionId, session) { + this._traceSessions.set(sessionId, session); + this._postNotification('trace-recording-started-' + providerId, sessionId); } /** - * @param {string} traceProviderId + * @param {string} providerId */ - stopTraceRecording(traceProviderId) { - this._postNotification('trace-recording-stopped-' + traceProviderId); + stopTraceRecording(providerId) { + this._postNotification('trace-recording-stopped-' + providerId); } /** @@ -310,6 +316,17 @@ return this._status.OK(); } + /** + * @param {!Object} message + */ + _onCompleteTraceSession(message) { + var session = this._traceSessions.get(message.id); + if (!session) + return this._status.E_NOTFOUND(message.id); + this._traceSessions.delete(message.id); + session.complete(message.url, message.timeOffset); + } + _onCreateSidebarPane(message) { if (message.panel !== 'elements' && message.panel !== 'sources') return this._status.E_NOTFOUND(message.panel); @@ -560,6 +577,7 @@ port._extensionOrigin, message.id, message.categoryName, message.categoryTooltip); this._clientObjects[message.id] = provider; this._traceProviders.push(provider); + this.dispatchEventToListeners(Extensions.ExtensionServer.Events.TraceProviderAdded); } /** @@ -964,7 +982,8 @@ /** @enum {symbol} */ Extensions.ExtensionServer.Events = { SidebarPaneAdded: Symbol('SidebarPaneAdded'), - AuditCategoryAdded: Symbol('AuditCategoryAdded') + AuditCategoryAdded: Symbol('AuditCategoryAdded'), + TraceProviderAdded: Symbol('TraceProviderAdded') }; /**
diff --git a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionTraceProvider.js b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionTraceProvider.js index b480c15..6a93dac 100644 --- a/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionTraceProvider.js +++ b/third_party/WebKit/Source/devtools/front_end/extensions/ExtensionTraceProvider.js
@@ -1,3 +1,7 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + /** * @unrestricted */ @@ -14,11 +18,52 @@ this._categoryName = categoryName; this._categoryTooltip = categoryTooltip; } - start() { - Extensions.extensionServer.startTraceRecording(this._id); + + /** + * @param {!Extensions.TracingSession} session + */ + start(session) { + var sessionId = String(++Extensions.ExtensionTraceProvider._lastSessionId); + Extensions.extensionServer.startTraceRecording(this._id, sessionId, session); } stop() { Extensions.extensionServer.stopTraceRecording(this._id); } + + /** + * @return {string} + */ + shortDisplayName() { + return this._categoryName; + } + + /** + * @return {string} + */ + longDisplayName() { + return this._categoryTooltip; + } + + /** + * @return {string} + */ + persistentIdentifier() { + return `${this._extensionOrigin}/${this._categoryName}`; + } +}; + +Extensions.ExtensionTraceProvider._lastSessionId = 0; + +/** + * @interface + */ +Extensions.TracingSession = function() {}; + +Extensions.TracingSession.prototype = { + /** + * @param {string} url + * @param {number} timeOffsetMicroseconds + */ + complete: function(url, timeOffsetMicroseconds) {} };
diff --git a/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js b/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js index 3acc1f6..d858aff 100644 --- a/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js +++ b/third_party/WebKit/Source/devtools/front_end/layer_viewer/Layers3DView.js
@@ -231,7 +231,6 @@ _updateTransformAndConstraints() { var paddingFraction = 0.1; var viewport = this._layerTree.viewportSize(); - var root = this._layerTree.root(); var baseWidth = viewport ? viewport.width : this._dimensionsForAutoscale.width; var baseHeight = viewport ? viewport.height : this._dimensionsForAutoscale.height; var canvasWidth = this._canvasElement.width;
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js index f52322b..3c7ae727 100644 --- a/third_party/WebKit/Source/devtools/front_end/main/Main.js +++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -182,8 +182,7 @@ new Bindings.BreakpointManager(null, Workspace.workspace, SDK.targetManager, Bindings.debuggerWorkspaceBinding); Extensions.extensionServer = new Extensions.ExtensionServer(); - var fileSystemWorkspaceBinding = - new Persistence.FileSystemWorkspaceBinding(Workspace.isolatedFileSystemManager, Workspace.workspace); + new Persistence.FileSystemWorkspaceBinding(Workspace.isolatedFileSystemManager, Workspace.workspace); Persistence.persistence = new Persistence.Persistence(Workspace.workspace, Bindings.breakpointManager, Workspace.fileSystemMapping);
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js index 8ccc296..45e5f03d 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js +++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogView.js
@@ -796,7 +796,6 @@ this.removeAllNodeHighlights(); - var oldBoundary = this.calculator().boundary(); this._timeCalculator.updateBoundariesForEventTime(this._mainRequestLoadTime); this._durationCalculator.updateBoundariesForEventTime(this._mainRequestLoadTime); this._timeCalculator.updateBoundariesForEventTime(this._mainRequestDOMContentLoadedTime);
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js index 6fb1f137..7e502ba 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js +++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkLogViewColumns.js
@@ -470,7 +470,7 @@ var index = this._columns.findIndex(columnConfig => columnConfig.id === headerId); if (index === -1) return false; - var columnConfig = this._columns.splice(index, 1); + this._columns.splice(index, 1); this._dataGrid.removeColumn(headerId); this._saveColumns(); this._updateColumns();
diff --git a/third_party/WebKit/Source/devtools/front_end/network/NetworkOverview.js b/third_party/WebKit/Source/devtools/front_end/network/NetworkOverview.js index 5b53515..a283e507 100644 --- a/third_party/WebKit/Source/devtools/front_end/network/NetworkOverview.js +++ b/third_party/WebKit/Source/devtools/front_end/network/NetworkOverview.js
@@ -11,12 +11,6 @@ /** @type {number} */ this._numBands = 1; - /** @type {number} */ - this._windowStart = 0; - /** @type {number} */ - this._windowEnd = 0; - /** @type {boolean} */ - this._restoringWindow = false; /** @type {boolean} */ this._updateScheduled = false; @@ -118,8 +112,6 @@ * @override */ reset() { - this._windowStart = 0; - this._windowEnd = 0; /** @type {?Components.FilmStripModel} */ this._filmStripModel = null; @@ -167,16 +159,9 @@ var span = calculator.boundarySpan(); while (this._span < span) this._span *= 1.25; + calculator.setBounds(calculator.minimumBoundary(), calculator.minimumBoundary() + this._span); this._lastBoundary = new Network.NetworkTimeBoundary(calculator.minimumBoundary(), calculator.maximumBoundary()); - if (this._windowStart || this._windowEnd) { - this._restoringWindow = true; - var startTime = calculator.minimumBoundary(); - var totalTime = calculator.boundarySpan(); - var left = (this._windowStart - startTime) / totalTime; - var right = (this._windowEnd - startTime) / totalTime; - this._restoringWindow = false; - } } var context = this.context();
diff --git a/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js b/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js index d22a345..8ecf83d 100644 --- a/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js +++ b/third_party/WebKit/Source/devtools/front_end/persistence/Persistence.js
@@ -135,6 +135,14 @@ if (!binding || binding[Persistence.Persistence._muteWorkingCopy]) return; var other = binding.network === uiSourceCode ? binding.fileSystem : binding.network; + if (!uiSourceCode.isDirty()) { + binding[Persistence.Persistence._muteWorkingCopy] = true; + other.resetWorkingCopy(); + binding[Persistence.Persistence._muteWorkingCopy] = false; + this._contentSyncedForTest(); + return; + } + var target = Bindings.NetworkProject.targetForUISourceCode(binding.network); if (target.isNodeJS()) { var newContent = uiSourceCode.workingCopy();
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/CPUProfileView.js b/third_party/WebKit/Source/devtools/front_end/profiler/CPUProfileView.js index 657eb562..3fb466a 100644 --- a/third_party/WebKit/Source/devtools/front_end/profiler/CPUProfileView.js +++ b/third_party/WebKit/Source/devtools/front_end/profiler/CPUProfileView.js
@@ -229,7 +229,8 @@ this.dispatchEventToListeners(Profiler.ProfileType.Events.ProfileComplete, recordedProfile); } - this.profileBeingRecorded().target() + this.profileBeingRecorded() + .target() .cpuProfilerModel.stopRecording() .then(didStopProfiling.bind(this)) .then(SDK.targetManager.resumeAllTargets.bind(SDK.targetManager)) @@ -374,7 +375,6 @@ var entryTotalTimes = new Float32Array(entries.length); var entrySelfTimes = new Float32Array(entries.length); var entryStartTimes = new Float64Array(entries.length); - var minimumBoundary = this.minimumBoundary(); for (var i = 0; i < entries.length; ++i) { var entry = entries[i];
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js b/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js index 1f28a061..1a61d12 100644 --- a/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js +++ b/third_party/WebKit/Source/devtools/front_end/profiler/ProfilesPanel.js
@@ -608,8 +608,6 @@ this.profileViews.removeChildren(); this._profileViewToolbar.removeToolbarItems(); - this.removeAllListeners(); - this._profileViewToolbar.element.classList.remove('hidden'); this.clearResultsButton.element.classList.remove('hidden'); this.profilesItemTreeElement.select();
diff --git a/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js b/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js index 34f8807..642c10f 100644 --- a/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js +++ b/third_party/WebKit/Source/devtools/front_end/sass/SASSSupport.js
@@ -36,7 +36,6 @@ */ function createTextNode(payload) { var range = Common.TextRange.fromObject(payload); - var value = text.extract(range); return new Sass.SASSSupport.TextNode(document, text.extract(range), range); }
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSParser.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSParser.js deleted file mode 100644 index b003f82..0000000 --- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSParser.js +++ /dev/null
@@ -1,117 +0,0 @@ -/** - * Copyright 2014 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/** - * @unrestricted - */ -SDK.CSSParser = class extends Common.Object { - constructor() { - super(); - this._rules = []; - this._terminated = false; - } - - /** - * @param {!SDK.CSSStyleSheetHeader} styleSheetHeader - * @param {function(!Array.<!Common.FormatterWorkerPool.CSSRule>)=} callback - */ - fetchAndParse(styleSheetHeader, callback) { - this._lock(); - this._finishedCallback = callback; - styleSheetHeader.requestContent().then(this._innerParse.bind(this)); - } - - /** - * @param {string} text - * @param {function(!Array.<!Common.FormatterWorkerPool.CSSRule>)=} callback - */ - parse(text, callback) { - this._lock(); - this._finishedCallback = callback; - this._innerParse(text); - } - - /** - * @param {string} text - * @return {!Promise<!Array.<!Common.FormatterWorkerPool.CSSRule>>} - */ - parsePromise(text) { - return new Promise(promiseConstructor.bind(this)); - - /** - * @param {function()} succ - * @param {function()} fail - * @this {SDK.CSSParser} - */ - function promiseConstructor(succ, fail) { - this.parse(text, succ); - } - } - - dispose() { - if (this._terminated) - return; - this._terminated = true; - this._runFinishedCallback([]); - } - - /** - * @return {!Array.<!Common.FormatterWorkerPool.CSSRule>} - */ - rules() { - return this._rules; - } - - _lock() { - console.assert(!this._parsingStyleSheet, 'Received request to parse stylesheet before previous was completed.'); - this._parsingStyleSheet = true; - } - - _unlock() { - delete this._parsingStyleSheet; - } - - /** - * @param {?string} text - */ - _innerParse(text) { - this._rules = []; - Common.formatterWorkerPool.parseCSS(text || '', this._onRuleChunk.bind(this)); - } - - /** - * @param {boolean} isLastChunk - * @param {!Array.<!Common.FormatterWorkerPool.CSSRule>} rules - */ - _onRuleChunk(isLastChunk, rules) { - if (this._terminated) - return; - this._rules = this._rules.concat(rules); - if (isLastChunk) - this._onFinishedParsing(); - this.dispatchEventToListeners(SDK.CSSParser.Events.RulesParsed); - } - - _onFinishedParsing() { - this._unlock(); - this._runFinishedCallback(this._rules); - } - - /** - * @param {!Array<!SDK.CSSRule>} rules - */ - _runFinishedCallback(rules) { - var callback = this._finishedCallback; - delete this._finishedCallback; - if (callback) - callback.call(null, rules); - } -}; - -/** @enum {symbol} */ -SDK.CSSParser.Events = { - RulesParsed: Symbol('RulesParsed') -};
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js index d95b8d5..b76ab642 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/DOMModel.js
@@ -1807,16 +1807,6 @@ * @param {function(?Protocol.Error)=} callback */ undo(callback) { - /** - * @param {?Protocol.Error} error - * @this {SDK.DOMModel} - */ - function mycallback(error) { - this.dispatchEventToListeners(SDK.DOMModel.Events.UndoRedoCompleted); - callback(error); - } - - this.dispatchEventToListeners(SDK.DOMModel.Events.UndoRedoRequested); this._agent.undo(callback); } @@ -1824,16 +1814,6 @@ * @param {function(?Protocol.Error)=} callback */ redo(callback) { - /** - * @param {?Protocol.Error} error - * @this {SDK.DOMModel} - */ - function mycallback(error) { - this.dispatchEventToListeners(SDK.DOMModel.Events.UndoRedoCompleted); - callback(error); - } - - this.dispatchEventToListeners(SDK.DOMModel.Events.UndoRedoRequested); this._agent.redo(callback); } @@ -1941,10 +1921,7 @@ NodeRemoved: Symbol('NodeRemoved'), DocumentUpdated: Symbol('DocumentUpdated'), ChildNodeCountUpdated: Symbol('ChildNodeCountUpdated'), - UndoRedoRequested: Symbol('UndoRedoRequested'), - UndoRedoCompleted: Symbol('UndoRedoCompleted'), DistributedNodesChanged: Symbol('DistributedNodesChanged'), - ModelSuspended: Symbol('ModelSuspended'), InspectModeWillBeToggled: Symbol('InspectModeWillBeToggled'), MarkersChanged: Symbol('MarkersChanged') };
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js index 177643a..e5802ee 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
@@ -216,7 +216,6 @@ } columnNumber = Math.max(columnNumber, minColumnNumber); - var target = this.target(); /** * @param {?Protocol.Error} error * @param {!Protocol.Debugger.BreakpointId} breakpointId @@ -240,8 +239,6 @@ * @param {function(?Protocol.Debugger.BreakpointId, !Array.<!SDK.DebuggerModel.Location>)=} callback */ setBreakpointBySourceId(rawLocation, condition, callback) { - var target = this.target(); - /** * @this {SDK.DebuggerModel} * @param {?Protocol.Error} error
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/SubTargetsManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/SubTargetsManager.js index 8561c06..ee930ca 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/SubTargetsManager.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/SubTargetsManager.js
@@ -185,7 +185,6 @@ * @param {string} targetId */ _detachedFromTarget(targetId) { - var target = this._attachedTargets.get(targetId); this._attachedTargets.delete(targetId); var connection = this._connections.get(targetId); connection._onDisconnect.call(null, 'target terminated');
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/TracingModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/TracingModel.js index 5e77ce79..996fc50 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/TracingModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/TracingModel.js
@@ -169,6 +169,28 @@ } /** + * @param {number} offset + */ + adjustTime(offset) { + this._minimumRecordTime += offset; + this._maximumRecordTime += offset; + for (const process of this._processById.values()) { + for (const thread of process._threads.values()) { + for (const event of thread.events()) { + event.startTime += offset; + if (typeof event.endTime === 'number') + event.endTime += offset; + } + for (const event of thread.asyncEvents()) { + event.startTime += offset; + if (typeof event.endTime === 'number') + event.endTime += offset; + } + } + } + } + + /** * @param {!SDK.TracingManager.EventPayload} payload */ _addEvent(payload) { @@ -474,7 +496,7 @@ finishWriting() {}, - reset() {}, + reset() {} }; /** @@ -612,10 +634,6 @@ } }; - -/** - * @unrestricted - */ SDK.TracingModel.ObjectSnapshot = class extends SDK.TracingModel.Event { /** * @param {string} category @@ -625,6 +643,12 @@ */ constructor(category, name, startTime, thread) { super(category, name, SDK.TracingModel.Phase.SnapshotObject, startTime, thread); + /** @type {?function():!Promise<?string>} */ + this._backingStorage = null; + /** @type {string} */ + this.id; + /** @type {?Promise<?>} */ + this._objectPromise = null; } /** @@ -743,11 +767,19 @@ } }; -/** - * @unrestricted - */ SDK.TracingModel.NamedObject = class { /** + * @param {!SDK.TracingModel} model + * @param {number} id + */ + constructor(model, id) { + this._model = model; + this._id = id; + this._name = ''; + this._sortIndex = 0; + } + + /** * @param {!Array.<!SDK.TracingModel.NamedObject>} array */ static _sort(array) { @@ -783,23 +815,16 @@ } }; - -/** - * @unrestricted - */ SDK.TracingModel.Process = class extends SDK.TracingModel.NamedObject { /** * @param {!SDK.TracingModel} model * @param {number} id */ constructor(model, id) { - super(); - this._setName('Process ' + id); - this._id = id; + super(model, id); /** @type {!Map<number, !SDK.TracingModel.Thread>} */ this._threads = new Map(); this._threadByName = new Map(); - this._model = model; } /** @@ -854,22 +879,17 @@ } }; -/** - * @unrestricted - */ SDK.TracingModel.Thread = class extends SDK.TracingModel.NamedObject { /** * @param {!SDK.TracingModel.Process} process * @param {number} id */ constructor(process, id) { - super(); + super(process._model, id); this._process = process; - this._setName('Thread ' + id); this._events = []; this._asyncEvents = []; - this._id = id; - this._model = process._model; + this._lastTopLevelEvent = null; } tracingComplete() {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/module.json b/third_party/WebKit/Source/devtools/front_end/sdk/module.json index 339aa901..4094fb4 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/module.json +++ b/third_party/WebKit/Source/devtools/front_end/sdk/module.json
@@ -88,7 +88,6 @@ "CSSMedia.js", "CSSMetadata.js", "CSSModel.js", - "CSSParser.js", "CSSProperty.js", "CSSRule.js", "CSSStyleDeclaration.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/SourcesTextEditor.js b/third_party/WebKit/Source/devtools/front_end/source_frame/SourcesTextEditor.js index 749a87f..e8578d71 100644 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/SourcesTextEditor.js +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/SourcesTextEditor.js
@@ -541,7 +541,6 @@ function modeConstructor(config, parserConfig) { function nextToken(stream) { - var pos = stream.pos; if (stream.match(/^\s+$/, true)) return true ? 'trailing-whitespace' : null; do
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js b/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js index 3711cf5..b15e0cd7 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js
@@ -123,7 +123,7 @@ var uiSourceCode = this._uiSourceCodes[itemIndex]; var fullDisplayName = uiSourceCode.fullDisplayName(); var indexes = []; - var score = new Sources.FilePathScoreFunction(query).score(fullDisplayName, indexes); + new Sources.FilePathScoreFunction(query).score(fullDisplayName, indexes); var fileNameIndex = fullDisplayName.lastIndexOf('/'); titleElement.textContent = uiSourceCode.displayName() + (this._queryLineNumberAndColumnNumber || '');
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js index d6ecba64..cadf734 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -417,7 +417,6 @@ } _resolveObjectForPopover(anchorBox, showCallback, objectGroupName) { - var target = UI.context.flavor(SDK.Target); var selectedCallFrame = UI.context.flavor(SDK.DebuggerModel.CallFrame); if (!selectedCallFrame) { this._popoverHelper.hidePopover();
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js index e11f4e8..d8fe76b 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/NavigatorView.js
@@ -157,7 +157,6 @@ var typeWeight1 = Sources.NavigatorView._treeElementOrder(treeElement1); var typeWeight2 = Sources.NavigatorView._treeElementOrder(treeElement2); - var result; if (typeWeight1 > typeWeight2) return 1; if (typeWeight1 < typeWeight2) @@ -705,9 +704,6 @@ * @param {!Workspace.UISourceCode=} uiSourceCodeToCopy */ create(project, path, uiSourceCodeToCopy) { - var filePath; - var uiSourceCode; - /** * @this {Sources.NavigatorView} * @param {?string} content
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js b/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js index 11d80c2e..8768ac0 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js
@@ -65,7 +65,6 @@ function onIdentifiers(text, scopeStart, prefix, identifiers) { var result = []; var cursor = new Common.TextCursor(text.lineEndings()); - var promises = []; for (var i = 0; i < identifiers.length; ++i) { var id = identifiers[i]; if (id.offset < prefix.length)
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js index b373530..97e6550 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/SourcesPanel.js
@@ -511,7 +511,6 @@ delete this._switchToPausedTargetTimeout; if (this._paused) return; - var target = UI.context.flavor(SDK.Target); if (debuggerModel.isPaused()) return; var debuggerModels = SDK.DebuggerModel.instances(); @@ -855,7 +854,6 @@ return; var uiLocation = /** @type {!Workspace.UILocation} */ (object); var uiSourceCode = uiLocation.uiSourceCode; - var projectType = uiSourceCode.project().type(); var contentType = uiSourceCode.contentType(); if (contentType.hasScripts()) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/StyleSheetOutlineDialog.js b/third_party/WebKit/Source/devtools/front_end/sources/StyleSheetOutlineDialog.js index 83dc4ba..c8b9802d 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/StyleSheetOutlineDialog.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/StyleSheetOutlineDialog.js
@@ -37,9 +37,12 @@ constructor(uiSourceCode, selectItemCallback) { super([]); this._selectItemCallback = selectItemCallback; - this._cssParser = new SDK.CSSParser(); - this._cssParser.addEventListener(SDK.CSSParser.Events.RulesParsed, this.refresh.bind(this)); - this._cssParser.parse(uiSourceCode.workingCopy()); + /** @type {!Array<!Common.FormatterWorkerPool.CSSRule>} */ + this._rules = []; + Common.formatterWorkerPool.parseCSS(uiSourceCode.workingCopy(), (isLastChunk, rules) => { + this._rules.push(...rules); + this.refresh(); + }); } /** @@ -57,7 +60,7 @@ * @return {number} */ itemCount() { - return this._cssParser.rules().length; + return this._rules.length; } /** @@ -66,7 +69,7 @@ * @return {string} */ itemKeyAt(itemIndex) { - var rule = this._cssParser.rules()[itemIndex]; + var rule = this._rules[itemIndex]; return rule.selectorText || rule.atRule; } @@ -77,7 +80,7 @@ * @return {number} */ itemScoreAt(itemIndex, query) { - var rule = this._cssParser.rules()[itemIndex]; + var rule = this._rules[itemIndex]; return -rule.lineNumber; } @@ -89,7 +92,7 @@ * @param {!Element} subtitleElement */ renderItem(itemIndex, query, titleElement, subtitleElement) { - var rule = this._cssParser.rules()[itemIndex]; + var rule = this._rules[itemIndex]; titleElement.textContent = rule.selectorText || rule.atRule; this.highlightRanges(titleElement, query); subtitleElement.textContent = ':' + (rule.lineNumber + 1); @@ -101,16 +104,9 @@ * @param {string} promptValue */ selectItem(itemIndex, promptValue) { - var rule = this._cssParser.rules()[itemIndex]; + var rule = this._rules[itemIndex]; var lineNumber = rule.lineNumber; if (!isNaN(lineNumber) && lineNumber >= 0) this._selectItemCallback(lineNumber, rule.columnNumber); } - - /** - * @override - */ - dispose() { - this._cssParser.dispose(); - } };
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js b/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js index 8e163c3..ed3add0 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/TabbedEditorContainer.js
@@ -298,7 +298,6 @@ if (!shouldPrompt || confirm(Common.UIString('Are you sure you want to close unsaved file: %s?', uiSourceCode.name()))) { uiSourceCode.resetWorkingCopy(); - var previousView = this._currentView; if (nextTabId) this._tabbedPane.selectTab(nextTabId, true); this._tabbedPane.closeTab(id, true);
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js b/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js index b48a7cf..694eb94 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js
@@ -232,6 +232,12 @@ refreshRecords() { } + /** + * @override + */ + extensionDataAdded() { + } + _clear() { var ctx = this._canvas.getContext('2d'); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/ExtensionTracingSession.js b/third_party/WebKit/Source/devtools/front_end/timeline/ExtensionTracingSession.js new file mode 100644 index 0000000..de108a8 --- /dev/null +++ b/third_party/WebKit/Source/devtools/front_end/timeline/ExtensionTracingSession.js
@@ -0,0 +1,78 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @implements {Extensions.TracingSession} + * @implements {Timeline.LoaderClient} + */ +Timeline.ExtensionTracingSession = class { + /** + * @param {!Extensions.ExtensionTraceProvider} provider + * @param {!Timeline.TimelineLifecycleDelegate} delegate + */ + constructor(provider, delegate) { + this._provider = provider; + this._delegate = delegate; + this._sessionGeneration = delegate.sessionGeneration(); + /** @type {function()} */ + this._completionCallback; + this._completionPromise = new Promise(fulfill => {this._completionCallback = fulfill;}); + /** @type {?SDK.TracingModel} */ + this._tracingModel = null; + /** @type {number} */ + this._timeOffset = 0; + } + + /** @override */ + loadingStarted() { + } + + /** + * @override + * @param {number=} progress + */ + loadingProgress(progress) { + } + + /** + * @override + * @param {boolean} success + */ + loadingComplete(success) { + if (!success || this._sessionGeneration !== this._delegate.sessionGeneration()) { + this._tracingModel.reset(); + } else { + this._delegate.addExtensionEvents( + this._provider.longDisplayName(), + /** @type {!SDK.TracingModel} */ (this._tracingModel), this._timeOffset); + } + this._completionCallback(); + } + + /** + * @override + * @param {string} url + * @param {number} timeOffsetMicroseconds + */ + complete(url, timeOffsetMicroseconds) { + if (!url || this._sessionGeneration !== this._delegate.sessionGeneration()) { + this._completionCallback(); + return; + } + var storage = new Bindings.TempFileBackingStorage('tracing'); + this._tracingModel = new SDK.TracingModel(storage); + this._timeOffset = timeOffsetMicroseconds; + Timeline.TimelineLoader.loadFromURL(this._tracingModel, url, this); + } + + start() { + this._provider.start(this); + } + + /** @return {!Promise<string>} */ + stop() { + this._provider.stop(); + return this._completionPromise; + } +};
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/MemoryCountersGraph.js b/third_party/WebKit/Source/devtools/front_end/timeline/MemoryCountersGraph.js index 99878329..ec8a943 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/MemoryCountersGraph.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/MemoryCountersGraph.js
@@ -80,4 +80,10 @@ } this.scheduleRefresh(); } + + /** + * @override + */ + extensionDataAdded() { + } };
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js index c646739..d189476 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineController.js
@@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -/** @typedef {!{range: !Protocol.CSS.SourceRange, styleSheetId: !Protocol.CSS.StyleSheetId, wasUsed: boolean}} */ -SDK.CSSModel.RuleUsage; - /** * @implements {SDK.TargetManager.Observer} * @implements {SDK.TracingManagerClient} @@ -21,6 +18,8 @@ this._target = target; this._tracingModel = tracingModel; this._targets = []; + /** @type {!Array<!Timeline.ExtensionTracingSession>} */ + this._extensionSessions = []; SDK.targetManager.observeTargets(this); if (Runtime.experiments.isEnabled('timelineRuleUsageRecording')) @@ -28,13 +27,10 @@ } /** - * @param {boolean} captureCauses - * @param {boolean} enableJSSampling - * @param {boolean} captureMemory - * @param {boolean} capturePictures - * @param {boolean} captureFilmStrip + * @param {!Timeline.TimelineController.CaptureOptions} options + * @param {!Array<!Extensions.ExtensionTraceProvider>} providers */ - startRecording(captureCauses, enableJSSampling, captureMemory, capturePictures, captureFilmStrip) { + startRecording(options, providers) { this._extensionTraceProviders = Extensions.extensionServer.traceProviders().slice(); function disabledByDefault(category) { @@ -47,30 +43,29 @@ ]; categoriesArray.push(TimelineModel.TimelineModel.Category.LatencyInfo); - if (Runtime.experiments.isEnabled('timelineV8RuntimeCallStats') && enableJSSampling) + if (Runtime.experiments.isEnabled('timelineV8RuntimeCallStats') && options.enableJSSampling) categoriesArray.push(disabledByDefault('v8.runtime_stats_sampling')); - if (Runtime.experiments.isEnabled('timelineTracingJSProfile') && enableJSSampling) { + if (Runtime.experiments.isEnabled('timelineTracingJSProfile') && options.enableJSSampling) { categoriesArray.push(disabledByDefault('v8.cpu_profiler')); if (Common.moduleSetting('highResolutionCpuProfiling').get()) categoriesArray.push(disabledByDefault('v8.cpu_profiler.hires')); } - if (captureCauses || enableJSSampling) + if (options.captureCauses || options.enableJSSampling) categoriesArray.push(disabledByDefault('devtools.timeline.stack')); - if (captureCauses && Runtime.experiments.isEnabled('timelineInvalidationTracking')) + if (options.captureCauses && Runtime.experiments.isEnabled('timelineInvalidationTracking')) categoriesArray.push(disabledByDefault('devtools.timeline.invalidationTracking')); - if (capturePictures) { + if (options.capturePictures) { categoriesArray.push( disabledByDefault('devtools.timeline.layers'), disabledByDefault('devtools.timeline.picture'), disabledByDefault('blink.graphics_context_annotations')); } - if (captureFilmStrip) + if (options.captureFilmStrip) categoriesArray.push(disabledByDefault('devtools.screenshot')); - for (var traceProvider of this._extensionTraceProviders) - traceProvider.start(); - + this._extensionSessions = providers.map(provider => new Timeline.ExtensionTracingSession(provider, this._delegate)); + this._extensionSessions.forEach(session => session.start()); var categories = categoriesArray.join(','); - this._startRecordingWithCategories(categories, enableJSSampling); + this._startRecordingWithCategories(categories, options.enableJSSampling); } stopRecording() { @@ -84,12 +79,16 @@ else this._addUnusedRulesToCoverage(); - Promise.all(tracingStoppedPromises).then(() => this._allSourcesFinished()); - this._delegate.loadingStarted(); - for (var traceProvider of this._extensionTraceProviders) - traceProvider.stop(); + var extensionCompletionPromises = this._extensionSessions.map(session => session.stop()); + if (extensionCompletionPromises.length) { + var timerId; + var timeoutPromise = new Promise(fulfill => timerId = setTimeout(fulfill, 5000)); + tracingStoppedPromises.push( + Promise.race([Promise.all(extensionCompletionPromises).then(() => clearTimeout(timerId)), timeoutPromise])); + } + Promise.all(tracingStoppedPromises).then(() => this._allSourcesFinished()); } /** @@ -308,3 +307,13 @@ this._delegate.loadingProgress(progress); } }; + +/** @typedef {!{ + * captureCauses: (boolean|undefined), + * enableJSSampling: (boolean|undefined), + * captureMemory: (boolean|undefined), + * capturePictures: (boolean|undefined), + * captureFilmStrip: (boolean|undefined) + * }} + */ +Timeline.TimelineController.CaptureOptions;
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js index fdbc8a73c..e8e45a1 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
@@ -47,6 +47,8 @@ this._irModel = irModel; this._consoleColorGenerator = new UI.FlameChart.ColorGenerator({min: 30, max: 55}, {min: 70, max: 100, count: 6}, 50, 0.7); + this._extensionColorGenerator = + new UI.FlameChart.ColorGenerator({min: 210, max: 300}, {min: 70, max: 100, count: 6}, 70, 0.7); const font = this.font(); this._headerLevel1 = { @@ -102,7 +104,7 @@ entryTitle(entryIndex) { var entryType = this._entryType(entryIndex); if (entryType === Timeline.TimelineFlameChartEntryType.Event) { - var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); + const event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); if (event.phase === SDK.TracingModel.Phase.AsyncStepInto || event.phase === SDK.TracingModel.Phase.AsyncStepPast) return event.name + ':' + event.args['step']; if (event._blackboxRoot) @@ -114,6 +116,10 @@ return detailsText; return detailsText ? Common.UIString('%s (%s)', name, detailsText) : name; } + if (entryType === Timeline.TimelineFlameChartEntryType.ExtensionEvent) { + const event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); + return event.name; + } var title = this._entryIndexToTitle[entryIndex]; if (!title) { title = Common.UIString('Unexpected entryIndex %d', entryIndex); @@ -153,6 +159,8 @@ this._asyncColorByCategory = new Map(); /** @type {!Map<!TimelineModel.TimelineIRModel.Phases, string>} */ this._asyncColorByInteractionPhase = new Map(); + /** @type {!Array<!{title: string, model: !SDK.TracingModel}>} */ + this._extensionInfo = []; } /** @@ -173,16 +181,18 @@ this._appendHeader(Common.UIString('Interactions'), this._interactionsHeaderLevel1); this._appendInteractionRecords(); + var eventEntryType = Timeline.TimelineFlameChartEntryType.Event; + var asyncEventGroups = TimelineModel.TimelineModel.AsyncEventGroup; var inputLatencies = this._model.mainThreadAsyncEvents().get(asyncEventGroups.input); if (inputLatencies && inputLatencies.length) { var title = Timeline.TimelineUIUtils.titleForAsyncEventGroup(asyncEventGroups.input); - this._appendAsyncEventsGroup(title, inputLatencies, this._interactionsHeaderLevel2); + this._appendAsyncEventsGroup(title, inputLatencies, this._interactionsHeaderLevel2, eventEntryType); } var animations = this._model.mainThreadAsyncEvents().get(asyncEventGroups.animation); if (animations && animations.length) { var title = Timeline.TimelineUIUtils.titleForAsyncEventGroup(asyncEventGroups.animation); - this._appendAsyncEventsGroup(title, animations, this._interactionsHeaderLevel2); + this._appendAsyncEventsGroup(title, animations, this._interactionsHeaderLevel2, eventEntryType); } var threads = this._model.virtualThreads(); if (!Runtime.experiments.isEnabled('timelinePerFrameTrack')) { @@ -203,13 +213,18 @@ this._appendHeader(Common.UIString('Raster'), this._headerLevel1); for (var i = 0; i < compositorThreads.length; ++i) { this._appendSyncEvents( - compositorThreads[i].events, Common.UIString('Rasterizer Thread %d', i), this._headerLevel2); + compositorThreads[i].events, Common.UIString('Rasterizer Thread %d', i), this._headerLevel2, + eventEntryType); } } this._appendGPUEvents(); otherThreads.forEach( - thread => this._appendThreadTimelineData(thread.name, thread.events, thread.asyncEventsByGroup)); + thread => this._appendThreadTimelineData( + thread.name || Common.UIString('Thread %d', thread.id), thread.events, thread.asyncEventsByGroup)); + + for (let extensionIndex = 0; extensionIndex < this._extensionInfo.length; extensionIndex++) + this._innerAppendExtensionEvents(extensionIndex); /** * @param {!Timeline.TimelineFlameChartMarker} a @@ -235,7 +250,7 @@ clonedHeader.nestingLevel = level; this._appendSyncEvents( events, Timeline.TimelineUIUtils.displayNameForFrame(frame), - /** @type {!UI.FlameChart.GroupStyle} */ (clonedHeader)); + /** @type {!UI.FlameChart.GroupStyle} */ (clonedHeader), Timeline.TimelineFlameChartEntryType.Event); frame.children.forEach(this._appendFrameEvents.bind(this, level + 1)); } @@ -246,23 +261,26 @@ * @param {boolean=} forceExpanded */ _appendThreadTimelineData(threadTitle, syncEvents, asyncEvents, forceExpanded) { + var entryType = Timeline.TimelineFlameChartEntryType.Event; this._appendAsyncEvents(asyncEvents); - this._appendSyncEvents(syncEvents, threadTitle, this._headerLevel1, forceExpanded); + this._appendSyncEvents(syncEvents, threadTitle, this._headerLevel1, entryType, forceExpanded); } /** * @param {!Array<!SDK.TracingModel.Event>} events * @param {string} title * @param {!UI.FlameChart.GroupStyle} style + * @param {!Timeline.TimelineFlameChartEntryType} entryType * @param {boolean=} forceExpanded */ - _appendSyncEvents(events, title, style, forceExpanded) { + _appendSyncEvents(events, title, style, entryType, forceExpanded) { + var isExtension = entryType === Timeline.TimelineFlameChartEntryType.ExtensionEvent; var openEvents = []; - var blackboxingEnabled = Runtime.experiments.isEnabled('blackboxJSFramesOnTimeline'); + var blackboxingEnabled = !isExtension && Runtime.experiments.isEnabled('blackboxJSFramesOnTimeline'); var maxStackDepth = 0; for (var i = 0; i < events.length; ++i) { var e = events[i]; - if (TimelineModel.TimelineModel.isMarkerEvent(e)) { + if (!isExtension && TimelineModel.TimelineModel.isMarkerEvent(e)) { this._markers.push(new Timeline.TimelineFlameChartMarker( e.startTime, e.startTime - this._model.minimumRecordTime(), Timeline.TimelineUIUtils.markerStyleForEvent(e))); @@ -272,7 +290,7 @@ continue; if (SDK.TracingModel.isAsyncPhase(e.phase)) continue; - if (!this._isVisible(e)) + if (!isExtension && !this._isVisible(e)) continue; } while (openEvents.length && openEvents.peekLast().endTime <= e.startTime) @@ -291,12 +309,15 @@ var level = this._currentLevel + openEvents.length; this._appendEvent(e, level); + if (!isExtension && TimelineModel.TimelineModel.isMarkerEvent(e)) + this._timelineData.entryTotalTimes[this._entryData.length] = undefined; + maxStackDepth = Math.max(maxStackDepth, openEvents.length + 1); if (e.endTime) openEvents.push(e); } this._entryTypeByLevel.length = this._currentLevel + maxStackDepth; - this._entryTypeByLevel.fill(Timeline.TimelineFlameChartEntryType.Event, this._currentLevel); + this._entryTypeByLevel.fill(entryType, this._currentLevel); this._currentLevel += maxStackDepth; } @@ -323,6 +344,7 @@ * @param {!Map<!TimelineModel.TimelineModel.AsyncEventGroup, !Array<!SDK.TracingModel.AsyncEvent>>} asyncEvents */ _appendAsyncEvents(asyncEvents) { + var entryType = Timeline.TimelineFlameChartEntryType.Event; var groups = TimelineModel.TimelineModel.AsyncEventGroup; var groupArray = Object.keys(groups).map(key => groups[key]); @@ -335,7 +357,7 @@ if (!events) continue; var title = Timeline.TimelineUIUtils.titleForAsyncEventGroup(group); - this._appendAsyncEventsGroup(title, events, this._headerLevel1); + this._appendAsyncEventsGroup(title, events, this._headerLevel1, entryType); } } @@ -343,8 +365,9 @@ * @param {string} header * @param {!Array<!SDK.TracingModel.AsyncEvent>} events * @param {!UI.FlameChart.GroupStyle} style + * @param {!Timeline.TimelineFlameChartEntryType} entryType */ - _appendAsyncEventsGroup(header, events, style) { + _appendAsyncEventsGroup(header, events, style, entryType) { var lastUsedTimeByLevel = []; var groupHeaderAppended = false; for (var i = 0; i < events.length; ++i) { @@ -363,12 +386,14 @@ lastUsedTimeByLevel[level] = asyncEvent.endTime; } this._entryTypeByLevel.length = this._currentLevel + lastUsedTimeByLevel.length; - this._entryTypeByLevel.fill(Timeline.TimelineFlameChartEntryType.Event, this._currentLevel); + this._entryTypeByLevel.fill(entryType, this._currentLevel); this._currentLevel += lastUsedTimeByLevel.length; } _appendGPUEvents() { - if (this._appendSyncEvents(this._model.gpuEvents(), Common.UIString('GPU'), this._headerLevel1, false)) + const eventType = Timeline.TimelineFlameChartEntryType.Event; + const gpuEvents = this._model.gpuEvents(); + if (this._appendSyncEvents(gpuEvents, Common.UIString('GPU'), this._headerLevel1, eventType, false)) ++this._currentLevel; } @@ -484,6 +509,10 @@ return 'white'; if (type === Timeline.TimelineFlameChartEntryType.InteractionRecord) return 'transparent'; + if (type === Timeline.TimelineFlameChartEntryType.ExtensionEvent) { + var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]); + return this._extensionColorGenerator.colorForID(event.name); + } return ''; } @@ -582,6 +611,32 @@ } /** + * @param {!{title: string, model: !SDK.TracingModel}} entry + */ + appendExtensionEvents(entry) { + this._extensionInfo.push(entry); + if (this._timelineData) + this._innerAppendExtensionEvents(this._extensionInfo.length - 1); + } + + /** + * @param {number} index + */ + _innerAppendExtensionEvents(index) { + var entry = this._extensionInfo[index]; + var entryType = Timeline.TimelineFlameChartEntryType.ExtensionEvent; + var allThreads = [].concat(...entry.model.sortedProcesses().map(process => process.sortedThreads())); + if (!allThreads.length) + return; + + this._appendHeader(entry.title, this._headerLevel1); + for (let thread of allThreads) { + this._appendAsyncEventsGroup(thread.name(), thread.asyncEvents(), this._headerLevel2, entryType); + this._appendSyncEvents(thread.events(), thread.name(), this._headerLevel2, entryType, false); + } + } + + /** * @param {string} title * @param {!UI.FlameChart.GroupStyle} style * @param {boolean=} expanded @@ -598,12 +653,8 @@ var index = this._entryData.length; this._entryData.push(event); this._timelineData.entryLevels[index] = level; - var duration; - if (TimelineModel.TimelineModel.isMarkerEvent(event)) - duration = undefined; - else - duration = event.duration || Timeline.TimelineFlameChartDataProvider.InstantEventVisibleDurationMs; - this._timelineData.entryTotalTimes[index] = duration; + this._timelineData.entryTotalTimes[index] = + event.duration || Timeline.TimelineFlameChartDataProvider.InstantEventVisibleDurationMs; this._timelineData.entryStartTimes[index] = event.startTime; }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js index 8e10f9a..7dbc9ce8 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChartView.js
@@ -192,6 +192,7 @@ Frame: Symbol('Frame'), Event: Symbol('Event'), InteractionRecord: Symbol('InteractionRecord'), + ExtensionEvent: Symbol('ExtensionEvent') }; /** @@ -283,14 +284,15 @@ * @param {!TimelineModel.TimelineModel} timelineModel * @param {!TimelineModel.TimelineFrameModel} frameModel * @param {!TimelineModel.TimelineIRModel} irModel + * @param {!Array<!{title: string, model: !SDK.TracingModel}>} extensionModels * @param {!Array<!TimelineModel.TimelineModel.Filter>} filters */ - constructor(delegate, timelineModel, frameModel, irModel, filters) { + constructor(delegate, timelineModel, frameModel, irModel, extensionModels, filters) { super(); this.element.classList.add('timeline-flamechart'); this._delegate = delegate; this._model = timelineModel; - + this._extensionModels = extensionModels; this._splitWidget = new UI.SplitWidget(false, false, 'timelineFlamechartMainView', 150); this._dataProvider = new Timeline.TimelineFlameChartDataProvider(this._model, frameModel, irModel, filters); @@ -311,6 +313,8 @@ this._onNetworkEntrySelected = this._onEntrySelected.bind(this, this._networkDataProvider); this._mainView.addEventListener(UI.FlameChart.Events.EntrySelected, this._onMainEntrySelected, this); this._networkView.addEventListener(UI.FlameChart.Events.EntrySelected, this._onNetworkEntrySelected, this); + this._nextExtensionIndex = 0; + Bindings.blackboxManager.addChangeListener(this.refreshRecords, this); } @@ -354,13 +358,25 @@ */ refreshRecords() { this._dataProvider.reset(); + this._nextExtensionIndex = 0; + this.extensionDataAdded(); this._mainView.scheduleUpdate(); + this._networkDataProvider.reset(); this._networkView.scheduleUpdate(); } /** * @override + */ + extensionDataAdded() { + while (this._nextExtensionIndex < this._extensionModels.length) + this._dataProvider.appendExtensionEvents(this._extensionModels[this._nextExtensionIndex++]); + this._mainView.scheduleUpdate(); + } + + /** + * @override * @param {?SDK.TracingModel.Event} event */ highlightEvent(event) {
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineLoader.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineLoader.js index e6180daa..8ad5a4698 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineLoader.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineLoader.js
@@ -9,7 +9,7 @@ Timeline.TimelineLoader = class { /** * @param {!SDK.TracingModel} model - * @param {!Timeline.TimelineLifecycleDelegate} delegate + * @param {!Timeline.LoaderClient} delegate */ constructor(model, delegate) { this._model = model; @@ -46,7 +46,7 @@ /** * @param {!SDK.TracingModel} model * @param {string} url - * @param {!Timeline.TimelineLifecycleDelegate} delegate + * @param {!Timeline.LoaderClient} delegate * @return {!Timeline.TimelineLoader} */ static loadFromURL(model, url, delegate) {
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js index 32353c98..7fe3956 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -67,10 +67,11 @@ new TimelineModel.TimelineFrameModel(event => Timeline.TimelineUIUtils.eventStyle(event).category.name); this._filmStripModel = new Components.FilmStripModel(this._tracingModel); this._irModel = new TimelineModel.TimelineIRModel(); - + /** @type {!Array<!{title: string, model: !SDK.TracingModel}>} */ + this._extensionTracingModels = []; this._cpuThrottlingManager = new Timeline.CPUThrottlingManager(); - /** @type {!Array.<!Timeline.TimelineModeView>} */ + /** @type {!Array<!Timeline.TimelineModeView>} */ this._currentViews = []; this._captureNetworkSetting = Common.settings.createSetting('timelineCaptureNetwork', false); @@ -118,6 +119,9 @@ this._onModeChanged(); this._recreateToolbarItems(); + Extensions.extensionServer.addEventListener( + Extensions.ExtensionServer.Events.TraceProviderAdded, this._recreateToolbarItems, this); + this._captureNetworkSetting.addChangeListener(this._onNetworkChanged, this); this._captureMemorySetting.addChangeListener(this._onModeChanged, this); this._captureFilmStripSetting.addChangeListener(this._onModeChanged, this); @@ -131,6 +135,10 @@ this._selectedSearchResult; /** @type {!Array<!SDK.TracingModel.Event>}|undefined */ this._searchResults; + /** @type {?symbol} */ + this._sessionGeneration = null; + /** @type {number} */ + this._recordingStartTime = 0; } /** @@ -383,6 +391,15 @@ Common.UIString('CSS coverage'), this._markUnusedCSS, Common.UIString('Mark unused CSS in souces.'))); } + const traceProviders = Extensions.extensionServer.traceProviders(); + if (traceProviders.length) { + this._panelToolbar.appendSeparator(); + for (let provider of traceProviders) { + const setting = Timeline.TimelinePanel._settingForTraceProvider(provider); + const checkbox = this._createSettingCheckbox(provider.shortDisplayName(), setting, provider.longDisplayName()); + this._panelToolbar.appendToolbarItem(checkbox); + } + } this._panelToolbar.appendSeparator(); this._panelToolbar.appendToolbarItem(UI.Toolbar.createActionButtonForId('components.collect-garbage')); @@ -395,6 +412,20 @@ } /** + * @param {!Extensions.ExtensionTraceProvider} traceProvider + * @return {!Common.Setting<boolean>} + */ + static _settingForTraceProvider(traceProvider) { + var setting = traceProvider[Timeline.TimelinePanel._traceProviderSettingSymbol]; + if (!setting) { + var providerId = traceProvider.persistentIdentifier(); + setting = Common.settings.createSetting(providerId, false); + traceProvider[Timeline.TimelinePanel._traceProviderSettingSymbol] = setting; + } + return setting; + } + + /** * @return {!UI.ToolbarComboBox} */ _createNetworkConditionsSelect() { @@ -530,8 +561,8 @@ // Set up the main view. this._removeAllModeViews(); - this._flameChart = - new Timeline.TimelineFlameChartView(this, this._model, this._frameModel, this._irModel, this._filters); + this._flameChart = new Timeline.TimelineFlameChartView( + this, this._model, this._frameModel, this._irModel, this._extensionTracingModels, this._filters); this._flameChart.enableNetworkPane(this._captureNetworkSetting.get()); this._addModeView(this._flameChart); @@ -583,12 +614,22 @@ if (Runtime.experiments.isEnabled('timelineRuleUsageRecording') && this._markUnusedCSS.get()) SDK.CSSModel.fromTarget(mainTarget).startRuleUsageTracking(); + this._sessionGeneration = Symbol('timelineSessionGeneration'); this._autoRecordGeneration = userInitiated ? null : Symbol('Generation'); + var enabledTraceProviders = Extensions.extensionServer.traceProviders().filter( + provider => Timeline.TimelinePanel._settingForTraceProvider(provider).get()); + + var captureOptions = { + captureCauses: true, + enableJSSampling: this._captureJSProfileSetting.get(), + captureMemory: this._captureMemorySetting.get(), + capturePictures: this._captureLayersAndPicturesSetting.get(), + captureFilmStrip: this._captureFilmStripSetting.get() + }; + this._controller = new Timeline.TimelineController(mainTarget, this, this._tracingModel); - this._controller.startRecording( - true, this._captureJSProfileSetting.get(), this._captureMemorySetting.get(), - this._captureLayersAndPicturesSetting.get(), - this._captureFilmStripSetting && this._captureFilmStripSetting.get()); + this._controller.startRecording(captureOptions, enabledTraceProviders); + this._recordingStartTime = Date.now(); for (var i = 0; i < this._overviewControls.length; ++i) this._overviewControls[i].timelineStarted(); @@ -634,6 +675,8 @@ _clear() { this._showRecordingHelpMessage(); this._detailsSplitWidget.hideSidebar(); + this._sessionGeneration = null; + this._recordingStartTime = 0; this._reset(); } @@ -644,6 +687,9 @@ Components.LineLevelProfile.instance().reset(); this._tracingModel.reset(); this._model.reset(); + for (let extensionEntry of this._extensionTracingModels) + extensionEntry.model.reset(); + this._extensionTracingModels.splice(0); this.requestWindowTimes(0, Infinity); delete this._selection; @@ -676,6 +722,29 @@ this._statusPane.updateProgressBar(Common.UIString('Buffer usage'), usage * 100); } + /** + * @override + * @param {string} title + * @param {!SDK.TracingModel} tracingModel + * @param {number} timeOffset + */ + addExtensionEvents(title, tracingModel, timeOffset) { + this._extensionTracingModels.push({title: title, model: tracingModel, timeOffset: timeOffset}); + if (this._state !== Timeline.TimelinePanel.State.Idle) + return; + tracingModel.adjustTime(this._model.minimumRecordTime() + (timeOffset / 1000) - this._recordingStartTime); + for (let view of this._currentViews) + view.extensionDataAdded(); + } + + /** + * @override + * @return {?symbol} + */ + sessionGeneration() { + return this._sessionGeneration; + } + _showRecordingHelpMessage() { if (Runtime.experiments.isEnabled('timelineLandingPage')) { this._showLandingPage(); @@ -797,6 +866,10 @@ if (this._statusPane) this._statusPane.hide(); delete this._statusPane; + + for (let entry of this._extensionTracingModels) + entry.model.adjustTime(this._model.minimumRecordTime() + (entry.timeOffset / 1000) - this._recordingStartTime); + this._flameChart.resizeToPreferredHeights(); this._overviewPane.reset(); this._overviewPane.setBounds(this._model.minimumRecordTime(), this._model.maximumRecordTime()); @@ -1077,7 +1150,7 @@ */ _showSnapshotInPaintProfiler(snapshot) { var paintProfilerView = this._paintProfilerView(); - var hasProfileData = paintProfilerView.setSnapshot(snapshot); + paintProfilerView.setSnapshot(snapshot); if (!this._detailsView.hasTab(Timeline.TimelinePanel.DetailsTab.PaintProfiler)) { this._detailsView.appendTab( Timeline.TimelinePanel.DetailsTab.PaintProfiler, Common.UIString('Paint Profiler'), paintProfilerView, @@ -1299,16 +1372,9 @@ /** * @interface */ -Timeline.TimelineLifecycleDelegate = function() {}; +Timeline.LoaderClient = function() {}; -Timeline.TimelineLifecycleDelegate.prototype = { - recordingStarted() {}, - - /** - * @param {number} usage - */ - recordingProgress(usage) {}, - +Timeline.LoaderClient.prototype = { loadingStarted() {}, /** @@ -1323,6 +1389,31 @@ }; /** + * @interface + * @extends {Timeline.LoaderClient} + */ +Timeline.TimelineLifecycleDelegate = function() {}; + +Timeline.TimelineLifecycleDelegate.prototype = { + recordingStarted() {}, + + /** + * @param {number} usage + */ + recordingProgress(usage) {}, + + /** + * @param {string} title + * @param {!SDK.TracingModel} tracingModel + * @param {number} timeOffset + */ + addExtensionEvents(title, tracingModel, timeOffset) {}, + + /** @return {?symbol} */ + sessionGeneration() {} +}; + +/** * @unrestricted */ Timeline.TimelineDetailsView = class extends UI.TabbedPane { @@ -1533,6 +1624,8 @@ refreshRecords() {}, + extensionDataAdded() {}, + /** * @param {?SDK.TracingModel.Event} event * @param {string=} regex @@ -1922,6 +2015,8 @@ } }; +Timeline.TimelinePanel._traceProviderSettingSymbol = Symbol('traceProviderSetting'); + /** @enum {symbol} */ Timeline.TimelineFilters.Events = { FilterChanged: Symbol('FilterChanged')
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js index 8fb0910..c1135885 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineUIUtils.js
@@ -993,8 +993,6 @@ * @param {!Object} aggregatedStats */ static _collectAggregatedStatsForRecord(record, startTime, endTime, aggregatedStats) { - var records = []; - if (!record.endTime() || record.endTime() < startTime || record.startTime() > endTime) return; @@ -1023,7 +1021,6 @@ var contentHelper = new Timeline.TimelineDetailsContentHelper(target, linkifier); var duration = request.endTime - (request.startTime || -Infinity); - var items = []; if (request.url) contentHelper.appendElementRow(Common.UIString('URL'), Components.Linkifier.linkifyURL(request.url)); if (isFinite(duration)) @@ -1511,7 +1508,6 @@ * @return {!Element} */ static generateDetailsContentForFrame(frameModel, frame, filmStripFrame) { - var pieChart = Timeline.TimelineUIUtils.generatePieChart(frame.timeByCategory); var contentHelper = new Timeline.TimelineDetailsContentHelper(null, null); contentHelper.addSection(Common.UIString('Frame'));
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/module.json b/third_party/WebKit/Source/devtools/front_end/timeline/module.json index 205c09a..698db2cc 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/module.json +++ b/third_party/WebKit/Source/devtools/front_end/timeline/module.json
@@ -123,6 +123,7 @@ ], "scripts": [ "CountersGraph.js", + "ExtensionTracingSession.js", "MemoryCountersGraph.js", "TimelineController.js", "TimelineLoader.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineFrameModel.js b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineFrameModel.js index ca15c78..2c3bc72 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineFrameModel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineFrameModel.js
@@ -323,8 +323,6 @@ */ _addMainThreadTraceEvent(event) { var eventNames = TimelineModel.TimelineModel.RecordType; - var timestamp = event.startTime; - var selfTime = event.selfTime || 0; if (SDK.TracingModel.isTopLevelEvent(event)) { this._currentTaskTimeByCategory = {};
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineIRModel.js b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineIRModel.js index 3a70fcd..f505bf7 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineIRModel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline_model/TimelineIRModel.js
@@ -22,9 +22,6 @@ * @param {?Array<!SDK.TracingModel.AsyncEvent>} animations */ populate(inputLatencies, animations) { - var eventTypes = TimelineModel.TimelineIRModel.InputEvents; - var phases = TimelineModel.TimelineIRModel.Phases; - this.reset(); if (!inputLatencies) return;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/InplaceEditor.js b/third_party/WebKit/Source/devtools/front_end/ui/InplaceEditor.js index 843d0f1f..836998c 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/InplaceEditor.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/InplaceEditor.js
@@ -100,13 +100,6 @@ var moveDirection = ''; var self = this; - /** - * @param {!Event} e - */ - function consumeCopy(e) { - e.consume(); - } - this.setUpEditor(editingContext); editingContext.oldText = isMultiline ? config.initialValue : this.editorContent(editingContext);
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js b/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js index 237c3e77..7878a136 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js
@@ -114,7 +114,7 @@ */ _createControls(item, element) { var controls = createElementWithClass('div', 'controls-container fill'); - var gradient = controls.createChild('div', 'controls-gradient'); + controls.createChild('div', 'controls-gradient'); var buttons = controls.createChild('div', 'controls-buttons'); var editButton = buttons.createChild('div', 'edit-button');
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Widget.js b/third_party/WebKit/Source/devtools/front_end/ui/Widget.js index 825ca18..a7525f6 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/Widget.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/Widget.js
@@ -384,7 +384,6 @@ if (this._parentWidget._defaultFocusedChild === this) this._parentWidget._defaultFocusedChild = null; this._parentWidget.childWasDetached(this); - var parent = this._parentWidget; this._parentWidget = null; this._processWasDetachedFromHierarchy(); } else {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css b/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css index cedc661..f0fb819 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/inspectorCommon.css
@@ -327,6 +327,10 @@ flex-shrink: 0; } +.icon-mask { + background-color: rgb(110, 110, 110); +} + .spritesheet-smallicons { background-image: -webkit-image-set(url(Images/smallIcons.png) 1x, url(Images/smallIcons_2x.png) 2x); background-size: 190px 30px;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js index e6031df..49d49e9a 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js +++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/DataGrid.js
@@ -602,7 +602,6 @@ // when the two columns that get resized get a percent value for // their widths, all the other columns already have percent values // for their widths. - var headerTableColumns = this._headerTableColumnGroup.children; // Use container size to avoid changes of table width caused by change of column widths. var tableWidth = this.element.offsetWidth - this._cornerWidth;
diff --git a/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js b/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js index 5a4b6735..12d57bd 100644 --- a/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js +++ b/third_party/WebKit/Source/devtools/front_end/workspace/UISourceCode.js
@@ -173,7 +173,6 @@ * @param {!Common.ResourceType=} contentType */ _updateName(name, url, contentType) { - var oldURL = this.url(); this._url = this._url.substring(0, this._url.length - this._name.length) + name; this._name = name; if (url)
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in index d82f8b0..cc14099 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -95,6 +95,7 @@ DOMConvenienceAPI status=stable DurableStorage status=stable ExpensiveBackgroundTimerThrottling status=experimental +FasterLocationReload status=experimental FontCacheScaling status=test ForceDisplayList2dCanvas // See crbug.com/585250.
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp index af4eb79..f230328 100644 --- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp +++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -949,12 +949,7 @@ // needs to be audited. See http://crbug.com/590369 for more details. frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets(); - bool selectReplacement = - frame()->editor().behavior().shouldSelectReplacement(); - bool smartReplace = true; - frame()->editor().replaceSelectionWithText( - text, selectReplacement, smartReplace, - InputEvent::InputType::InsertReplacementText); + frame()->editor().replaceSelection(text); } void WebLocalFrameImpl::setMarkedText(const WebString& text,
diff --git a/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp b/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp index 0d80dda0..1038ec61 100644 --- a/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp +++ b/third_party/WebKit/Source/web/tests/RootScrollerTest.cpp
@@ -524,8 +524,9 @@ // No root scroller set, the documentElement should be the effective root // and the main FrameView's scroll layer should be the layer to use. { - EXPECT_EQ(mainController.rootScrollerLayer(), - mainFrameView()->layerForScrolling()); + EXPECT_EQ( + mainController.rootScrollerLayer(), + mainFrameView()->layoutViewportScrollableArea()->layerForScrolling()); EXPECT_TRUE(mainController.isViewportScrollCallback( mainFrame()->document()->documentElement()->getApplyScroll())); } @@ -536,8 +537,9 @@ iframe->contentDocument()->setRootScroller(container, nonThrow); mainFrameView()->updateAllLifecyclePhases(); - EXPECT_EQ(mainController.rootScrollerLayer(), - mainFrameView()->layerForScrolling()); + EXPECT_EQ( + mainController.rootScrollerLayer(), + mainFrameView()->layoutViewportScrollableArea()->layerForScrolling()); EXPECT_TRUE(mainController.isViewportScrollCallback( mainFrame()->document()->documentElement()->getApplyScroll())); } @@ -568,7 +570,10 @@ iframe->contentDocument()->setRootScroller(nullptr, nonThrow); mainFrameView()->updateAllLifecyclePhases(); EXPECT_EQ(mainController.rootScrollerLayer(), - iframe->contentDocument()->view()->layerForScrolling()); + iframe->contentDocument() + ->view() + ->layoutViewportScrollableArea() + ->layerForScrolling()); EXPECT_FALSE( mainController.isViewportScrollCallback(container->getApplyScroll())); EXPECT_FALSE(mainController.isViewportScrollCallback( @@ -582,8 +587,9 @@ { mainFrame()->document()->setRootScroller(nullptr, nonThrow); mainFrameView()->updateAllLifecyclePhases(); - EXPECT_EQ(mainController.rootScrollerLayer(), - mainFrameView()->layerForScrolling()); + EXPECT_EQ( + mainController.rootScrollerLayer(), + mainFrameView()->layoutViewportScrollableArea()->layerForScrolling()); EXPECT_TRUE(mainController.isViewportScrollCallback( mainFrame()->document()->documentElement()->getApplyScroll())); EXPECT_FALSE( @@ -729,6 +735,12 @@ m_helper.reset(); } +GraphicsLayer* scrollingLayer(LayoutView& layoutView) { + if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) + return layoutView.layer()->compositedLayerMapping()->scrollingLayer(); + return layoutView.compositor()->rootContentLayer(); +} + // Tests that clipping layers belonging to any compositors in the ancestor chain // of the global root scroller have their masking bit removed. TEST_F(RootScrollerTest, RemoveClippingOnCompositorLayers) { @@ -745,10 +757,10 @@ TopDocumentRootScrollerController& globalController = frameHost().globalRootScrollerController(); - PaintLayerCompositor* mainCompositor = - mainFrameView()->layoutViewItem().compositor(); - PaintLayerCompositor* childCompositor = - iframe->contentDocument()->view()->layoutViewItem().compositor(); + LayoutView* mainLayoutView = mainFrameView()->layoutView(); + LayoutView* childLayoutView = iframe->contentDocument()->layoutView(); + PaintLayerCompositor* mainCompositor = mainLayoutView->compositor(); + PaintLayerCompositor* childCompositor = childLayoutView->compositor(); NonThrowableExceptionState nonThrow; @@ -757,14 +769,14 @@ // container layers should also clip. { EXPECT_TRUE( - mainCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*mainLayoutView)->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->containerLayer()->platformLayer()->masksToBounds()); EXPECT_TRUE( - childCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*childLayoutView)->platformLayer()->masksToBounds()); EXPECT_TRUE( childCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_TRUE( @@ -783,14 +795,14 @@ ASSERT_EQ(container, &childController.effectiveRootScroller()); EXPECT_FALSE( - mainCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*mainLayoutView)->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->containerLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE( - childCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*childLayoutView)->platformLayer()->masksToBounds()); EXPECT_FALSE( childCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE( @@ -811,14 +823,14 @@ globalController.globalRootScroller()); EXPECT_FALSE( - mainCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*mainLayoutView)->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->containerLayer()->platformLayer()->masksToBounds()); EXPECT_TRUE( - childCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*childLayoutView)->platformLayer()->masksToBounds()); EXPECT_FALSE( childCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE( @@ -842,14 +854,14 @@ globalController.globalRootScroller()); EXPECT_TRUE( - mainCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*mainLayoutView)->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->containerLayer()->platformLayer()->masksToBounds()); EXPECT_TRUE( - childCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*childLayoutView)->platformLayer()->masksToBounds()); EXPECT_TRUE( childCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_TRUE( @@ -871,14 +883,14 @@ globalController.globalRootScroller()); EXPECT_FALSE( - mainCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*mainLayoutView)->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->containerLayer()->platformLayer()->masksToBounds()); EXPECT_TRUE( - childCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*childLayoutView)->platformLayer()->masksToBounds()); EXPECT_FALSE( childCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE( @@ -896,14 +908,14 @@ ASSERT_EQ(container, &childController.effectiveRootScroller()); EXPECT_TRUE( - mainCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*mainLayoutView)->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE( mainCompositor->containerLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE( - childCompositor->rootContentLayer()->platformLayer()->masksToBounds()); + scrollingLayer(*childLayoutView)->platformLayer()->masksToBounds()); EXPECT_FALSE( childCompositor->rootGraphicsLayer()->platformLayer()->masksToBounds()); EXPECT_FALSE(
diff --git a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp index b28dd7a3..1a5df9e 100644 --- a/third_party/WebKit/Source/web/tests/WebFrameTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebFrameTest.cpp
@@ -4130,7 +4130,7 @@ // Reload the page and end up at the same url. State should be propagated. webViewHelper.webView()->mainFrame()->reloadWithOverrideURL( - toKURL(m_baseURL + firstURL), WebFrameLoadType::Reload); + toKURL(m_baseURL + firstURL), WebFrameLoadType::ReloadMainResource); FrameTestHelpers::pumpPendingRequestsForFrameToLoad( webViewHelper.webView()->mainFrame()); EXPECT_EQ(previousOffset.width, @@ -4141,7 +4141,7 @@ // Reload the page using the cache. State should not be propagated. webViewHelper.webView()->mainFrame()->reloadWithOverrideURL( - toKURL(m_baseURL + secondURL), WebFrameLoadType::Reload); + toKURL(m_baseURL + secondURL), WebFrameLoadType::ReloadMainResource); FrameTestHelpers::pumpPendingRequestsForFrameToLoad( webViewHelper.webView()->mainFrame()); EXPECT_EQ(0, webViewHelper.webView()->mainFrame()->getScrollOffset().width);
diff --git a/third_party/WebKit/Source/web/tests/data/root-scroller-child.html b/third_party/WebKit/Source/web/tests/data/root-scroller-child.html index 0223fdd..2c150d6 100644 --- a/third_party/WebKit/Source/web/tests/data/root-scroller-child.html +++ b/third_party/WebKit/Source/web/tests/data/root-scroller-child.html
@@ -33,5 +33,6 @@ <div id="container"> <div id="spacer"></div> </div> + <div id="spacer"></div> </body> </html>
diff --git a/third_party/WebKit/Source/web/tests/data/root-scroller-iframe.html b/third_party/WebKit/Source/web/tests/data/root-scroller-iframe.html index b6a6db1..4bb6e9b 100644 --- a/third_party/WebKit/Source/web/tests/data/root-scroller-iframe.html +++ b/third_party/WebKit/Source/web/tests/data/root-scroller-iframe.html
@@ -21,10 +21,16 @@ height: 100%; border-style: none; } + + #spacer { + width: 800px; + height: 800px; + } </style> </head> <body> <iframe src="root-scroller-child.html" id="iframe"></iframe> + <div id="spacer"></div> </body> </html>
diff --git a/third_party/WebKit/public/web/WebFrame.h b/third_party/WebKit/public/web/WebFrame.h index 2dae4ef..581e3c8 100644 --- a/third_party/WebKit/public/web/WebFrame.h +++ b/third_party/WebKit/public/web/WebFrame.h
@@ -320,13 +320,12 @@ // Reload the current document. // Note: reload() and reloadWithOverrideURL() will be deprecated. // Do not use these APIs any more, but use loadRequest() instead. - virtual void reload(WebFrameLoadType = WebFrameLoadType::Reload) = 0; + virtual void reload(WebFrameLoadType) = 0; // This is used for situations where we want to reload a different URL because // of a redirect. - virtual void reloadWithOverrideURL( - const WebURL& overrideUrl, - WebFrameLoadType = WebFrameLoadType::Reload) = 0; + virtual void reloadWithOverrideURL(const WebURL& overrideUrl, + WebFrameLoadType) = 0; // Load the given URL. virtual void loadRequest(const WebURLRequest&) = 0;
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 168e7f1d..e856f24b 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -25912,6 +25912,13 @@ </summary> </histogram> +<histogram base="true" name="Media.WebMediaPlayerImpl.Memory" units="KB"> + <owner>servolk@chromium.org</owner> + <summary> + Amount of memory used by the WebMediaPlayerImpl and its components. + </summary> +</histogram> + <histogram name="Media.WindowsCoreAudioInput" enum="BooleanSuccess"> <owner>henrika@chromium.org</owner> <summary> @@ -51249,6 +51256,16 @@ <summary>Number of unlimited origins using temporary storage.</summary> </histogram> +<histogram name="Quota.OSAccomodationDelta" units="MB"> + <owner>michaeln@chromium.org</owner> + <summary> + If our hardcoded OS accomodation is too large for the volume size, we define + the value as a fraction of the total volume size instead. The + OSAccomodationDelta is the difference between the hardcoded and computed + values. + </summary> +</histogram> + <histogram name="Quota.QuotaForOrigin" units="MB"> <owner>michaeln@chromium.org</owner> <summary> @@ -51284,7 +51301,18 @@ <summary>Time spent to an eviction round.</summary> </histogram> +<histogram name="Quota.TimeToGetSettings" units="ms"> + <owner>michaeln@chromium.org</owner> + <summary> + Time spent querying the embedder for the settings values. Logged at + irregular intervals as the values are refreshed. + </summary> +</histogram> + <histogram name="Quota.TimeToInitializeGlobalQuota" units="ms"> + <obsolete> + Removed November 2016 + </obsolete> <owner>michaeln@chromium.org</owner> <summary> Time spent initializing the global quota. Logged when the storage @@ -53642,6 +53670,33 @@ </summary> </histogram> +<histogram name="SafeBrowsing.ReferrerAttributionResult" + enum="SafeBrowsingAttributionResultTypes"> + <owner>jialiul@chromium.org</owner> + <summary> + The result of referrer attribution, including different types of success or + failure. This is incremented each time a safe browsing ping or download ping + is generated. + </summary> +</histogram> + +<histogram name="SafeBrowsing.ReferrerHasInvalidTabID" enum="BooleanInvalid"> + <owner>jialiul@chromium.org</owner> + <summary> + Number of times referrer attribution encounters an invalid tab ID. This is + incremented a safe browsing ping or download ping is generated and an + invalid tab ID is encountered during attribution. + </summary> +</histogram> + +<histogram name="SafeBrowsing.ReferrerURLChainSize"> + <owner>jialiul@chromium.org</owner> + <summary> + The length of referrer URL chain we get from referrer attribution. This is + incremented each time a safe browsing ping or download ping is generated. + </summary> +</histogram> + <histogram name="SafeBrowsing.UnverifiedDownloads.Allowed" enum="SBClientDownloadExtensions"> <owner>asanka@chromium.org</owner> @@ -101021,6 +101076,14 @@ <int value="1" label="Kill (He's dead, Jim!)"/> </enum> +<enum name="SafeBrowsingAttributionResultTypes" type="int"> + <int value="1" label="SUCCESS"/> + <int value="2" label="SUCCESS_LANDING_PAGE"/> + <int value="3" label="SUCCESS_LANDING_REFERRER"/> + <int value="4" label="INVALID_URL"/> + <int value="5" label="NAVIGATION_EVENT_NOT_FOUND"/> +</enum> + <enum name="SafeBrowsingParseV4HashResult" type="int"> <int value="0" label="PARSE_FROM_STRING_ERROR"/> <int value="1" label="UNEXPECTED_THREAT_ENTRY_TYPE_ERROR"/> @@ -110584,6 +110647,14 @@ <affected-histogram name="Media.WatchTime"/> </histogram_suffixes> +<histogram_suffixes name="MediaWMPIMemoryUsage" separator="."> + <suffix name="Audio"/> + <suffix name="DataSource"/> + <suffix name="Demuxer"/> + <suffix name="Video"/> + <affected-histogram name="Media.WebMediaPlayerImpl.Memory"/> +</histogram_suffixes> + <histogram_suffixes name="MemoryStateTransition" separator="."> <suffix name="NormalToThrottled"/> <suffix name="NormalToSuspended"/> @@ -113636,6 +113707,19 @@ <affected-histogram name="Renderer4.ImageDecodeTaskDurationUs"/> </histogram_suffixes> +<histogram_suffixes name="ReferrerAttribution" separator="."> + <suffix name="DownloadAttribution" label="Download referrer attribution."/> + <suffix name="PhishingInterstitialAttribution" + label="Phishing interstitial referrer attribution."/> + <suffix name="MalwareInterstitialAttribution" + label="Malware interstitial referrer attribution."/> + <suffix name="UwsInterstitialAttribution" + label="UwS interstitial referrer attribution."/> + <affected-histogram name="SafeBrowsing.ReferrerAttributionResult"/> + <affected-histogram name="SafeBrowsing.ReferrerHasInvalidTabID"/> + <affected-histogram name="SafeBrowsing.ReferrerURLChainSize"/> +</histogram_suffixes> + <histogram_suffixes name="RemoteProcessWarmStartFast" separator=""> <suffix name="" label="Normal start."/> <suffix name="Fast"
diff --git a/ui/aura/mus/window_tree_host_mus.cc b/ui/aura/mus/window_tree_host_mus.cc index 895ef4b..c5c314b02 100644 --- a/ui/aura/mus/window_tree_host_mus.cc +++ b/ui/aura/mus/window_tree_host_mus.cc
@@ -108,9 +108,11 @@ SetBoundsInPixels(bounds); } -void WindowTreeHostMus::SetClientArea(const gfx::Insets& insets) { +void WindowTreeHostMus::SetClientArea( + const gfx::Insets& insets, + const std::vector<gfx::Rect>& additional_client_area) { delegate_->OnWindowTreeHostClientAreaWillChange(this, insets, - std::vector<gfx::Rect>()); + additional_client_area); } void WindowTreeHostMus::SetHitTestMask(const base::Optional<gfx::Rect>& rect) {
diff --git a/ui/aura/mus/window_tree_host_mus.h b/ui/aura/mus/window_tree_host_mus.h index 4cf6f1b..0d923b4 100644 --- a/ui/aura/mus/window_tree_host_mus.h +++ b/ui/aura/mus/window_tree_host_mus.h
@@ -61,7 +61,8 @@ InputMethodMus* input_method() { return input_method_.get(); } // Sets the client area on the underlying mus window. - void SetClientArea(const gfx::Insets& insets); + void SetClientArea(const gfx::Insets& insets, + const std::vector<gfx::Rect>& additional_client_area); // Sets the hit test mask on the underlying mus window. Pass base::nullopt to // clear.
diff --git a/ui/aura/mus/window_tree_host_mus_unittest.cc b/ui/aura/mus/window_tree_host_mus_unittest.cc index fd2e93b..ac644ac 100644 --- a/ui/aura/mus/window_tree_host_mus_unittest.cc +++ b/ui/aura/mus/window_tree_host_mus_unittest.cc
@@ -16,7 +16,7 @@ base::MakeUnique<WindowTreeHostMus>(window_tree_client_impl()); gfx::Insets new_insets(10, 11, 12, 13); - window_tree_host_mus->SetClientArea(new_insets); + window_tree_host_mus->SetClientArea(new_insets, std::vector<gfx::Rect>()); EXPECT_EQ(new_insets, window_tree()->last_client_area()); }
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.css b/ui/file_manager/file_manager/foreground/elements/files_quick_view.css index 0b31eea..242da315 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.css +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.css
@@ -50,7 +50,9 @@ #contentPanel { background-color: transparent; + display: flex; height: 100%; + justify-content: center; position: relative; } @@ -76,25 +78,26 @@ color: white; display: flex; flex-direction: column; - height: 70%; justify-content: center; - margin: auto; outline: none; + padding: 24px 15%; position: relative; text-align: center; - top: 15%; - width: 70%; + width: 100%; +} + +#innerContentPanel[type="audio"], +#innerContentPanel[type="image"], +#innerContentPanel[type="video"] { + align-self: center; + height: 70%; + padding-bottom: initial; + padding-top: initial; } .content { - bottom: 0; - left: 0; - margin: auto; - max-height: 100%; - max-width: 100%; - position: absolute; - right: 0; - top: 0; + height: 100%; + width: 100%; } #toolbar { @@ -188,27 +191,28 @@ height: 88px; } +[generic-thumbnail=".folder"] { + background-image: -webkit-image-set( + url(../images/files/ui/quick_view/filetype_folder.png) 1x, + url(../images/files/ui/quick_view/2x/filetype_folder.png) 2x); + height: 72px; +} + [generic-thumbnail='audio'] { - background: -webkit-image-set( + background-image: -webkit-image-set( url(../images/files/ui/quick_view/filetype_audio.png) 1x, - url(../images/files/ui/quick_view/2x/filetype_audio.png) 2x) - center - no-repeat; + url(../images/files/ui/quick_view/2x/filetype_audio.png) 2x); } [generic-thumbnail='image'] { - background: -webkit-image-set( + background-image: -webkit-image-set( url(../images/files/ui/quick_view/filetype_image.png) 1x, - url(../images/files/ui/quick_view/2x/filetype_image.png) 2x) - center - no-repeat; + url(../images/files/ui/quick_view/2x/filetype_image.png) 2x); } [generic-thumbnail='video'] { - background: -webkit-image-set( + background-image: -webkit-image-set( url(../images/files/ui/quick_view/filetype_video.png) 1x, - url(../images/files/ui/quick_view/2x/filetype_video.png) 2x) - center - no-repeat; + url(../images/files/ui/quick_view/2x/filetype_video.png) 2x); height: 72px; }
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html index bc34644..a70e66c 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.html +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.html
@@ -21,7 +21,7 @@ <paper-toolbar id="toolbar"> <div>[[filePath]]</div> <div id="buttons"> - <paper-button id="open-button" on-tap="onOpenInNewButtonTap" hidden$="[[isUnsupported_(type)]]" i18n-values="aria-label:QUICK_VIEW_OPEN_IN_NEW_BUTTON_LABEL" tabindex="0" has-tooltip> + <paper-button id="open-button" on-tap="onOpenInNewButtonTap" hidden$="[[isUnsupported_(type, browsable)]]" i18n-values="aria-label:QUICK_VIEW_OPEN_IN_NEW_BUTTON_LABEL" tabindex="0" has-tooltip> <iron-icon icon="files:open-in-new"></iron-icon> </paper-button> <files-icon-button toggles id="metadata-button" on-tap="onMetadataButtonTap_" active="{{metadataBoxActive}}" i18n-values="aria-label:QUICK_VIEW_TOGGLE_METADATA_BOX_BUTTON_LABEL" tabindex="0" has-tooltip> @@ -30,11 +30,14 @@ </paper-toolbar> <div id="mainPanel"> <div id="contentPanel" metadata-box-active$="[[metadataBoxActive]]" on-tap="onContentPanelTap_"> - <div id="innerContentPanel" tabindex="0"> + <div id="innerContentPanel" type$="[[type]]" tabindex="0"> + <!-- PDF, Text --> + <template is="dom-if" if="[[browsable]]"> + <webview class="content" src="[[contentUrl]]"></webview> + </template> + <!-- Image --> <template is="dom-if" if="[[isImage_(type)]]"> - <div hidden="[[!contentUrl]]"> - <files-safe-media type="image" class="content no-close-on-click" src="[[contentUrl]]"></files-safe-media> - </div> + <files-safe-media hidden="[[!contentUrl]]" type="image" class="content no-close-on-click" src="[[contentUrl]]"></files-safe-media> <template is="dom-if" if="[[!contentUrl]]"> <div generic-thumbnail="image"></div> <div class="no-preivew">[[noPreviewText]]</div> @@ -66,9 +69,8 @@ <div class="no-preivew">[[noPlaybackText]]</div> </template> </template> - <!-- TODO(oka): Support folder icon --> - <div hidden="[[!isUnsupported_(type)]]"> - <div generic-thumbnail></div> + <div hidden="[[!isUnsupported_(type, browsable)]]"> + <div generic-thumbnail$="[[type]]"></div> <div class="no-preview">[[noPreviewText]]</div> </div> </div> <!-- innerContentPanel -->
diff --git a/ui/file_manager/file_manager/foreground/elements/files_quick_view.js b/ui/file_manager/file_manager/foreground/elements/files_quick_view.js index f887b5e3..c551cd52 100644 --- a/ui/file_manager/file_manager/foreground/elements/files_quick_view.js +++ b/ui/file_manager/file_manager/foreground/elements/files_quick_view.js
@@ -15,6 +15,10 @@ videoPoster: String, audioArtwork: String, autoplay: Boolean, + // True if this file is not image, audio nor video but supported on Chrome, + // i.e. preview-able by directly src-ing the file path to webview. + // Example: pdf, text. + browsable: Boolean, // metadata-box-active-changed event is fired on attribute change. metadataBoxActive: { @@ -41,6 +45,7 @@ this.videoPoster = ''; this.audioArtwork = ''; this.autoplay = false; + this.browsable = false; }, // Opens the dialog. @@ -154,8 +159,9 @@ * * @private */ - isUnsupported_: function(type) { - return !this.isImage_(type) && !this.isVideo_(type) && !this.isAudio_(type); + isUnsupported_: function(type, browsable) { + return !this.isImage_(type) && !this.isVideo_(type) && + !this.isAudio_(type) && !browsable; }, });
diff --git a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js index 2b04daa..c651a9e0 100644 --- a/ui/file_manager/file_manager/foreground/js/quick_view_controller.js +++ b/ui/file_manager/file_manager/foreground/js/quick_view_controller.js
@@ -203,12 +203,13 @@ */ QuickViewController.prototype.onMetadataLoaded_ = function(entry, items) { return this.getQuickViewParameters_(entry, items).then(function(params) { - this.quickView_.contentUrl = params.contentUrl || ''; this.quickView_.type = params.type || ''; this.quickView_.filePath = params.filePath || ''; + this.quickView_.contentUrl = params.contentUrl || ''; this.quickView_.videoPoster = params.videoPoster || ''; this.quickView_.audioArtwork = params.audioArtwork || ''; this.quickView_.autoplay = params.autoplay || false; + this.quickView_.browsable = params.browsable || false; }.bind(this)); }; @@ -219,7 +220,8 @@ * contentUrl: (string|undefined), * videoPoster: (string|undefined), * audioArtwork: (string|undefined), - * autoplay: (boolean|undefined) + * autoplay: (boolean|undefined), + * browsable: (boolean|undefined), * }} */ var QuickViewParams; @@ -311,7 +313,27 @@ }); } } - return Promise.resolve(params); + if (item.externalFileUrl || type === '.folder') { + return Promise.resolve(params); + } + return Promise + .all([ + getFile(entry), + new Promise(function(resolve) { + chrome.fileManagerPrivate.getFileTasks([entry], resolve); + }) + ]) + .then(function(values) { + var file = values[0]; + var tasks = values[1]; + var browsable = tasks.some(function(task) { + return ['view-in-browser', 'view-pdf'].includes( + task.taskId.split('|')[2]); + }); + params.browsable = browsable; + params.contentUrl = browsable && URL.createObjectURL(file); + return params; + }); }; /**
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc index f502133..4b280c4dc 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.cc +++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -31,11 +31,6 @@ namespace { -bool ShouldSetClientArea(views::Widget::InitParams::Type type) { - using WIP = views::Widget::InitParams; - return type == WIP::TYPE_WINDOW || type == WIP::TYPE_PANEL; -} - // As the window manager renderers the non-client decorations this class does // very little but honor the client area insets from the window manager. class ClientSideNonClientFrameView : public NonClientFrameView { @@ -201,7 +196,7 @@ } void DesktopWindowTreeHostMus::SendClientAreaToServer() { - if (!ShouldSetClientArea(desktop_native_widget_aura_->widget_type())) + if (!ShouldSendClientAreaToServer()) return; NonClientView* non_client_view = @@ -210,10 +205,12 @@ return; const gfx::Rect client_area_rect(non_client_view->client_view()->bounds()); - SetClientArea(gfx::Insets( - client_area_rect.y(), client_area_rect.x(), - non_client_view->bounds().height() - client_area_rect.bottom(), - non_client_view->bounds().width() - client_area_rect.right())); + SetClientArea( + gfx::Insets( + client_area_rect.y(), client_area_rect.x(), + non_client_view->bounds().height() - client_area_rect.bottom(), + non_client_view->bounds().width() - client_area_rect.right()), + std::vector<gfx::Rect>()); } void DesktopWindowTreeHostMus::SendHitTestMaskToServer() { @@ -241,6 +238,15 @@ SetBoundsInPixels(gfx::ConvertRectToPixel(GetScaleFactor(), bounds_in_dip)); } +bool DesktopWindowTreeHostMus::ShouldSendClientAreaToServer() const { + if (!auto_update_client_area_) + return false; + + using WIP = views::Widget::InitParams; + const WIP::Type type = desktop_native_widget_aura_->widget_type(); + return type == WIP::TYPE_WINDOW || type == WIP::TYPE_PANEL; +} + void DesktopWindowTreeHostMus::Init(aura::Window* content_window, const Widget::InitParams& params) { // Needed so we don't render over the non-client area the window manager @@ -554,7 +560,7 @@ } NonClientFrameView* DesktopWindowTreeHostMus::CreateNonClientFrameView() { - if (!ShouldSetClientArea(desktop_native_widget_aura_->widget_type())) + if (!ShouldSendClientAreaToServer()) return nullptr; return new ClientSideNonClientFrameView(native_widget_delegate_->AsWidget());
diff --git a/ui/views/mus/desktop_window_tree_host_mus.h b/ui/views/mus/desktop_window_tree_host_mus.h index 6603cf3..562eb0a 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.h +++ b/ui/views/mus/desktop_window_tree_host_mus.h
@@ -37,6 +37,11 @@ // Called when the window was deleted on the server. void ServerDestroyedWindow() { CloseNow(); } + // Controls whether the client area is automatically updated as necessary. + void set_auto_update_client_area(bool value) { + auto_update_client_area_ = value; + } + private: bool IsDocked() const; @@ -48,6 +53,9 @@ void SetBoundsInDIP(const gfx::Rect& bounds_in_dip); + // Returns true if the client area should be set on this. + bool ShouldSendClientAreaToServer() const; + // DesktopWindowTreeHost: void Init(aura::Window* content_window, const Widget::InitParams& params) override; @@ -142,6 +150,8 @@ std::unique_ptr<wm::CursorManager> cursor_manager_; + bool auto_update_client_area_ = true; + // Used so that Close() isn't immediate. base::WeakPtrFactory<DesktopWindowTreeHostMus> close_widget_factory_;
diff --git a/ui/views/style/platform_style.cc b/ui/views/style/platform_style.cc index 1febd1f..c7cbab1 100644 --- a/ui/views/style/platform_style.cc +++ b/ui/views/style/platform_style.cc
@@ -17,7 +17,9 @@ #include "ui/views/controls/focusable_border.h" #include "ui/views/controls/scrollbar/scroll_bar_views.h" -#if defined(OS_LINUX) && !defined(OS_CHROMEOS) +#if defined(OS_CHROMEOS) +#include "ui/views/controls/scrollbar/overlay_scroll_bar.h" +#elif defined(OS_LINUX) #define DESKTOP_LINUX #endif @@ -56,7 +58,11 @@ // static std::unique_ptr<ScrollBar> PlatformStyle::CreateScrollBar(bool is_horizontal) { +#if defined(OS_CHROMEOS) + return base::MakeUnique<OverlayScrollBar>(is_horizontal); +#else return base::MakeUnique<ScrollBarViews>(is_horizontal); +#endif } // static
diff --git a/ui/views_content_client/DEPS b/ui/views_content_client/DEPS index 7f82ac5..5be0a24 100644 --- a/ui/views_content_client/DEPS +++ b/ui/views_content_client/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+content/public", "+content/shell", + "+storage/browser/quota", "+ui/aura", "+ui/base", "+ui/display",
diff --git a/ui/views_content_client/views_content_browser_client.cc b/ui/views_content_client/views_content_browser_client.cc index 29b6dec..f8c5a854 100644 --- a/ui/views_content_client/views_content_browser_client.cc +++ b/ui/views_content_client/views_content_browser_client.cc
@@ -4,6 +4,10 @@ #include "ui/views_content_client/views_content_browser_client.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/storage_partition.h" +#include "storage/browser/quota/quota_settings.h" #include "ui/views_content_client/views_content_client_main_parts.h" namespace ui { @@ -24,4 +28,15 @@ return views_content_main_parts_; } +void ViewsContentBrowserClient::GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) { + content::BrowserThread::PostTaskAndReplyWithResult( + content::BrowserThread::FILE, FROM_HERE, + base::Bind(&storage::CalculateNominalDynamicSettings, + partition->GetPath(), context->IsOffTheRecord()), + callback); +} + } // namespace ui
diff --git a/ui/views_content_client/views_content_browser_client.h b/ui/views_content_client/views_content_browser_client.h index 408fb8a..017ae63 100644 --- a/ui/views_content_client/views_content_browser_client.h +++ b/ui/views_content_client/views_content_browser_client.h
@@ -22,6 +22,10 @@ // content::ContentBrowserClient: content::BrowserMainParts* CreateBrowserMainParts( const content::MainFunctionParams& parameters) override; + void GetQuotaSettings( + content::BrowserContext* context, + content::StoragePartition* partition, + const storage::OptionalQuotaSettingsCallback& callback) override; private: ViewsContentClientMainParts* views_content_main_parts_;