summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhajimehoshi@chromium.org <hajimehoshi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-27 10:10:13 +0000
committerhajimehoshi@chromium.org <hajimehoshi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-01-27 10:10:13 +0000
commit4562cf71dc6b216455843eccf0676dcff6e61013 (patch)
treefb506074edd017ed9ddbac999c923997147f9f1f
parent86aa0ae6229e258746fc53df7e3436bb874f9ee6 (diff)
downloadchromium_src-4562cf71dc6b216455843eccf0676dcff6e61013.zip
chromium_src-4562cf71dc6b216455843eccf0676dcff6e61013.tar.gz
chromium_src-4562cf71dc6b216455843eccf0676dcff6e61013.tar.bz2
Leak detection at content_shell
At the layout test, about:blank is loaded before and after one test. We're adding a method to count objects (https://codereview.chromium.org/132913003/) and using this at about:blank, and comparing the numbers of objects at about:blank, we can detect a leak. https://docs.google.com/a/chromium.org/document/d/1sFAsZxeISKnbGdXoLZlB2tDZ8pvO102ePFQx6TX4X14/edit# BUG=332630 Review URL: https://codereview.chromium.org/132243006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247209 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/content_shell.gypi3
-rw-r--r--content/shell/browser/shell_browser_main.cc82
-rw-r--r--content/shell/browser/shell_content_browser_client.cc3
-rw-r--r--content/shell/browser/webkit_test_controller.cc31
-rw-r--r--content/shell/browser/webkit_test_controller.h2
-rw-r--r--content/shell/common/leak_detection_result.h18
-rw-r--r--content/shell/common/shell_messages.h12
-rw-r--r--content/shell/common/shell_switches.cc4
-rw-r--r--content/shell/common/shell_switches.h1
-rw-r--r--content/shell/renderer/leak_detector.cc39
-rw-r--r--content/shell/renderer/leak_detector.h41
-rw-r--r--content/shell/renderer/webkit_test_runner.cc24
-rw-r--r--content/shell/renderer/webkit_test_runner.h8
13 files changed, 234 insertions, 34 deletions
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index f300629..d3373ad 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -146,6 +146,7 @@
'shell/browser/shell_web_contents_view_delegate_win.cc',
'shell/browser/webkit_test_controller.cc',
'shell/browser/webkit_test_controller.h',
+ 'shell/common/leak_detection_result.h',
'shell/common/shell_content_client.cc',
'shell/common/shell_content_client.h',
'shell/common/shell_messages.cc',
@@ -162,6 +163,8 @@
'shell/geolocation/shell_access_token_store.h',
'shell/renderer/gc_controller.cc',
'shell/renderer/gc_controller.h',
+ 'shell/renderer/leak_detector.cc',
+ 'shell/renderer/leak_detector.h',
'shell/renderer/shell_content_renderer_client.cc',
'shell/renderer/shell_content_renderer_client.h',
'shell/renderer/shell_render_frame_observer.cc',
diff --git a/content/shell/browser/shell_browser_main.cc b/content/shell/browser/shell_browser_main.cc
index ca2cd82..7b17cd4 100644
--- a/content/shell/browser/shell_browser_main.cc
+++ b/content/shell/browser/shell_browser_main.cc
@@ -17,6 +17,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "content/public/browser/browser_main_runner.h"
+#include "content/public/common/url_constants.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/webkit_test_controller.h"
#include "content/shell/common/shell_switches.h"
@@ -106,6 +107,46 @@ bool GetNextTest(const CommandLine::StringVector& args,
return true;
}
+bool RunOneTest(const std::string& test_string,
+ bool* ran_at_least_once,
+ const scoped_ptr<content::BrowserMainRunner>& main_runner) {
+ if (test_string.empty())
+ return true;
+ if (test_string == "QUIT")
+ return false;
+
+ bool enable_pixel_dumps;
+ std::string pixel_hash;
+ base::FilePath cwd;
+ GURL test_url = GetURLForLayoutTest(
+ test_string, &cwd, &enable_pixel_dumps, &pixel_hash);
+ if (!content::WebKitTestController::Get()->PrepareForLayoutTest(
+ test_url, cwd, enable_pixel_dumps, pixel_hash)) {
+ return false;
+ }
+
+ *ran_at_least_once = true;
+#if defined(OS_ANDROID)
+ // The message loop on Android is provided by the system, and does not
+ // offer a blocking Run() method. For layout tests, use a nested loop
+ // together with a base::RunLoop so it can block until a QuitClosure.
+ base::RunLoop run_loop;
+ run_loop.Run();
+#else
+ main_runner->Run();
+#endif
+
+ if (!content::WebKitTestController::Get()->ResetAfterLayoutTest())
+ return false;
+
+#if defined(OS_ANDROID)
+ // There will be left-over tasks in the queue for Android because the
+ // main window is being destroyed. Run them before starting the next test.
+ base::MessageLoop::current()->RunUntilIdle();
+#endif
+ return true;
+}
+
} // namespace
// Main routine for running as the Browser process.
@@ -163,41 +204,16 @@ int ShellBrowserMain(
std::cout << "#READY\n";
std::cout.flush();
- while (GetNextTest(args, &command_line_position, &test_string)) {
- if (test_string.empty())
- continue;
- if (test_string == "QUIT")
- break;
-
- bool enable_pixel_dumps;
- std::string pixel_hash;
- base::FilePath cwd;
- GURL test_url = GetURLForLayoutTest(
- test_string, &cwd, &enable_pixel_dumps, &pixel_hash);
- if (!content::WebKitTestController::Get()->PrepareForLayoutTest(
- test_url, cwd, enable_pixel_dumps, pixel_hash)) {
- break;
- }
+ // To detect leaks, the numbers of objects are counted at about:blank before
+ // loading a page and after loading a page. The first content should be
+ // about:blank when the leak detection is enabled.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableLeakDetection))
+ RunOneTest(content::kAboutBlankURL, &ran_at_least_once, main_runner);
- ran_at_least_once = true;
-#if defined(OS_ANDROID)
- // The message loop on Android is provided by the system, and does not
- // offer a blocking Run() method. For layout tests, use a nested loop
- // together with a base::RunLoop so it can block until a QuitClosure.
- base::RunLoop run_loop;
- run_loop.Run();
-#else
- main_runner->Run();
-#endif
-
- if (!content::WebKitTestController::Get()->ResetAfterLayoutTest())
+ while (GetNextTest(args, &command_line_position, &test_string)) {
+ if (!RunOneTest(test_string, &ran_at_least_once, main_runner))
break;
-
-#if defined(OS_ANDROID)
- // There will be left-over tasks in the queue for Android because the
- // main window is being destroyed. Run them before starting the next test.
- base::MessageLoop::current()->RunUntilIdle();
-#endif
}
if (!ran_at_least_once) {
base::MessageLoop::current()->PostTask(FROM_HERE,
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 53eb7f7..6b51c49 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -212,6 +212,9 @@ void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
CommandLine::ForCurrentProcess()->GetSwitchValuePath(
switches::kCrashDumpsDir));
}
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableLeakDetection))
+ command_line->AppendSwitch(switches::kEnableLeakDetection);
}
void ShellContentBrowserClient::OverrideWebkitPrefs(
diff --git a/content/shell/browser/webkit_test_controller.cc b/content/shell/browser/webkit_test_controller.cc
index 106540e..9a3b92b 100644
--- a/content/shell/browser/webkit_test_controller.cc
+++ b/content/shell/browser/webkit_test_controller.cc
@@ -26,6 +26,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_browser_context.h"
#include "content/shell/browser/shell_content_browser_client.h"
@@ -378,6 +379,7 @@ bool WebKitTestController::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseRemainingWindows,
OnCloseRemainingWindows)
IPC_MESSAGE_HANDLER(ShellViewHostMsg_ResetDone, OnResetDone)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_LeakDetectionDone, OnLeakDetectionDone)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -652,8 +654,37 @@ void WebKitTestController::OnCloseRemainingWindows() {
}
void WebKitTestController::OnResetDone() {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableLeakDetection)) {
+ if (main_window_ && main_window_->web_contents()) {
+ RenderViewHost* render_view_host =
+ main_window_->web_contents()->GetRenderViewHost();
+ render_view_host->Send(
+ new ShellViewMsg_TryLeakDetection(render_view_host->GetRoutingID()));
+ }
+ return;
+ }
+
base::MessageLoop::current()->PostTask(FROM_HERE,
base::MessageLoop::QuitClosure());
}
+void WebKitTestController::OnLeakDetectionDone(
+ const LeakDetectionResult& result) {
+ if (!result.leaked) {
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::MessageLoop::QuitClosure());
+ return;
+ }
+
+ printer_->AddErrorMessage("#LEAK");
+ printer_->AddErrorMessage(
+ base::StringPrintf(" Number of live documents: %d",
+ result.number_of_live_documents));
+ printer_->AddErrorMessage(
+ base::StringPrintf(" Number of live nodes: %d",
+ result.number_of_live_nodes));
+ DiscardMainWindow();
+}
+
} // namespace content
diff --git a/content/shell/browser/webkit_test_controller.h b/content/shell/browser/webkit_test_controller.h
index a23841d..865e395 100644
--- a/content/shell/browser/webkit_test_controller.h
+++ b/content/shell/browser/webkit_test_controller.h
@@ -16,6 +16,7 @@
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/web_contents_observer.h"
+#include "content/shell/common/leak_detection_result.h"
#include "ui/gfx/size.h"
#include "webkit/common/webpreferences.h"
@@ -173,6 +174,7 @@ class WebKitTestController : public base::NonThreadSafe,
void OnCaptureSessionHistory();
void OnCloseRemainingWindows();
void OnResetDone();
+ void OnLeakDetectionDone(const content::LeakDetectionResult& result);
scoped_ptr<WebKitTestResultPrinter> printer_;
diff --git a/content/shell/common/leak_detection_result.h b/content/shell/common/leak_detection_result.h
new file mode 100644
index 0000000..7afcfd3
--- /dev/null
+++ b/content/shell/common/leak_detection_result.h
@@ -0,0 +1,18 @@
+// Copyright 2014 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 CONTENT_SHELL_COMMON_LEAK_DETECTION_RESULT_H_
+#define CONTENT_SHELL_COMMON_LEAK_DETECTION_RESULT_H_
+
+namespace content {
+
+struct LeakDetectionResult {
+ bool leaked;
+ unsigned number_of_live_documents;
+ unsigned number_of_live_nodes;
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_COMMON_LEAK_DETECTION_RESULT_H_
diff --git a/content/shell/common/shell_messages.h b/content/shell/common/shell_messages.h
index 253baf4..62fc8f9 100644
--- a/content/shell/common/shell_messages.h
+++ b/content/shell/common/shell_messages.h
@@ -8,6 +8,7 @@
#include "content/public/common/common_param_traits.h"
#include "content/public/common/page_state.h"
+#include "content/shell/common/leak_detection_result.h"
#include "content/shell/common/shell_test_configuration.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_platform_file.h"
@@ -50,6 +51,8 @@ IPC_MESSAGE_ROUTED3(
std::vector<std::vector<content::PageState> > /* session_histories */,
std::vector<unsigned> /* current_entry_indexes */)
+IPC_MESSAGE_ROUTED0(ShellViewMsg_TryLeakDetection)
+
// Send a text dump of the WebContents to the render host.
IPC_MESSAGE_ROUTED1(ShellViewHostMsg_TextDump,
std::string /* dump */)
@@ -99,3 +102,12 @@ IPC_MESSAGE_ROUTED1(ShellViewHostMsg_SetDeviceScaleFactor,
float /* factor */)
IPC_MESSAGE_ROUTED0(ShellViewHostMsg_CaptureSessionHistory)
IPC_MESSAGE_ROUTED0(ShellViewHostMsg_CloseRemainingWindows)
+
+IPC_STRUCT_TRAITS_BEGIN(content::LeakDetectionResult)
+IPC_STRUCT_TRAITS_MEMBER(leaked)
+IPC_STRUCT_TRAITS_MEMBER(number_of_live_documents)
+IPC_STRUCT_TRAITS_MEMBER(number_of_live_nodes)
+IPC_STRUCT_TRAITS_END()
+
+IPC_MESSAGE_ROUTED1(ShellViewHostMsg_LeakDetectionDone,
+ content::LeakDetectionResult /* result */)
diff --git a/content/shell/common/shell_switches.cc b/content/shell/common/shell_switches.cc
index dcd66a5..3e6b31f 100644
--- a/content/shell/common/shell_switches.cc
+++ b/content/shell/common/shell_switches.cc
@@ -27,6 +27,10 @@ const char kDumpRenderTree[] = "dump-render-tree";
// Enable accelerated 2D canvas.
const char kEnableAccelerated2DCanvas[] = "enable-accelerated-2d-canvas";
+// Enables the leak detection of loading webpages. This allows us to check
+// whether or not reloading a webpage releases web-related objects correctly.
+const char kEnableLeakDetection[] = "enable-leak-detection";
+
// Encode binary layout test results (images, audio) using base64.
const char kEncodeBinary[] = "encode-binary";
diff --git a/content/shell/common/shell_switches.h b/content/shell/common/shell_switches.h
index 72797f8..094eabf 100644
--- a/content/shell/common/shell_switches.h
+++ b/content/shell/common/shell_switches.h
@@ -16,6 +16,7 @@ extern const char kContentShellDataPath[];
extern const char kCrashDumpsDir[];
extern const char kDumpRenderTree[];
extern const char kEnableAccelerated2DCanvas[];
+extern const char kEnableLeakDetection[];
extern const char kEncodeBinary[];
extern const char kExposeInternalsForTesting[];
extern const char kStableReleaseMode[];
diff --git a/content/shell/renderer/leak_detector.cc b/content/shell/renderer/leak_detector.cc
new file mode 100644
index 0000000..2af12be
--- /dev/null
+++ b/content/shell/renderer/leak_detector.cc
@@ -0,0 +1,39 @@
+// Copyright 2014 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/shell/renderer/leak_detector.h"
+
+#include "base/logging.h"
+#include "third_party/WebKit/public/web/WebLeakDetector.h"
+
+using blink::WebLeakDetector;
+
+namespace content {
+
+LeakDetector::LeakDetector()
+ : previous_number_of_live_documents_(0),
+ previous_number_of_live_nodes_(0) {
+}
+
+LeakDetectionResult LeakDetector::TryLeakDetection(blink::WebFrame* frame) {
+ LeakDetectionResult result;
+ result.number_of_live_documents = 0;
+ result.number_of_live_nodes = 0;
+
+ WebLeakDetector::collectGarbargeAndGetDOMCounts(
+ frame, &result.number_of_live_documents, &result.number_of_live_nodes);
+
+ result.leaked =
+ previous_number_of_live_documents_ > 0 &&
+ previous_number_of_live_nodes_ > 0 &&
+ (previous_number_of_live_documents_ < result.number_of_live_documents ||
+ previous_number_of_live_nodes_ < result.number_of_live_nodes);
+
+ previous_number_of_live_documents_ = result.number_of_live_documents;
+ previous_number_of_live_nodes_ = result.number_of_live_nodes;
+
+ return result;
+}
+
+} // namespace content
diff --git a/content/shell/renderer/leak_detector.h b/content/shell/renderer/leak_detector.h
new file mode 100644
index 0000000..e9935c2
--- /dev/null
+++ b/content/shell/renderer/leak_detector.h
@@ -0,0 +1,41 @@
+// Copyright 2014 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 CONTENT_SHELL_RENDERER_LEAK_DETECTOR_H_
+#define CONTENT_SHELL_RENDERER_LEAK_DETECTOR_H_
+
+#include "base/basictypes.h"
+#include "content/shell/common/leak_detection_result.h"
+
+namespace blink {
+class WebFrame;
+}
+
+namespace content {
+
+// LeakDetector counts DOM objects and compare them between two pages.
+class LeakDetector {
+ public:
+ LeakDetector();
+
+ // Counts DOM objects, compare the previous status and returns the result of
+ // leak detection. It is assumed that this method is always called when a
+ // specific page, like about:blank is loaded to compare the previous
+ // circumstance of DOM objects. If the number of objects increses, there
+ // should be a leak.
+ LeakDetectionResult TryLeakDetection(blink::WebFrame* frame);
+
+ private:
+ // The number of the live documents last time.
+ unsigned previous_number_of_live_documents_;
+
+ // The number of the live nodes last time.
+ unsigned previous_number_of_live_nodes_;
+
+ DISALLOW_COPY_AND_ASSIGN(LeakDetector);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_RENDERER_LEAK_DETECTOR_H_
diff --git a/content/shell/renderer/webkit_test_runner.cc b/content/shell/renderer/webkit_test_runner.cc
index 09804e7..0484667 100644
--- a/content/shell/renderer/webkit_test_runner.cc
+++ b/content/shell/renderer/webkit_test_runner.cc
@@ -27,8 +27,10 @@
#include "content/public/renderer/render_view_visitor.h"
#include "content/public/test/layouttest_support.h"
#include "content/shell/common/shell_messages.h"
+#include "content/shell/common/shell_switches.h"
#include "content/shell/common/webkit_test_helpers.h"
#include "content/shell/renderer/gc_controller.h"
+#include "content/shell/renderer/leak_detector.h"
#include "content/shell/renderer/shell_render_process_observer.h"
#include "content/shell/renderer/test_runner/WebTask.h"
#include "content/shell/renderer/test_runner/WebTestInterfaces.h"
@@ -56,6 +58,7 @@
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebHistoryItem.h"
#include "third_party/WebKit/public/web/WebKit.h"
+#include "third_party/WebKit/public/web/WebLeakDetector.h"
#include "third_party/WebKit/public/web/WebScriptSource.h"
#include "third_party/WebKit/public/web/WebTestingSupport.h"
#include "third_party/WebKit/public/web/WebView.h"
@@ -208,7 +211,9 @@ WebKitTestRunner::WebKitTestRunner(RenderView* render_view)
proxy_(NULL),
focused_view_(NULL),
is_main_window_(false),
- focus_on_next_commit_(false) {
+ focus_on_next_commit_(false),
+ leak_detector_(new LeakDetector())
+{
UseMockMediaStreams(render_view);
}
@@ -562,6 +567,7 @@ bool WebKitTestRunner::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(ShellViewMsg_SessionHistory, OnSessionHistory)
IPC_MESSAGE_HANDLER(ShellViewMsg_Reset, OnReset)
IPC_MESSAGE_HANDLER(ShellViewMsg_NotifyDone, OnNotifyDone)
+ IPC_MESSAGE_HANDLER(ShellViewMsg_TryLeakDetection, OnTryLeakDetection)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -707,4 +713,20 @@ void WebKitTestRunner::OnNotifyDone() {
WebScriptSource(WebString::fromUTF8("testRunner.notifyDone();")));
}
+void WebKitTestRunner::OnTryLeakDetection() {
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&WebKitTestRunner::TryLeakDetection, base::Unretained(this)));
+}
+
+void WebKitTestRunner::TryLeakDetection() {
+ WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
+ DCHECK_EQ(GURL(kAboutBlankURL), GURL(main_frame->document().url()));
+ DCHECK(!main_frame->isLoading());
+
+ LeakDetectionResult result = leak_detector_->TryLeakDetection(
+ render_view()->GetWebView()->mainFrame());
+ Send(new ShellViewHostMsg_LeakDetectionDone(routing_id(), result));
+}
+
} // namespace content
diff --git a/content/shell/renderer/webkit_test_runner.h b/content/shell/renderer/webkit_test_runner.h
index 6399e7a..b6f9b02 100644
--- a/content/shell/renderer/webkit_test_runner.h
+++ b/content/shell/renderer/webkit_test_runner.h
@@ -31,6 +31,8 @@ class WebTestProxyBase;
namespace content {
+class LeakDetector;
+
// This is the renderer side of the webkit test runner.
class WebKitTestRunner : public RenderViewObserver,
public RenderViewObserverTracker<WebKitTestRunner>,
@@ -119,11 +121,14 @@ class WebKitTestRunner : public RenderViewObserver,
const std::vector<unsigned>& current_entry_indexes);
void OnReset();
void OnNotifyDone();
+ void OnTryLeakDetection();
// After finishing the test, retrieves the audio, text, and pixel dumps from
// the TestRunner library and sends them to the browser process.
void CaptureDump();
+ void TryLeakDetection();
+
::WebTestRunner::WebTestProxyBase* proxy_;
RenderView* focused_view_;
@@ -140,6 +145,9 @@ class WebKitTestRunner : public RenderViewObserver,
bool focus_on_next_commit_;
+ scoped_ptr<LeakDetector> leak_detector_;
+ bool needs_leak_detector_;
+
DISALLOW_COPY_AND_ASSIGN(WebKitTestRunner);
};