// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/performance_manager/worker_watcher.h"

#include <utility>
#include <vector>

#include "base/metrics/histogram_macros.h"
#include "components/performance_manager/frame_node_source.h"
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/graph/worker_node_impl.h"
#include "components/performance_manager/performance_manager_impl.h"
#include "components/performance_manager/process_node_source.h"
#include "components/performance_manager/public/features.h"
#include "third_party/blink/public/common/tokens/tokens.h"

namespace performance_manager {

namespace {

// Emits a boolean value that indicates if the client frame's node was found
// when trying to connect the worker to a client frame.
void RecordWorkerClientFound(bool found) {
  UMA_HISTOGRAM_BOOLEAN("PerformanceManager.WorkerClientFound", found);
}

// Helper function to add |client_frame_node| as a client of |worker_node| on
// the PM sequence.
void ConnectClientFrameOnGraph(WorkerNodeImpl* worker_node,
                               FrameNodeImpl* client_frame_node) {
  PerformanceManagerImpl::CallOnGraphImpl(
      FROM_HERE,
      base::BindOnce(&WorkerNodeImpl::AddClientFrame,
                     base::Unretained(worker_node), client_frame_node));
}

// Helper function to remove |client_frame_node| as a client of |worker_node|
// on the PM sequence.
void DisconnectClientFrameOnGraph(WorkerNodeImpl* worker_node,
                                  FrameNodeImpl* client_frame_node) {
  PerformanceManagerImpl::CallOnGraphImpl(
      FROM_HERE,
      base::BindOnce(&WorkerNodeImpl::RemoveClientFrame,
                     base::Unretained(worker_node), client_frame_node));
}

// Helper function to add |client_worker_node| as a client of |worker_node| on
// the PM sequence.
void ConnectClientWorkerOnGraph(WorkerNodeImpl* worker_node,
                                WorkerNodeImpl* client_worker_node) {
  PerformanceManagerImpl::CallOnGraphImpl(
      FROM_HERE,
      base::BindOnce(&WorkerNodeImpl::AddClientWorker,
                     base::Unretained(worker_node), client_worker_node));
}

// Helper function to remove |client_worker_node| as a client of |worker_node|
// on the PM sequence.
void DisconnectClientWorkerOnGraph(WorkerNodeImpl* worker_node,
                                   WorkerNodeImpl* client_worker_node) {
  PerformanceManagerImpl::CallOnGraphImpl(
      FROM_HERE,
      base::BindOnce(&WorkerNodeImpl::RemoveClientWorker,
                     base::Unretained(worker_node), client_worker_node));
}

// Helper function to remove |client_frame_node| as a client of all worker nodes
// in |worker_nodes| on the PM sequence.
void DisconnectClientsOnGraph(base::flat_set<WorkerNodeImpl*> worker_nodes,
                              FrameNodeImpl* client_frame_node) {
  PerformanceManagerImpl::CallOnGraphImpl(
      FROM_HERE, base::BindOnce(
                     [](base::flat_set<WorkerNodeImpl*> worker_nodes,
                        FrameNodeImpl* client_frame_node) {
                       for (auto* worker_node : worker_nodes)
                         worker_node->RemoveClientFrame(client_frame_node);
                     },
                     std::move(worker_nodes), client_frame_node));
}

void DisconnectClientsOnGraph(
    base::flat_map<WorkerNodeImpl*, size_t> worker_node_connections,
    FrameNodeImpl* client_frame_node) {
  base::flat_set<WorkerNodeImpl*>::container_type client_workers;
  for (auto& kv : worker_node_connections)
    client_workers.push_back(kv.first);

  DisconnectClientsOnGraph(
      base::flat_set<WorkerNodeImpl*>(base::sorted_unique, client_workers),
      client_frame_node);
}

// Helper function to remove |client_worker_node| as a client of all worker
// nodes in |worker_nodes| on the PM sequence.
void DisconnectClientsOnGraph(base::flat_set<WorkerNodeImpl*> worker_nodes,
                              WorkerNodeImpl* client_worker_node) {
  PerformanceManagerImpl::CallOnGraphImpl(
      FROM_HERE, base::BindOnce(
                     [](base::flat_set<WorkerNodeImpl*> worker_nodes,
                        WorkerNodeImpl* client_worker_node) {
                       for (auto* worker_node : worker_nodes)
                         worker_node->RemoveClientWorker(client_worker_node);
                     },
                     std::move(worker_nodes), client_worker_node));
}

// Helper function that posts a task on the PM sequence that will invoke
// OnFinalResponseURLDetermined() on |worker_node|.
void SetFinalResponseURL(WorkerNodeImpl* worker_node, const GURL& url) {
  PerformanceManagerImpl::CallOnGraphImpl(
      FROM_HERE, base::BindOnce(&WorkerNodeImpl::OnFinalResponseURLDetermined,
                                base::Unretained(worker_node), url));
}

}  // namespace

WorkerWatcher::WorkerWatcher(
    const std::string& browser_context_id,
    content::DedicatedWorkerService* dedicated_worker_service,
    content::SharedWorkerService* shared_worker_service,
    content::ServiceWorkerContext* service_worker_context,
    ProcessNodeSource* process_node_source,
    FrameNodeSource* frame_node_source)
    : browser_context_id_(browser_context_id),
      process_node_source_(process_node_source),
      frame_node_source_(frame_node_source) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(dedicated_worker_service);
  DCHECK(shared_worker_service);
  DCHECK(service_worker_context);
  DCHECK(process_node_source_);
  DCHECK(frame_node_source_);

  dedicated_worker_service_observation_.Observe(dedicated_worker_service);
  shared_worker_service_observation_.Observe(shared_worker_service);
  service_worker_context_observation_.Observe(service_worker_context);
}

WorkerWatcher::~WorkerWatcher() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(frame_node_child_worker_connections_.empty());
  DCHECK(dedicated_worker_nodes_.empty());
  DCHECK(!dedicated_worker_service_observation_.IsObserving());
  DCHECK(shared_worker_nodes_.empty());
  DCHECK(!shared_worker_service_observation_.IsObserving());
  DCHECK(service_worker_nodes_.empty());
  DCHECK(!service_worker_context_observation_.IsObserving());
}

void WorkerWatcher::TearDown() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  // First clear client-child connections between frames and workers.
  for (auto& kv : frame_node_child_worker_connections_) {
    const content::GlobalFrameRoutingId& render_frame_host_id = kv.first;
    WorkerNodeConnections& child_worker_connections = kv.second;
    DCHECK(!child_worker_connections.empty());

    frame_node_source_->UnsubscribeFromFrameNode(render_frame_host_id);

    // Disconnect all child workers from |frame_node|.
    FrameNodeImpl* frame_node =
        frame_node_source_->GetFrameNode(render_frame_host_id);
    DCHECK(frame_node);
    DisconnectClientsOnGraph(std::move(child_worker_connections), frame_node);
  }
  frame_node_child_worker_connections_.clear();

  // Then clear client-child connections for dedicated workers.
  for (auto& kv : dedicated_worker_child_workers_) {
    const blink::DedicatedWorkerToken& dedicated_worker_token = kv.first;
    base::flat_set<WorkerNodeImpl*>& child_workers = kv.second;
    DCHECK(!child_workers.empty());

    // Disconnect all child workers from |dedicated_worker_token|.
    WorkerNodeImpl* dedicated_worker_node =
        GetDedicatedWorkerNode(dedicated_worker_token);
    DisconnectClientsOnGraph(std::move(child_workers), dedicated_worker_node);
  }
  dedicated_worker_child_workers_.clear();

  // Finally, clear client-child connections for shared workers.
  for (auto& kv : shared_worker_child_workers_) {
    const blink::SharedWorkerToken& shared_worker_token = kv.first;
    base::flat_set<WorkerNodeImpl*>& child_workers = kv.second;
    DCHECK(!child_workers.empty());

    // Disconnect all child workers from |shared_worker_token|.
    WorkerNodeImpl* shared_worker_node =
        GetSharedWorkerNode(shared_worker_token);
    DisconnectClientsOnGraph(std::move(child_workers), shared_worker_node);
  }
  shared_worker_child_workers_.clear();

  // Then clean all the worker nodes.
  std::vector<std::unique_ptr<NodeBase>> nodes;
  nodes.reserve(dedicated_worker_nodes_.size() + shared_worker_nodes_.size() +
                service_worker_nodes_.size());

  for (auto& node : dedicated_worker_nodes_)
    nodes.push_back(std::move(node.second));
  dedicated_worker_nodes_.clear();

  for (auto& node : shared_worker_nodes_)
    nodes.push_back(std::move(node.second));
  shared_worker_nodes_.clear();

  for (auto& node : service_worker_nodes_)
    nodes.push_back(std::move(node.second));
  service_worker_nodes_.clear();

  PerformanceManagerImpl::BatchDeleteNodes(std::move(nodes));

  DCHECK(dedicated_worker_service_observation_.IsObserving());
  dedicated_worker_service_observation_.Reset();
  DCHECK(shared_worker_service_observation_.IsObserving());
  shared_worker_service_observation_.Reset();
  DCHECK(service_worker_context_observation_.IsObserving());
  service_worker_context_observation_.Reset();
}

void WorkerWatcher::OnWorkerCreated(
    const blink::DedicatedWorkerToken& dedicated_worker_token,
    int worker_process_id,
    content::GlobalFrameRoutingId ancestor_render_frame_host_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  // TODO(https://crbug.com/993029): Plumb through the URL.
  auto worker_node = PerformanceManagerImpl::CreateWorkerNode(
      browser_context_id_, WorkerNode::WorkerType::kDedicated,
      process_node_source_->GetProcessNode(worker_process_id),
      dedicated_worker_token);
  auto insertion_result = dedicated_worker_nodes_.emplace(
      dedicated_worker_token, std::move(worker_node));
  DCHECK(insertion_result.second);

  AddFrameClientConnection(insertion_result.first->second.get(),
                           ancestor_render_frame_host_id);
}

void WorkerWatcher::OnBeforeWorkerDestroyed(
    const blink::DedicatedWorkerToken& dedicated_worker_token,
    content::GlobalFrameRoutingId ancestor_render_frame_host_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto it = dedicated_worker_nodes_.find(dedicated_worker_token);
  DCHECK(it != dedicated_worker_nodes_.end());

  auto worker_node = std::move(it->second);

  // First disconnect the ancestor's frame node from this worker node.
  RemoveFrameClientConnection(worker_node.get(), ancestor_render_frame_host_id);

#if DCHECK_IS_ON()
  DCHECK(!base::Contains(detached_frame_count_per_worker_, worker_node.get()));
#endif  // DCHECK_IS_ON()
  PerformanceManagerImpl::DeleteNode(std::move(worker_node));

  dedicated_worker_nodes_.erase(it);
}

void WorkerWatcher::OnFinalResponseURLDetermined(
    const blink::DedicatedWorkerToken& dedicated_worker_token,
    const GURL& url) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  SetFinalResponseURL(GetDedicatedWorkerNode(dedicated_worker_token), url);
}

void WorkerWatcher::OnWorkerCreated(
    const blink::SharedWorkerToken& shared_worker_token,
    int worker_process_id,
    const base::UnguessableToken& /* dev_tools_token */) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto worker_node = PerformanceManagerImpl::CreateWorkerNode(
      browser_context_id_, WorkerNode::WorkerType::kShared,
      process_node_source_->GetProcessNode(worker_process_id),
      shared_worker_token);

  bool inserted =
      shared_worker_nodes_.emplace(shared_worker_token, std::move(worker_node))
          .second;
  DCHECK(inserted);
}

void WorkerWatcher::OnBeforeWorkerDestroyed(
    const blink::SharedWorkerToken& shared_worker_token) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto it = shared_worker_nodes_.find(shared_worker_token);
  DCHECK(it != shared_worker_nodes_.end());

  auto worker_node = std::move(it->second);

  // Disconnect all child workers before destroying the node.
  auto child_it = shared_worker_child_workers_.find(shared_worker_token);
  if (child_it != shared_worker_child_workers_.end()) {
    DisconnectClientsOnGraph(child_it->second, worker_node.get());
    shared_worker_child_workers_.erase(child_it);
  }

#if DCHECK_IS_ON()
  DCHECK(!base::Contains(detached_frame_count_per_worker_, worker_node.get()));
#endif  // DCHECK_IS_ON()
  PerformanceManagerImpl::DeleteNode(std::move(worker_node));

  shared_worker_nodes_.erase(it);
}

void WorkerWatcher::OnFinalResponseURLDetermined(
    const blink::SharedWorkerToken& shared_worker_token,
    const GURL& url) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  SetFinalResponseURL(GetSharedWorkerNode(shared_worker_token), url);
}

void WorkerWatcher::OnClientAdded(
    const blink::SharedWorkerToken& shared_worker_token,
    content::GlobalFrameRoutingId render_frame_host_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  AddFrameClientConnection(GetSharedWorkerNode(shared_worker_token),
                           render_frame_host_id);
}

void WorkerWatcher::OnClientRemoved(
    const blink::SharedWorkerToken& shared_worker_token,
    content::GlobalFrameRoutingId render_frame_host_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  RemoveFrameClientConnection(GetSharedWorkerNode(shared_worker_token),
                              render_frame_host_id);
}

void WorkerWatcher::OnVersionStartedRunning(
    int64_t version_id,
    const content::ServiceWorkerRunningInfo& running_info) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto insertion_result = service_worker_nodes_.emplace(
      version_id,
      PerformanceManagerImpl::CreateWorkerNode(
          browser_context_id_, WorkerNode::WorkerType::kService,
          process_node_source_->GetProcessNode(running_info.render_process_id),
          running_info.token));
  DCHECK(insertion_result.second);

  // Exclusively for service workers, some notifications for clients
  // (OnControlleeAdded) may have been received before the worker started.
  // Add those clients to the service worker on the PM graph.
  ConnectAllServiceWorkerClients(insertion_result.first->second.get(),
                                 version_id);
}

void WorkerWatcher::OnVersionStoppedRunning(int64_t version_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto it = service_worker_nodes_.find(version_id);
  DCHECK(it != service_worker_nodes_.end());

  auto service_worker_node = std::move(it->second);

  // First, disconnect all current clients of this service worker.
  DisconnectAllServiceWorkerClients(service_worker_node.get(), version_id);

#if DCHECK_IS_ON()
  DCHECK(!base::Contains(detached_frame_count_per_worker_,
                         service_worker_node.get()));
#endif  // DCHECK_IS_ON()
  PerformanceManagerImpl::DeleteNode(std::move(service_worker_node));

  service_worker_nodes_.erase(it);
}

void WorkerWatcher::OnControlleeAdded(
    int64_t version_id,
    const std::string& client_uuid,
    const content::ServiceWorkerClientInfo& client_info) {
  if (!base::FeatureList::IsEnabled(
          features::kServiceWorkerRelationshipsInGraph))
    return;

  switch (client_info.type()) {
    case blink::mojom::ServiceWorkerClientType::kWindow: {
      // For window clients, it is necessary to wait until the navigation has
      // committed to a render frame host.
      bool inserted = client_frames_awaiting_commit_
                          .insert(AwaitingKey(version_id, client_uuid))
                          .second;
      DCHECK(inserted);
      break;
    }
    case blink::mojom::ServiceWorkerClientType::kDedicatedWorker: {
      blink::DedicatedWorkerToken dedicated_worker_token =
          client_info.GetDedicatedWorkerToken();

      bool inserted = service_worker_clients_[version_id]
                          .emplace(client_uuid, dedicated_worker_token)
                          .second;
      DCHECK(inserted);

      // If the service worker is already started, connect it to the client.
      WorkerNodeImpl* service_worker_node = GetServiceWorkerNode(version_id);
      if (service_worker_node)
        ConnectDedicatedWorkerClient(service_worker_node,
                                     dedicated_worker_token);
      break;
    }
    case blink::mojom::ServiceWorkerClientType::kSharedWorker: {
      blink::SharedWorkerToken shared_worker_token =
          client_info.GetSharedWorkerToken();

      bool inserted = service_worker_clients_[version_id]
                          .emplace(client_uuid, shared_worker_token)
                          .second;
      DCHECK(inserted);

      // If the service worker is already started, connect it to the client.
      WorkerNodeImpl* service_worker_node = GetServiceWorkerNode(version_id);
      if (service_worker_node)
        ConnectSharedWorkerClient(service_worker_node, shared_worker_token);
      break;
    }
    case blink::mojom::ServiceWorkerClientType::kAll:
      NOTREACHED();
      break;
  }
}

void WorkerWatcher::OnControlleeRemoved(int64_t version_id,
                                        const std::string& client_uuid) {
  if (!base::FeatureList::IsEnabled(
          features::kServiceWorkerRelationshipsInGraph))
    return;

  // Nothing to do for a frame client whose navigation never committed.
  size_t removed = client_frames_awaiting_commit_.erase(
      AwaitingKey(version_id, client_uuid));
  if (removed) {
#if DCHECK_IS_ON()
    // |client_uuid| should not be part of this service worker's clients.
    auto it = service_worker_clients_.find(version_id);
    if (it != service_worker_clients_.end())
      DCHECK(!base::Contains(it->second, client_uuid));
#endif  // DCHECK_IS_ON()
    return;
  }

  // First get clients for this worker.
  auto it = service_worker_clients_.find(version_id);
  DCHECK(it != service_worker_clients_.end());

  base::flat_map<std::string /*client_uuid*/, ServiceWorkerClient>& clients =
      it->second;

  auto it2 = clients.find(client_uuid);
  DCHECK(it2 != clients.end());
  const ServiceWorkerClient client = it2->second;
  clients.erase(it2);

  if (clients.empty())
    service_worker_clients_.erase(it);

  // Now disconnect the client if the service worker is still running.
  WorkerNodeImpl* worker_node = GetServiceWorkerNode(version_id);
  if (!worker_node)
    return;

  switch (client.type()) {
    case blink::mojom::ServiceWorkerClientType::kWindow:
      RemoveFrameClientConnection(worker_node, client.GetRenderFrameHostId());
      break;
    case blink::mojom::ServiceWorkerClientType::kDedicatedWorker:
      DisconnectDedicatedWorkerClient(worker_node,
                                      client.GetDedicatedWorkerToken());
      break;
    case blink::mojom::ServiceWorkerClientType::kSharedWorker:
      DisconnectSharedWorkerClient(worker_node, client.GetSharedWorkerToken());
      break;
    case blink::mojom::ServiceWorkerClientType::kAll:
      NOTREACHED();
      break;
  }
}

void WorkerWatcher::OnControlleeNavigationCommitted(
    int64_t version_id,
    const std::string& client_uuid,
    content::GlobalFrameRoutingId render_frame_host_id) {
  if (!base::FeatureList::IsEnabled(
          features::kServiceWorkerRelationshipsInGraph))
    return;

  size_t removed = client_frames_awaiting_commit_.erase(
      AwaitingKey(version_id, client_uuid));
  DCHECK_EQ(removed, 1u);

  bool inserted = service_worker_clients_[version_id]
                      .emplace(client_uuid, render_frame_host_id)
                      .second;
  DCHECK(inserted);

  WorkerNodeImpl* service_worker_node = GetServiceWorkerNode(version_id);
  if (service_worker_node)
    AddFrameClientConnection(service_worker_node, render_frame_host_id);
}

void WorkerWatcher::AddFrameClientConnection(
    WorkerNodeImpl* worker_node,
    content::GlobalFrameRoutingId client_render_frame_host_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(worker_node);

  FrameNodeImpl* frame_node =
      frame_node_source_->GetFrameNode(client_render_frame_host_id);
  // TODO(https://crbug.com/1078161): The client frame's node should always be
  // accessible. If it isn't, this means there is a missing
  // CreatePageNodeForWebContents() somewhere.
  if (!frame_node) {
    RecordWorkerClientFound(false);
#if DCHECK_IS_ON()
    // A call to RemoveFrameClientConnection() is still expected to be received
    // for this worker and frame pair.
    detached_frame_count_per_worker_[worker_node]++;
#endif  // DCHECK_IS_ON()
    return;
  }

  RecordWorkerClientFound(true);

  // Keep track of the workers that this frame is a client to.
  bool is_first_child_worker = false;
  bool is_first_child_worker_connection = false;
  ;
  AddChildWorkerConnection(client_render_frame_host_id, worker_node,
                           &is_first_child_worker,
                           &is_first_child_worker_connection);

  if (is_first_child_worker) {
    frame_node_source_->SubscribeToFrameNode(
        client_render_frame_host_id,
        base::BindOnce(&WorkerWatcher::OnBeforeFrameNodeRemoved,
                       base::Unretained(this), client_render_frame_host_id));
  }

  if (is_first_child_worker_connection) {
    // Connect the nodes on the graph only on the 0->1 transition.
    ConnectClientFrameOnGraph(worker_node, frame_node);
  }
}

void WorkerWatcher::RemoveFrameClientConnection(
    WorkerNodeImpl* worker_node,
    content::GlobalFrameRoutingId client_render_frame_host_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(worker_node);

  FrameNodeImpl* frame_node =
      frame_node_source_->GetFrameNode(client_render_frame_host_id);

  // It's possible that the frame was destroyed before receiving the
  // OnClientRemoved() for all of its child shared worker. Nothing to do in
  // that case because OnBeforeFrameNodeRemoved() took care of removing this
  // client from its child worker nodes.
  //
  // TODO(https://crbug.com/1078161): A second possibility is that it wasn't
  // possible to connect a worker to its client frame.
  if (!frame_node) {
#if DCHECK_IS_ON()
    // These debug only checks are used to ensure that this
    // RemoveFrameClientConnection() call was still expected even though the
    // client frame node no longer exist.
    auto it = detached_frame_count_per_worker_.find(worker_node);
    DCHECK(it != detached_frame_count_per_worker_.end());

    int& count = it->second;
    DCHECK_GT(count, 0);
    --count;

    if (count == 0)
      detached_frame_count_per_worker_.erase(it);
#endif  // DCHECK_IS_ON()
    return;
  }
  // Remove |worker_node| from the set of workers that this frame is a client
  // of.
  bool was_last_child_worker = false;
  bool was_last_child_worker_connection = false;
  RemoveChildWorkerConnection(client_render_frame_host_id, worker_node,
                              &was_last_child_worker,
                              &was_last_child_worker_connection);

  if (was_last_child_worker)
    frame_node_source_->UnsubscribeFromFrameNode(client_render_frame_host_id);

  if (was_last_child_worker_connection) {
    // Disconnect the nodes on the graph only on the 1->0 transition.
    DisconnectClientFrameOnGraph(worker_node, frame_node);
  }
}

void WorkerWatcher::ConnectDedicatedWorkerClient(
    WorkerNodeImpl* worker_node,
    blink::DedicatedWorkerToken client_dedicated_worker_token) {
  DCHECK(worker_node);

  ConnectClientWorkerOnGraph(
      worker_node, GetDedicatedWorkerNode(client_dedicated_worker_token));

  // Remember that |worker_node| is a child worker of this dedicated worker.
  bool inserted = dedicated_worker_child_workers_[client_dedicated_worker_token]
                      .insert(worker_node)
                      .second;
  DCHECK(inserted);
}

void WorkerWatcher::DisconnectDedicatedWorkerClient(
    WorkerNodeImpl* worker_node,
    blink::DedicatedWorkerToken client_dedicated_worker_token) {
  DCHECK(worker_node);

  // Remove |worker_node| from the set of child workers of this dedicated
  // worker.
  auto it = dedicated_worker_child_workers_.find(client_dedicated_worker_token);
  DCHECK(it != dedicated_worker_child_workers_.end());
  auto& child_workers = it->second;

  size_t removed = child_workers.erase(worker_node);
  DCHECK_EQ(removed, 1u);

  if (child_workers.empty())
    dedicated_worker_child_workers_.erase(it);

  DisconnectClientWorkerOnGraph(
      worker_node, GetDedicatedWorkerNode(client_dedicated_worker_token));
}

void WorkerWatcher::ConnectSharedWorkerClient(
    WorkerNodeImpl* worker_node,
    blink::SharedWorkerToken client_shared_worker_token) {
  DCHECK(worker_node);

  ConnectClientWorkerOnGraph(worker_node,
                             GetSharedWorkerNode(client_shared_worker_token));

  // Remember that |worker_node| is a child worker of this shared worker.
  bool inserted = shared_worker_child_workers_[client_shared_worker_token]
                      .insert(worker_node)
                      .second;
  DCHECK(inserted);
}

void WorkerWatcher::DisconnectSharedWorkerClient(
    WorkerNodeImpl* worker_node,
    blink::SharedWorkerToken client_shared_worker_token) {
  DCHECK(worker_node);

  // This notification may arrive after the client worker has been deleted,
  // in which case the relationship has already been cleaned up.
  auto worker_it = shared_worker_nodes_.find(client_shared_worker_token);
  if (worker_it == shared_worker_nodes_.end()) {
    // Make sure there aren't any child relationships for this worker.
    DCHECK(shared_worker_child_workers_.find(client_shared_worker_token) ==
           shared_worker_child_workers_.end());

    return;
  }

  // Remove |worker_node| from the set of child workers of this shared worker.
  auto child_it = shared_worker_child_workers_.find(client_shared_worker_token);
  DCHECK(child_it != shared_worker_child_workers_.end());
  auto& child_workers = child_it->second;

  size_t removed = child_workers.erase(worker_node);
  DCHECK_EQ(removed, 1u);

  if (child_workers.empty())
    shared_worker_child_workers_.erase(child_it);

  DisconnectClientWorkerOnGraph(
      worker_node, GetSharedWorkerNode(client_shared_worker_token));
}

void WorkerWatcher::ConnectAllServiceWorkerClients(
    WorkerNodeImpl* service_worker_node,
    int64_t version_id) {
  // Nothing to do if there are no clients.
  auto it = service_worker_clients_.find(version_id);
  if (it == service_worker_clients_.end())
    return;

  for (const auto& kv : it->second) {
    const ServiceWorkerClient& client = kv.second;

    switch (client.type()) {
      case blink::mojom::ServiceWorkerClientType::kWindow:
        AddFrameClientConnection(service_worker_node,
                                 client.GetRenderFrameHostId());
        break;
      case blink::mojom::ServiceWorkerClientType::kDedicatedWorker:
        ConnectDedicatedWorkerClient(service_worker_node,
                                     client.GetDedicatedWorkerToken());
        break;
      case blink::mojom::ServiceWorkerClientType::kSharedWorker:
        ConnectSharedWorkerClient(service_worker_node,
                                  client.GetSharedWorkerToken());
        break;
      case blink::mojom::ServiceWorkerClientType::kAll:
        NOTREACHED();
        break;
    }
  }
}

void WorkerWatcher::DisconnectAllServiceWorkerClients(
    WorkerNodeImpl* service_worker_node,
    int64_t version_id) {
  // Nothing to do if there are no clients.
  auto it = service_worker_clients_.find(version_id);
  if (it == service_worker_clients_.end())
    return;

  for (const auto& kv : it->second) {
    const ServiceWorkerClient& client = kv.second;

    switch (client.type()) {
      case blink::mojom::ServiceWorkerClientType::kWindow:
        RemoveFrameClientConnection(service_worker_node,
                                    client.GetRenderFrameHostId());
        break;
      case blink::mojom::ServiceWorkerClientType::kDedicatedWorker:
        DisconnectDedicatedWorkerClient(service_worker_node,
                                        client.GetDedicatedWorkerToken());
        break;
      case blink::mojom::ServiceWorkerClientType::kSharedWorker:
        DisconnectSharedWorkerClient(service_worker_node,
                                     client.GetSharedWorkerToken());
        break;
      case blink::mojom::ServiceWorkerClientType::kAll:
        NOTREACHED();
        break;
    }
  }
}

void WorkerWatcher::OnBeforeFrameNodeRemoved(
    content::GlobalFrameRoutingId render_frame_host_id,
    FrameNodeImpl* frame_node) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto it = frame_node_child_worker_connections_.find(render_frame_host_id);
  DCHECK(it != frame_node_child_worker_connections_.end());

  // Clean up all child workers of this frame node.
  WorkerNodeConnections child_worker_connections = std::move(it->second);
  frame_node_child_worker_connections_.erase(it);

  // Disconnect all child workers from |frame_node|.
  DCHECK(!child_worker_connections.empty());
  DisconnectClientsOnGraph(child_worker_connections, frame_node);

#if DCHECK_IS_ON()
  for (auto kv : child_worker_connections) {
    // A call to RemoveFrameClientConnection() is still expected to be received
    // for this frame for each connection workers in |child_worker_connections|.
    // Note: the [] operator is intentionally used to default initialize the
    // count to zero if needed.
    detached_frame_count_per_worker_[kv.first] += kv.second;
  }
#endif  // DCHECK_IS_ON()
}

void WorkerWatcher::AddChildWorkerConnection(
    content::GlobalFrameRoutingId render_frame_host_id,
    WorkerNodeImpl* child_worker_node,
    bool* is_first_child_worker,
    bool* is_first_child_worker_connection) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto insertion_result =
      frame_node_child_worker_connections_.insert({render_frame_host_id, {}});
  *is_first_child_worker = insertion_result.second;

  auto& child_worker_connections = insertion_result.first->second;
  const size_t count = ++child_worker_connections[child_worker_node];
  DCHECK_LE(0u, count);
  *is_first_child_worker_connection = count == 1;
}

void WorkerWatcher::RemoveChildWorkerConnection(
    content::GlobalFrameRoutingId render_frame_host_id,
    WorkerNodeImpl* child_worker_node,
    bool* was_last_child_worker,
    bool* was_last_child_worker_connection) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto it = frame_node_child_worker_connections_.find(render_frame_host_id);
  DCHECK(it != frame_node_child_worker_connections_.end());
  auto& child_worker_connections = it->second;

  DCHECK_LE(1u, child_worker_connections[child_worker_node]);
  const size_t count = --child_worker_connections[child_worker_node];
  *was_last_child_worker_connection = count == 0;

  if (count == 0) {
    const size_t removed = child_worker_connections.erase(child_worker_node);
    DCHECK_EQ(removed, 1u);
  }

  *was_last_child_worker = child_worker_connections.empty();
  if (child_worker_connections.empty()) {
    frame_node_child_worker_connections_.erase(it);
  }
}

WorkerNodeImpl* WorkerWatcher::GetDedicatedWorkerNode(
    const blink::DedicatedWorkerToken& dedicated_worker_token) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto it = dedicated_worker_nodes_.find(dedicated_worker_token);
  if (it == dedicated_worker_nodes_.end()) {
    NOTREACHED();
    return nullptr;
  }
  return it->second.get();
}

WorkerNodeImpl* WorkerWatcher::GetSharedWorkerNode(
    const blink::SharedWorkerToken& shared_worker_token) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto it = shared_worker_nodes_.find(shared_worker_token);
  if (it == shared_worker_nodes_.end()) {
    NOTREACHED();
    return nullptr;
  }
  return it->second.get();
}

WorkerNodeImpl* WorkerWatcher::GetServiceWorkerNode(int64_t version_id) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);

  auto it = service_worker_nodes_.find(version_id);
  if (it == service_worker_nodes_.end()) {
    return nullptr;
  }
  return it->second.get();
}

}  // namespace performance_manager
