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/providers/arc/arc_process_task_provider.h"
6 
7 #include <stddef.h>
8 
9 #include <queue>
10 #include <set>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/bind.h"
15 #include "base/callback.h"
16 #include "base/logging.h"
17 #include "base/process/process.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/trace_event/trace_event.h"
20 #include "chrome/browser/chromeos/arc/process/arc_process_service.h"
21 #include "components/arc/mojom/process.mojom.h"
22 
23 namespace task_manager {
24 
25 using std::set;
26 using arc::ArcProcess;
27 using base::Process;
28 using base::ProcessId;
29 
ArcProcessTaskProvider()30 ArcProcessTaskProvider::ArcProcessTaskProvider() : is_updating_(false) {}
31 
32 ArcProcessTaskProvider::~ArcProcessTaskProvider() = default;
33 
GetTaskOfUrlRequest(int child_id,int route_id)34 Task* ArcProcessTaskProvider::GetTaskOfUrlRequest(int child_id, int route_id) {
35   // ARC tasks are not associated with any URL request.
36   return nullptr;
37 }
38 
UpdateProcessList(ArcTaskMap * pid_to_task,std::vector<ArcProcess> processes)39 void ArcProcessTaskProvider::UpdateProcessList(
40     ArcTaskMap* pid_to_task,
41     std::vector<ArcProcess> processes) {
42   if (!is_updating_)
43     return;
44 
45   // NB: |processes| can be already stale here because it is sent via IPC, and
46   // we can never avoid that. See also the comment at the declaration of
47   // ArcProcessTaskProvider.
48 
49   set<ProcessId> nspid_to_remove;
50   for (const auto& entry : *pid_to_task)
51     nspid_to_remove.insert(entry.first);
52 
53   for (auto& entry : processes) {
54     if (nspid_to_remove.erase(entry.nspid()) == 0) {
55       // New arc process.
56       std::unique_ptr<ArcProcessTask>& task = (*pid_to_task)[entry.nspid()];
57       // After calling NotifyObserverTaskAdded(), the raw pointer of |task| is
58       // remebered somewhere else. One should not (implicitly) delete the
59       // referenced object before calling NotifyObserverTaskRemoved() first
60       // (crbug.com/587707).
61       DCHECK(!task.get()) <<
62           "Task with the same pid should not be added twice.";
63       task = std::make_unique<ArcProcessTask>(std::move(entry));
64       NotifyObserverTaskAdded(task.get());
65     } else {
66       // Update process state of existing process.
67       std::unique_ptr<ArcProcessTask>& task = (*pid_to_task)[entry.nspid()];
68       DCHECK(task.get());
69       task->SetProcessState(entry.process_state());
70     }
71   }
72 
73   for (const auto& entry : nspid_to_remove) {
74     // Stale arc process.
75     NotifyObserverTaskRemoved((*pid_to_task)[entry].get());
76     pid_to_task->erase(entry);
77   }
78 }
79 
OnUpdateAppProcessList(OptionalArcProcessList processes)80 void ArcProcessTaskProvider::OnUpdateAppProcessList(
81     OptionalArcProcessList processes) {
82   if (!processes) {
83     VLOG(2) << "ARC process instance is not ready.";
84     ScheduleNextAppRequest();
85     return;
86   }
87 
88   TRACE_EVENT0("browser", "ArcProcessTaskProvider::OnUpdateAppProcessList");
89   UpdateProcessList(&nspid_to_task_, std::move(*processes));
90   ScheduleNextAppRequest();
91 }
92 
OnUpdateSystemProcessList(OptionalArcProcessList processes)93 void ArcProcessTaskProvider::OnUpdateSystemProcessList(
94     OptionalArcProcessList processes) {
95   if (processes)
96     UpdateProcessList(&nspid_to_sys_task_, std::move(*processes));
97   ScheduleNextSystemRequest();
98 }
99 
RequestAppProcessList()100 void ArcProcessTaskProvider::RequestAppProcessList() {
101   arc::ArcProcessService* arc_process_service =
102       arc::ArcProcessService::Get();
103   if (!arc_process_service) {
104     VLOG(2) << "ARC process instance is not ready.";
105     ScheduleNextAppRequest();
106     return;
107   }
108 
109   auto callback =
110       base::BindOnce(&ArcProcessTaskProvider::OnUpdateAppProcessList,
111                      weak_ptr_factory_.GetWeakPtr());
112   arc_process_service->RequestAppProcessList(std::move(callback));
113 }
114 
RequestSystemProcessList()115 void ArcProcessTaskProvider::RequestSystemProcessList() {
116   arc::ArcProcessService* arc_process_service = arc::ArcProcessService::Get();
117   if (!arc_process_service) {
118     VLOG(2) << "ARC process instance is not ready.";
119     ScheduleNextSystemRequest();
120     return;
121   }
122 
123   auto callback =
124       base::BindOnce(&ArcProcessTaskProvider::OnUpdateSystemProcessList,
125                      weak_ptr_factory_.GetWeakPtr());
126   arc_process_service->RequestSystemProcessList(std::move(callback));
127 }
128 
StartUpdating()129 void ArcProcessTaskProvider::StartUpdating() {
130   is_updating_ = true;
131   RequestAppProcessList();
132   RequestSystemProcessList();
133 }
134 
StopUpdating()135 void ArcProcessTaskProvider::StopUpdating() {
136   is_updating_ = false;
137   weak_ptr_factory_.InvalidateWeakPtrs();
138   nspid_to_task_.clear();
139   nspid_to_sys_task_.clear();
140 }
141 
ScheduleNextRequest(base::OnceClosure task)142 void ArcProcessTaskProvider::ScheduleNextRequest(base::OnceClosure task) {
143   if (!is_updating_)
144     return;
145   // TODO(nya): Remove this timer once ARC starts to send us UpdateProcessList
146   // message when the process list changed. As of today, ARC does not send
147   // the process list unless we request it by RequestAppProcessList message.
148   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
149       FROM_HERE, std::move(task),
150       arc::ArcProcessService::kProcessSnapshotRefreshTime);
151 }
152 
ScheduleNextAppRequest()153 void ArcProcessTaskProvider::ScheduleNextAppRequest() {
154   ScheduleNextRequest(
155       base::BindOnce(&ArcProcessTaskProvider::RequestAppProcessList,
156                      weak_ptr_factory_.GetWeakPtr()));
157 }
158 
ScheduleNextSystemRequest()159 void ArcProcessTaskProvider::ScheduleNextSystemRequest() {
160   ScheduleNextRequest(
161       base::BindOnce(&ArcProcessTaskProvider::RequestSystemProcessList,
162                      weak_ptr_factory_.GetWeakPtr()));
163 }
164 
165 }  // namespace task_manager
166