Chromium Code Reviews| Index: content/browser/site_per_process_browsertest.cc |
| diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc |
| index e00123815bc6da00b34ab33fa3ce1dd3fd9fb28e..f61bdb707805bfc763abc03b11f40ba3a592ce70 100644 |
| --- a/content/browser/site_per_process_browsertest.cc |
| +++ b/content/browser/site_per_process_browsertest.cc |
| @@ -31,8 +31,10 @@ |
| #include "content/browser/renderer_host/render_view_host_impl.h" |
| #include "content/browser/renderer_host/render_widget_host_input_event_router.h" |
| #include "content/browser/renderer_host/render_widget_host_view_aura.h" |
| +#include "content/common/child_process_messages.h" |
| #include "content/common/frame_messages.h" |
| #include "content/common/input/synthetic_tap_gesture_params.h" |
| +#include "content/common/input_messages.h" |
| #include "content/common/view_messages.h" |
| #include "content/public/browser/cert_store.h" |
| #include "content/public/browser/notification_observer.h" |
| @@ -6413,4 +6415,83 @@ IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| crash_renderer_and_wait_for_input_state_none(host_process); |
| } |
| +// Helper class to wait for a ChildProcessHostMsg_ShutdownRequest message to |
| +// arrive. |
| +class ShutdownRequestMessageFilter : public BrowserMessageFilter { |
| + public: |
| + ShutdownRequestMessageFilter() |
| + : BrowserMessageFilter(ChildProcessMsgStart), |
| + message_loop_runner_(new MessageLoopRunner) {} |
| + |
| + bool OnMessageReceived(const IPC::Message& message) override { |
| + if (message.type() == ChildProcessHostMsg_ShutdownRequest::ID) { |
| + content::BrowserThread::PostTask( |
| + content::BrowserThread::UI, FROM_HERE, |
| + base::Bind(&ShutdownRequestMessageFilter::OnShutdownRequest, this)); |
| + } |
| + return false; |
| + } |
| + |
| + void OnShutdownRequest() { message_loop_runner_->Quit(); } |
| + |
| + void Wait() { message_loop_runner_->Run(); } |
| + |
| + private: |
| + ~ShutdownRequestMessageFilter() override {} |
| + |
| + scoped_refptr<MessageLoopRunner> message_loop_runner_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ShutdownRequestMessageFilter); |
| +}; |
| + |
| +// Test for https://crbug.com/568836. From an A-embed-B page, navigate the |
| +// subframe from B to A. This cleans up the process for B, but the test delays |
| +// the browser side from killing the B process right away. This allows the |
| +// B process to process two ViewMsg_Close messages sent to the subframe's |
| +// RenderWidget and RenderView, in that order. In the bug, the latter crashed |
|
nasko
2016/04/18 21:24:26
nit: "and the RenderView".
alexmos
2016/04/22 05:09:34
Done. (I used "and to the RenderView".)
|
| +// while detaching the subframe's LocalFrame (triggered as part of closing the |
| +// RenderView), because this tried to access the subframe's WebFrameWidget |
| +// (from RenderFrameImpl::didChangeSelection), which had already been cleared |
| +// by the former. |
| +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, |
| + CloseSubframeWidgetAndViewOnProcessExit) { |
| + GURL main_url(embedded_test_server()->GetURL( |
| + "a.com", "/cross_site_iframe_factory.html?a(b)")); |
| + EXPECT_TRUE(NavigateToURL(shell(), main_url)); |
| + |
| + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) |
| + ->GetFrameTree() |
| + ->root(); |
| + |
| + // "Select all" in the subframe. The bug only happens if there's a selection |
| + // change, which triggers the path through didChangeSelection. |
| + root->child_at(0)->current_frame_host()->Send(new InputMsg_SelectAll( |
| + root->child_at(0)->current_frame_host()->GetRoutingID())); |
| + |
| + // Prevent b.com process from terminating right away once the subframe |
| + // navigates away from b.com below. This is necessary so that the renderer |
| + // process has time to process the closings of RenderWidget and RenderView, |
| + // which is where the original bug was triggered. Incrementing worker |
| + // RefCount will cause RenderProcessHostImpl::Cleanup to forego process |
| + // termination. |
| + RenderProcessHost* subframe_process = |
| + root->child_at(0)->current_frame_host()->GetProcess(); |
| + subframe_process->IncrementWorkerRefCount(); |
| + |
| + // Navigate the subframe away from b.com. Since this is the last active |
| + // frame in the b.com process, this causes the RenderWidget and RenderView to |
| + // be closed. If this succeeds without crashing, the renderer will release |
| + // the process and send a ChildProcessHostMsg_ShutdownRequest to the browser |
| + // process to ask whether it's ok to terminate. Thus, wait for this message |
| + // to ensure that the RenderView and widget were closed without crashing. |
| + scoped_refptr<ShutdownRequestMessageFilter> filter = |
| + new ShutdownRequestMessageFilter(); |
| + subframe_process->AddFilter(filter.get()); |
| + NavigateFrameToURL(root->child_at(0), |
| + embedded_test_server()->GetURL("a.com", "/title1.html")); |
| + filter->Wait(); |
| + |
| + subframe_process->DecrementWorkerRefCount(); |
|
nasko
2016/04/18 21:24:26
Do we care to wait for process termination at all?
alexmos
2016/04/22 05:09:34
Correct, we don't need to wait for process termina
|
| +} |
| + |
| } // namespace content |