blob: b546ae05222c20696fef765cc79b2f7c6572072f [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_H_
#define CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_H_
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/callback_helpers.h"
#include "base/gtest_prod_util.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/resource_coordinator/lifecycle_unit.h"
#include "chrome/browser/resource_coordinator/lifecycle_unit_observer.h"
#include "chrome/browser/resource_coordinator/lifecycle_unit_source_observer.h"
#include "chrome/browser/resource_coordinator/lifecycle_unit_state.mojom-forward.h"
#include "chrome/browser/resource_coordinator/tab_lifecycle_observer.h"
#include "chrome/browser/resource_coordinator/tab_manager_features.h"
#include "chrome/browser/resource_coordinator/usage_clock.h"
#include "chrome/browser/sessions/session_restore_observer.h"
#include "content/public/browser/navigation_throttle.h"
#include "ui/gfx/native_widget_types.h"
class GURL;
namespace content {
class WebContents;
} // namespace content
namespace resource_coordinator {
#if BUILDFLAG(IS_CHROMEOS_ASH)
class TabManagerDelegate;
#endif
// TabManager is responsible for triggering tab lifecycle state transitions.
//
// Note that the browser tests are only active for platforms that use
// TabManager (CrOS only for now) and need to be adjusted accordingly if
// support for new platforms is added.
//
// Tabs are identified by a unique ID vended by this component. These IDs are
// not reused in a session. They are stable for a given conceptual tab, and will
// follow it through discards, reloads, tab strip operations, etc.
//
// TODO(fdoray): Rename to LifecycleManager. https://crbug.com/775644
class TabManager : public LifecycleUnitObserver,
public LifecycleUnitSourceObserver {
public:
// Forward declaration of resource coordinator signal observer.
class ResourceCoordinatorSignalObserver;
using TabDiscardDoneCB = base::ScopedClosureRunner;
TabManager();
TabManager(const TabManager&) = delete;
TabManager& operator=(const TabManager&) = delete;
~TabManager() override;
// Start the Tab Manager.
void Start();
// Returns the LifecycleUnits managed by this, sorted from less to most
// important to the user. It is unsafe to access a pointer in the returned
// vector after a LifecycleUnit has been destroyed.
LifecycleUnitVector GetSortedLifecycleUnits();
// Discards a tab to free the memory occupied by its renderer. The tab still
// exists in the tab-strip; clicking on it will reload it. If the |reason| is
// urgent, an aggressive fast-kill will be attempted if the sudden termination
// disablers are allowed to be ignored (e.g. On ChromeOS, we can ignore an
// unload handler and fast-kill the tab regardless).
void DiscardTab(
LifecycleUnitDiscardReason reason,
TabDiscardDoneCB tab_discard_done = TabDiscardDoneCB(base::DoNothing()));
// Method used by the extensions API to discard tabs. If |contents| is null,
// discards the least important tab using DiscardTab(). Otherwise discards
// the given contents. Returns the new web_contents or null if no tab
// was discarded.
content::WebContents* DiscardTabByExtension(content::WebContents* contents);
#if BUILDFLAG(IS_CHROMEOS_ASH)
// Discards a tab in response to memory pressure.
void DiscardTabFromMemoryPressure();
#endif
// TODO(fdoray): Remove these methods. TabManager shouldn't know about tabs.
// https://crbug.com/775644
void AddObserver(TabLifecycleObserver* observer);
void RemoveObserver(TabLifecycleObserver* observer);
// Returns the number of tabs open in all browser instances.
int GetTabCount() const;
UsageClock* usage_clock() { return &usage_clock_; }
private:
friend class TabManagerStatsCollectorTest;
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, AutoDiscardable);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, CanOnlyDiscardOnce);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ChildProcessNotifications);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, EnablePageAlmostIdleSignal);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, InvalidOrEmptyURL);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TabDiscardDoneCallback);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsInternalPage);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, IsTabRestoredInForeground);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, OomPressureListener);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectDevToolsTabsFromDiscarding);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectPDFPages);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
ProtectRecentlyUsedTabsFromUrgentDiscarding);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, ProtectVideoTabs);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TabManagerBasics);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, TabManagerWasDiscarded);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
TabManagerWasDiscardedCrossSiteSubFrame);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
TrackingNumberOfLoadedLifecycleUnits);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, UrgentFastShutdownSharedTabProcess);
FRIEND_TEST_ALL_PREFIXES(TabManagerTestWithTwoTabs,
UrgentFastShutdownSingleTabProcess);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest,
UrgentFastShutdownWithBeforeunloadHandler);
FRIEND_TEST_ALL_PREFIXES(TabManagerTest, UrgentFastShutdownWithUnloadHandler);
// Returns true if the |url| represents an internal Chrome web UI page that
// can be easily reloaded and hence makes a good choice to discard.
static bool IsInternalPage(const GURL& url);
#if BUILDFLAG(IS_CHROMEOS_ASH)
// Called by the memory pressure listener when the memory pressure rises.
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
// Called when we finished handling the memory pressure by discarding tabs.
void OnTabDiscardDone();
// Register to start listening to memory pressure. Called on startup or end
// of tab discards.
void RegisterMemoryPressureListener();
// Unregister to stop listening to memory pressure. Called on shutdown or
// beginning of tab discards.
void UnregisterMemoryPressureListener();
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
// Discards the less important LifecycleUnit that supports discarding under
// |reason|.
content::WebContents* DiscardTabImpl(
LifecycleUnitDiscardReason reason,
TabDiscardDoneCB tab_discard_done = TabDiscardDoneCB(base::DoNothing()));
void OnSessionRestoreStartedLoadingTabs();
void OnSessionRestoreFinishedLoadingTabs();
void OnWillRestoreTab(content::WebContents* contents);
// Returns the number of tabs that are not pending load or discarded.
int GetNumAliveTabs() const;
// LifecycleUnitObserver:
void OnLifecycleUnitDestroyed(LifecycleUnit* lifecycle_unit) override;
// LifecycleUnitSourceObserver:
void OnLifecycleUnitCreated(LifecycleUnit* lifecycle_unit) override;
// LifecycleUnits managed by this.
LifecycleUnitSet lifecycle_units_;
// A listener to global memory pressure events.
std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
#if BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<TabManagerDelegate> delegate_;
#endif
class TabManagerSessionRestoreObserver;
std::unique_ptr<TabManagerSessionRestoreObserver> session_restore_observer_;
// A clock that advances when Chrome is in use.
UsageClock usage_clock_;
// Weak pointer factory used for posting delayed tasks.
base::WeakPtrFactory<TabManager> weak_ptr_factory_{this};
};
} // namespace resource_coordinator
#endif // CHROME_BROWSER_RESOURCE_COORDINATOR_TAB_MANAGER_H_