chromium/chrome/browser/chromeos/extensions/file_system_provider/service_worker_lifetime_manager.cc

// 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/process_manager.h"
#include "extensions/browser/process_manager_factory.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_database.mojom.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);
    }
  }
}

Event::DidDispatchCallback
ServiceWorkerLifetimeManager::CreateDispatchCallbackForRequest(
    const RequestKey& request_key) {
  return base::BindRepeating(
      &extensions::file_system_provider::ServiceWorkerLifetimeManager::
          RequestDispatched,
      weak_ptr_factory_.GetWeakPtr(), request_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=*/"")
      .AsLowercaseString();
}

void ServiceWorkerLifetimeManager::DecrementKeepalive(const KeepaliveKey& key) {
  base::Uuid uuid = base::Uuid::ParseLowercase(key.request_uuid);
  process_manager_->DecrementServiceWorkerKeepaliveCount(
      key.worker_id, 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()
    : ProfileKeyedServiceFactory(
          "ServiceWorkerLifetimeManagerFactory",
          ProfileSelections::Builder()
              .WithRegular(ProfileSelection::kOriginalOnly)
              // TODO(crbug.com/40257657): Check if this service is needed in
              // Guest mode.
              .WithGuest(ProfileSelection::kOriginalOnly)
              // TODO(crbug.com/41488885): Check if this service is needed for
              // Ash Internals.
              .WithAshInternals(ProfileSelection::kOriginalOnly)
              .Build()) {
  DependsOn(extensions::ProcessManagerFactory::GetInstance());
}

ServiceWorkerLifetimeManagerFactory::~ServiceWorkerLifetimeManagerFactory() =
    default;

std::unique_ptr<KeyedService>
ServiceWorkerLifetimeManagerFactory::BuildServiceInstanceForBrowserContext(
    content::BrowserContext* context) const {
  return std::make_unique<ServiceWorkerLifetimeManager>(context);
}

}  // namespace extensions::file_system_provider