Commit fdb4fa0c authored by Patrick Monette's avatar Patrick Monette Committed by Commit Bot

Make shared workers enumerable via the SharedWorkerService

This will allow the WorkerTaskProvider to do accurate bookkeeping on
running shared workers, even though it dynamically subscribe and
unsubscribe to the SharedWorkerService while some workers are already
running.

Bug: 1041093
Change-Id: I4480eff07b9735d7b0b2132caaed75a7e78311d2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2015565
Commit-Queue: Patrick Monette <pmonette@chromium.org>
Reviewed-by: default avatarSigurður Ásgeirsson <siggi@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Reviewed-by: default avatarHiroki Nakagawa <nhiroki@chromium.org>
Cr-Commit-Position: refs/heads/master@{#737440}
parent 72531a08
......@@ -63,6 +63,7 @@ class TestSharedWorkerService : public content::SharedWorkerService {
// content::SharedWorkerService
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
void EnumerateSharedWorkers(Observer* observer) override;
bool TerminateWorker(const GURL& url,
const std::string& name,
const url::Origin& constructor_origin) override;
......@@ -108,12 +109,18 @@ void TestSharedWorkerService::AddObserver(Observer* observer) {
void TestSharedWorkerService::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
void TestSharedWorkerService::EnumerateSharedWorkers(Observer* observer) {
// Not implemented.
ADD_FAILURE();
}
bool TestSharedWorkerService::TerminateWorker(
const GURL& url,
const std::string& name,
const url::Origin& constructor_origin) {
return true;
// Not implemented.
ADD_FAILURE();
return false;
}
content::SharedWorkerInstance TestSharedWorkerService::StartSharedWorker(
......
......@@ -152,9 +152,8 @@ void SharedWorkerHost::Start(
// Register with DevTools.
bool pause_on_start;
base::UnguessableToken devtools_worker_token;
devtools_handle_ = std::make_unique<ScopedDevToolsHandle>(
this, &pause_on_start, &devtools_worker_token);
this, &pause_on_start, &dev_tools_token_);
auto renderer_preferences = blink::mojom::RendererPreferences::New();
GetContentClient()->browser()->UpdateRendererPreferencesForWorker(
......@@ -204,7 +203,7 @@ void SharedWorkerHost::Start(
factory_.Bind(std::move(factory));
factory_->CreateSharedWorker(
std::move(info), GetContentClient()->browser()->GetUserAgent(),
pause_on_start, devtools_worker_token, std::move(renderer_preferences),
pause_on_start, dev_tools_token_, std::move(renderer_preferences),
std::move(preference_watcher_receiver), std::move(content_settings),
service_worker_handle_->TakeProviderInfo(),
appcache_handle_
......@@ -236,7 +235,7 @@ void SharedWorkerHost::Start(
// Notify the service that the worker was started and that some clients were
// already connected.
service_->NotifyWorkerStarted(instance_, worker_process_host_->GetID(),
devtools_worker_token);
dev_tools_token_);
for (const auto& client : clients_) {
service_->NotifyClientAdded(instance_, client.render_frame_host_id);
}
......
......@@ -124,6 +124,13 @@ class CONTENT_EXPORT SharedWorkerHost : public blink::mojom::SharedWorkerHost,
const SharedWorkerInstance& instance() const { return instance_; }
const base::UnguessableToken& dev_tools_token() const {
DCHECK(started_);
return dev_tools_token_;
}
bool started() const { return started_; }
// Signals the remote worker to terminate and returns the mojo::Remote
// instance so the caller can be notified when the connection is lost. Should
// be called right before deleting this instance.
......@@ -221,6 +228,8 @@ class CONTENT_EXPORT SharedWorkerHost : public blink::mojom::SharedWorkerHost,
std::unique_ptr<ServiceWorkerMainResourceHandle> service_worker_handle_;
base::UnguessableToken dev_tools_token_;
// Indicates if Start() was invoked on this instance.
bool started_ = false;
......
......@@ -77,6 +77,16 @@ void SharedWorkerServiceImpl::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void SharedWorkerServiceImpl::EnumerateSharedWorkers(Observer* observer) {
for (const auto& host : worker_hosts_) {
if (host->started()) {
observer->OnWorkerStarted(host->instance(),
host->GetProcessHost()->GetID(),
host->dev_tools_token());
}
}
}
bool SharedWorkerServiceImpl::TerminateWorker(
const GURL& url,
const std::string& name,
......
......@@ -52,6 +52,7 @@ class CONTENT_EXPORT SharedWorkerServiceImpl : public SharedWorkerService {
// SharedWorkerService implementation.
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
void EnumerateSharedWorkers(Observer* observer) override;
bool TerminateWorker(const GURL& url,
const std::string& name,
const url::Origin& constructor_origin) override;
......
......@@ -1368,6 +1368,60 @@ TEST_F(SharedWorkerServiceImplTest, Observer) {
EXPECT_EQ(0u, observer.GetClientCount());
}
TEST_F(SharedWorkerServiceImplTest, EnumerateSharedWorkers) {
TestSharedWorkerServiceObserver observer;
std::unique_ptr<TestWebContents> web_contents =
CreateWebContents(GURL("http://example.com/"));
TestRenderFrameHost* render_frame_host = web_contents->GetMainFrame();
MockRenderProcessHost* renderer_host = render_frame_host->GetProcess();
const int process_id = renderer_host->GetID();
renderer_host->OverrideBinderForTesting(
blink::mojom::SharedWorkerFactory::Name_,
base::BindRepeating(&SharedWorkerServiceImplTest::BindSharedWorkerFactory,
base::Unretained(this), process_id));
MockSharedWorkerClient client;
MessagePortChannel local_port;
const GURL kUrl("http://example.com/w.js");
ConnectToSharedWorker(
MakeSharedWorkerConnector(render_frame_host->GetGlobalFrameRoutingId()),
kUrl, "name", &client, &local_port);
mojo::PendingReceiver<blink::mojom::SharedWorkerFactory> factory_receiver =
WaitForFactoryReceiver(process_id);
MockSharedWorkerFactory factory(std::move(factory_receiver));
base::RunLoop().RunUntilIdle();
mojo::Remote<blink::mojom::SharedWorkerHost> worker_host;
mojo::PendingReceiver<blink::mojom::SharedWorker> worker_receiver;
EXPECT_TRUE(factory.CheckReceivedCreateSharedWorker(
kUrl, "name", network::mojom::ContentSecurityPolicyType::kReport,
&worker_host, &worker_receiver));
MockSharedWorker worker(std::move(worker_receiver));
base::RunLoop().RunUntilIdle();
int connection_request_id;
MessagePortChannel port;
EXPECT_TRUE(worker.CheckReceivedConnect(&connection_request_id, &port));
EXPECT_TRUE(client.CheckReceivedOnCreated());
// The observer was never registered to the SharedWorkerService.
EXPECT_EQ(0u, observer.GetWorkerCount());
// Retrieve running shared workers.
content::BrowserContext::GetDefaultStoragePartition(browser_context_.get())
->GetSharedWorkerService()
->EnumerateSharedWorkers(&observer);
EXPECT_EQ(1u, observer.GetWorkerCount());
// Cleanup.
worker_host->OnContextClosed();
base::RunLoop().RunUntilIdle();
}
TEST_F(SharedWorkerServiceImplTest, CollapseDuplicateNotifications) {
TestSharedWorkerServiceObserver observer;
......
......@@ -59,6 +59,18 @@ class CONTENT_EXPORT SharedWorkerService {
virtual void AddObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
// Invokes OnWorkerStarted() on |observer| for all existing shared workers.
//
// This function must be invoked in conjunction with AddObserver(). It is
// meant to be used by an observer that dynamically subscribe to the
// SharedWorkerService while some workers are already running. It avoids
// receiving a OnBeforeWorkerTerminated() event without having received the
// corresponding OnWorkerStart() event.
//
// Note: Due to current callers not needing it, this function does NOT call
// OnClientAdded() for each worker's clients.
virtual void EnumerateSharedWorkers(Observer* observer) = 0;
// Terminates the given shared worker identified by its name, the URL of
// its main script resource, and the constructor origin. Returns true on
// success.
......
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