blob: 4be5301c97f69276523763ab3c28649493428c25 [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.
#include "content/browser/renderer_host/page_lifecycle_state_manager.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/public/browser/render_process_host.h"
#include "services/service_manager/public/cpp/interface_provider.h"
namespace {
constexpr base::TimeDelta kBackForwardCacheTimeoutInSeconds =
base::TimeDelta::FromSeconds(3);
}
namespace content {
PageLifecycleStateManager::PageLifecycleStateManager(
RenderViewHostImpl* render_view_host_impl,
blink::mojom::PageVisibilityState web_contents_visibility_state)
: web_contents_visibility_(web_contents_visibility_state),
render_view_host_impl_(render_view_host_impl) {
last_acknowledged_state_ = CalculatePageLifecycleState();
last_state_sent_to_renderer_ = last_acknowledged_state_.Clone();
}
PageLifecycleStateManager::~PageLifecycleStateManager() = default;
void PageLifecycleStateManager::SetIsFrozen(bool frozen) {
if (is_set_frozen_called_ == frozen)
return;
is_set_frozen_called_ = frozen;
SendUpdatesToRendererIfNeeded(base::nullopt);
}
void PageLifecycleStateManager::SetWebContentsVisibility(
blink::mojom::PageVisibilityState visibility) {
if (web_contents_visibility_ == visibility)
return;
web_contents_visibility_ = visibility;
SendUpdatesToRendererIfNeeded(base::nullopt);
// TODO(yuzus): When a page is frozen and made visible, the page should
// automatically resume.
}
void PageLifecycleStateManager::SetIsInBackForwardCache(
bool is_in_back_forward_cache,
base::Optional<base::TimeTicks> navigation_start) {
if (is_in_back_forward_cache_ == is_in_back_forward_cache)
return;
is_in_back_forward_cache_ = is_in_back_forward_cache;
if (is_in_back_forward_cache) {
// When a page is put into BackForwardCache, the page can run a busy loop.
// Set a timeout monitor to check that the transition finishes within the
// time limit.
back_forward_cache_timeout_monitor_ =
std::make_unique<OneShotTimeoutMonitor>(
base::BindOnce(
&PageLifecycleStateManager::OnBackForwardCacheTimeout,
weak_ptr_factory_.GetWeakPtr()),
kBackForwardCacheTimeoutInSeconds);
}
SendUpdatesToRendererIfNeeded(navigation_start);
}
void PageLifecycleStateManager::SendUpdatesToRendererIfNeeded(
base::Optional<base::TimeTicks> navigation_start) {
if (!render_view_host_impl_->GetAssociatedPageBroadcast()) {
// For some tests, |render_view_host_impl_| does not have the associated
// page.
return;
}
auto new_state = CalculatePageLifecycleState();
if (last_state_sent_to_renderer_ &&
last_state_sent_to_renderer_.Equals(new_state)) {
// TODO(yuzus): Send updates to renderer only when the effective state (per
// page lifecycle state) has changed since last sent to renderer. It is
// possible that the web contents state has changed but the effective state
// has not.
}
last_state_sent_to_renderer_ = new_state.Clone();
auto state = new_state.Clone();
render_view_host_impl_->GetAssociatedPageBroadcast()->SetPageLifecycleState(
std::move(state), std::move(navigation_start),
base::BindOnce(&PageLifecycleStateManager::OnPageLifecycleChangedAck,
weak_ptr_factory_.GetWeakPtr(), std::move(new_state)));
}
blink::mojom::PageLifecycleStatePtr
PageLifecycleStateManager::CalculatePageLifecycleState() {
auto state = blink::mojom::PageLifecycleState::New();
state->is_in_back_forward_cache = is_in_back_forward_cache_;
state->is_frozen = is_in_back_forward_cache_ ? true : is_set_frozen_called_;
state->visibility = is_in_back_forward_cache_
? blink::mojom::PageVisibilityState::kHidden
: web_contents_visibility_;
return state;
}
void PageLifecycleStateManager::OnPageLifecycleChangedAck(
blink::mojom::PageLifecycleStatePtr acknowledged_state) {
last_acknowledged_state_ = std::move(acknowledged_state);
if (last_acknowledged_state_->is_in_back_forward_cache) {
back_forward_cache_timeout_monitor_.reset(nullptr);
}
}
void PageLifecycleStateManager::OnBackForwardCacheTimeout() {
DCHECK(!last_acknowledged_state_->is_in_back_forward_cache);
render_view_host_impl_->OnBackForwardCacheTimeout();
back_forward_cache_timeout_monitor_.reset(nullptr);
}
} // namespace content