Commit c0330ff2 authored by Karan Bhatia's avatar Karan Bhatia Committed by Commit Bot

Reland "Extensions: Fix memory leak in ExtensionApiFrameIdMap."

This is a reland of 613ba331. This collided with
r541891.

Original change's description:
> Extensions: Fix memory leak in ExtensionApiFrameIdMap.
>
> Currently in ExtensionApiFrameIdMap::UpdateTabAndWindowId and
> ExtensionApiFrameIdMap::LookupFrameDataOnUI we don't check whether a
> RenderFrameHost is alive, before storing it's frame data. It's possible that
> such a RenderFrameHost never becomes alive, and hence we don't get any
> OnRenderFrameDeleted notification for it. Since ExtensionApiFrameIdMap is a
> singleton, this causes a memory leak. To fix, ensure that only live
> RenderFrameHosts are tracked.
>
> Also ensure in InProcessBrowserTest::TearDown that ExtensionApiFrameIdMap is not
> leaking memory for any browser test.
>
> BUG=817205
>
> Change-Id: I78bf06cee7e10465f9eb5973ee8e59f525a74d93
> Reviewed-on: https://chromium-review.googlesource.com/951975
> Reviewed-by: Scott Violet <sky@chromium.org>
> Reviewed-by: Devlin <rdevlin.cronin@chromium.org>
> Commit-Queue: Karan Bhatia <karandeepb@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#541950}

TBR=sky@chromium.org,rdevlin.cronin@chromium.org

Bug: 817205
Change-Id: I7b3ac6806d0c747d439e74f80f623a7fd4412050
Reviewed-on: https://chromium-review.googlesource.com/956762
Commit-Queue: Karan Bhatia <karandeepb@chromium.org>
Reviewed-by: default avatarKaran Bhatia <karandeepb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542025}
parent 46fb6df7
...@@ -4413,6 +4413,7 @@ if (!is_android) { ...@@ -4413,6 +4413,7 @@ if (!is_android) {
"//components/nacl/common:buildflags", "//components/nacl/common:buildflags",
"//components/os_crypt:test_support", "//components/os_crypt:test_support",
"//content/public/browser:browser", "//content/public/browser:browser",
"//extensions/buildflags",
"//skia", "//skia",
"//testing/gtest", "//testing/gtest",
"//third_party/WebKit/public:blink_headers", "//third_party/WebKit/public:blink_headers",
...@@ -4424,6 +4425,10 @@ if (!is_android) { ...@@ -4424,6 +4425,10 @@ if (!is_android) {
"ppapi/ppapi_test.h", "ppapi/ppapi_test.h",
] ]
} }
if (enable_extensions) {
deps += [ "//extensions/browser" ]
}
} }
import("//third_party/protobuf/proto_library.gni") import("//third_party/protobuf/proto_library.gni")
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_launcher.h" #include "content/public/test/test_launcher.h"
#include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_navigation_observer.h"
#include "extensions/buildflags/buildflags.h"
#include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/embedded_test_server.h"
#include "ui/display/display_switches.h" #include "ui/display/display_switches.h"
...@@ -91,6 +92,10 @@ ...@@ -91,6 +92,10 @@
#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
namespace { namespace {
// Passed as value of kTestType. // Passed as value of kTestType.
...@@ -286,6 +291,14 @@ void InProcessBrowserTest::TearDown() { ...@@ -286,6 +291,14 @@ void InProcessBrowserTest::TearDown() {
BrowserTestBase::TearDown(); BrowserTestBase::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
} }
void InProcessBrowserTest::CloseBrowserSynchronously(Browser* browser) { void InProcessBrowserTest::CloseBrowserSynchronously(Browser* browser) {
......
...@@ -162,6 +162,10 @@ ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::KeyToValue( ...@@ -162,6 +162,10 @@ ExtensionApiFrameIdMap::FrameData ExtensionApiFrameIdMap::KeyToValue(
const RenderFrameIdKey& key) const { const RenderFrameIdKey& key) const {
content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
key.render_process_id, key.frame_routing_id); key.render_process_id, key.frame_routing_id);
if (!rfh || !rfh->IsRenderFrameLive())
return FrameData();
int tab_id = extension_misc::kUnknownTabId; int tab_id = extension_misc::kUnknownTabId;
int window_id = extension_misc::kUnknownWindowId; int window_id = extension_misc::kUnknownWindowId;
if (helper_) if (helper_)
...@@ -347,19 +351,18 @@ void ExtensionApiFrameIdMap::UpdateTabAndWindowId( ...@@ -347,19 +351,18 @@ void ExtensionApiFrameIdMap::UpdateTabAndWindowId(
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());
// Only track FrameData for live render frames.
if (!rfh->IsRenderFrameLive()) {
return;
}
base::AutoLock lock(frame_data_map_lock_); base::AutoLock lock(frame_data_map_lock_);
FrameDataMap::iterator iter = frame_data_map_.find(key); FrameDataMap::iterator iter = frame_data_map_.find(key);
if (iter != frame_data_map_.end()) { // The FrameData for |rfh| should have already been initialized.
iter->second.tab_id = tab_id; DCHECK(iter != frame_data_map_.end());
iter->second.window_id = window_id; iter->second.tab_id = tab_id;
} else { iter->second.window_id = window_id;
DCHECK(!rfh->IsRenderFrameLive());
// TODO(crbug.com/817205): Remove this branch. We should only maintain frame
// data for tracked live render frames. Most probably this is causing a
// memory leak.
frame_data_map_[key] =
FrameData(GetFrameId(rfh), GetParentFrameId(rfh), tab_id, window_id);
}
} }
bool ExtensionApiFrameIdMap::HasCachedFrameDataForTesting( bool ExtensionApiFrameIdMap::HasCachedFrameDataForTesting(
......
...@@ -131,7 +131,7 @@ class ExtensionApiFrameIdMap { ...@@ -131,7 +131,7 @@ class ExtensionApiFrameIdMap {
// the given render frame. // the given render frame.
void OnRenderFrameDeleted(content::RenderFrameHost* rfh); void OnRenderFrameDeleted(content::RenderFrameHost* rfh);
// Updates the tab and window id for the given RenderFrameHost, if any exists. // Updates the tab and window id for the given RenderFrameHost if necessary.
void UpdateTabAndWindowId(int tab_id, void UpdateTabAndWindowId(int tab_id,
int window_id, int window_id,
content::RenderFrameHost* rfh); content::RenderFrameHost* rfh);
...@@ -179,8 +179,9 @@ class ExtensionApiFrameIdMap { ...@@ -179,8 +179,9 @@ class ExtensionApiFrameIdMap {
virtual ~ExtensionApiFrameIdMap(); virtual ~ExtensionApiFrameIdMap();
// Determines the value to be stored in |frame_data_map_| for a given key. // Determines the value to be stored in |frame_data_map_| for a given key.
// This method is only called when |key| is not in |frame_data_map_|. // Returns empty FrameData when the corresponding RenderFrameHost is not
// virtual for testing. // alive. This method is only called when |key| is not in |frame_data_map_|.
// Virtual for testing.
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_|.
......
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