| Index: chrome/browser/metrics/first_web_contents_profiler.cc
|
| diff --git a/chrome/browser/metrics/first_web_contents_profiler.cc b/chrome/browser/metrics/first_web_contents_profiler.cc
|
| index dcff83a5e2d9247a5307b811832ce65a239e8d4a..9a219ced2ce21c8612e5f30b96999d8bb1711673 100644
|
| --- a/chrome/browser/metrics/first_web_contents_profiler.cc
|
| +++ b/chrome/browser/metrics/first_web_contents_profiler.cc
|
| @@ -2,14 +2,13 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -#if !defined(OS_ANDROID)
|
| -
|
| #include "chrome/browser/metrics/first_web_contents_profiler.h"
|
|
|
| #include <string>
|
|
|
| #include "base/location.h"
|
| #include "base/logging.h"
|
| +#include "base/macros.h"
|
| #include "base/metrics/histogram_macros.h"
|
| #include "base/time/time.h"
|
| #include "build/build_config.h"
|
| @@ -20,29 +19,82 @@
|
| #include "components/metrics/proto/profiler_event.pb.h"
|
| #include "components/startup_metric_utils/browser/startup_metric_utils.h"
|
| #include "content/public/browser/navigation_handle.h"
|
| +#include "content/public/browser/web_contents.h"
|
| +#include "content/public/browser/web_contents_observer.h"
|
| #include "content/public/common/browser_side_navigation_policy.h"
|
|
|
| -// static
|
| -void FirstWebContentsProfiler::Start() {
|
| - for (auto* browser : *BrowserList::GetInstance()) {
|
| - content::WebContents* web_contents =
|
| - browser->tab_strip_model()->GetActiveWebContents();
|
| - if (web_contents) {
|
| - // FirstWebContentsProfiler owns itself and is also bound to
|
| - // |web_contents|'s lifetime by observing WebContentsDestroyed().
|
| - new FirstWebContentsProfiler(web_contents);
|
| - return;
|
| - }
|
| - }
|
| -}
|
| +namespace {
|
| +
|
| +class FirstWebContentsProfiler : public content::WebContentsObserver {
|
| + public:
|
| + FirstWebContentsProfiler(content::WebContents* web_contents,
|
| + startup_metric_utils::WebContentsWorkload workload);
|
| +
|
| + private:
|
| + // Reasons for which profiling is deemed complete. Logged in UMA (do not re-
|
| + // order or re-assign).
|
| + enum FinishReason {
|
| + // All metrics were successfully gathered.
|
| + DONE = 0,
|
| + // Abandon if blocking UI was shown during startup.
|
| + ABANDON_BLOCKING_UI = 1,
|
| + // Abandon if the content is hidden (lowers scheduling priority).
|
| + ABANDON_CONTENT_HIDDEN = 2,
|
| + // Abandon if the content is destroyed.
|
| + ABANDON_CONTENT_DESTROYED = 3,
|
| + // Abandon if the WebContents navigates away from its initial page.
|
| + ABANDON_NEW_NAVIGATION = 4,
|
| + // Abandon if the WebContents fails to load (e.g. network error, etc.).
|
| + ABANDON_NAVIGATION_ERROR = 5,
|
| + ENUM_MAX
|
| + };
|
| +
|
| + ~FirstWebContentsProfiler() override = default;
|
| +
|
| + // content::WebContentsObserver:
|
| + void DidFirstVisuallyNonEmptyPaint() override;
|
| + void DocumentOnLoadCompletedInMainFrame() override;
|
| + void DidStartNavigation(
|
| + content::NavigationHandle* navigation_handle) override;
|
| + void DidFinishNavigation(
|
| + content::NavigationHandle* navigation_handle) override;
|
| + void WasHidden() override;
|
| + void WebContentsDestroyed() override;
|
| +
|
| + // Whether this instance has finished collecting first-paint and main-frame-
|
| + // load metrics (navigation metrics are recorded on a best effort but don't
|
| + // prevent the FirstWebContentsProfiler from calling it).
|
| + bool IsFinishedCollectingMetrics();
|
| +
|
| + // Logs |finish_reason| to UMA and deletes this FirstWebContentsProfiler.
|
| + void FinishedCollectingMetrics(FinishReason finish_reason);
|
| +
|
| + // Whether an attempt was made to collect the "NonEmptyPaint" metric.
|
| + bool collected_paint_metric_;
|
| +
|
| + // Whether an attempt was made to collect the "MainFrameLoad" metric.
|
| + bool collected_load_metric_;
|
| +
|
| + // Whether an attempt was made to collect the "MainNavigationStart" metric.
|
| + bool collected_main_navigation_start_metric_;
|
| +
|
| + // Whether an attempt was made to collect the "MainNavigationFinished" metric.
|
| + bool collected_main_navigation_finished_metric_;
|
| +
|
| + const startup_metric_utils::WebContentsWorkload workload_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(FirstWebContentsProfiler);
|
| +};
|
|
|
| FirstWebContentsProfiler::FirstWebContentsProfiler(
|
| - content::WebContents* web_contents)
|
| + content::WebContents* web_contents,
|
| + startup_metric_utils::WebContentsWorkload workload)
|
| : content::WebContentsObserver(web_contents),
|
| collected_paint_metric_(false),
|
| collected_load_metric_(false),
|
| collected_main_navigation_start_metric_(false),
|
| - collected_main_navigation_finished_metric_(false) {}
|
| + collected_main_navigation_finished_metric_(false),
|
| + workload_(workload) {}
|
|
|
| void FirstWebContentsProfiler::DidFirstVisuallyNonEmptyPaint() {
|
| if (collected_paint_metric_)
|
| @@ -100,7 +152,7 @@ void FirstWebContentsProfiler::DidStartNavigation(
|
|
|
| collected_main_navigation_start_metric_ = true;
|
| startup_metric_utils::RecordFirstWebContentsMainNavigationStart(
|
| - base::TimeTicks::Now());
|
| + base::TimeTicks::Now(), workload_);
|
| }
|
|
|
| void FirstWebContentsProfiler::DidFinishNavigation(
|
| @@ -136,7 +188,7 @@ void FirstWebContentsProfiler::DidFinishNavigation(
|
|
|
| if (content::IsBrowserSideNavigationEnabled()) {
|
| startup_metric_utils::RecordFirstWebContentsMainNavigationStart(
|
| - navigation_handle->NavigationStart());
|
| + navigation_handle->NavigationStart(), workload_);
|
| collected_main_navigation_start_metric_ = true;
|
| }
|
|
|
| @@ -175,4 +227,32 @@ void FirstWebContentsProfiler::FinishedCollectingMetrics(
|
| delete this;
|
| }
|
|
|
| -#endif // !defined(OS_ANDROID)
|
| +} // namespace
|
| +
|
| +namespace metrics {
|
| +
|
| +void BeginFirstWebContentsProfiling() {
|
| + using startup_metric_utils::WebContentsWorkload;
|
| +
|
| + const BrowserList* browser_list = BrowserList::GetInstance();
|
| +
|
| + const auto first_browser = browser_list->begin();
|
| + if (first_browser == browser_list->end())
|
| + return;
|
| +
|
| + const TabStripModel* tab_strip = (*first_browser)->tab_strip_model();
|
| + DCHECK(!tab_strip->empty());
|
| +
|
| + content::WebContents* web_contents = tab_strip->GetActiveWebContents();
|
| + DCHECK(web_contents);
|
| +
|
| + const bool single_tab = browser_list->size() == 1 && tab_strip->count() == 1;
|
| +
|
| + // FirstWebContentsProfiler owns itself and is also bound to
|
| + // |web_contents|'s lifetime by observing WebContentsDestroyed().
|
| + new FirstWebContentsProfiler(web_contents,
|
| + single_tab ? WebContentsWorkload::SINGLE_TAB
|
| + : WebContentsWorkload::MULTI_TABS);
|
| +}
|
| +
|
| +} // namespace metrics
|
|
|