[headless] Improved Simple CDP Client callback handling.
Previous implementation of the asynchronous callbacks posted a task
for each result and event which is suboptimal. This CL changes logic
so that all the result and event callbacks are called from a single
task posted on the browser UI thread.
Drive by: fixed occasional use-after-move in event handler.
Bug: 1382993
Change-Id: I031044a5bfdaab2b88455d1649f53e4adf053140
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4026625
Reviewed-by: Dmitry Gozman <dgozman@chromium.org>
Commit-Queue: Peter Kvitek <kvitekp@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1071300}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
310f6f4a45
commit
3acd45eb60
components/devtools/simple_devtools_protocol_client
BUILD.gnDEPSsimple_devtools_protocol_client.ccsimple_devtools_protocol_client.hsimple_devtools_protocol_client_unittest.cc
headless/app
@@ -26,6 +26,7 @@ source_set("unit_tests") {
|
|||||||
":simple_devtools_protocol_client",
|
":simple_devtools_protocol_client",
|
||||||
"//base",
|
"//base",
|
||||||
"//content/public/browser",
|
"//content/public/browser",
|
||||||
|
"//content/test:test_support",
|
||||||
"//testing/gmock",
|
"//testing/gmock",
|
||||||
"//testing/gtest",
|
"//testing/gtest",
|
||||||
]
|
]
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
include_rules = [
|
include_rules = [
|
||||||
"+content/public/browser",
|
"+content/public/browser",
|
||||||
|
"+content/public/test",
|
||||||
]
|
]
|
@@ -35,6 +35,7 @@ int g_next_message_id = 0;
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SimpleDevToolsProtocolClient::SimpleDevToolsProtocolClient() = default;
|
SimpleDevToolsProtocolClient::SimpleDevToolsProtocolClient() = default;
|
||||||
|
|
||||||
SimpleDevToolsProtocolClient::SimpleDevToolsProtocolClient(
|
SimpleDevToolsProtocolClient::SimpleDevToolsProtocolClient(
|
||||||
const std::string& session_id)
|
const std::string& session_id)
|
||||||
: session_id_(session_id) {}
|
: session_id_(session_id) {}
|
||||||
@@ -44,10 +45,6 @@ SimpleDevToolsProtocolClient::~SimpleDevToolsProtocolClient() {
|
|||||||
parent_client_->sessions_.erase(session_id_);
|
parent_client_->sessions_.erase(session_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleDevToolsProtocolClient::InitBrowserMainThread() {
|
|
||||||
browser_main_thread_ = content::GetUIThreadTaskRunner({});
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimpleDevToolsProtocolClient::AttachClient(
|
void SimpleDevToolsProtocolClient::AttachClient(
|
||||||
scoped_refptr<content::DevToolsAgentHost> agent_host) {
|
scoped_refptr<content::DevToolsAgentHost> agent_host) {
|
||||||
DCHECK(!agent_host_);
|
DCHECK(!agent_host_);
|
||||||
@@ -94,12 +91,19 @@ void SimpleDevToolsProtocolClient::DispatchProtocolMessage(
|
|||||||
if (const std::string* session_id = message.FindString("sessionId")) {
|
if (const std::string* session_id = message.FindString("sessionId")) {
|
||||||
auto it = sessions_.find(*session_id);
|
auto it = sessions_.find(*session_id);
|
||||||
if (it != sessions_.cend()) {
|
if (it != sessions_.cend()) {
|
||||||
it->second->DispatchProtocolMessage(std::move(message));
|
content::GetUIThreadTaskRunner({})->PostTask(
|
||||||
|
FROM_HERE,
|
||||||
|
base::BindOnce(
|
||||||
|
&SimpleDevToolsProtocolClient::DispatchProtocolMessageTask,
|
||||||
|
base::Unretained(it->second), std::move(message)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchProtocolMessage(std::move(message));
|
content::GetUIThreadTaskRunner({})->PostTask(
|
||||||
|
FROM_HERE,
|
||||||
|
base::BindOnce(&SimpleDevToolsProtocolClient::DispatchProtocolMessageTask,
|
||||||
|
base::Unretained(this), std::move(message)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleDevToolsProtocolClient::AgentHostClosed(
|
void SimpleDevToolsProtocolClient::AgentHostClosed(
|
||||||
@@ -110,7 +114,7 @@ void SimpleDevToolsProtocolClient::AgentHostClosed(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleDevToolsProtocolClient::DispatchProtocolMessage(
|
void SimpleDevToolsProtocolClient::DispatchProtocolMessageTask(
|
||||||
base::Value::Dict message) {
|
base::Value::Dict message) {
|
||||||
// Handle response message shutting down the host if it's unexpected.
|
// Handle response message shutting down the host if it's unexpected.
|
||||||
if (absl::optional<int> id = message.FindInt(kId)) {
|
if (absl::optional<int> id = message.FindInt(kId)) {
|
||||||
@@ -127,12 +131,7 @@ void SimpleDevToolsProtocolClient::DispatchProtocolMessage(
|
|||||||
ResponseCallback callback(std::move(it->second));
|
ResponseCallback callback(std::move(it->second));
|
||||||
pending_response_map_.erase(it);
|
pending_response_map_.erase(it);
|
||||||
|
|
||||||
if (browser_main_thread_) {
|
std::move(callback).Run(std::move(message));
|
||||||
browser_main_thread_->PostTask(
|
|
||||||
FROM_HERE, base::BindOnce(std::move(callback), std::move(message)));
|
|
||||||
} else {
|
|
||||||
std::move(callback).Run(std::move(message));
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,12 +153,7 @@ void SimpleDevToolsProtocolClient::DispatchProtocolMessage(
|
|||||||
for (auto& callback : handlers) {
|
for (auto& callback : handlers) {
|
||||||
if (first_callback || HasEventHandler(*event_name, callback)) {
|
if (first_callback || HasEventHandler(*event_name, callback)) {
|
||||||
first_callback = false;
|
first_callback = false;
|
||||||
if (browser_main_thread_) {
|
callback.Run(message);
|
||||||
browser_main_thread_->PostTask(
|
|
||||||
FROM_HERE, base::BindOnce(std::move(callback), std::move(message)));
|
|
||||||
} else {
|
|
||||||
callback.Run(std::move(message));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,6 @@
|
|||||||
#include "base/containers/span.h"
|
#include "base/containers/span.h"
|
||||||
#include "base/memory/raw_ptr.h"
|
#include "base/memory/raw_ptr.h"
|
||||||
#include "base/memory/scoped_refptr.h"
|
#include "base/memory/scoped_refptr.h"
|
||||||
#include "base/task/sequenced_task_runner.h"
|
|
||||||
#include "base/values.h"
|
#include "base/values.h"
|
||||||
#include "content/public/browser/devtools_agent_host.h"
|
#include "content/public/browser/devtools_agent_host.h"
|
||||||
|
|
||||||
@@ -33,8 +32,6 @@ class SimpleDevToolsProtocolClient : public content::DevToolsAgentHostClient {
|
|||||||
|
|
||||||
~SimpleDevToolsProtocolClient() override;
|
~SimpleDevToolsProtocolClient() override;
|
||||||
|
|
||||||
void InitBrowserMainThread();
|
|
||||||
|
|
||||||
void AttachClient(scoped_refptr<content::DevToolsAgentHost> agent_host);
|
void AttachClient(scoped_refptr<content::DevToolsAgentHost> agent_host);
|
||||||
void DetachClient();
|
void DetachClient();
|
||||||
|
|
||||||
@@ -66,7 +63,7 @@ class SimpleDevToolsProtocolClient : public content::DevToolsAgentHostClient {
|
|||||||
base::span<const uint8_t> json_message) override;
|
base::span<const uint8_t> json_message) override;
|
||||||
void AgentHostClosed(content::DevToolsAgentHost* agent_host) override;
|
void AgentHostClosed(content::DevToolsAgentHost* agent_host) override;
|
||||||
|
|
||||||
void DispatchProtocolMessage(base::Value::Dict message);
|
void DispatchProtocolMessageTask(base::Value::Dict message);
|
||||||
|
|
||||||
void SendProtocolMessage(base::Value::Dict message);
|
void SendProtocolMessage(base::Value::Dict message);
|
||||||
|
|
||||||
@@ -74,7 +71,6 @@ class SimpleDevToolsProtocolClient : public content::DevToolsAgentHostClient {
|
|||||||
const EventCallback& event_callback);
|
const EventCallback& event_callback);
|
||||||
|
|
||||||
const std::string session_id_;
|
const std::string session_id_;
|
||||||
scoped_refptr<base::SequencedTaskRunner> browser_main_thread_;
|
|
||||||
base::raw_ptr<SimpleDevToolsProtocolClient> parent_client_ = nullptr;
|
base::raw_ptr<SimpleDevToolsProtocolClient> parent_client_ = nullptr;
|
||||||
base::flat_map<std::string, SimpleDevToolsProtocolClient*> sessions_;
|
base::flat_map<std::string, SimpleDevToolsProtocolClient*> sessions_;
|
||||||
|
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include "base/memory/scoped_refptr.h"
|
#include "base/memory/scoped_refptr.h"
|
||||||
#include "base/values.h"
|
#include "base/values.h"
|
||||||
#include "content/public/browser/devtools_agent_host.h"
|
#include "content/public/browser/devtools_agent_host.h"
|
||||||
|
#include "content/public/test/browser_task_environment.h"
|
||||||
#include "testing/gmock/include/gmock/gmock.h"
|
#include "testing/gmock/include/gmock/gmock.h"
|
||||||
#include "testing/gtest/include/gtest/gtest.h"
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
|
||||||
@@ -86,6 +87,11 @@ class SimpleDevToolsProtocolClientTest : public SimpleDevToolsProtocolClient,
|
|||||||
SimpleDevToolsProtocolClientTest() {
|
SimpleDevToolsProtocolClientTest() {
|
||||||
AttachClient(new MockDevToolsAgentHost);
|
AttachClient(new MockDevToolsAgentHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RunUntilIdle() { task_environment_.RunUntilIdle(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
content::BrowserTaskEnvironment task_environment_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SimpleDevToolsProtocolClientSendCommandTest
|
class SimpleDevToolsProtocolClientSendCommandTest
|
||||||
@@ -99,6 +105,7 @@ class SimpleDevToolsProtocolClientSendCommandTest
|
|||||||
base::BindOnce(&SimpleDevToolsProtocolClientSendCommandTest::
|
base::BindOnce(&SimpleDevToolsProtocolClientSendCommandTest::
|
||||||
OnSendCommand1Response,
|
OnSendCommand1Response,
|
||||||
base::Unretained(this)));
|
base::Unretained(this)));
|
||||||
|
RunUntilIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnSendCommand1Response(base::Value::Dict params) {
|
void OnSendCommand1Response(base::Value::Dict params) {
|
||||||
@@ -108,6 +115,7 @@ class SimpleDevToolsProtocolClientSendCommandTest
|
|||||||
base::BindOnce(&SimpleDevToolsProtocolClientSendCommandTest::
|
base::BindOnce(&SimpleDevToolsProtocolClientSendCommandTest::
|
||||||
OnSendCommand2Response,
|
OnSendCommand2Response,
|
||||||
base::Unretained(this)));
|
base::Unretained(this)));
|
||||||
|
RunUntilIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnSendCommand2Response(base::Value::Dict params) {
|
void OnSendCommand2Response(base::Value::Dict params) {
|
||||||
@@ -120,6 +128,7 @@ class SimpleDevToolsProtocolClientSendCommandTest
|
|||||||
self->OnSendCommand3Response(std::move(params));
|
self->OnSendCommand3Response(std::move(params));
|
||||||
},
|
},
|
||||||
base::Unretained(this)));
|
base::Unretained(this)));
|
||||||
|
RunUntilIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnSendCommand3Response(base::Value::Dict params) {
|
void OnSendCommand3Response(base::Value::Dict params) {
|
||||||
@@ -147,6 +156,7 @@ class SimpleDevToolsProtocolClientEventHandlerTest
|
|||||||
base::JSONWriter::Write(base::Value(std::move(params)), &json);
|
base::JSONWriter::Write(base::Value(std::move(params)), &json);
|
||||||
DispatchProtocolMessage(agent_host_.get(),
|
DispatchProtocolMessage(agent_host_.get(),
|
||||||
base::as_bytes(base::make_span(json)));
|
base::as_bytes(base::make_span(json)));
|
||||||
|
RunUntilIdle();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -242,8 +242,6 @@ void HeadlessShell::OnBrowserStart(HeadlessBrowser* browser) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
devtools_client_.InitBrowserMainThread();
|
|
||||||
|
|
||||||
file_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
|
file_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
|
||||||
{base::MayBlock(), base::TaskPriority::BEST_EFFORT});
|
{base::MayBlock(), base::TaskPriority::BEST_EFFORT});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user