Commit eafed872 authored by Clark DuVall's avatar Clark DuVall Committed by Commit Bot

Fix flaky ExtensionWebRequestApiTest.WebRequestTypes

This started flaking after WebRequest was moved to UI in
http://crrev.com/c/1682434. Previously, we got lucky that the beacon
requests from unloaded frames came in before the FrameData was removed
from the frame data map, since WebRequest could grab the FrameData on IO
before the beacon request started.

This CL stores recently deleted frames, and posts a task for the removal
of the deleted frame's FrameData so we have access to it when the beacon
request comes in.

Bug: 522129, 980774
Change-Id: I1fa0d16d52c52cf61d1095588882170b48ab3e32
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1713864
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarKaran Bhatia <karandeepb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#680134}
parent 65a71703
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/navigation_handle.h" #include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
...@@ -148,7 +149,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, FrameDataCached) { ...@@ -148,7 +149,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, FrameDataCached) {
// Returns the cached frame data for |rfh|. // Returns the cached frame data for |rfh|.
auto get_frame_data = [](content::RenderFrameHost* rfh) { auto get_frame_data = [](content::RenderFrameHost* rfh) {
return ExtensionApiFrameIdMap::Get()->GetFrameData(rfh); return ExtensionApiFrameIdMap::Get()->GetFrameData(
rfh->GetProcess()->GetID(), rfh->GetRoutingID());
}; };
// Adds an iframe with the given |name| and |src| to the given |web_contents| // Adds an iframe with the given |name| and |src| to the given |web_contents|
......
...@@ -106,10 +106,6 @@ ...@@ -106,10 +106,6 @@
#include "ui/views/test/test_desktop_screen_x11.h" #include "ui/views/test/test_desktop_screen_x11.h"
#endif #endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "extensions/browser/extension_api_frame_id_map.h"
#endif
#if defined(TOOLKIT_VIEWS) #if defined(TOOLKIT_VIEWS)
#include "chrome/test/views/accessibility_checker.h" #include "chrome/test/views/accessibility_checker.h"
#include "ui/views/views_delegate.h" #include "ui/views/views_delegate.h"
...@@ -316,14 +312,6 @@ void InProcessBrowserTest::TearDown() { ...@@ -316,14 +312,6 @@ void InProcessBrowserTest::TearDown() {
OSCryptMocker::TearDown(); OSCryptMocker::TearDown();
ChromeContentBrowserClient::SetDefaultQuotaSettingsForTesting(nullptr); ChromeContentBrowserClient::SetDefaultQuotaSettingsForTesting(nullptr);
#if BUILDFLAG(ENABLE_EXTENSIONS)
// By now, all the WebContents should be destroyed, Ensure that we are not
// leaking memory in ExtensionAPIFrameIdMap. crbug.com/817205.
EXPECT_EQ(
0u,
extensions::ExtensionApiFrameIdMap::Get()->GetFrameDataCountForTesting());
#endif
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
chromeos::device_sync::DeviceSyncImpl::Factory::SetInstanceForTesting( chromeos::device_sync::DeviceSyncImpl::Factory::SetInstanceForTesting(
nullptr); nullptr);
......
...@@ -1462,9 +1462,8 @@ bool ExtensionWebRequestEventRouter::DispatchEvent( ...@@ -1462,9 +1462,8 @@ bool ExtensionWebRequestEventRouter::DispatchEvent(
// TODO(http://crbug.com/980774): Investigate if this is necessary. // TODO(http://crbug.com/980774): Investigate if this is necessary.
if (!request->frame_data) { if (!request->frame_data) {
content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( request->frame_data = ExtensionApiFrameIdMap::Get()->GetFrameData(
request->render_process_id, request->frame_id); request->render_process_id, request->frame_id);
request->frame_data = ExtensionApiFrameIdMap::Get()->GetFrameData(rfh);
} }
event_details->SetFrameData(request->frame_data.value()); event_details->SetFrameData(request->frame_data.value());
DispatchEventToListeners(browser_context, std::move(listeners_to_dispatch), DispatchEventToListeners(browser_context, std::move(listeners_to_dispatch),
......
...@@ -141,10 +141,9 @@ void WebRequestEventDetails::SetFrameData( ...@@ -141,10 +141,9 @@ void WebRequestEventDetails::SetFrameData(
void WebRequestEventDetails::DetermineFrameDataOnUI() { void WebRequestEventDetails::DetermineFrameDataOnUI() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
content::RenderFrameHost* rfh =
content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
ExtensionApiFrameIdMap::FrameData frame_data = ExtensionApiFrameIdMap::FrameData frame_data =
ExtensionApiFrameIdMap::Get()->GetFrameData(rfh); ExtensionApiFrameIdMap::Get()->GetFrameData(render_process_id_,
render_frame_id_);
SetFrameData(frame_data); SetFrameData(frame_data);
} }
......
...@@ -213,8 +213,8 @@ void WebRequestInfoInitParams::InitializeWebViewAndFrameData( ...@@ -213,8 +213,8 @@ void WebRequestInfoInitParams::InitializeWebViewAndFrameData(
} }
// For subresource loads we attempt to resolve the FrameData immediately. // For subresource loads we attempt to resolve the FrameData immediately.
frame_data = ExtensionApiFrameIdMap::Get()->GetFrameData( frame_data = ExtensionApiFrameIdMap::Get()->GetFrameData(render_process_id,
content::RenderFrameHost::FromID(render_process_id, frame_id)); frame_id);
} }
} }
......
...@@ -188,36 +188,35 @@ ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::KeyToValue( ...@@ -188,36 +188,35 @@ ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::KeyToValue(
} }
ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::LookupFrameDataOnUI( ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::LookupFrameDataOnUI(
const RenderFrameIdKey& key) { const RenderFrameIdKey& key,
bool check_deleted_frames) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
bool lookup_successful = false;
FrameData data;
FrameDataMap::const_iterator frame_id_iter = frame_data_map_.find(key); FrameDataMap::const_iterator frame_id_iter = frame_data_map_.find(key);
if (frame_id_iter != frame_data_map_.end()) {
lookup_successful = true; if (frame_id_iter != frame_data_map_.end())
data = frame_id_iter->second; return frame_id_iter->second;
} else {
data = KeyToValue(key); if (check_deleted_frames) {
// Don't save invalid values in the map. frame_id_iter = deleted_frame_data_map_.find(key);
if (data.frame_id != kInvalidFrameId) { if (frame_id_iter != deleted_frame_data_map_.end())
lookup_successful = true; return frame_id_iter->second;
auto kvpair = FrameDataMap::value_type(key, data);
frame_data_map_.insert(kvpair);
}
} }
FrameData data = KeyToValue(key);
// Don't save invalid values in the map.
if (data.frame_id != kInvalidFrameId)
frame_data_map_.insert({key, data});
return data; return data;
} }
ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::GetFrameData( ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::GetFrameData(
content::RenderFrameHost* rfh) { int render_process_id,
int render_frame_id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
const RenderFrameIdKey key(render_process_id, render_frame_id);
if (!rfh) return LookupFrameDataOnUI(key, true /* check_deleted_frames */);
return FrameData();
const RenderFrameIdKey key(rfh->GetProcess()->GetID(), rfh->GetRoutingID());
return LookupFrameDataOnUI(key);
} }
void ExtensionApiFrameIdMap::InitializeRenderFrameData( void ExtensionApiFrameIdMap::InitializeRenderFrameData(
...@@ -227,21 +226,33 @@ void ExtensionApiFrameIdMap::InitializeRenderFrameData( ...@@ -227,21 +226,33 @@ void ExtensionApiFrameIdMap::InitializeRenderFrameData(
DCHECK(rfh->IsRenderFrameLive()); DCHECK(rfh->IsRenderFrameLive());
const RenderFrameIdKey key(rfh->GetProcess()->GetID(), rfh->GetRoutingID()); const RenderFrameIdKey key(rfh->GetProcess()->GetID(), rfh->GetRoutingID());
CacheFrameData(key); LookupFrameDataOnUI(key, false /* check_deleted_frames */);
DCHECK(frame_data_map_.find(key) != frame_data_map_.end()); DCHECK(frame_data_map_.find(key) != frame_data_map_.end());
} }
void ExtensionApiFrameIdMap::CacheFrameData(const RenderFrameIdKey& key) {
LookupFrameDataOnUI(key);
}
void ExtensionApiFrameIdMap::OnRenderFrameDeleted( void ExtensionApiFrameIdMap::OnRenderFrameDeleted(
content::RenderFrameHost* rfh) { content::RenderFrameHost* rfh) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(rfh); DCHECK(rfh);
const RenderFrameIdKey key(rfh->GetProcess()->GetID(), rfh->GetRoutingID()); const RenderFrameIdKey key(rfh->GetProcess()->GetID(), rfh->GetRoutingID());
RemoveFrameData(key); // TODO(http://crbug.com/522129): This is necessary right now because beacon
// requests made in window.onunload may start after this has been called.
// Delay the RemoveFrameData() call, so we will still have the frame data
// cached when the beacon request comes in.
auto iter = frame_data_map_.find(key);
if (iter == frame_data_map_.end())
return;
deleted_frame_data_map_.insert({key, iter->second});
frame_data_map_.erase(key);
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(
[](ExtensionApiFrameIdMap* self, const RenderFrameIdKey& key) {
self->deleted_frame_data_map_.erase(key);
},
base::Unretained(this), key));
} }
void ExtensionApiFrameIdMap::UpdateTabAndWindowId( void ExtensionApiFrameIdMap::UpdateTabAndWindowId(
...@@ -350,10 +361,4 @@ size_t ExtensionApiFrameIdMap::GetFrameDataCountForTesting() const { ...@@ -350,10 +361,4 @@ size_t ExtensionApiFrameIdMap::GetFrameDataCountForTesting() const {
return frame_data_map_.size(); return frame_data_map_.size();
} }
void ExtensionApiFrameIdMap::RemoveFrameData(const RenderFrameIdKey& key) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
frame_data_map_.erase(key);
}
} // namespace extensions } // namespace extensions
...@@ -123,10 +123,12 @@ class ExtensionApiFrameIdMap { ...@@ -123,10 +123,12 @@ class ExtensionApiFrameIdMap {
content::WebContents* web_contents, content::WebContents* web_contents,
int frame_id); int frame_id);
// Retrieves the FrameData for a given |rfh|. The map may be updated with the // Retrieves the FrameData for a given |render_process_id| and
// result if the map did not contain the FrameData before the lookup. // |render_frame_id|. The map may be updated with the result if the map did
// If |rfh| is nullptr, then the map is not modified. // not contain the FrameData before the lookup. If a RenderFrameHost is not
FrameData GetFrameData(content::RenderFrameHost* rfh) WARN_UNUSED_RESULT; // found, then the map is not modified.
FrameData GetFrameData(int render_process_id,
int render_frame_id) WARN_UNUSED_RESULT;
// Initializes the FrameData for the given |rfh|. // Initializes the FrameData for the given |rfh|.
void InitializeRenderFrameData(content::RenderFrameHost* rfh); void InitializeRenderFrameData(content::RenderFrameHost* rfh);
...@@ -199,13 +201,10 @@ class ExtensionApiFrameIdMap { ...@@ -199,13 +201,10 @@ class ExtensionApiFrameIdMap {
virtual FrameData KeyToValue(const RenderFrameIdKey& key) const; virtual FrameData KeyToValue(const RenderFrameIdKey& key) const;
// Looks up the data for the given |key| and adds it to the |frame_data_map_|. // Looks up the data for the given |key| and adds it to the |frame_data_map_|.
FrameData LookupFrameDataOnUI(const RenderFrameIdKey& key); // If |check_deleted_frames| is true, |deleted_frame_data_map_| will also be
// used.
// Implementation of CacheFrameData(RenderFrameHost), separated for testing. FrameData LookupFrameDataOnUI(const RenderFrameIdKey& key,
void CacheFrameData(const RenderFrameIdKey& key); bool check_deleted_frames);
// Implementation of RemoveFrameData(RenderFrameHost), separated for testing.
void RemoveFrameData(const RenderFrameIdKey& key);
std::unique_ptr<ExtensionApiFrameIdMapHelper> helper_; std::unique_ptr<ExtensionApiFrameIdMapHelper> helper_;
...@@ -213,6 +212,11 @@ class ExtensionApiFrameIdMap { ...@@ -213,6 +212,11 @@ class ExtensionApiFrameIdMap {
// TODO(http://crbug.com/980774): Investigate if this is still needed. // TODO(http://crbug.com/980774): Investigate if this is still needed.
FrameDataMap frame_data_map_; FrameDataMap frame_data_map_;
// Holds mappings of render frame key to FrameData from frames that have been
// recently deleted. These are kept for a short time so beacon requests that
// continue after a frame is unloaded can access the FrameData.
FrameDataMap deleted_frame_data_map_;
// The set of pending main frame navigations for which ReadyToCommitNavigation // The set of pending main frame navigations for which ReadyToCommitNavigation
// has been fired. Only used on the UI thread. This is needed to clear state // has been fired. Only used on the UI thread. This is needed to clear state
// set up in OnMainFrameReadyToCommitNavigation for navigations which // set up in OnMainFrameReadyToCommitNavigation for navigations which
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment