blob: 30efcd857088096e77fd49f2ca4c1940da562ad6 [file] [log] [blame]
// Copyright 2020 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 CHROME_BROWSER_PERFORMANCE_MANAGER_POLICIES_PAGE_FREEZING_POLICY_H_
#define CHROME_BROWSER_PERFORMANCE_MANAGER_POLICIES_PAGE_FREEZING_POLICY_H_
#include <array>
#include "base/containers/flat_map.h"
#include "base/timer/timer.h"
#include "components/performance_manager/public/decorators/page_live_state_decorator.h"
#include "components/performance_manager/public/freezing/freezing.h"
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/public/graph/page_node.h"
namespace performance_manager {
namespace mechanism {
class PageFreezer;
} // namespace mechanism
namespace policies {
// A simple freezing policy that attempts to freeze pages when their associated
// freezing vote is positive.
//
// Tabs in one of the following states won't be frozen:
// - Audible;
// - Holding at least one WebLock.
// - Holding at least one IndexedDB lock;
// - Connected to a USB device;
// - Connected to a bluetooth device;
// - Capturing video;
// - Capturing audio;
// - Mirrored;
// - Capturing window;
// - Capturing display;
//
// Note that visible tabs can't be frozen and tabs that becomes visible are
// automatically unfrozen, there's no need to track this feature here.
class PageFreezingPolicy : public GraphObserver,
public GraphOwnedDefaultImpl,
public PageNode::ObserverDefaultImpl,
public PageLiveStateObserver {
public:
PageFreezingPolicy();
PageFreezingPolicy(const PageFreezingPolicy&) = delete;
PageFreezingPolicy(PageFreezingPolicy&&) = delete;
PageFreezingPolicy& operator=(const PageFreezingPolicy&) = delete;
PageFreezingPolicy& operator=(PageFreezingPolicy&&) = delete;
~PageFreezingPolicy() override;
void SetPageFreezerForTesting(
std::unique_ptr<mechanism::PageFreezer> page_freezer) {
page_freezer_ = std::move(page_freezer);
}
static const base::TimeDelta GetUnfreezeIntervalForTesting();
static const base::TimeDelta GetUnfreezeDurationForTesting();
protected:
// List of states that prevent a tab from being frozen.
enum CannotFreezeReason {
kAudible = 0,
kHoldingWebLock,
kHoldingIndexedDBLock,
kConnectedToUsbDevice,
kConnectedToBluetoothDevice,
kCapturingVideo,
kCapturingAudio,
kBeingMirrored,
kCapturingWindow,
kCapturingDisplay,
kCount,
};
// Helper function to convert a |CannotFreezeReason| to a string.
static const char* CannotFreezeReasonToString(CannotFreezeReason reason);
private:
// Actions that can be performed by the temporary unfreeze logic. It either
// should unfreeze the page node or refreeze it.
enum class PageNodeUnfreezeAction {
kTemporaryUnfreeze,
kRefreeze,
};
// GraphObserver implementation:
void OnBeforeGraphDestroyed(Graph* graph) override;
// GraphOwned implementation:
void OnPassedToGraph(Graph* graph) override;
// PageNodeObserver implementation:
void OnPageNodeAdded(const PageNode* page_node) override;
void OnBeforePageNodeRemoved(const PageNode* page_node) override;
void OnIsAudibleChanged(const PageNode* page_node) override;
void OnPageIsHoldingWebLockChanged(const PageNode* page_node) override;
void OnPageIsHoldingIndexedDBLockChanged(const PageNode* page_node) override;
void OnFreezingVoteChanged(
const PageNode* page_node,
absl::optional<performance_manager::freezing::FreezingVote> previous_vote)
override;
void OnLoadingStateChanged(const PageNode* page_node) override;
void OnPageLifecycleStateChanged(const PageNode* page_node) override;
// PageLiveStateObserver:
void OnIsConnectedToUSBDeviceChanged(const PageNode* page_node) override;
void OnIsConnectedToBluetoothDeviceChanged(
const PageNode* page_node) override;
void OnIsCapturingVideoChanged(const PageNode* page_node) override;
void OnIsCapturingAudioChanged(const PageNode* page_node) override;
void OnIsBeingMirroredChanged(const PageNode* page_node) override;
void OnIsCapturingWindowChanged(const PageNode* page_node) override;
void OnIsCapturingDisplayChanged(const PageNode* page_node) override;
void OnIsAutoDiscardableChanged(const PageNode* page_node) override {}
void OnWasDiscardedChanged(const PageNode* page_node) override {}
// Helper function that either calls SubmitNegativeVote() or
// InvalidateNegativeVote() when the value of a property changes.
void OnPropertyChanged(const PageNode* page_node,
bool submit_vote,
CannotFreezeReason reason);
// Submits or invalidates a negative freezing vote for |page_node| for
// |reason|. There can only be one vote associated with this reason.
void SubmitNegativeFreezingVote(const PageNode* page_node,
CannotFreezeReason reason);
void InvalidateNegativeFreezingVote(const PageNode* page_node,
CannotFreezeReason reason);
// Unfreeze |page_node| and schedule a task to refreeze it.
void TemporarilyUnfreezePageNode(const PageNode* page_node);
// Refreeze |page_node| after it has been temporarily unfrozen.
void FreezePageNodeAfterTemporaryUnfreeze(const PageNode* page_node);
// Holds one voting channel per CannotFreezeReason.
std::array<freezing::FreezingVotingChannel, CannotFreezeReason::kCount>
voting_channels_;
// Map that tracks the frozen |page_node| and the periodic unfreeze/refreeze
// tasks associated to them.
base::flat_map<
const PageNode*,
std::pair<PageNodeUnfreezeAction, std::unique_ptr<base::OneShotTimer>>>
page_nodes_unfreeze_tasks_;
// The page node being removed, used to avoid freezing/unfreezing a page node
// while it's being removed.
const PageNode* page_node_being_removed_ = nullptr;
// The freezing mechanism used to do the actual freezing.
std::unique_ptr<mechanism::PageFreezer> page_freezer_;
};
} // namespace policies
} // namespace performance_manager
#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_POLICIES_PAGE_FREEZING_POLICY_H_