Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(408)

Side by Side Diff: chrome/browser/chromeos/arc/arc_process_service.cc

Issue 2441563002: arc: Create intermediate directories in c/b/c/arc (Closed)
Patch Set: Re-rebase to ToT Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 // The main point of this class is to cache ARC proc nspid<->pid mapping
6 // globally. Since the calculation is costly, a dedicated worker thread is
7 // used. All read/write of its internal data structure (i.e., the mapping)
8 // should be on this thread.
9
10 #include "chrome/browser/chromeos/arc/arc_process_service.h"
11
12 #include <algorithm>
13 #include <queue>
14 #include <string>
15 #include <unordered_map>
16 #include <unordered_set>
17 #include <utility>
18
19 #include "base/callback.h"
20 #include "base/logging.h"
21 #include "base/process/process.h"
22 #include "base/process/process_iterator.h"
23 #include "base/task_runner_util.h"
24 #include "base/trace_event/trace_event.h"
25 #include "components/arc/arc_bridge_service.h"
26 #include "content/public/browser/browser_thread.h"
27
28 namespace arc {
29
30 using base::kNullProcessId;
31 using base::Process;
32 using base::ProcessId;
33 using base::SequencedWorkerPool;
34 using std::vector;
35
36 namespace {
37
38 // Weak pointer. This class is owned by ArcServiceManager.
39 ArcProcessService* g_arc_process_service = nullptr;
40 static constexpr char kInitName[] = "/init";
41 static constexpr bool kNotFocused = false;
42 static constexpr int64_t kNoActivityTimeInfo = 0L;
43
44 // Matches the process name "/init" in the process tree and get the
45 // corresponding process ID.
46 base::ProcessId GetArcInitProcessId(
47 const base::ProcessIterator::ProcessEntries& entry_list) {
48 for (const base::ProcessEntry& entry : entry_list) {
49 if (entry.cmd_line_args().empty()) {
50 continue;
51 }
52 // TODO(nya): Add more constraints to avoid mismatches.
53 const std::string& process_name = entry.cmd_line_args()[0];
54 if (process_name == kInitName) {
55 return entry.pid();
56 }
57 }
58 return base::kNullProcessId;
59 }
60
61 std::vector<ArcProcess> GetArcSystemProcessList() {
62 std::vector<ArcProcess> ret_processes;
63 const base::ProcessIterator::ProcessEntries& entry_list =
64 base::ProcessIterator(nullptr).Snapshot();
65 const base::ProcessId arc_init_pid = GetArcInitProcessId(entry_list);
66
67 if (arc_init_pid == base::kNullProcessId) {
68 return ret_processes;
69 }
70
71 // Enumerate the child processes of ARC init for gathering ARC System
72 // Processes.
73 for (const base::ProcessEntry& entry : entry_list) {
74 if (entry.cmd_line_args().empty()) {
75 continue;
76 }
77 // TODO(hctsai): For now, we only gather direct child process of init, need
78 // to get the processes below. For example, installd might fork dex2oat and
79 // it can be executed for minutes.
80 if (entry.parent_pid() == arc_init_pid) {
81 const base::ProcessId child_pid = entry.pid();
82 const base::ProcessId child_nspid =
83 base::Process(child_pid).GetPidInNamespace();
84 if (child_nspid != base::kNullProcessId) {
85 const std::string& process_name = entry.cmd_line_args()[0];
86 // The is_focused and last_activity_time is not needed thus mocked
87 ret_processes.emplace_back(child_nspid, child_pid, process_name,
88 mojom::ProcessState::PERSISTENT, kNotFocused,
89 kNoActivityTimeInfo);
90 }
91 }
92 }
93 return ret_processes;
94 }
95
96 void UpdateNspidToPidMap(
97 scoped_refptr<ArcProcessService::NSPidToPidMap> pid_map) {
98 TRACE_EVENT0("browser", "ArcProcessService::UpdateNspidToPidMap");
99
100 // NB: Despite of its name, ProcessIterator::Snapshot() may return
101 // inconsistent information because it simply walks procfs. Especially
102 // we must not assume the parent-child relationships are consistent.
103 const base::ProcessIterator::ProcessEntries& entry_list =
104 base::ProcessIterator(nullptr).Snapshot();
105
106 // Construct the process tree.
107 // NB: This can contain a loop in case of race conditions.
108 std::unordered_map<ProcessId, std::vector<ProcessId>> process_tree;
109 for (const base::ProcessEntry& entry : entry_list)
110 process_tree[entry.parent_pid()].push_back(entry.pid());
111
112 ProcessId arc_init_pid = GetArcInitProcessId(entry_list);
113
114 // Enumerate all processes under ARC init and create nspid -> pid map.
115 if (arc_init_pid != kNullProcessId) {
116 std::queue<ProcessId> queue;
117 std::unordered_set<ProcessId> visited;
118 queue.push(arc_init_pid);
119 while (!queue.empty()) {
120 ProcessId pid = queue.front();
121 queue.pop();
122 // Do not visit the same process twice. Otherwise we may enter an infinite
123 // loop if |process_tree| contains a loop.
124 if (!visited.insert(pid).second)
125 continue;
126
127 const ProcessId nspid = base::Process(pid).GetPidInNamespace();
128
129 // All ARC processes should be in namespace so nspid is usually non-null,
130 // but this can happen if the process has already gone.
131 // Only add processes we're interested in (those appear as keys in
132 // |pid_map|).
133 if (nspid != kNullProcessId && pid_map->find(nspid) != pid_map->end())
134 (*pid_map)[nspid] = pid;
135
136 for (ProcessId child_pid : process_tree[pid])
137 queue.push(child_pid);
138 }
139 }
140 }
141
142 std::vector<ArcProcess> FilterProcessList(
143 const ArcProcessService::NSPidToPidMap& pid_map,
144 mojo::Array<mojom::RunningAppProcessInfoPtr> processes) {
145 std::vector<ArcProcess> ret_processes;
146 for (const auto& entry : processes) {
147 const auto it = pid_map.find(entry->pid);
148 // The nspid could be missing due to race condition. For example, the
149 // process is still running when we get the process snapshot and ends when
150 // we update the nspid to pid mapping.
151 if (it == pid_map.end() || it->second == base::kNullProcessId) {
152 continue;
153 }
154 // Constructs the ArcProcess instance if the mapping is found.
155 ArcProcess arc_process(entry->pid, pid_map.at(entry->pid),
156 entry->process_name, entry->process_state,
157 entry->is_focused, entry->last_activity_time);
158 // |entry->packages| is provided only when process.mojom's verion is >=4.
159 if (entry->packages) {
160 for (const auto& package : entry->packages) {
161 arc_process.packages().push_back(package.get());
162 }
163 }
164 ret_processes.push_back(std::move(arc_process));
165 }
166 return ret_processes;
167 }
168
169 std::vector<ArcProcess> UpdateAndReturnProcessList(
170 scoped_refptr<ArcProcessService::NSPidToPidMap> nspid_map,
171 mojo::Array<mojom::RunningAppProcessInfoPtr> processes) {
172 ArcProcessService::NSPidToPidMap& pid_map = *nspid_map;
173 // Cleanup dead pids in the cache |pid_map|.
174 std::unordered_set<ProcessId> nspid_to_remove;
175 for (const auto& entry : pid_map) {
176 nspid_to_remove.insert(entry.first);
177 }
178 bool unmapped_nspid = false;
179 for (const auto& entry : processes) {
180 // erase() returns 0 if coudln't find the key. It means a new process.
181 if (nspid_to_remove.erase(entry->pid) == 0) {
182 pid_map[entry->pid] = base::kNullProcessId;
183 unmapped_nspid = true;
184 }
185 }
186 for (const auto& entry : nspid_to_remove) {
187 pid_map.erase(entry);
188 }
189
190 // The operation is costly so avoid calling it when possible.
191 if (unmapped_nspid) {
192 UpdateNspidToPidMap(nspid_map);
193 }
194
195 return FilterProcessList(pid_map, std::move(processes));
196 }
197
198 void Reset(scoped_refptr<ArcProcessService::NSPidToPidMap> pid_map) {
199 if (pid_map.get())
200 pid_map->clear();
201 }
202
203 } // namespace
204
205 ArcProcessService::ArcProcessService(ArcBridgeService* bridge_service)
206 : ArcService(bridge_service),
207 heavy_task_thread_("ArcProcessServiceThread"),
208 nspid_to_pid_(new NSPidToPidMap()),
209 weak_ptr_factory_(this) {
210 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
211 arc_bridge_service()->process()->AddObserver(this);
212 DCHECK(!g_arc_process_service);
213 g_arc_process_service = this;
214 heavy_task_thread_.Start();
215 }
216
217 ArcProcessService::~ArcProcessService() {
218 DCHECK(g_arc_process_service == this);
219 heavy_task_thread_.Stop();
220 g_arc_process_service = nullptr;
221 arc_bridge_service()->process()->RemoveObserver(this);
222 }
223
224 // static
225 ArcProcessService* ArcProcessService::Get() {
226 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
227 return g_arc_process_service;
228 }
229
230 void ArcProcessService::OnInstanceReady() {
231 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
232 GetTaskRunner()->PostTask(FROM_HERE, base::Bind(&Reset, nspid_to_pid_));
233 }
234
235 void ArcProcessService::RequestSystemProcessList(
236 RequestProcessListCallback callback) {
237 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
238
239 base::PostTaskAndReplyWithResult(GetTaskRunner().get(), FROM_HERE,
240 base::Bind(&GetArcSystemProcessList),
241 callback);
242 }
243
244 bool ArcProcessService::RequestAppProcessList(
245 RequestProcessListCallback callback) {
246 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
247
248 mojom::ProcessInstance* process_instance =
249 arc_bridge_service()->process()->GetInstanceForMethod(
250 "RequestProcessList");
251 if (!process_instance) {
252 return false;
253 }
254 process_instance->RequestProcessList(
255 base::Bind(&ArcProcessService::OnReceiveProcessList,
256 weak_ptr_factory_.GetWeakPtr(), callback));
257 return true;
258 }
259
260 void ArcProcessService::OnReceiveProcessList(
261 const RequestProcessListCallback& callback,
262 mojo::Array<mojom::RunningAppProcessInfoPtr> instance_processes) {
263 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
264
265 base::PostTaskAndReplyWithResult(
266 GetTaskRunner().get(), FROM_HERE,
267 base::Bind(&UpdateAndReturnProcessList, nspid_to_pid_,
268 base::Passed(&instance_processes)),
269 callback);
270 }
271
272 scoped_refptr<base::SingleThreadTaskRunner> ArcProcessService::GetTaskRunner() {
273 return heavy_task_thread_.task_runner();
274 }
275
276 inline ArcProcessService::NSPidToPidMap::NSPidToPidMap() {}
277
278 inline ArcProcessService::NSPidToPidMap::~NSPidToPidMap() {}
279
280 } // namespace arc
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/arc/arc_process_service.h ('k') | chrome/browser/chromeos/arc/arc_service_launcher.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698