Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / task_management / providers / child_process_task_provider.cc
blobca00a514b022f2382c3abeabbc3519c152b7fa2d
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/task_management/providers/child_process_task_provider.h"
7 #include "base/process/process.h"
8 #include "base/stl_util.h"
9 #include "chrome/browser/task_management/providers/child_process_task.h"
10 #include "content/public/browser/browser_child_process_host_iterator.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/child_process_data.h"
14 using content::BrowserChildProcessHostIterator;
15 using content::BrowserThread;
16 using content::ChildProcessData;
18 namespace task_management {
20 namespace {
22 // Collects and returns the child processes data on the IO thread to get all the
23 // pre-existing child process before we start observing
24 // |BrowserChildProcessObserver|.
25 scoped_ptr<std::vector<ChildProcessData>> CollectChildProcessData() {
26 // The |BrowserChildProcessHostIterator| must only be used on the IO thread.
27 DCHECK_CURRENTLY_ON(BrowserThread::IO);
29 scoped_ptr<std::vector<ChildProcessData>> child_processes(
30 new std::vector<ChildProcessData>());
31 for (BrowserChildProcessHostIterator itr; !itr.Done(); ++itr) {
32 const ChildProcessData& process_data = itr.GetData();
34 // Only add processes that have already started, i.e. with valid handles.
35 if (process_data.handle == base::kNullProcessHandle)
36 continue;
38 child_processes->push_back(process_data);
41 return child_processes.Pass();
44 } // namespace
46 ChildProcessTaskProvider::ChildProcessTaskProvider()
47 : tasks_by_handle_(),
48 tasks_by_pid_(),
49 weak_ptr_factory_(this) {
52 ChildProcessTaskProvider::~ChildProcessTaskProvider() {
55 Task* ChildProcessTaskProvider::GetTaskOfUrlRequest(int origin_pid,
56 int child_id,
57 int route_id) {
58 DCHECK_CURRENTLY_ON(BrowserThread::UI);
59 auto itr = tasks_by_pid_.find(static_cast<base::ProcessId>(origin_pid));
60 if (itr == tasks_by_pid_.end())
61 return nullptr;
63 return itr->second;
66 void ChildProcessTaskProvider::BrowserChildProcessHostConnected(
67 const content::ChildProcessData& data) {
68 DCHECK_CURRENTLY_ON(BrowserThread::UI);
69 if (data.handle == base::kNullProcessHandle)
70 return;
72 CreateTask(data);
75 void ChildProcessTaskProvider::BrowserChildProcessHostDisconnected(
76 const content::ChildProcessData& data) {
77 DCHECK_CURRENTLY_ON(BrowserThread::UI);
78 DeleteTask(data.handle);
81 void ChildProcessTaskProvider::StartUpdating() {
82 DCHECK_CURRENTLY_ON(BrowserThread::UI);
83 DCHECK(tasks_by_handle_.empty());
84 DCHECK(tasks_by_pid_.empty());
86 // First, get the pre-existing child processes data.
87 BrowserThread::PostTaskAndReplyWithResult(
88 BrowserThread::IO,
89 FROM_HERE,
90 base::Bind(&CollectChildProcessData),
91 base::Bind(&ChildProcessTaskProvider::ChildProcessDataCollected,
92 weak_ptr_factory_.GetWeakPtr()));
95 void ChildProcessTaskProvider::StopUpdating() {
96 DCHECK_CURRENTLY_ON(BrowserThread::UI);
98 // ChildProcessDataCollected() should never be called after this, and hence
99 // we must invalidate the weak pointers.
100 weak_ptr_factory_.InvalidateWeakPtrs();
102 // First, stop observing.
103 BrowserChildProcessObserver::Remove(this);
105 // Remember: You can't notify the observer of tasks removal here,
106 // StopUpdating() is called after the observer has been cleared.
108 // Then delete all tasks (if any).
109 STLDeleteValues(&tasks_by_handle_); // This will clear |tasks_by_handle_|.
110 tasks_by_pid_.clear();
113 void ChildProcessTaskProvider::ChildProcessDataCollected(
114 scoped_ptr<const std::vector<content::ChildProcessData>> child_processes) {
115 DCHECK_CURRENTLY_ON(BrowserThread::UI);
117 for (auto& process_data : *child_processes)
118 CreateTask(process_data);
120 // Now start observing.
121 BrowserChildProcessObserver::Add(this);
124 void ChildProcessTaskProvider::CreateTask(
125 const content::ChildProcessData& data) {
126 if (tasks_by_handle_.find(data.handle) != tasks_by_handle_.end()) {
127 // This case can happen when some of the child process data we collect upon
128 // StartUpdating() might be of BrowserChildProcessHosts whose channels
129 // hadn't connected yet. So we just return.
130 return;
133 // Create the task and notify the observer.
134 ChildProcessTask* task = new ChildProcessTask(data);
135 tasks_by_handle_[data.handle] = task;
136 tasks_by_pid_[task->process_id()] = task;
137 NotifyObserverTaskAdded(task);
140 void ChildProcessTaskProvider::DeleteTask(base::ProcessHandle handle) {
141 auto itr = tasks_by_handle_.find(handle);
143 // The following case should never happen since we start observing
144 // |BrowserChildProcessObserver| only after we collect all pre-existing child
145 // processes and are notified (on the UI thread) that the collection is
146 // completed at |ChildProcessDataCollected()|.
147 if (itr == tasks_by_handle_.end()) {
148 NOTREACHED();
149 return;
152 ChildProcessTask* task = itr->second;
154 NotifyObserverTaskRemoved(task);
156 // Finally delete the task.
157 tasks_by_handle_.erase(itr);
158 tasks_by_pid_.erase(task->process_id());
159 delete task;
162 } // namespace task_management