File: child_process_task_provider.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (129 lines) | stat: -rw-r--r-- 4,257 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// Copyright 2015 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/task_manager/providers/child_process_task_provider.h"

#include <memory>

#include "base/functional/bind.h"
#include "base/process/process.h"
#include "chrome/browser/task_manager/providers/child_process_task.h"
#include "content/public/browser/browser_child_process_host_iterator.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_data.h"

using content::BrowserChildProcessHostIterator;
using content::BrowserThread;
using content::ChildProcessData;

namespace task_manager {

ChildProcessTaskProvider::ChildProcessTaskProvider() = default;

ChildProcessTaskProvider::~ChildProcessTaskProvider() = default;

Task* ChildProcessTaskProvider::GetTaskOfUrlRequest(int child_id,
                                                    int route_id) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  auto itr = tasks_by_child_id_.find(child_id);
  if (itr == tasks_by_child_id_.end())
    return nullptr;

  return itr->second;
}

void ChildProcessTaskProvider::BrowserChildProcessLaunchedAndConnected(
    const content::ChildProcessData& data) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (!data.GetProcess().IsValid())
    return;

  CreateTask(data);
}

void ChildProcessTaskProvider::BrowserChildProcessHostDisconnected(
    const content::ChildProcessData& data) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  DeleteTask(data.GetProcess().Handle());
}

void ChildProcessTaskProvider::StartUpdating() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  DCHECK(tasks_by_processid_.empty());
  DCHECK(tasks_by_child_id_.empty());

  // First, get the pre-existing child processes data.
  for (BrowserChildProcessHostIterator itr; !itr.Done(); ++itr) {
    const ChildProcessData& process_data = itr.GetData();

    // Only add processes that have already started, i.e. with valid handles.
    if (!process_data.GetProcess().IsValid())
      continue;

    CreateTask(process_data);
  }

  // Now start observing.
  BrowserChildProcessObserver::Add(this);
}

void ChildProcessTaskProvider::StopUpdating() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);

  // First, stop observing.
  BrowserChildProcessObserver::Remove(this);

  // Remember: You can't notify the observer of tasks removal here,
  // StopUpdating() is called after the observer has been cleared.

  // Then delete all tasks (if any).
  tasks_by_processid_.clear();
  tasks_by_child_id_.clear();
}

void ChildProcessTaskProvider::CreateTask(
    const content::ChildProcessData& data) {
  std::unique_ptr<ChildProcessTask>& task =
      tasks_by_processid_[data.GetProcess().Pid()];
  if (task) {
    // This task is already known to us. This case can happen when some of the
    // child process data we collect upon StartUpdating() might be of
    // BrowserChildProcessHosts whose process hadn't launched yet. So we just
    // return.
    return;
  }

  // Create the task and notify the observer.
  task = std::make_unique<ChildProcessTask>(
      data, ChildProcessTask::ProcessSubtype::kNoSubtype);
  tasks_by_child_id_[task->GetChildProcessUniqueID()] = task.get();
  NotifyObserverTaskAdded(task.get());
}

void ChildProcessTaskProvider::DeleteTask(base::ProcessHandle handle) {
  auto itr = tasks_by_processid_.find(base::GetProcId(handle));

  // The following case should never happen since we start observing
  // |BrowserChildProcessObserver| only after we collect all pre-existing child
  // processes and are notified (on the UI thread) that the collection is
  // completed at |ChildProcessDataCollected()|.
  if (itr == tasks_by_processid_.end()) {
    // BUG(crbug.com/611067): Temporarily removing due to test flakes. The
    // reason why this happens is well understood (see bug), but there's no
    // quick and easy fix.
    // NOTREACHED();
    return;
  }

  NotifyObserverTaskRemoved(itr->second.get());

  // Clear from the child_id index.
  tasks_by_child_id_.erase(itr->second->GetChildProcessUniqueID());

  // Finally delete the task.
  tasks_by_processid_.erase(itr);
}

}  // namespace task_manager