1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116

android_webview / browser / page_load_metrics / service_level_page_load_metrics_observer.cc [blame]

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "android_webview/browser/page_load_metrics/service_level_page_load_metrics_observer.h"

#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
#include "components/page_load_metrics/browser/page_load_metrics_observer_delegate.h"
#include "components/page_load_metrics/browser/page_load_metrics_util.h"
#include "content/public/browser/navigation_handle.h"

namespace android_webview {

namespace {
constexpr char kPageAttemptsHistogram[] =
    "PageLoad.Clients.WebView.PageAttempts";
constexpr char kPageAttemptResultsHistogram[] =
    "PageLoad.Clients.WebView.PageAttemptResults";
}  // namespace

const char* ServiceLevelPageLoadMetricsObserver::GetObserverName() const {
  static const char kName[] = "ServiceLevelPageLoadMetricsObserver";
  return kName;
}

page_load_metrics::PageLoadMetricsObserver::ObservePolicy
ServiceLevelPageLoadMetricsObserver::OnStart(
    content::NavigationHandle* navigation_handle,
    const GURL& currently_committed_url,
    bool started_in_foreground) {
  if (!started_in_foreground) {
    return STOP_OBSERVING;
  }
  base::UmaHistogramBoolean(kPageAttemptsHistogram, true);
  return CONTINUE_OBSERVING;
}

void ServiceLevelPageLoadMetricsObserver::OnComplete(
    const page_load_metrics::mojom::PageLoadTiming& timing) {
  LogPageAttemptEnd(timing, GetDelegate());
}

void ServiceLevelPageLoadMetricsObserver::OnFailedProvisionalLoad(
    const page_load_metrics::FailedProvisionalLoadInfo&
        failed_provisional_load_info) {
  LogPageAttemptEnd(failed_provisional_load_info.discard_reason);
}

page_load_metrics::PageLoadMetricsObserver::ObservePolicy
ServiceLevelPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
    const page_load_metrics::mojom::PageLoadTiming& timing) {
  LogPageAttemptEnd(timing, GetDelegate());
  return STOP_OBSERVING;
}

void ServiceLevelPageLoadMetricsObserver::OnDidInternalNavigationAbort(
    content::NavigationHandle* navigation_handle) {
  if (navigation_handle->GetNavigationDiscardReason().has_value()) {
    LogPageAttemptEnd(navigation_handle->GetNavigationDiscardReason().value());
  }
}

page_load_metrics::PageLoadMetricsObserver::ObservePolicy
ServiceLevelPageLoadMetricsObserver::OnPrerenderStart(
    content::NavigationHandle* navigation_handle,
    const GURL& currently_committed_url) {
  return STOP_OBSERVING;
}

page_load_metrics::PageLoadMetricsObserver::ObservePolicy
ServiceLevelPageLoadMetricsObserver::OnFencedFramesStart(
    content::NavigationHandle* navigation_handle,
    const GURL& currently_committed_url) {
  return STOP_OBSERVING;
}

void ServiceLevelPageLoadMetricsObserver::LogPageAttemptEnd(
    const page_load_metrics::mojom::PageLoadTiming& timing,
    const page_load_metrics::PageLoadMetricsObserverDelegate& delegate) {
  if (timing.paint_timing->first_contentful_paint.has_value() &&
      page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
          timing.paint_timing->first_contentful_paint, delegate)) {
    LogPageAttemptEnd(WebViewPageAttemptResult::kSuccess);
    return;
  }

  switch (delegate.GetPageEndReason()) {
    case page_load_metrics::PageEndReason::END_RENDER_PROCESS_GONE:
      LogPageAttemptEnd(WebViewPageAttemptResult::kFailure);
      return;
    default:
      LogPageAttemptEnd(WebViewPageAttemptResult::kEarlyFinish);
      return;
  }
}

void ServiceLevelPageLoadMetricsObserver::LogPageAttemptEnd(
    content::NavigationDiscardReason discard_reason) {
  switch (discard_reason) {
    case content::NavigationDiscardReason::kRenderProcessGone:
      LogPageAttemptEnd(WebViewPageAttemptResult::kFailure);
      return;
    default:
      LogPageAttemptEnd(WebViewPageAttemptResult::kEarlyFinish);
      return;
  }
}

void ServiceLevelPageLoadMetricsObserver::LogPageAttemptEnd(
    WebViewPageAttemptResult result) {
  CHECK(!logged_end_);
  logged_end_ = true;
  base::UmaHistogramEnumeration(kPageAttemptResultsHistogram, result);
}

}  // namespace android_webview