Fix ceftest failures with BackForwardCache enabled (see issue #2421)

When BackForwardCache is enabled the old RFH tree may be cached instead of being
immediately deleted as a result of main frame navigation. If a RFH is cached
then delivery of the CefFrameHandler::OnFrameDetached callback will be delayed
until the the RFH is ejected from the cache (possibly not occurring until the
browser is destroyed). This change in OnFrameDetached timing was causing
FrameHandlerTest.OrderSubCrossOrigin* to fail, and the inclusion of cached
frames in CefBrowserInfo::GetAllFrames was causing
FrameTest.NestedIframesDiffOrigin to fail.

BackForwardCache is currently being tested via field trials (see
https://crbug.com/1171298) and can be explicitly disabled using the
`--disable-back-forward-cache` or `--disable-features=BackForwardCache`
command-line flags.
This commit is contained in:
Marshall Greenblatt
2021-07-25 13:31:39 -04:00
parent 645b62257c
commit 92ec2dcbdd
7 changed files with 296 additions and 115 deletions

View File

@@ -153,6 +153,32 @@ void CefBrowserInfo::MaybeCreateFrame(content::RenderFrameHost* host,
frame_info_set_.insert(base::WrapUnique(frame_info));
}
void CefBrowserInfo::FrameHostStateChanged(
content::RenderFrameHost* host,
content::RenderFrameHost::LifecycleState old_state,
content::RenderFrameHost::LifecycleState new_state) {
CEF_REQUIRE_UIT();
// We currently only care about BackForwardCache state changes.
bool added_to_bfcache =
new_state ==
content::RenderFrameHost::LifecycleState::kInBackForwardCache;
bool removed_from_bfcache =
old_state ==
content::RenderFrameHost::LifecycleState::kInBackForwardCache;
if (!added_to_bfcache && !removed_from_bfcache)
return;
base::AutoLock lock_scope(lock_);
const auto frame_id = CefFrameHostImpl::MakeFrameId(host);
auto it = frame_id_map_.find(frame_id);
DCHECK(it != frame_id_map_.end());
DCHECK((!it->second->is_in_bfcache_ && added_to_bfcache) ||
(it->second->is_in_bfcache_ && removed_from_bfcache));
it->second->is_in_bfcache_ = added_to_bfcache;
}
void CefBrowserInfo::RemoveFrame(content::RenderFrameHost* host) {
CEF_REQUIRE_UIT();
@@ -190,8 +216,8 @@ void CefBrowserInfo::RemoveFrame(content::RenderFrameHost* host) {
// Explicitly Detach everything but the current main frame.
const auto& frame_info = *it2;
if (frame_info->frame_ && !frame_info->IsCurrentMainFrame()) {
frame_info->frame_->Detach();
MaybeNotifyFrameDetached(browser_, frame_info->frame_);
if (frame_info->frame_->Detach())
MaybeNotifyFrameDetached(browser_, frame_info->frame_);
}
frame_info_set_.erase(it2);
@@ -314,8 +340,9 @@ CefBrowserInfo::FrameHostList CefBrowserInfo::GetAllFrames() const {
base::AutoLock lock_scope(lock_);
FrameHostList frames;
for (const auto& info : frame_info_set_) {
if (info->frame_ && !info->is_speculative_)
if (info->frame_ && !info->is_speculative_ && !info->is_in_bfcache_) {
frames.insert(info->frame_);
}
}
return frames;
}
@@ -438,8 +465,8 @@ void CefBrowserInfo::SetMainFrame(CefRefPtr<CefBrowserHostBase> browser,
CefRefPtr<CefFrameHostImpl> old_frame;
if (main_frame_) {
old_frame = main_frame_;
old_frame->Detach();
MaybeNotifyFrameDetached(browser, old_frame);
if (old_frame->Detach())
MaybeNotifyFrameDetached(browser, old_frame);
}
main_frame_ = frame;
@@ -520,8 +547,8 @@ void CefBrowserInfo::RemoveAllFrames(
// Explicitly Detach everything but the current main frame.
for (auto& info : frame_info_set_) {
if (info->frame_ && !info->IsCurrentMainFrame()) {
info->frame_->Detach();
MaybeNotifyFrameDetached(old_browser, info->frame_);
if (info->frame_->Detach())
MaybeNotifyFrameDetached(old_browser, info->frame_);
}
}