blob: 906a8b2fcd9ec94b0b19971522539df553f8d855 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/web_state_list/web_state_list_metrics_browser_agent.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "components/navigation_metrics/navigation_metrics.h"
#include "components/profile_metrics/browser_profile_type.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/chrome_url_constants.h"
#include "ios/chrome/browser/crash_report/crash_loop_detection_util.h"
#import "ios/chrome/browser/sessions/session_restoration_browser_agent.h"
#include "ios/chrome/browser/ui/util/uikit_ui_util.h"
#include "ios/chrome/browser/web_state_list/session_metrics.h"
#import "ios/chrome/browser/web_state_list/web_state_list.h"
#include "ios/web/public/browser_state.h"
#include "ios/web/public/navigation/navigation_context.h"
#include "ios/web/public/navigation/navigation_item.h"
#include "ios/web/public/navigation/navigation_manager.h"
#import "ios/web/public/web_state.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
BROWSER_USER_DATA_KEY_IMPL(WebStateListMetricsBrowserAgent)
// static
void WebStateListMetricsBrowserAgent::CreateForBrowser(
Browser* browser,
SessionMetrics* session_metrics) {
if (!FromBrowser(browser)) {
browser->SetUserData(UserDataKey(),
base::WrapUnique(new WebStateListMetricsBrowserAgent(
browser, session_metrics)));
}
}
WebStateListMetricsBrowserAgent::WebStateListMetricsBrowserAgent(
Browser* browser,
SessionMetrics* session_metrics)
: web_state_list_(browser->GetWebStateList()),
session_metrics_(session_metrics) {
DCHECK(web_state_list_);
DCHECK(session_metrics_);
browser->AddObserver(this);
web_state_list_->AddObserver(this);
for (int index = 0; index < web_state_list_->count(); ++index) {
web::WebState* web_state = web_state_list_->GetWebStateAt(index);
web_state->AddObserver(this);
}
SessionRestorationBrowserAgent* restoration_agent =
SessionRestorationBrowserAgent::FromBrowser(browser);
if (restoration_agent)
restoration_agent->AddObserver(this);
}
WebStateListMetricsBrowserAgent::~WebStateListMetricsBrowserAgent() = default;
void WebStateListMetricsBrowserAgent::WillStartSessionRestoration() {
metric_collection_paused_ = true;
}
void WebStateListMetricsBrowserAgent::SessionRestorationFinished(
const std::vector<web::WebState*>& restored_web_states) {
metric_collection_paused_ = false;
}
void WebStateListMetricsBrowserAgent::WebStateInsertedAt(
WebStateList* web_state_list,
web::WebState* web_state,
int index,
bool activating) {
web_state->AddObserver(this);
if (metric_collection_paused_)
return;
base::RecordAction(base::UserMetricsAction("MobileNewTabOpened"));
session_metrics_->OnWebStateInserted();
}
void WebStateListMetricsBrowserAgent::WebStateDetachedAt(
WebStateList* web_state_list,
web::WebState* web_state,
int index) {
web_state->RemoveObserver(this);
if (metric_collection_paused_)
return;
base::RecordAction(base::UserMetricsAction("MobileTabClosed"));
session_metrics_->OnWebStateDetached();
}
void WebStateListMetricsBrowserAgent::WebStateActivatedAt(
WebStateList* web_state_list,
web::WebState* old_web_state,
web::WebState* new_web_state,
int active_index,
ActiveWebStateChangeReason reason) {
if (metric_collection_paused_)
return;
session_metrics_->OnWebStateActivated();
if (reason == ActiveWebStateChangeReason::Replaced)
return;
base::RecordAction(base::UserMetricsAction("MobileTabSwitched"));
}
void WebStateListMetricsBrowserAgent::WebStateReplacedAt(
WebStateList* web_state_list,
web::WebState* old_web_state,
web::WebState* new_web_state,
int index) {
old_web_state->RemoveObserver(this);
new_web_state->AddObserver(this);
}
// web::WebStateObserver
void WebStateListMetricsBrowserAgent::DidStartNavigation(
web::WebState* web_state,
web::NavigationContext* navigation_context) {
// In order to avoid false positive in the crash loop detection, disable the
// counter as soon as an URL is loaded. This requires an user action and is a
// significant source of crashes. Ignore NTP as it is loaded by default after
// a crash.
if (navigation_context->GetUrl().host_piece() != kChromeUINewTabHost) {
static dispatch_once_t dispatch_once_token;
dispatch_once(&dispatch_once_token, ^{
crash_util::ResetFailedStartupAttemptCount();
});
}
}
void WebStateListMetricsBrowserAgent::DidFinishNavigation(
web::WebState* web_state,
web::NavigationContext* navigation_context) {
if (!navigation_context->HasCommitted())
return;
if (!navigation_context->IsSameDocument() &&
!web_state->GetBrowserState()->IsOffTheRecord()) {
int tab_count = static_cast<int>(web_state_list_->count());
UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.TabCountPerLoad", tab_count, 1, 200, 50);
}
web::NavigationItem* item =
web_state->GetNavigationManager()->GetLastCommittedItem();
navigation_metrics::RecordMainFrameNavigation(
item ? item->GetVirtualURL() : GURL::EmptyGURL(),
navigation_context->IsSameDocument(),
web_state->GetBrowserState()->IsOffTheRecord(),
profile_metrics::GetBrowserProfileType(web_state->GetBrowserState()));
}
void WebStateListMetricsBrowserAgent::PageLoaded(
web::WebState* web_state,
web::PageLoadCompletionStatus load_completion_status) {
switch (GetInterfaceOrientation()) {
case UIInterfaceOrientationPortrait:
case UIInterfaceOrientationPortraitUpsideDown:
UMA_HISTOGRAM_BOOLEAN("Tab.PageLoadInPortrait", YES);
break;
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationLandscapeRight:
UMA_HISTOGRAM_BOOLEAN("Tab.PageLoadInPortrait", NO);
break;
case UIInterfaceOrientationUnknown:
// TODO(crbug.com/228832): Convert from a boolean histogram to an
// enumerated histogram and log this case as well.
break;
}
}
void WebStateListMetricsBrowserAgent::BrowserDestroyed(Browser* browser) {
DCHECK_EQ(browser->GetWebStateList(), web_state_list_);
SessionRestorationBrowserAgent* restoration_agent =
SessionRestorationBrowserAgent::FromBrowser(browser);
if (restoration_agent)
restoration_agent->RemoveObserver(this);
for (int index = 0; index < web_state_list_->count(); ++index) {
web::WebState* web_state = web_state_list_->GetWebStateAt(index);
web_state->RemoveObserver(this);
}
web_state_list_->RemoveObserver(this);
web_state_list_ = nullptr;
browser->RemoveObserver(this);
}