blob: 1291746a214e6488b887b8b5a3581597a46a26b8 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_METRICS_TAB_USAGE_RECORDER_BROWSER_AGENT_H_
#define IOS_CHROME_BROWSER_METRICS_TAB_USAGE_RECORDER_BROWSER_AGENT_H_
#include <map>
#include <memory>
#include <vector>
#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "ios/chrome/browser/main/browser_observer.h"
#include "ios/chrome/browser/main/browser_user_data.h"
#include "ios/chrome/browser/metrics/tab_usage_recorder_metrics.h"
#include "ios/chrome/browser/sessions/session_restoration_observer.h"
#import "ios/chrome/browser/web_state_list/web_state_list_observer.h"
#include "ios/web/common/user_agent.h"
#include "ios/web/public/web_state_observer.h"
class PrerenderService;
class WebStateList;
namespace web {
class WebState;
}
// Reports usage about the lifecycle of a single Browser's tabs.
class TabUsageRecorderBrowserAgent
: BrowserObserver,
public BrowserUserData<TabUsageRecorderBrowserAgent>,
web::WebStateObserver,
public WebStateListObserver,
public SessionRestorationObserver {
public:
// Not copyable or moveable
TabUsageRecorderBrowserAgent(const TabUsageRecorderBrowserAgent&) = delete;
TabUsageRecorderBrowserAgent& operator=(const TabUsageRecorderBrowserAgent&) =
delete;
~TabUsageRecorderBrowserAgent() override;
// Called during startup when the tab model is created, or shortly after a
// post-crash launch if the tabs are restored. |web_states| is an array
// containing/ the tabs being restored in the current tab model.
// |active_web_state| is the tab currently in the foreground.
void InitialRestoredTabs(web::WebState* active_web_state,
const std::vector<web::WebState*>& web_states);
// Called when a tab switch is made. Determines what value to record, and
// when to reset the page load counter.
void RecordTabSwitched(web::WebState* old_web_state,
web::WebState* new_web_state);
// Called when the tab model which the user is primarily interacting with has
// changed. The |active_web_state| is the current tab of the tab model. If the
// user began interacting with |active_web_state|, |primary_tab_model| should
// be true. If the user stopped interacting with |active_web_state|,
// |primary_tab_model| should be false.
void RecordPrimaryTabModelChange(bool primary_tab_model,
web::WebState* active_web_state);
// Called when a page load begins, to keep track of how many page loads
// happen before an evicted tab is seen.
void RecordPageLoadStart(web::WebState* web_state);
// Called when a page load finishes, to track the load time for evicted tabs.
void RecordPageLoadDone(web::WebState* web_state, bool success);
// Called when there is a user-initiated reload.
void RecordReload(web::WebState* web_state);
// Called when WKWebView's renderer is terminated. |tab| contains the tab
// whose renderer was terminated, |tab_visible| indicates whether or not
// the tab was visible when the renderer terminated and |application_active|
// indicates whether the application was in the foreground or background.
void RendererTerminated(web::WebState* web_state,
bool web_state_visible,
bool application_active);
// Called when the app has been backgrounded.
void AppDidEnterBackground();
// Called when the app has been foregrounded.
void AppWillEnterForeground();
// Resets the page load count.
void ResetPageLoads();
// Size of |evicted_web_states_|. Used for testing.
int EvictedTabsMapSize();
// Resets all tracked data. Used for testing.
void ResetAll();
private:
// TODO(crbug.com/731724): remove this once the code has been refactored not
// to depends on injecting values in |termination_timestamps_|.
friend class TabUsageRecorderBrowserAgentTest;
explicit TabUsageRecorderBrowserAgent(Browser* browser);
friend class BrowserUserData<TabUsageRecorderBrowserAgent>;
BROWSER_USER_DATA_KEY_DECL();
// BrowserObserver methods
void BrowserDestroyed(Browser* browser) override;
// Clear out all state regarding a current evicted tab.
void ResetEvictedTab();
// Whether or not a tab can be disregarded by the metrics.
bool ShouldIgnoreWebState(web::WebState* web_state);
// Whether or not the tab has already been evicted.
bool WebStateAlreadyEvicted(web::WebState* web_state);
// Returns the state of the given tab. Call only once per tab, as it removes
// the tab from |evicted_web_states_|.
tab_usage_recorder::TabStateWhenSelected ExtractWebStateState(
web::WebState* web_state);
// Records various time metrics when a restore of an evicted tab begins.
void RecordRestoreStartTime();
// Returns the number of WebState that are still alive (in-memory).
int GetLiveWebStatesCount() const;
// Called before one of the tracked WebState is destroyed. The WebState is
// still valid but will become invalid afterwards, so any reference to it
// should be removed.
void OnWebStateDestroyed(web::WebState* web_state);
// Returns whether |agent_type| and |other_agent_type| are different user
// agent types. If either of them is web::UserAgentType::NONE, then return
// false.
bool IsTransitionBetweenDesktopAndMobileUserAgent(
web::UserAgentType agent_type,
web::UserAgentType other_agent_type);
// Returns whether RecordPageLoadStart should be called for the given
// navigation.
bool ShouldRecordPageLoadStartForNavigation(
web::NavigationContext* navigation);
// web::WebStateObserver implementation.
void DidStartNavigation(web::WebState* web_state,
web::NavigationContext* navigation_context) override;
void PageLoaded(
web::WebState* web_state,
web::PageLoadCompletionStatus load_completion_status) override;
void RenderProcessGone(web::WebState* web_state) override;
void WebStateDestroyed(web::WebState* web_state) override;
// WebStateListObserver implementation.
void WebStateInsertedAt(WebStateList* web_state_list,
web::WebState* web_state,
int index,
bool activating) override;
void WebStateReplacedAt(WebStateList* web_state_list,
web::WebState* old_web_state,
web::WebState* new_web_state,
int index) override;
void WebStateDetachedAt(WebStateList* web_state_list,
web::WebState* web_state,
int index) override;
void WebStateActivatedAt(WebStateList* web_state_list,
web::WebState* old_web_state,
web::WebState* new_web_state,
int active_index,
ActiveWebStateChangeReason reason) override;
// SessionRestorationObserver implementation.
void SessionRestorationFinished(
const std::vector<web::WebState*>& restored_web_states) override;
// Keep track of when the most recent tab restore begins, to record the time
// between evicted-tab-reloads.
base::TimeTicks restore_start_time_;
// Keep track of the timestamps of renderer terminations in order to find the
// number of recently alive tabs when a renderer termination occurs.
base::circular_deque<base::TimeTicks> termination_timestamps_;
// Number of page loads since the last evicted tab was seen.
unsigned int page_loads_ = 0;
// Keep track of the current tab, but only if it has been evicted.
// This is kept as a pointer value only - it should never be dereferenced.
web::WebState* evicted_web_state_ = nullptr;
// State of |evicted_web_state_| at the time it became the current tab.
tab_usage_recorder::TabStateWhenSelected evicted_web_state_state_ =
tab_usage_recorder::IN_MEMORY;
// Keep track of the tab last selected when this tab model was switched
// away from to another mode (e.g. to incognito).
// Kept as a pointer value only - it should never be dereferenced.
web::WebState* mode_switch_web_state_ = nullptr;
// Keep track of a tab that was created to be immediately selected. It should
// not contribute to the "StatusWhenSwitchedBackToForeground" metric.
web::WebState* web_state_created_selected_ = nullptr;
// Keep track of when the evicted tab starts to reload, so that the total
// time it takes to reload can be recorded.
base::TimeTicks evicted_web_state_reload_start_time_;
// Keep track of the tabs that have a known eviction cause.
std::map<web::WebState*, tab_usage_recorder::TabStateWhenSelected>
evicted_web_states_;
// The WebStateList containing all the monitored tabs.
WebStateList* web_state_list_; // weak
// The PrerenderService used to check whether a tab is pre-rendering. May
// be null during unit testing.
PrerenderService* prerender_service_;
// Observers for NSNotificationCenter notifications.
__strong id<NSObject> application_backgrounding_observer_;
__strong id<NSObject> application_foregrounding_observer_;
};
#endif // IOS_CHROME_BROWSER_METRICS_TAB_USAGE_RECORDER_BROWSER_AGENT_H_