Commit bdc18689 authored by Yury Semikhatsky's avatar Yury Semikhatsky Committed by Commit Bot

[DevTools] Make Page.crash and Target.targetCrashed work for OOPIFs

WebContents dispatches RenderProcessGone only for the main frame's
process. To receive such notifications for out-of-process iframes
we now subscribe to the frame's process events directly.

Bug: none
Change-Id: I3cd4b4b7f9a69ed749e624ac82c6feb94111f207
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2040051
Commit-Queue: Yury Semikhatsky <yurys@chromium.org>
Auto-Submit: Yury Semikhatsky <yurys@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#738787}
parent 9e98ffbc
......@@ -168,6 +168,13 @@ class TestJavaScriptDialogManager : public JavaScriptDialogManager,
} // namespace
class SitePerProcessDevToolsProtocolTest : public DevToolsProtocolTest {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
DevToolsProtocolTest::SetUpCommandLine(command_line);
IsolateAllSitesForTesting(command_line);
}
};
class TestInterstitialDelegate : public InterstitialPageDelegate {
private:
......@@ -785,6 +792,87 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, DISABLED_SynthesizeTapGesture) {
}
#endif // defined(OS_ANDROID)
IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, PageCrash) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html");
NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
Attach();
std::unique_ptr<base::DictionaryValue> command_params;
command_params.reset(new base::DictionaryValue());
command_params->SetBoolean("discover", true);
SendCommand("Target.setDiscoverTargets", std::move(command_params));
std::string target_id;
std::unique_ptr<base::DictionaryValue> params;
std::string type;
params = WaitForNotification("Target.targetCreated", true);
ASSERT_TRUE(params->GetString("targetInfo.type", &type));
ASSERT_EQ(type, "page");
ASSERT_TRUE(params->GetString("targetInfo.targetId", &target_id));
ClearNotifications();
{
content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes;
SendCommand("Page.crash", nullptr, false);
params = WaitForNotification("Target.targetCrashed", true);
}
ASSERT_TRUE(params);
std::string crashed_target_id;
ASSERT_TRUE(params->GetString("targetId", &crashed_target_id));
EXPECT_EQ(target_id, crashed_target_id);
ClearNotifications();
shell()->LoadURL(test_url);
WaitForNotification("Inspector.targetReloadedAfterCrash", true);
}
IN_PROC_BROWSER_TEST_F(SitePerProcessDevToolsProtocolTest, PageCrashInFrame) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url =
embedded_test_server()->GetURL("/devtools/page-with-oopif.html");
NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
Attach();
std::unique_ptr<base::DictionaryValue> command_params;
command_params.reset(new base::DictionaryValue());
command_params->SetBoolean("discover", true);
SendCommand("Target.setDiscoverTargets", std::move(command_params));
std::string frame_target_id;
std::unique_ptr<base::DictionaryValue> params;
for (int targetCount = 1; true; targetCount++) {
params = WaitForNotification("Target.targetCreated", true);
std::string type;
ASSERT_TRUE(params->GetString("targetInfo.type", &type));
if (type == "iframe") {
ASSERT_TRUE(params->GetString("targetInfo.targetId", &frame_target_id));
break;
}
ASSERT_LT(targetCount, 2);
}
command_params.reset(new base::DictionaryValue());
command_params->SetString("targetId", frame_target_id);
command_params->SetBoolean("flatten", true);
base::DictionaryValue* result =
SendCommand("Target.attachToTarget", std::move(command_params));
ASSERT_NE(nullptr, result);
std::string session_id;
ASSERT_TRUE(result->GetString("sessionId", &session_id));
ClearNotifications();
{
content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes;
SendSessionCommand("Page.crash", nullptr, session_id, false);
params = WaitForNotification("Target.targetCrashed", true);
}
ASSERT_TRUE(params);
std::string crashed_target_id;
ASSERT_TRUE(params->GetString("targetId", &crashed_target_id));
EXPECT_EQ(frame_target_id, crashed_target_id);
}
IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, NavigationPreservesMessages) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html");
......@@ -1663,20 +1751,6 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, InterstitialShownOnAttach) {
WaitForNotification("Page.interstitialShown", true);
}
class SitePerProcessDevToolsProtocolTest : public DevToolsProtocolTest {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
DevToolsProtocolTest::SetUpCommandLine(command_line);
IsolateAllSitesForTesting(command_line);
}
void SetUpOnMainThread() override {
DevToolsProtocolTest::SetUpOnMainThread();
content::SetupCrossSiteRedirector(embedded_test_server());
ASSERT_TRUE(embedded_test_server()->Start());
}
};
IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SetAndGetCookies) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url = embedded_test_server()->GetURL("/title1.html");
......
......@@ -19,6 +19,7 @@ namespace content {
namespace {
const char kIdParam[] = "id";
const char kSessionIdParam[] = "sessionId";
const char kMethodParam[] = "method";
const char kParamsParam[] = "params";
......@@ -46,9 +47,10 @@ bool DevToolsProtocolTest::DidAddMessageToConsole(
return true;
}
base::DictionaryValue* DevToolsProtocolTest::SendCommand(
base::DictionaryValue* DevToolsProtocolTest::SendSessionCommand(
const std::string& method,
std::unique_ptr<base::Value> params,
const std::string& session_id,
bool wait) {
in_dispatch_ = true;
base::DictionaryValue command;
......@@ -56,6 +58,8 @@ base::DictionaryValue* DevToolsProtocolTest::SendCommand(
command.SetString(kMethodParam, method);
if (params)
command.Set(kParamsParam, std::move(params));
if (!session_id.empty())
command.SetString(kSessionIdParam, session_id);
std::string json_command;
base::JSONWriter::Write(command, &json_command);
......
......@@ -47,7 +47,20 @@ class DevToolsProtocolTest : public ContentBrowserTest,
base::DictionaryValue* SendCommand(const std::string& method,
std::unique_ptr<base::Value> params,
bool wait);
bool wait) {
return SendSessionCommand(method, std::move(params), std::string(), wait);
}
base::DictionaryValue* SendSessionCommand(const std::string& method,
std::unique_ptr<base::Value> params,
const std::string& session_id) {
return SendSessionCommand(method, std::move(params), session_id, true);
}
base::DictionaryValue* SendSessionCommand(const std::string& method,
std::unique_ptr<base::Value> params,
const std::string& session_id,
bool wait);
void WaitForResponse();
......
......@@ -367,12 +367,12 @@ Response PageHandler::Disable() {
}
Response PageHandler::Crash() {
WebContentsImpl* web_contents = GetWebContents();
WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
if (!web_contents)
return Response::Error("Not attached to a page");
if (web_contents->IsCrashed())
return Response::Error("The target has already crashed");
if (web_contents->GetMainFrame()->frame_tree_node()->navigation_request())
if (host_->frame_tree_node()->navigation_request())
return Response::Error("Page has pending navigations, not killing");
return Response::FallThrough();
}
......
......@@ -243,7 +243,7 @@ RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost(
: DevToolsAgentHostImpl(frame_tree_node->devtools_frame_token().ToString()),
frame_tree_node_(nullptr) {
SetFrameTreeNode(frame_tree_node);
frame_host_ = frame_host;
ChangeFrameHostAndObservedProcess(frame_host);
render_frame_alive_ = frame_host_ && frame_host_->IsRenderFrameLive();
AddRef(); // Balanced in DestroyOnRenderFrameGone.
NotifyCreated();
......@@ -383,6 +383,7 @@ void RenderFrameDevToolsAgentHost::InspectElement(RenderFrameHost* frame_host,
RenderFrameDevToolsAgentHost::~RenderFrameDevToolsAgentHost() {
SetFrameTreeNode(nullptr);
ChangeFrameHostAndObservedProcess(nullptr);
}
void RenderFrameDevToolsAgentHost::ReadyToCommitNavigation(
......@@ -456,7 +457,7 @@ void RenderFrameDevToolsAgentHost::UpdateFrameHost(
}
RenderFrameHostImpl* old_host = frame_host_;
frame_host_ = frame_host;
ChangeFrameHostAndObservedProcess(frame_host);
if (IsAttached())
UpdateRawHeadersAccess(old_host, frame_host);
......@@ -523,7 +524,7 @@ void RenderFrameDevToolsAgentHost::DestroyOnRenderFrameGone() {
ForceDetachAllSessions();
UpdateRawHeadersAccess(frame_host_, nullptr);
}
frame_host_ = nullptr;
ChangeFrameHostAndObservedProcess(nullptr);
UpdateRendererChannel(IsAttached());
SetFrameTreeNode(nullptr);
Release();
......@@ -548,9 +549,19 @@ device::mojom::WakeLock* RenderFrameDevToolsAgentHost::GetWakeLock() {
}
#endif
void RenderFrameDevToolsAgentHost::RenderProcessGone(
base::TerminationStatus status) {
switch (status) {
void RenderFrameDevToolsAgentHost::ChangeFrameHostAndObservedProcess(
RenderFrameHostImpl* frame_host) {
if (frame_host_)
frame_host_->GetProcess()->RemoveObserver(this);
frame_host_ = frame_host;
if (frame_host_)
frame_host_->GetProcess()->AddObserver(this);
}
void RenderFrameDevToolsAgentHost::RenderProcessExited(
RenderProcessHost* host,
const ChildProcessTerminationInfo& info) {
switch (info.status) {
case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
#if defined(OS_CHROMEOS)
......@@ -563,7 +574,7 @@ void RenderFrameDevToolsAgentHost::RenderProcessGone(
case base::TERMINATION_STATUS_LAUNCH_FAILED:
for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
inspector->TargetCrashed();
NotifyCrashed(status);
NotifyCrashed(info.status);
break;
default:
for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
......
......@@ -18,6 +18,7 @@
#include "content/browser/devtools/devtools_agent_host_impl.h"
#include "content/common/content_export.h"
#include "content/common/navigation_params.mojom.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/web_contents_observer.h"
#include "net/base/net_errors.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
......@@ -42,7 +43,8 @@ class RenderFrameHostImpl;
class CONTENT_EXPORT RenderFrameDevToolsAgentHost
: public DevToolsAgentHostImpl,
private WebContentsObserver {
private WebContentsObserver,
private RenderProcessHostObserver {
public:
static void AddAllAgentHosts(DevToolsAgentHost::List* result);
......@@ -122,17 +124,21 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
RenderFrameHost* new_host) override;
void FrameDeleted(RenderFrameHost* rfh) override;
void RenderFrameDeleted(RenderFrameHost* rfh) override;
void RenderProcessGone(base::TerminationStatus status) override;
void DidAttachInterstitialPage() override;
void DidDetachInterstitialPage() override;
void OnVisibilityChanged(content::Visibility visibility) override;
void OnPageScaleFactorChanged(float page_scale_factor) override;
// RenderProcessHostObserver overrides.
void RenderProcessExited(RenderProcessHost* host,
const ChildProcessTerminationInfo& info) override;
bool IsChildFrame();
void DestroyOnRenderFrameGone();
void UpdateFrameHost(RenderFrameHostImpl* frame_host);
void SetFrameTreeNode(FrameTreeNode* frame_tree_node);
void ChangeFrameHostAndObservedProcess(RenderFrameHostImpl* frame_host);
bool ShouldAllowSession(DevToolsSession* session);
......
<html>
<body>
<h1>Top frame</h1>
<body>
<iframe src="/cross-site/bar.com/title1.html"></iframe>
</body>
</html>
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