Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fileSystemProvider: service worker lifetime manager
Add a keyed service to track initiation and completion of FSP requests and increment/decrement keepalive count of a service worker that has an outstanding request. Bug: b:255520330, b:249182641 Change-Id: I25f924da1e89505f52405e0d94288fe88d0e1d35 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4105401 Reviewed-by: Luciano Pacheco <lucmult@chromium.org> Commit-Queue: Alexander Bolodurin <alexbn@chromium.org> Cr-Commit-Position: refs/heads/main@{#1084821}
- Loading branch information
Alexander Bolodurin
authored and
Chromium LUCI CQ
committed
Dec 19, 2022
1 parent
b21ea70
commit 7d7bfdc
Showing
5 changed files
with
513 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#include "chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.h" | ||
|
||
#include <tuple> | ||
#include <utility> | ||
|
||
#include "components/keyed_service/content/browser_context_dependency_manager.h" | ||
#include "extensions/browser/event_router.h" | ||
#include "extensions/browser/process_manager.h" | ||
#include "extensions/browser/process_manager_factory.h" | ||
#include "third_party/blink/public/mojom/service_worker/service_worker_database.mojom-forward.h" | ||
|
||
namespace extensions::file_system_provider { | ||
|
||
bool RequestKey::operator<(const RequestKey& other) const { | ||
return std::tie(extension_id, file_system_id, request_id) < | ||
std::tie(other.extension_id, other.file_system_id, other.request_id); | ||
} | ||
|
||
ServiceWorkerLifetimeManager::ServiceWorkerLifetimeManager( | ||
content::BrowserContext* context) | ||
// Context can be null in tests. | ||
: process_manager_(context ? extensions::ProcessManager::Get(context) | ||
: nullptr) {} | ||
|
||
ServiceWorkerLifetimeManager::~ServiceWorkerLifetimeManager() = default; | ||
|
||
ServiceWorkerLifetimeManager* ServiceWorkerLifetimeManager::Get( | ||
content::BrowserContext* context) { | ||
return ServiceWorkerLifetimeManagerFactory::GetForBrowserContext(context); | ||
} | ||
|
||
void ServiceWorkerLifetimeManager::StartRequest(const RequestKey& key) { | ||
DCHECK(!base::Contains(requests_, key)); | ||
requests_[key] = {}; | ||
} | ||
|
||
void ServiceWorkerLifetimeManager::FinishRequest( | ||
const RequestKey& request_key) { | ||
auto it = requests_.find(request_key); | ||
if (it == requests_.end()) { | ||
return; | ||
} | ||
std::set<KeepaliveKey> keepalive_keys = std::move(it->second); | ||
requests_.erase(it); | ||
for (const KeepaliveKey& keepalive_key : keepalive_keys) { | ||
DecrementKeepalive(keepalive_key); | ||
} | ||
} | ||
|
||
void ServiceWorkerLifetimeManager::RequestDispatched( | ||
const RequestKey& key, | ||
const EventTarget& target) { | ||
if (target.service_worker_version_id == | ||
blink::mojom::kInvalidServiceWorkerVersionId) { | ||
return; | ||
} | ||
auto it = requests_.find(key); | ||
if (it == requests_.end()) { | ||
return; | ||
} | ||
std::set<KeepaliveKey>& keepalive_keys = it->second; | ||
WorkerId worker_id{ | ||
target.extension_id, | ||
target.render_process_id, | ||
target.service_worker_version_id, | ||
target.worker_thread_id, | ||
}; | ||
std::string uuid = IncrementKeepalive(worker_id); | ||
keepalive_keys.insert(KeepaliveKey{worker_id, uuid}); | ||
} | ||
|
||
void ServiceWorkerLifetimeManager::Shutdown() { | ||
for (const auto& [_, keys] : requests_) { | ||
for (const KeepaliveKey& key : keys) { | ||
DecrementKeepalive(key); | ||
} | ||
} | ||
} | ||
|
||
bool ServiceWorkerLifetimeManager::KeepaliveKey::operator<( | ||
const KeepaliveKey& other) const { | ||
return std::tie(worker_id, request_uuid) < | ||
std::tie(other.worker_id, other.request_uuid); | ||
} | ||
|
||
std::string ServiceWorkerLifetimeManager::IncrementKeepalive( | ||
const WorkerId& worker_id) { | ||
return process_manager_->IncrementServiceWorkerKeepaliveCount( | ||
worker_id, | ||
content::ServiceWorkerExternalRequestTimeoutType::kDoesNotTimeout, | ||
extensions::Activity::Type::EVENT, /*extra_data=*/""); | ||
} | ||
|
||
void ServiceWorkerLifetimeManager::DecrementKeepalive(const KeepaliveKey& key) { | ||
process_manager_->DecrementServiceWorkerKeepaliveCount( | ||
key.worker_id, key.request_uuid, extensions::Activity::Type::EVENT, | ||
/*extra_data=*/""); | ||
} | ||
|
||
// static | ||
ServiceWorkerLifetimeManager* | ||
ServiceWorkerLifetimeManagerFactory::GetForBrowserContext( | ||
content::BrowserContext* context) { | ||
return static_cast<ServiceWorkerLifetimeManager*>( | ||
GetInstance()->GetServiceForBrowserContext(context, true)); | ||
} | ||
|
||
// static | ||
ServiceWorkerLifetimeManagerFactory* | ||
ServiceWorkerLifetimeManagerFactory::GetInstance() { | ||
return base::Singleton<ServiceWorkerLifetimeManagerFactory>::get(); | ||
} | ||
|
||
ServiceWorkerLifetimeManagerFactory::ServiceWorkerLifetimeManagerFactory() | ||
: BrowserContextKeyedServiceFactory( | ||
"ServiceWorkerLifetimeManagerFactory", | ||
BrowserContextDependencyManager::GetInstance()) { | ||
DependsOn(extensions::ProcessManagerFactory::GetInstance()); | ||
} | ||
|
||
ServiceWorkerLifetimeManagerFactory::~ServiceWorkerLifetimeManagerFactory() = | ||
default; | ||
|
||
KeyedService* ServiceWorkerLifetimeManagerFactory::BuildServiceInstanceFor( | ||
content::BrowserContext* context) const { | ||
return new ServiceWorkerLifetimeManager(context); | ||
} | ||
|
||
} // namespace extensions::file_system_provider |
120 changes: 120 additions & 0 deletions
120
chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// Copyright 2022 The Chromium Authors | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_SYSTEM_PROVIDER_SERVICE_WORKER_LIFETIME_MANAGER_H_ | ||
#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_SYSTEM_PROVIDER_SERVICE_WORKER_LIFETIME_MANAGER_H_ | ||
|
||
#include <map> | ||
#include <set> | ||
#include <string> | ||
|
||
#include "base/memory/singleton.h" | ||
#include "components/keyed_service/content/browser_context_keyed_service_factory.h" | ||
#include "components/keyed_service/core/keyed_service.h" | ||
#include "extensions/browser/service_worker/worker_id.h" | ||
#include "extensions/common/extension_id.h" | ||
|
||
namespace content { | ||
class BrowserContext; | ||
} | ||
|
||
namespace extensions { | ||
|
||
class ProcessManager; | ||
struct EventTarget; | ||
|
||
namespace file_system_provider { | ||
|
||
// Identifies a unique fileSystemProvider request: request ID sequence of | ||
// integers tracked per a filesystem instance, or per provider (extension) for | ||
// requests that aren't specific to a filesystem instance. | ||
struct RequestKey { | ||
extensions::ExtensionId extension_id; | ||
std::string file_system_id; | ||
int request_id; | ||
|
||
bool operator<(const RequestKey& other) const; | ||
}; | ||
|
||
// Tracks fileSystemProvider requests that have been dispatched to service | ||
// workers but not replied to yet, and keeps service workers alive while there | ||
// are requests in progress. | ||
class ServiceWorkerLifetimeManager : public KeyedService { | ||
public: | ||
ServiceWorkerLifetimeManager(const ServiceWorkerLifetimeManager&) = delete; | ||
ServiceWorkerLifetimeManager& operator=(const ServiceWorkerLifetimeManager&) = | ||
delete; | ||
~ServiceWorkerLifetimeManager() override; | ||
|
||
static ServiceWorkerLifetimeManager* Get(content::BrowserContext*); | ||
|
||
// Signals that a request has been sent to a fileSystemProvider. Called when | ||
// the request is about to be dispatched (the actual targets that received the | ||
// request aren't known yet). | ||
void StartRequest(const RequestKey&); | ||
// Signals that a request previously sent to a fileSystemProvider has | ||
// finished. Called either when a request has been replied to (the first | ||
// response finishes the request), or is cancelled, due to timeout or being | ||
// aborted. | ||
void FinishRequest(const RequestKey&); | ||
// Signals that a request has been dispatched to a service worker with | ||
// registered fileSystemProvider listeners. Called for each service worker the | ||
// request has been dispatched to. | ||
void RequestDispatched(const RequestKey&, const EventTarget&); | ||
// KeyedService: | ||
void Shutdown() override; | ||
|
||
protected: | ||
struct KeepaliveKey { | ||
WorkerId worker_id; | ||
std::string request_uuid; | ||
|
||
bool operator==(const KeepaliveKey& other) const; | ||
bool operator<(const KeepaliveKey& other) const; | ||
}; | ||
|
||
explicit ServiceWorkerLifetimeManager(content::BrowserContext*); | ||
|
||
// Virtual for tests. | ||
virtual std::string IncrementKeepalive(const WorkerId&); | ||
virtual void DecrementKeepalive(const KeepaliveKey&); | ||
|
||
private: | ||
friend class ServiceWorkerLifetimeManagerFactory; | ||
FRIEND_TEST_ALL_PREFIXES(ServiceWorkerLifetimeManagerTest, | ||
TestDispatchMultipleEvents); | ||
|
||
raw_ptr<ProcessManager> process_manager_; | ||
std::map<RequestKey, std::set<KeepaliveKey>> requests_; | ||
}; | ||
|
||
// KeyedService factory for ServiceWorkerLifetimeManager. | ||
class ServiceWorkerLifetimeManagerFactory | ||
: public BrowserContextKeyedServiceFactory { | ||
public: | ||
ServiceWorkerLifetimeManagerFactory( | ||
const ServiceWorkerLifetimeManagerFactory&) = delete; | ||
ServiceWorkerLifetimeManagerFactory& operator=( | ||
const ServiceWorkerLifetimeManagerFactory&) = delete; | ||
|
||
static ServiceWorkerLifetimeManager* GetForBrowserContext( | ||
content::BrowserContext*); | ||
static ServiceWorkerLifetimeManagerFactory* GetInstance(); | ||
|
||
private: | ||
friend struct base::DefaultSingletonTraits< | ||
ServiceWorkerLifetimeManagerFactory>; | ||
|
||
ServiceWorkerLifetimeManagerFactory(); | ||
~ServiceWorkerLifetimeManagerFactory() override; | ||
|
||
// BrowserContextKeyedServiceFactory: | ||
KeyedService* BuildServiceInstanceFor( | ||
content::BrowserContext* context) const override; | ||
}; | ||
|
||
} // namespace file_system_provider | ||
} // namespace extensions | ||
|
||
#endif // CHROME_BROWSER_CHROMEOS_EXTENSIONS_FILE_SYSTEM_PROVIDER_SERVICE_WORKER_LIFETIME_MANAGER_H_ |
Oops, something went wrong.