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, ...@@ -168,6 +168,13 @@ class TestJavaScriptDialogManager : public JavaScriptDialogManager,
} // namespace } // namespace
class SitePerProcessDevToolsProtocolTest : public DevToolsProtocolTest {
public:
void SetUpCommandLine(base::CommandLine* command_line) override {
DevToolsProtocolTest::SetUpCommandLine(command_line);
IsolateAllSitesForTesting(command_line);
}
};
class TestInterstitialDelegate : public InterstitialPageDelegate { class TestInterstitialDelegate : public InterstitialPageDelegate {
private: private:
...@@ -785,6 +792,87 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, DISABLED_SynthesizeTapGesture) { ...@@ -785,6 +792,87 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, DISABLED_SynthesizeTapGesture) {
} }
#endif // defined(OS_ANDROID) #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) { IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, NavigationPreservesMessages) {
ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html"); GURL test_url = embedded_test_server()->GetURL("/devtools/navigation.html");
...@@ -1663,20 +1751,6 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, InterstitialShownOnAttach) { ...@@ -1663,20 +1751,6 @@ IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, InterstitialShownOnAttach) {
WaitForNotification("Page.interstitialShown", true); 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) { IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, SetAndGetCookies) {
ASSERT_TRUE(embedded_test_server()->Start()); ASSERT_TRUE(embedded_test_server()->Start());
GURL test_url = embedded_test_server()->GetURL("/title1.html"); GURL test_url = embedded_test_server()->GetURL("/title1.html");
......
...@@ -19,6 +19,7 @@ namespace content { ...@@ -19,6 +19,7 @@ namespace content {
namespace { namespace {
const char kIdParam[] = "id"; const char kIdParam[] = "id";
const char kSessionIdParam[] = "sessionId";
const char kMethodParam[] = "method"; const char kMethodParam[] = "method";
const char kParamsParam[] = "params"; const char kParamsParam[] = "params";
...@@ -46,9 +47,10 @@ bool DevToolsProtocolTest::DidAddMessageToConsole( ...@@ -46,9 +47,10 @@ bool DevToolsProtocolTest::DidAddMessageToConsole(
return true; return true;
} }
base::DictionaryValue* DevToolsProtocolTest::SendCommand( base::DictionaryValue* DevToolsProtocolTest::SendSessionCommand(
const std::string& method, const std::string& method,
std::unique_ptr<base::Value> params, std::unique_ptr<base::Value> params,
const std::string& session_id,
bool wait) { bool wait) {
in_dispatch_ = true; in_dispatch_ = true;
base::DictionaryValue command; base::DictionaryValue command;
...@@ -56,6 +58,8 @@ base::DictionaryValue* DevToolsProtocolTest::SendCommand( ...@@ -56,6 +58,8 @@ base::DictionaryValue* DevToolsProtocolTest::SendCommand(
command.SetString(kMethodParam, method); command.SetString(kMethodParam, method);
if (params) if (params)
command.Set(kParamsParam, std::move(params)); command.Set(kParamsParam, std::move(params));
if (!session_id.empty())
command.SetString(kSessionIdParam, session_id);
std::string json_command; std::string json_command;
base::JSONWriter::Write(command, &json_command); base::JSONWriter::Write(command, &json_command);
......
...@@ -47,6 +47,19 @@ class DevToolsProtocolTest : public ContentBrowserTest, ...@@ -47,6 +47,19 @@ class DevToolsProtocolTest : public ContentBrowserTest,
base::DictionaryValue* SendCommand(const std::string& method, base::DictionaryValue* SendCommand(const std::string& method,
std::unique_ptr<base::Value> params, std::unique_ptr<base::Value> params,
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); bool wait);
void WaitForResponse(); void WaitForResponse();
......
...@@ -367,12 +367,12 @@ Response PageHandler::Disable() { ...@@ -367,12 +367,12 @@ Response PageHandler::Disable() {
} }
Response PageHandler::Crash() { Response PageHandler::Crash() {
WebContentsImpl* web_contents = GetWebContents(); WebContents* web_contents = WebContents::FromRenderFrameHost(host_);
if (!web_contents) if (!web_contents)
return Response::Error("Not attached to a page"); return Response::Error("Not attached to a page");
if (web_contents->IsCrashed()) if (web_contents->IsCrashed())
return Response::Error("The target has already crashed"); 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::Error("Page has pending navigations, not killing");
return Response::FallThrough(); return Response::FallThrough();
} }
......
...@@ -243,7 +243,7 @@ RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost( ...@@ -243,7 +243,7 @@ RenderFrameDevToolsAgentHost::RenderFrameDevToolsAgentHost(
: DevToolsAgentHostImpl(frame_tree_node->devtools_frame_token().ToString()), : DevToolsAgentHostImpl(frame_tree_node->devtools_frame_token().ToString()),
frame_tree_node_(nullptr) { frame_tree_node_(nullptr) {
SetFrameTreeNode(frame_tree_node); SetFrameTreeNode(frame_tree_node);
frame_host_ = frame_host; ChangeFrameHostAndObservedProcess(frame_host);
render_frame_alive_ = frame_host_ && frame_host_->IsRenderFrameLive(); render_frame_alive_ = frame_host_ && frame_host_->IsRenderFrameLive();
AddRef(); // Balanced in DestroyOnRenderFrameGone. AddRef(); // Balanced in DestroyOnRenderFrameGone.
NotifyCreated(); NotifyCreated();
...@@ -383,6 +383,7 @@ void RenderFrameDevToolsAgentHost::InspectElement(RenderFrameHost* frame_host, ...@@ -383,6 +383,7 @@ void RenderFrameDevToolsAgentHost::InspectElement(RenderFrameHost* frame_host,
RenderFrameDevToolsAgentHost::~RenderFrameDevToolsAgentHost() { RenderFrameDevToolsAgentHost::~RenderFrameDevToolsAgentHost() {
SetFrameTreeNode(nullptr); SetFrameTreeNode(nullptr);
ChangeFrameHostAndObservedProcess(nullptr);
} }
void RenderFrameDevToolsAgentHost::ReadyToCommitNavigation( void RenderFrameDevToolsAgentHost::ReadyToCommitNavigation(
...@@ -456,7 +457,7 @@ void RenderFrameDevToolsAgentHost::UpdateFrameHost( ...@@ -456,7 +457,7 @@ void RenderFrameDevToolsAgentHost::UpdateFrameHost(
} }
RenderFrameHostImpl* old_host = frame_host_; RenderFrameHostImpl* old_host = frame_host_;
frame_host_ = frame_host; ChangeFrameHostAndObservedProcess(frame_host);
if (IsAttached()) if (IsAttached())
UpdateRawHeadersAccess(old_host, frame_host); UpdateRawHeadersAccess(old_host, frame_host);
...@@ -523,7 +524,7 @@ void RenderFrameDevToolsAgentHost::DestroyOnRenderFrameGone() { ...@@ -523,7 +524,7 @@ void RenderFrameDevToolsAgentHost::DestroyOnRenderFrameGone() {
ForceDetachAllSessions(); ForceDetachAllSessions();
UpdateRawHeadersAccess(frame_host_, nullptr); UpdateRawHeadersAccess(frame_host_, nullptr);
} }
frame_host_ = nullptr; ChangeFrameHostAndObservedProcess(nullptr);
UpdateRendererChannel(IsAttached()); UpdateRendererChannel(IsAttached());
SetFrameTreeNode(nullptr); SetFrameTreeNode(nullptr);
Release(); Release();
...@@ -548,9 +549,19 @@ device::mojom::WakeLock* RenderFrameDevToolsAgentHost::GetWakeLock() { ...@@ -548,9 +549,19 @@ device::mojom::WakeLock* RenderFrameDevToolsAgentHost::GetWakeLock() {
} }
#endif #endif
void RenderFrameDevToolsAgentHost::RenderProcessGone( void RenderFrameDevToolsAgentHost::ChangeFrameHostAndObservedProcess(
base::TerminationStatus status) { RenderFrameHostImpl* frame_host) {
switch (status) { 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_ABNORMAL_TERMINATION:
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
...@@ -563,7 +574,7 @@ void RenderFrameDevToolsAgentHost::RenderProcessGone( ...@@ -563,7 +574,7 @@ void RenderFrameDevToolsAgentHost::RenderProcessGone(
case base::TERMINATION_STATUS_LAUNCH_FAILED: case base::TERMINATION_STATUS_LAUNCH_FAILED:
for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this)) for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
inspector->TargetCrashed(); inspector->TargetCrashed();
NotifyCrashed(status); NotifyCrashed(info.status);
break; break;
default: default:
for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this)) for (auto* inspector : protocol::InspectorHandler::ForAgentHost(this))
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "content/browser/devtools/devtools_agent_host_impl.h" #include "content/browser/devtools/devtools_agent_host_impl.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/common/navigation_params.mojom.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 "content/public/browser/web_contents_observer.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h" #include "services/network/public/mojom/url_loader_factory.mojom.h"
...@@ -42,7 +43,8 @@ class RenderFrameHostImpl; ...@@ -42,7 +43,8 @@ class RenderFrameHostImpl;
class CONTENT_EXPORT RenderFrameDevToolsAgentHost class CONTENT_EXPORT RenderFrameDevToolsAgentHost
: public DevToolsAgentHostImpl, : public DevToolsAgentHostImpl,
private WebContentsObserver { private WebContentsObserver,
private RenderProcessHostObserver {
public: public:
static void AddAllAgentHosts(DevToolsAgentHost::List* result); static void AddAllAgentHosts(DevToolsAgentHost::List* result);
...@@ -122,17 +124,21 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost ...@@ -122,17 +124,21 @@ class CONTENT_EXPORT RenderFrameDevToolsAgentHost
RenderFrameHost* new_host) override; RenderFrameHost* new_host) override;
void FrameDeleted(RenderFrameHost* rfh) override; void FrameDeleted(RenderFrameHost* rfh) override;
void RenderFrameDeleted(RenderFrameHost* rfh) override; void RenderFrameDeleted(RenderFrameHost* rfh) override;
void RenderProcessGone(base::TerminationStatus status) override;
void DidAttachInterstitialPage() override; void DidAttachInterstitialPage() override;
void DidDetachInterstitialPage() override; void DidDetachInterstitialPage() override;
void OnVisibilityChanged(content::Visibility visibility) override; void OnVisibilityChanged(content::Visibility visibility) override;
void OnPageScaleFactorChanged(float page_scale_factor) override; void OnPageScaleFactorChanged(float page_scale_factor) override;
// RenderProcessHostObserver overrides.
void RenderProcessExited(RenderProcessHost* host,
const ChildProcessTerminationInfo& info) override;
bool IsChildFrame(); bool IsChildFrame();
void DestroyOnRenderFrameGone(); void DestroyOnRenderFrameGone();
void UpdateFrameHost(RenderFrameHostImpl* frame_host); void UpdateFrameHost(RenderFrameHostImpl* frame_host);
void SetFrameTreeNode(FrameTreeNode* frame_tree_node); void SetFrameTreeNode(FrameTreeNode* frame_tree_node);
void ChangeFrameHostAndObservedProcess(RenderFrameHostImpl* frame_host);
bool ShouldAllowSession(DevToolsSession* session); 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