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
{
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
)
38 child_processes
->push_back(process_data
);
41 return child_processes
.Pass();
46 ChildProcessTaskProvider::ChildProcessTaskProvider()
49 weak_ptr_factory_(this) {
52 ChildProcessTaskProvider::~ChildProcessTaskProvider() {
55 Task
* ChildProcessTaskProvider::GetTaskOfUrlRequest(int origin_pid
,
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())
66 void ChildProcessTaskProvider::BrowserChildProcessHostConnected(
67 const content::ChildProcessData
& data
) {
68 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
69 if (data
.handle
== base::kNullProcessHandle
)
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(
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.
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()) {
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());
162 } // namespace task_management