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.
4
5 #include "chrome/browser/task_manager/sampling/task_manager_impl.h"
6
7 #include <algorithm>
8 #include <memory>
9 #include <string>
10 #include <unordered_map>
11 #include <unordered_set>
12 #include <utility>
13 #include <vector>
14
15 #include "base/bind.h"
16 #include "base/command_line.h"
17 #include "base/containers/adapters.h"
18 #include "base/task/post_task.h"
19 #include "base/task/thread_pool.h"
20 #include "build/build_config.h"
21 #include "chrome/browser/task_manager/providers/browser_process_task_provider.h"
22 #include "chrome/browser/task_manager/providers/child_process_task_provider.h"
23 #include "chrome/browser/task_manager/providers/fallback_task_provider.h"
24 #include "chrome/browser/task_manager/providers/render_process_host_task_provider.h"
25 #include "chrome/browser/task_manager/providers/spare_render_process_host_task_provider.h"
26 #include "chrome/browser/task_manager/providers/web_contents/web_contents_task_provider.h"
27 #include "chrome/browser/task_manager/providers/worker_task_provider.h"
28 #include "chrome/browser/task_manager/sampling/shared_sampler.h"
29 #include "components/nacl/common/buildflags.h"
30 #include "content/public/browser/browser_thread.h"
31 #include "content/public/browser/gpu_data_manager.h"
32 #include "content/public/browser/network_service_instance.h"
33 #include "content/public/browser/render_frame_host.h"
34 #include "content/public/browser/render_process_host.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/common/child_process_host.h"
37 #include "content/public/common/content_features.h"
38 #include "services/network/public/cpp/features.h"
39 #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
40
41 #if defined(OS_CHROMEOS)
42 #include "chrome/browser/chromeos/arc/process/arc_process_service.h"
43 #include "chrome/browser/task_manager/providers/arc/arc_process_task_provider.h"
44 #include "chrome/browser/task_manager/providers/vm/vm_process_task_provider.h"
45 #include "components/arc/arc_util.h"
46 #endif // defined(OS_CHROMEOS)
47
48 namespace task_manager {
49
50 namespace {
51
52 base::LazyInstance<TaskManagerImpl>::DestructorAtExit
53 lazy_task_manager_instance = LAZY_INSTANCE_INITIALIZER;
54
CalculateNewBytesTransferred(int64_t this_refresh_bytes,int64_t last_refresh_bytes)55 int64_t CalculateNewBytesTransferred(int64_t this_refresh_bytes,
56 int64_t last_refresh_bytes) {
57 // Network Service could have restarted between the refresh, causing the
58 // accumulator to be cleared.
59 if (this_refresh_bytes < last_refresh_bytes)
60 return this_refresh_bytes;
61
62 return this_refresh_bytes - last_refresh_bytes;
63 }
64
65 } // namespace
66
operator ()(const BytesTransferredKey & key) const67 size_t BytesTransferredKey::Hasher::operator()(
68 const BytesTransferredKey& key) const {
69 return base::HashInts(key.child_id, key.route_id);
70 }
71
operator ==(const BytesTransferredKey & other) const72 bool BytesTransferredKey::operator==(const BytesTransferredKey& other) const {
73 return child_id == other.child_id && route_id == other.route_id;
74 }
75
TaskManagerImpl()76 TaskManagerImpl::TaskManagerImpl()
77 : on_background_data_ready_callback_(base::BindRepeating(
78 &TaskManagerImpl::OnTaskGroupBackgroundCalculationsDone,
79 base::Unretained(this))),
80 blocking_pool_runner_(base::ThreadPool::CreateSequencedTaskRunner(
81 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
82 base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
83 shared_sampler_(new SharedSampler(blocking_pool_runner_)),
84 is_running_(false),
85 waiting_for_memory_dump_(false) {
86 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
87
88 task_providers_.push_back(std::make_unique<BrowserProcessTaskProvider>());
89 task_providers_.push_back(std::make_unique<ChildProcessTaskProvider>());
90
91 // Put all task providers for various types of RenderProcessHosts in this
92 // section. All of them should be added as primary subproviders for the
93 // FallbackTaskProvider, so that a fallback task can be shown for a renderer
94 // process if no other provider is shown for it.
95 std::vector<std::unique_ptr<TaskProvider>> primary_subproviders;
96 primary_subproviders.push_back(
97 std::make_unique<SpareRenderProcessHostTaskProvider>());
98 primary_subproviders.push_back(std::make_unique<WorkerTaskProvider>());
99 primary_subproviders.push_back(std::make_unique<WebContentsTaskProvider>());
100 task_providers_.push_back(std::make_unique<FallbackTaskProvider>(
101 std::move(primary_subproviders),
102 std::make_unique<RenderProcessHostTaskProvider>()));
103
104 #if defined(OS_CHROMEOS)
105 if (arc::IsArcAvailable())
106 task_providers_.push_back(std::make_unique<ArcProcessTaskProvider>());
107 task_providers_.push_back(std::make_unique<VmProcessTaskProvider>());
108 arc_shared_sampler_ = std::make_unique<ArcSharedSampler>();
109 #endif // defined(OS_CHROMEOS)
110 }
111
~TaskManagerImpl()112 TaskManagerImpl::~TaskManagerImpl() {
113 }
114
115 // static
GetInstance()116 TaskManagerImpl* TaskManagerImpl::GetInstance() {
117 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
118
119 return lazy_task_manager_instance.Pointer();
120 }
121
ActivateTask(TaskId task_id)122 void TaskManagerImpl::ActivateTask(TaskId task_id) {
123 GetTaskByTaskId(task_id)->Activate();
124 }
125
IsTaskKillable(TaskId task_id)126 bool TaskManagerImpl::IsTaskKillable(TaskId task_id) {
127 return GetTaskByTaskId(task_id)->IsKillable();
128 }
129
KillTask(TaskId task_id)130 void TaskManagerImpl::KillTask(TaskId task_id) {
131 GetTaskByTaskId(task_id)->Kill();
132 }
133
GetPlatformIndependentCPUUsage(TaskId task_id) const134 double TaskManagerImpl::GetPlatformIndependentCPUUsage(TaskId task_id) const {
135 return GetTaskGroupByTaskId(task_id)->platform_independent_cpu_usage();
136 }
137
GetStartTime(TaskId task_id) const138 base::Time TaskManagerImpl::GetStartTime(TaskId task_id) const {
139 #if defined(OS_WIN)
140 return GetTaskGroupByTaskId(task_id)->start_time();
141 #else
142 NOTIMPLEMENTED();
143 return base::Time();
144 #endif
145 }
146
GetCpuTime(TaskId task_id) const147 base::TimeDelta TaskManagerImpl::GetCpuTime(TaskId task_id) const {
148 #if defined(OS_WIN)
149 return GetTaskGroupByTaskId(task_id)->cpu_time();
150 #else
151 NOTIMPLEMENTED();
152 return base::TimeDelta();
153 #endif
154 }
155
GetMemoryFootprintUsage(TaskId task_id) const156 int64_t TaskManagerImpl::GetMemoryFootprintUsage(TaskId task_id) const {
157 return GetTaskGroupByTaskId(task_id)->footprint_bytes();
158 }
159
GetSwappedMemoryUsage(TaskId task_id) const160 int64_t TaskManagerImpl::GetSwappedMemoryUsage(TaskId task_id) const {
161 #if defined(OS_CHROMEOS)
162 return GetTaskGroupByTaskId(task_id)->swapped_bytes();
163 #else
164 return -1;
165 #endif
166 }
167
GetGpuMemoryUsage(TaskId task_id,bool * has_duplicates) const168 int64_t TaskManagerImpl::GetGpuMemoryUsage(TaskId task_id,
169 bool* has_duplicates) const {
170 const TaskGroup* task_group = GetTaskGroupByTaskId(task_id);
171 if (has_duplicates)
172 *has_duplicates = task_group->gpu_memory_has_duplicates();
173 return task_group->gpu_memory();
174 }
175
GetIdleWakeupsPerSecond(TaskId task_id) const176 int TaskManagerImpl::GetIdleWakeupsPerSecond(TaskId task_id) const {
177 return GetTaskGroupByTaskId(task_id)->idle_wakeups_per_second();
178 }
179
GetHardFaultsPerSecond(TaskId task_id) const180 int TaskManagerImpl::GetHardFaultsPerSecond(TaskId task_id) const {
181 #if defined(OS_WIN)
182 return GetTaskGroupByTaskId(task_id)->hard_faults_per_second();
183 #else
184 return -1;
185 #endif
186 }
187
GetNaClDebugStubPort(TaskId task_id) const188 int TaskManagerImpl::GetNaClDebugStubPort(TaskId task_id) const {
189 #if BUILDFLAG(ENABLE_NACL)
190 return GetTaskGroupByTaskId(task_id)->nacl_debug_stub_port();
191 #else
192 return -2;
193 #endif // BUILDFLAG(ENABLE_NACL)
194 }
195
GetGDIHandles(TaskId task_id,int64_t * current,int64_t * peak) const196 void TaskManagerImpl::GetGDIHandles(TaskId task_id,
197 int64_t* current,
198 int64_t* peak) const {
199 #if defined(OS_WIN)
200 const TaskGroup* task_group = GetTaskGroupByTaskId(task_id);
201 *current = task_group->gdi_current_handles();
202 *peak = task_group->gdi_peak_handles();
203 #else
204 *current = -1;
205 *peak = -1;
206 #endif // defined(OS_WIN)
207 }
208
GetUSERHandles(TaskId task_id,int64_t * current,int64_t * peak) const209 void TaskManagerImpl::GetUSERHandles(TaskId task_id,
210 int64_t* current,
211 int64_t* peak) const {
212 #if defined(OS_WIN)
213 const TaskGroup* task_group = GetTaskGroupByTaskId(task_id);
214 *current = task_group->user_current_handles();
215 *peak = task_group->user_peak_handles();
216 #else
217 *current = -1;
218 *peak = -1;
219 #endif // defined(OS_WIN)
220 }
221
GetOpenFdCount(TaskId task_id) const222 int TaskManagerImpl::GetOpenFdCount(TaskId task_id) const {
223 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_BSD)
224 return GetTaskGroupByTaskId(task_id)->open_fd_count();
225 #else
226 return -1;
227 #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_BSD)
228 }
229
IsTaskOnBackgroundedProcess(TaskId task_id) const230 bool TaskManagerImpl::IsTaskOnBackgroundedProcess(TaskId task_id) const {
231 return GetTaskGroupByTaskId(task_id)->is_backgrounded();
232 }
233
GetTitle(TaskId task_id) const234 const base::string16& TaskManagerImpl::GetTitle(TaskId task_id) const {
235 return GetTaskByTaskId(task_id)->title();
236 }
237
GetProfileName(TaskId task_id) const238 base::string16 TaskManagerImpl::GetProfileName(TaskId task_id) const {
239 return GetTaskByTaskId(task_id)->GetProfileName();
240 }
241
GetIcon(TaskId task_id) const242 const gfx::ImageSkia& TaskManagerImpl::GetIcon(TaskId task_id) const {
243 return GetTaskByTaskId(task_id)->icon();
244 }
245
GetProcessHandle(TaskId task_id) const246 const base::ProcessHandle& TaskManagerImpl::GetProcessHandle(
247 TaskId task_id) const {
248 return GetTaskGroupByTaskId(task_id)->process_handle();
249 }
250
GetProcessId(TaskId task_id) const251 const base::ProcessId& TaskManagerImpl::GetProcessId(TaskId task_id) const {
252 return GetTaskGroupByTaskId(task_id)->process_id();
253 }
254
GetType(TaskId task_id) const255 Task::Type TaskManagerImpl::GetType(TaskId task_id) const {
256 return GetTaskByTaskId(task_id)->GetType();
257 }
258
GetTabId(TaskId task_id) const259 SessionID TaskManagerImpl::GetTabId(TaskId task_id) const {
260 return GetTaskByTaskId(task_id)->GetTabId();
261 }
262
GetChildProcessUniqueId(TaskId task_id) const263 int TaskManagerImpl::GetChildProcessUniqueId(TaskId task_id) const {
264 return GetTaskByTaskId(task_id)->GetChildProcessUniqueID();
265 }
266
GetTerminationStatus(TaskId task_id,base::TerminationStatus * out_status,int * out_error_code) const267 void TaskManagerImpl::GetTerminationStatus(TaskId task_id,
268 base::TerminationStatus* out_status,
269 int* out_error_code) const {
270 GetTaskByTaskId(task_id)->GetTerminationStatus(out_status, out_error_code);
271 }
272
GetNetworkUsage(TaskId task_id) const273 int64_t TaskManagerImpl::GetNetworkUsage(TaskId task_id) const {
274 return GetTaskByTaskId(task_id)->network_usage_rate();
275 }
276
GetCumulativeNetworkUsage(TaskId task_id) const277 int64_t TaskManagerImpl::GetCumulativeNetworkUsage(TaskId task_id) const {
278 return GetTaskByTaskId(task_id)->cumulative_network_usage();
279 }
280
GetProcessTotalNetworkUsage(TaskId task_id) const281 int64_t TaskManagerImpl::GetProcessTotalNetworkUsage(TaskId task_id) const {
282 return GetTaskGroupByTaskId(task_id)->per_process_network_usage_rate();
283 }
284
GetCumulativeProcessTotalNetworkUsage(TaskId task_id) const285 int64_t TaskManagerImpl::GetCumulativeProcessTotalNetworkUsage(
286 TaskId task_id) const {
287 return GetTaskGroupByTaskId(task_id)->cumulative_per_process_network_usage();
288 }
289
GetSqliteMemoryUsed(TaskId task_id) const290 int64_t TaskManagerImpl::GetSqliteMemoryUsed(TaskId task_id) const {
291 return GetTaskByTaskId(task_id)->GetSqliteMemoryUsed();
292 }
293
GetV8Memory(TaskId task_id,int64_t * allocated,int64_t * used) const294 bool TaskManagerImpl::GetV8Memory(TaskId task_id,
295 int64_t* allocated,
296 int64_t* used) const {
297 const Task* task = GetTaskByTaskId(task_id);
298 const int64_t allocated_memory = task->GetV8MemoryAllocated();
299 const int64_t used_memory = task->GetV8MemoryUsed();
300 if (allocated_memory == -1 || used_memory == -1)
301 return false;
302
303 *allocated = allocated_memory;
304 *used = used_memory;
305
306 return true;
307 }
308
GetWebCacheStats(TaskId task_id,blink::WebCacheResourceTypeStats * stats) const309 bool TaskManagerImpl::GetWebCacheStats(
310 TaskId task_id,
311 blink::WebCacheResourceTypeStats* stats) const {
312 const Task* task = GetTaskByTaskId(task_id);
313 if (!task->ReportsWebCacheStats())
314 return false;
315
316 *stats = task->GetWebCacheStats();
317
318 return true;
319 }
320
GetKeepaliveCount(TaskId task_id) const321 int TaskManagerImpl::GetKeepaliveCount(TaskId task_id) const {
322 const Task* task = GetTaskByTaskId(task_id);
323 if (!task)
324 return -1;
325
326 return task->GetKeepaliveCount();
327 }
328
GetTaskIdsList() const329 const TaskIdList& TaskManagerImpl::GetTaskIdsList() const {
330 DCHECK(is_running_) << "Task manager is not running. You must observe the "
331 "task manager for it to start running";
332
333 if (sorted_task_ids_.empty()) {
334 // |comparator| groups and sorts by subtask-ness (to push all subtasks to be
335 // last), then by process type (e.g. the browser process should be first;
336 // renderer processes should be together), then tab id (processes used by
337 // the same tab should be kept together, and a tab should have a stable
338 // position in the list as it cycles through processes, and tab creation
339 // order is meaningful), and finally by task id (when all else is equal, put
340 // the oldest tasks first).
341 auto comparator = [](const Task* a, const Task* b) -> bool {
342 return std::make_tuple(a->HasParentTask(), a->GetType(), a->GetTabId(),
343 a->task_id()) <
344 std::make_tuple(b->HasParentTask(), b->GetType(), b->GetTabId(),
345 b->task_id());
346 };
347
348 const size_t num_groups =
349 task_groups_by_proc_id_.size() + arc_vm_task_groups_by_proc_id_.size();
350
351 // |task_groups_by_task_id_| contains all tasks, both VM and non-VM.
352 const size_t num_tasks = task_groups_by_task_id_.size();
353
354 // Populate |tasks_to_visit| with one task from each group.
355 std::vector<const Task*> tasks_to_visit;
356 tasks_to_visit.reserve(num_groups);
357 std::unordered_map<const Task*, std::vector<const Task*>> children;
358 for (const auto& groups_pair : task_groups_by_proc_id_) {
359 // The first task in the group (per |comparator|) is the one used for
360 // sorting the group relative to other groups.
361 const std::vector<Task*>& tasks = groups_pair.second->tasks();
362 Task* group_task =
363 *std::min_element(tasks.begin(), tasks.end(), comparator);
364 tasks_to_visit.push_back(group_task);
365
366 // Build the parent-to-child map, for use later.
367 for (const Task* task : tasks) {
368 if (task->HasParentTask())
369 children[task->GetParentTask()].push_back(task);
370 else
371 DCHECK(!group_task->HasParentTask());
372 }
373 }
374
375 for (const auto& groups_pair : arc_vm_task_groups_by_proc_id_) {
376 const std::vector<Task*>& tasks = groups_pair.second->tasks();
377 Task* group_task =
378 *std::min_element(tasks.begin(), tasks.end(), comparator);
379 tasks_to_visit.push_back(group_task);
380 }
381
382 // Now sort |tasks_to_visit| in reverse order (putting the browser process
383 // at back()). We will treat it as a stack from now on.
384 std::sort(tasks_to_visit.rbegin(), tasks_to_visit.rend(), comparator);
385 DCHECK_EQ(Task::BROWSER, tasks_to_visit.back()->GetType());
386
387 // Using |tasks_to_visit| as a stack, and |visited_groups| to track which
388 // groups we've already added, add groups to |sorted_task_ids_| until all
389 // groups have been added.
390 sorted_task_ids_.reserve(num_tasks);
391 std::unordered_set<TaskGroup*> visited_groups;
392 visited_groups.reserve(num_groups);
393 std::vector<Task*> current_group_tasks; // Outside loop for fewer mallocs.
394 while (visited_groups.size() < num_groups) {
395 DCHECK(!tasks_to_visit.empty());
396 TaskGroup* current_group =
397 GetTaskGroupByTaskId(tasks_to_visit.back()->task_id());
398 tasks_to_visit.pop_back();
399
400 // Mark |current_group| as visited. If this fails, we've already added
401 // the group, and should skip over it.
402 if (!visited_groups.insert(current_group).second)
403 continue;
404
405 // Make a copy of |current_group->tasks()|, sort it, and append the ids.
406 current_group_tasks = current_group->tasks();
407 std::sort(current_group_tasks.begin(), current_group_tasks.end(),
408 comparator);
409 for (Task* task : current_group_tasks)
410 sorted_task_ids_.push_back(task->task_id());
411
412 // Find the children of the tasks we just added, and push them into
413 // |tasks_to_visit|, so that we visit them soon. Work in reverse order,
414 // so that we visit them in forward order.
415 for (Task* parent : base::Reversed(current_group_tasks)) {
416 auto children_of_parent = children.find(parent);
417 if (children_of_parent != children.end()) {
418 // Sort children[parent], and then append in reversed order.
419 std::sort(children_of_parent->second.begin(),
420 children_of_parent->second.end(), comparator);
421 tasks_to_visit.insert(tasks_to_visit.end(),
422 children_of_parent->second.rbegin(),
423 children_of_parent->second.rend());
424 }
425 }
426 }
427 DCHECK_EQ(num_tasks, sorted_task_ids_.size());
428 }
429
430 return sorted_task_ids_;
431 }
432
GetIdsOfTasksSharingSameProcess(TaskId task_id) const433 TaskIdList TaskManagerImpl::GetIdsOfTasksSharingSameProcess(
434 TaskId task_id) const {
435 DCHECK(is_running_) << "Task manager is not running. You must observe the "
436 "task manager for it to start running";
437
438 TaskIdList result;
439 TaskGroup* group = GetTaskGroupByTaskId(task_id);
440 if (group) {
441 result.reserve(group->tasks().size());
442 for (Task* task : group->tasks())
443 result.push_back(task->task_id());
444 }
445 return result;
446 }
447
GetNumberOfTasksOnSameProcess(TaskId task_id) const448 size_t TaskManagerImpl::GetNumberOfTasksOnSameProcess(TaskId task_id) const {
449 return GetTaskGroupByTaskId(task_id)->num_tasks();
450 }
451
IsRunningInVM(TaskId task_id) const452 bool TaskManagerImpl::IsRunningInVM(TaskId task_id) const {
453 return GetTaskByTaskId(task_id)->IsRunningInVM();
454 }
455
GetTaskIdForWebContents(content::WebContents * web_contents) const456 TaskId TaskManagerImpl::GetTaskIdForWebContents(
457 content::WebContents* web_contents) const {
458 if (!web_contents)
459 return -1;
460 content::RenderFrameHost* rfh = web_contents->GetMainFrame();
461 Task* task = GetTaskByRoute(rfh->GetProcess()->GetID(), rfh->GetRoutingID());
462 if (!task)
463 return -1;
464 return task->task_id();
465 }
466
TaskAdded(Task * task)467 void TaskManagerImpl::TaskAdded(Task* task) {
468 DCHECK(task);
469
470 const base::ProcessId proc_id = task->process_id();
471 const TaskId task_id = task->task_id();
472 const bool is_running_in_vm = task->IsRunningInVM();
473
474 TaskManagerImpl::PidToTaskGroupMap& task_group_map =
475 is_running_in_vm ? arc_vm_task_groups_by_proc_id_
476 : task_groups_by_proc_id_;
477
478 std::unique_ptr<TaskGroup>& task_group = task_group_map[proc_id];
479 if (!task_group) {
480 task_group.reset(new TaskGroup(task->process_handle(), proc_id,
481 is_running_in_vm,
482 on_background_data_ready_callback_,
483 shared_sampler_, blocking_pool_runner_));
484 #if defined(OS_CHROMEOS)
485 if (task->GetType() == Task::ARC)
486 task_group->SetArcSampler(arc_shared_sampler_.get());
487 #endif
488 }
489
490 task_group->AddTask(task);
491
492 task_groups_by_task_id_[task_id] = task_group.get();
493
494 // Invalidate the cached sorted IDs by clearing the list.
495 sorted_task_ids_.clear();
496
497 NotifyObserversOnTaskAdded(task_id);
498 }
499
TaskRemoved(Task * task)500 void TaskManagerImpl::TaskRemoved(Task* task) {
501 DCHECK(task);
502
503 const base::ProcessId proc_id = task->process_id();
504 const TaskId task_id = task->task_id();
505 const bool is_running_in_vm = task->IsRunningInVM();
506
507 TaskManagerImpl::PidToTaskGroupMap& task_group_map =
508 is_running_in_vm ? arc_vm_task_groups_by_proc_id_
509 : task_groups_by_proc_id_;
510
511 DCHECK(task_group_map.count(proc_id));
512
513 NotifyObserversOnTaskToBeRemoved(task_id);
514
515 TaskGroup* task_group = GetTaskGroupByTaskId(task_id);
516 task_group->RemoveTask(task);
517 task_groups_by_task_id_.erase(task_id);
518
519 if (task_group->empty())
520 task_group_map.erase(proc_id); // Deletes |task_group|.
521
522 // Invalidate the cached sorted IDs by clearing the list.
523 sorted_task_ids_.clear();
524 }
525
TaskUnresponsive(Task * task)526 void TaskManagerImpl::TaskUnresponsive(Task* task) {
527 DCHECK(task);
528 NotifyObserversOnTaskUnresponsive(task->task_id());
529 }
530
OnTotalNetworkUsages(std::vector<network::mojom::NetworkUsagePtr> total_network_usages)531 void TaskManagerImpl::OnTotalNetworkUsages(
532 std::vector<network::mojom::NetworkUsagePtr> total_network_usages) {
533 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
534 BytesTransferredMap new_total_network_usages_map;
535 for (const auto& entry : total_network_usages) {
536 BytesTransferredKey process_info = {entry->process_id, entry->routing_id};
537 BytesTransferredParam total_bytes_transferred = {
538 entry->total_bytes_received, entry->total_bytes_sent};
539 new_total_network_usages_map[process_info] = total_bytes_transferred;
540
541 auto last_refresh_usage =
542 last_refresh_total_network_usages_map_[process_info];
543 BytesTransferredParam new_bytes_transferred;
544 new_bytes_transferred.byte_read_count =
545 CalculateNewBytesTransferred(total_bytes_transferred.byte_read_count,
546 last_refresh_usage.byte_read_count);
547 new_bytes_transferred.byte_sent_count =
548 CalculateNewBytesTransferred(total_bytes_transferred.byte_sent_count,
549 last_refresh_usage.byte_sent_count);
550 DCHECK_GE(new_bytes_transferred.byte_read_count, 0);
551 DCHECK_GE(new_bytes_transferred.byte_sent_count, 0);
552
553 if (!UpdateTasksWithBytesTransferred(process_info, new_bytes_transferred)) {
554 // We can't match a task to the notification. That might mean the
555 // tab that started a download was closed, or the request may have had
556 // no originating task associated with it in the first place.
557 //
558 // Orphaned/unaccounted activity is credited to the Browser process.
559 BytesTransferredKey browser_process_key = {
560 content::ChildProcessHost::kInvalidUniqueID, MSG_ROUTING_NONE};
561 UpdateTasksWithBytesTransferred(browser_process_key,
562 new_bytes_transferred);
563 }
564 }
565 last_refresh_total_network_usages_map_.swap(new_total_network_usages_map);
566 }
567
OnVideoMemoryUsageStatsUpdate(const gpu::VideoMemoryUsageStats & gpu_memory_stats)568 void TaskManagerImpl::OnVideoMemoryUsageStatsUpdate(
569 const gpu::VideoMemoryUsageStats& gpu_memory_stats) {
570 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
571
572 gpu_memory_stats_ = gpu_memory_stats;
573 }
574
OnReceivedMemoryDump(bool success,std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump)575 void TaskManagerImpl::OnReceivedMemoryDump(
576 bool success,
577 std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump) {
578 waiting_for_memory_dump_ = false;
579 // We can ignore the value of success as it is a coarse grained indicator
580 // of whether the global dump was successful; usually because of a missing
581 // process or OS dumps. There may still be useful information for other
582 // processes in the global dump when success is false.
583 if (!dump)
584 return;
585 for (const auto& pmd : dump->process_dumps()) {
586 auto it = task_groups_by_proc_id_.find(pmd.pid());
587 if (it == task_groups_by_proc_id_.end())
588 continue;
589 it->second->set_footprint_bytes(
590 static_cast<uint64_t>(pmd.os_dump().private_footprint_kb) * 1024);
591 }
592 }
593
Refresh()594 void TaskManagerImpl::Refresh() {
595 if (IsResourceRefreshEnabled(REFRESH_TYPE_GPU_MEMORY)) {
596 content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate(
597 base::BindOnce(&TaskManagerImpl::OnVideoMemoryUsageStatsUpdate,
598 weak_ptr_factory_.GetWeakPtr()));
599 }
600
601 if (IsResourceRefreshEnabled(REFRESH_TYPE_MEMORY_FOOTPRINT) &&
602 !waiting_for_memory_dump_) {
603 // The callback keeps this object alive until the callback is invoked.
604 waiting_for_memory_dump_ = true;
605 auto callback = base::BindOnce(&TaskManagerImpl::OnReceivedMemoryDump,
606 weak_ptr_factory_.GetWeakPtr());
607 memory_instrumentation::MemoryInstrumentation::GetInstance()
608 ->RequestPrivateMemoryFootprint(base::kNullProcessId,
609 std::move(callback));
610 }
611
612 if (TaskManagerObserver::IsResourceRefreshEnabled(
613 REFRESH_TYPE_NETWORK_USAGE, enabled_resources_flags())) {
614 content::GetNetworkService()->GetTotalNetworkUsages(
615 base::BindOnce(&TaskManagerImpl::OnTotalNetworkUsages,
616 weak_ptr_factory_.GetWeakPtr()));
617 }
618
619 for (auto& groups_itr : task_groups_by_proc_id_) {
620 groups_itr.second->Refresh(gpu_memory_stats_,
621 GetCurrentRefreshTime(),
622 enabled_resources_flags());
623 }
624
625 for (auto& groups_itr : arc_vm_task_groups_by_proc_id_) {
626 groups_itr.second->Refresh(gpu_memory_stats_, GetCurrentRefreshTime(),
627 enabled_resources_flags());
628 }
629
630 #if defined(OS_CHROMEOS)
631 if (TaskManagerObserver::IsResourceRefreshEnabled(
632 REFRESH_TYPE_MEMORY_FOOTPRINT, enabled_resources_flags())) {
633 arc_shared_sampler_->Refresh();
634 }
635 #endif // defined(OS_CHROMEOS)
636
637 NotifyObserversOnRefresh(GetTaskIdsList());
638 }
639
StartUpdating()640 void TaskManagerImpl::StartUpdating() {
641 if (is_running_)
642 return;
643
644 is_running_ = true;
645
646 for (const auto& provider : task_providers_)
647 provider->SetObserver(this);
648
649 // Kick off fetch of asynchronous data, e.g., memory footprint, so that it
650 // will be displayed sooner after opening the task manager.
651 Refresh();
652 }
653
StopUpdating()654 void TaskManagerImpl::StopUpdating() {
655 if (!is_running_)
656 return;
657
658 is_running_ = false;
659
660 for (const auto& provider : task_providers_)
661 provider->ClearObserver();
662
663 task_groups_by_proc_id_.clear();
664 arc_vm_task_groups_by_proc_id_.clear();
665 task_groups_by_task_id_.clear();
666 sorted_task_ids_.clear();
667 }
668
GetTaskByRoute(int child_id,int route_id) const669 Task* TaskManagerImpl::GetTaskByRoute(int child_id, int route_id) const {
670 for (const auto& task_provider : task_providers_) {
671 Task* task = task_provider->GetTaskOfUrlRequest(child_id, route_id);
672 if (task)
673 return task;
674 }
675 return nullptr;
676 }
677
UpdateTasksWithBytesTransferred(const BytesTransferredKey & key,const BytesTransferredParam & param)678 bool TaskManagerImpl::UpdateTasksWithBytesTransferred(
679 const BytesTransferredKey& key,
680 const BytesTransferredParam& param) {
681 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
682
683 Task* task = GetTaskByRoute(key.child_id, key.route_id);
684 if (task) {
685 task->OnNetworkBytesRead(param.byte_read_count);
686 task->OnNetworkBytesSent(param.byte_sent_count);
687 return true;
688 }
689
690 // Couldn't match the bytes to any existing task.
691 return false;
692 }
693
GetTaskGroupByTaskId(TaskId task_id) const694 TaskGroup* TaskManagerImpl::GetTaskGroupByTaskId(TaskId task_id) const {
695 auto it = task_groups_by_task_id_.find(task_id);
696 DCHECK(it != task_groups_by_task_id_.end());
697 return it->second;
698 }
699
GetTaskByTaskId(TaskId task_id) const700 Task* TaskManagerImpl::GetTaskByTaskId(TaskId task_id) const {
701 return GetTaskGroupByTaskId(task_id)->GetTaskById(task_id);
702 }
703
OnTaskGroupBackgroundCalculationsDone()704 void TaskManagerImpl::OnTaskGroupBackgroundCalculationsDone() {
705 for (const auto& groups_itr : task_groups_by_proc_id_) {
706 if (!groups_itr.second->AreBackgroundCalculationsDone())
707 return;
708 }
709 NotifyObserversOnRefreshWithBackgroundCalculations(GetTaskIdsList());
710 for (const auto& groups_itr : task_groups_by_proc_id_)
711 groups_itr.second->ClearCurrentBackgroundCalculationsFlags();
712 }
713
714 } // namespace task_manager
715