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/process/arc_process_service.h"
11 
12 #include <algorithm>
13 #include <set>
14 #include <string>
15 #include <unordered_map>
16 #include <unordered_set>
17 #include <utility>
18 
19 #include "base/bind.h"
20 #include "base/containers/flat_set.h"
21 #include "base/containers/queue.h"
22 #include "base/logging.h"
23 #include "base/memory/scoped_refptr.h"
24 #include "base/memory/singleton.h"
25 #include "base/process/process.h"
26 #include "base/process/process_iterator.h"
27 #include "base/stl_util.h"
28 #include "base/task/post_task.h"
29 #include "base/task/task_traits.h"
30 #include "base/task/thread_pool.h"
31 #include "base/task_runner_util.h"
32 #include "base/time/time.h"
33 #include "base/trace_event/trace_event.h"
34 #include "chrome/browser/chromeos/process_snapshot_server.h"
35 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
36 #include "components/arc/arc_util.h"
37 #include "components/arc/mojom/process.mojom.h"
38 #include "components/arc/session/arc_bridge_service.h"
39 #include "content/public/browser/browser_thread.h"
40 
41 namespace arc {
42 
43 using base::kNullProcessId;
44 using base::Process;
45 using base::ProcessId;
46 using std::vector;
47 
48 namespace {
49 
50 static constexpr char kInitName[] = "/init";
51 static constexpr bool kNotFocused = false;
52 static constexpr int64_t kNoActivityTimeInfo = 0L;
53 
54 // Matches the process name "/init" in the process tree and get the
55 // corresponding process ID.
GetArcInitProcessId(const base::ProcessIterator::ProcessEntries & entry_list)56 base::ProcessId GetArcInitProcessId(
57     const base::ProcessIterator::ProcessEntries& entry_list) {
58   for (const base::ProcessEntry& entry : entry_list) {
59     if (entry.cmd_line_args().empty()) {
60       continue;
61     }
62     // TODO(nya): Add more constraints to avoid mismatches.
63     const std::string& process_name = entry.cmd_line_args()[0];
64     if (process_name == kInitName) {
65       return entry.pid();
66     }
67   }
68   return base::kNullProcessId;
69 }
70 
GetArcSystemProcessList(const base::ProcessIterator::ProcessEntries & process_list)71 std::vector<ArcProcess> GetArcSystemProcessList(
72     const base::ProcessIterator::ProcessEntries& process_list) {
73   TRACE_EVENT0("browser", "GetArcSystemProcessList");
74   std::vector<ArcProcess> ret_processes;
75   if (arc::IsArcVmEnabled()) {
76     // TODO(b/122992194): Fix this for ARCVM.
77     return ret_processes;
78   }
79 
80   const base::ProcessId arc_init_pid = GetArcInitProcessId(process_list);
81 
82   if (arc_init_pid == base::kNullProcessId) {
83     return ret_processes;
84   }
85 
86   // Enumerate the child processes of ARC init for gathering ARC System
87   // Processes.
88   for (const base::ProcessEntry& entry : process_list) {
89     if (entry.cmd_line_args().empty()) {
90       continue;
91     }
92     // TODO(hctsai): For now, we only gather direct child process of init, need
93     // to get the processes below. For example, installd might fork dex2oat and
94     // it can be executed for minutes.
95     if (entry.parent_pid() == arc_init_pid) {
96       const base::ProcessId child_pid = entry.pid();
97       const base::ProcessId child_nspid =
98           base::Process(child_pid).GetPidInNamespace();
99       if (child_nspid != base::kNullProcessId) {
100         const std::string& process_name = entry.cmd_line_args()[0];
101         // The is_focused and last_activity_time is not needed thus mocked
102         ret_processes.emplace_back(child_nspid, child_pid, process_name,
103                                    mojom::ProcessState::PERSISTENT, kNotFocused,
104                                    kNoActivityTimeInfo);
105       }
106     }
107   }
108   return ret_processes;
109 }
110 
UpdateNspidToPidMap(const base::ProcessIterator::ProcessEntries & process_list,scoped_refptr<ArcProcessService::NSPidToPidMap> pid_map)111 void UpdateNspidToPidMap(
112     const base::ProcessIterator::ProcessEntries& process_list,
113     scoped_refptr<ArcProcessService::NSPidToPidMap> pid_map) {
114   TRACE_EVENT0("browser", "ArcProcessService::UpdateNspidToPidMap");
115 
116   // NB: |process_list| may have inconsistent information because the
117   // ProcessSnapshotServer gets them by simply walking procfs. Especially
118   // we must not assume the parent-child relationships are consistent.
119 
120   // Construct the process tree.
121   // NB: This can contain a loop in case of race conditions.
122   std::unordered_map<ProcessId, std::vector<ProcessId>> process_tree;
123   for (const base::ProcessEntry& entry : process_list)
124     process_tree[entry.parent_pid()].push_back(entry.pid());
125 
126   ProcessId arc_init_pid = GetArcInitProcessId(process_list);
127 
128   // Enumerate all processes under ARC init and create nspid -> pid map.
129   if (arc_init_pid != kNullProcessId) {
130     base::queue<ProcessId> queue;
131     std::unordered_set<ProcessId> visited;
132     queue.push(arc_init_pid);
133     while (!queue.empty()) {
134       ProcessId pid = queue.front();
135       queue.pop();
136       // Do not visit the same process twice. Otherwise we may enter an infinite
137       // loop if |process_tree| contains a loop.
138       if (!visited.insert(pid).second)
139         continue;
140 
141       const ProcessId nspid = base::Process(pid).GetPidInNamespace();
142 
143       // All ARC processes should be in namespace so nspid is usually non-null,
144       // but this can happen if the process has already gone.
145       // Only add processes we're interested in (those appear as keys in
146       // |pid_map|).
147       if (nspid != kNullProcessId && pid_map->find(nspid) != pid_map->end())
148         (*pid_map)[nspid] = pid;
149 
150       for (ProcessId child_pid : process_tree[pid])
151         queue.push(child_pid);
152     }
153   }
154 }
155 
FilterProcessList(const ArcProcessService::NSPidToPidMap & pid_map,std::vector<mojom::RunningAppProcessInfoPtr> processes)156 std::vector<ArcProcess> FilterProcessList(
157     const ArcProcessService::NSPidToPidMap& pid_map,
158     std::vector<mojom::RunningAppProcessInfoPtr> processes) {
159   std::vector<ArcProcess> ret_processes;
160   for (const auto& entry : processes) {
161     base::ProcessId pid;
162     if (arc::IsArcVmEnabled()) {
163       // When VM is enabled, there is no external pid. Set the pid here to the
164       // guest pid. Setting the pid to zero was considered but the task manager
165       // groups tasks by pid and this can cause incorrect aggregated stats to
166       // be displayed. The task manager will handle these cases by checking if
167       // the task is in VM (via Task::IsRunningInVM) and know to partition off
168       // these processes.
169       pid = entry->pid;
170     } else {
171       const auto it = pid_map.find(entry->pid);
172       // The nspid could be missing due to race condition. For example, the
173       // process is still running when we get the process snapshot and ends when
174       // we update the nspid to pid mapping.
175       if (it == pid_map.end() || it->second == base::kNullProcessId) {
176         continue;
177       }
178       pid = it->second;
179     }
180     // Constructs the ArcProcess instance if the mapping is found.
181     ArcProcess arc_process(entry->pid, pid, entry->process_name,
182                            entry->process_state, entry->is_focused,
183                            entry->last_activity_time);
184     // |entry->packages| is provided only when process.mojom's verion is >=4.
185     if (entry->packages) {
186       for (const auto& package : *entry->packages) {
187         arc_process.packages().push_back(package);
188       }
189     }
190     ret_processes.push_back(std::move(arc_process));
191   }
192   return ret_processes;
193 }
194 
UpdateAndReturnProcessList(const base::ProcessIterator::ProcessEntries & process_list,scoped_refptr<ArcProcessService::NSPidToPidMap> nspid_map,std::vector<mojom::RunningAppProcessInfoPtr> processes)195 std::vector<ArcProcess> UpdateAndReturnProcessList(
196     const base::ProcessIterator::ProcessEntries& process_list,
197     scoped_refptr<ArcProcessService::NSPidToPidMap> nspid_map,
198     std::vector<mojom::RunningAppProcessInfoPtr> processes) {
199   ArcProcessService::NSPidToPidMap& pid_map = *nspid_map;
200   if (!arc::IsArcVmEnabled()) {
201     // Cleanup dead pids in the cache |pid_map|.
202     std::unordered_set<ProcessId> nspid_to_remove;
203     for (const auto& entry : pid_map) {
204       nspid_to_remove.insert(entry.first);
205     }
206     bool unmapped_nspid = false;
207     for (const auto& entry : processes) {
208       // erase() returns 0 if coudln't find the key. It means a new process.
209       if (nspid_to_remove.erase(entry->pid) == 0) {
210         pid_map[entry->pid] = base::kNullProcessId;
211         unmapped_nspid = true;
212       }
213     }
214     for (const auto& entry : nspid_to_remove) {
215       pid_map.erase(entry);
216     }
217 
218     // The operation is costly so avoid calling it when possible.
219     if (unmapped_nspid) {
220       UpdateNspidToPidMap(process_list, nspid_map);
221     }
222   }
223 
224   return FilterProcessList(pid_map, std::move(processes));
225 }
226 
UpdateAndReturnMemoryInfo(const base::ProcessIterator::ProcessEntries & process_list,scoped_refptr<ArcProcessService::NSPidToPidMap> nspid_map,std::vector<mojom::ArcMemoryDumpPtr> process_dumps)227 std::vector<mojom::ArcMemoryDumpPtr> UpdateAndReturnMemoryInfo(
228     const base::ProcessIterator::ProcessEntries& process_list,
229     scoped_refptr<ArcProcessService::NSPidToPidMap> nspid_map,
230     std::vector<mojom::ArcMemoryDumpPtr> process_dumps) {
231   if (!arc::IsArcVmEnabled()) {
232     ArcProcessService::NSPidToPidMap& pid_map = *nspid_map;
233     // Cleanup dead processes in pid_map
234     base::flat_set<ProcessId> nspid_to_remove;
235     for (const auto& entry : pid_map)
236       nspid_to_remove.insert(entry.first);
237 
238     bool unmapped_nspid = false;
239     for (const auto& proc : process_dumps) {
240       // erase() returns 0 if couldn't find the key (new process)
241       if (nspid_to_remove.erase(proc->pid) == 0) {
242         pid_map[proc->pid] = base::kNullProcessId;
243         unmapped_nspid = true;
244       }
245     }
246     for (const auto& old_nspid : nspid_to_remove)
247       pid_map.erase(old_nspid);
248 
249     if (unmapped_nspid)
250       UpdateNspidToPidMap(process_list, nspid_map);
251 
252     // Return memory info only for processes that have a mapping nspid->pid
253     for (auto& proc : process_dumps) {
254       auto it = pid_map.find(proc->pid);
255       proc->pid = it == pid_map.end() ? kNullProcessId : it->second;
256     }
257     base::EraseIf(process_dumps,
258                   [](const auto& proc) { return proc->pid == kNullProcessId; });
259   }
260   return process_dumps;
261 }
262 
Reset(scoped_refptr<ArcProcessService::NSPidToPidMap> pid_map)263 void Reset(scoped_refptr<ArcProcessService::NSPidToPidMap> pid_map) {
264   if (pid_map.get())
265     pid_map->clear();
266 }
267 
268 // Singleton factory for ArcProcessService.
269 class ArcProcessServiceFactory
270     : public internal::ArcBrowserContextKeyedServiceFactoryBase<
271           ArcProcessService,
272           ArcProcessServiceFactory> {
273  public:
274   // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
275   static constexpr const char* kName = "ArcProcessServiceFactory";
276 
GetInstance()277   static ArcProcessServiceFactory* GetInstance() {
278     return base::Singleton<ArcProcessServiceFactory>::get();
279   }
280 
281  private:
282   friend base::DefaultSingletonTraits<ArcProcessServiceFactory>;
283   ArcProcessServiceFactory() = default;
284   ~ArcProcessServiceFactory() override = default;
285 };
286 
287 }  // namespace
288 
289 // static
GetForBrowserContext(content::BrowserContext * context)290 ArcProcessService* ArcProcessService::GetForBrowserContext(
291     content::BrowserContext* context) {
292   return ArcProcessServiceFactory::GetForBrowserContext(context);
293 }
294 
ArcProcessService(content::BrowserContext * context,ArcBridgeService * bridge_service)295 ArcProcessService::ArcProcessService(content::BrowserContext* context,
296                                      ArcBridgeService* bridge_service)
297     : ProcessSnapshotServer::Observer(kProcessSnapshotRefreshTime),
298       arc_bridge_service_(bridge_service),
299       task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
300           {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
301            base::TaskPriority::USER_VISIBLE})),
302       nspid_to_pid_(new NSPidToPidMap()) {
303   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
304   arc_bridge_service_->process()->AddObserver(this);
305 }
306 
~ArcProcessService()307 ArcProcessService::~ArcProcessService() {
308   arc_bridge_service_->process()->RemoveObserver(this);
309   if (is_observing_process_snapshot_)
310     ProcessSnapshotServer::Get()->RemoveObserver(this);
311 }
312 
313 // static
314 constexpr base::TimeDelta ArcProcessService::kProcessSnapshotRefreshTime;
315 
316 // static
Get()317 ArcProcessService* ArcProcessService::Get() {
318   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
319   // This is called from TaskManager implementation, which is isolated
320   // from BrowserContext.
321   // Use ArcServiceManager's BrowserContext instance, since 1) it is always
322   // allowed to use ARC, and 2) the rest of ARC service's lifetime are
323   // tied to it.
324   auto* arc_service_manager = ArcServiceManager::Get();
325   if (!arc_service_manager || !arc_service_manager->browser_context())
326     return nullptr;
327   return GetForBrowserContext(arc_service_manager->browser_context());
328 }
329 
RequestAppProcessList(RequestProcessListCallback callback)330 void ArcProcessService::RequestAppProcessList(
331     RequestProcessListCallback callback) {
332   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
333   HandleRequest(
334       base::BindOnce(&ArcProcessService::ContinueAppProcessListRequest,
335                      base::Unretained(this), std::move(callback)));
336 }
337 
RequestSystemProcessList(RequestProcessListCallback callback)338 void ArcProcessService::RequestSystemProcessList(
339     RequestProcessListCallback callback) {
340   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
341   HandleRequest(
342       base::BindOnce(&ArcProcessService::ContinueSystemProcessListRequest,
343                      base::Unretained(this), std::move(callback)));
344 }
345 
RequestAppMemoryInfo(RequestMemoryInfoCallback callback)346 void ArcProcessService::RequestAppMemoryInfo(
347     RequestMemoryInfoCallback callback) {
348   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
349   HandleRequest(base::BindOnce(&ArcProcessService::ContinueAppMemoryInfoRequest,
350                                base::Unretained(this), std::move(callback)));
351 }
352 
RequestSystemMemoryInfo(RequestMemoryInfoCallback callback)353 void ArcProcessService::RequestSystemMemoryInfo(
354     RequestMemoryInfoCallback callback) {
355   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
356   HandleRequest(
357       base::BindOnce(&ArcProcessService::ContinueSystemMemoryInfoRequest,
358                      base::Unretained(this), std::move(callback)));
359 }
360 
OnProcessSnapshotRefreshed(const base::ProcessIterator::ProcessEntries & snapshot)361 void ArcProcessService::OnProcessSnapshotRefreshed(
362     const base::ProcessIterator::ProcessEntries& snapshot) {
363   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
364   cached_process_snapshot_ = snapshot;
365   last_process_snapshot_time_ = base::Time::Now();
366 
367   // Handle any pending requests.
368   while (!pending_requests_.empty()) {
369     std::move(pending_requests_.front()).Run();
370     pending_requests_.pop();
371   }
372 }
373 
OnReceiveProcessList(RequestProcessListCallback callback,std::vector<mojom::RunningAppProcessInfoPtr> processes)374 void ArcProcessService::OnReceiveProcessList(
375     RequestProcessListCallback callback,
376     std::vector<mojom::RunningAppProcessInfoPtr> processes) {
377   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
378   base::PostTaskAndReplyWithResult(
379       task_runner_.get(), FROM_HERE,
380       base::BindOnce(&UpdateAndReturnProcessList, cached_process_snapshot_,
381                      nspid_to_pid_, std::move(processes)),
382       std::move(callback));
383 
384   MaybeStopObservingProcessSnapshots();
385 }
386 
OnReceiveMemoryInfo(RequestMemoryInfoCallback callback,std::vector<mojom::ArcMemoryDumpPtr> process_dumps)387 void ArcProcessService::OnReceiveMemoryInfo(
388     RequestMemoryInfoCallback callback,
389     std::vector<mojom::ArcMemoryDumpPtr> process_dumps) {
390   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
391   base::PostTaskAndReplyWithResult(
392       task_runner_.get(), FROM_HERE,
393       base::BindOnce(&UpdateAndReturnMemoryInfo, cached_process_snapshot_,
394                      nspid_to_pid_, std::move(process_dumps)),
395       std::move(callback));
396 
397   MaybeStopObservingProcessSnapshots();
398 }
399 
OnGetSystemProcessList(RequestMemoryInfoCallback callback,std::vector<ArcProcess> procs)400 void ArcProcessService::OnGetSystemProcessList(
401     RequestMemoryInfoCallback callback,
402     std::vector<ArcProcess> procs) {
403   mojom::ProcessInstance* process_instance = ARC_GET_INSTANCE_FOR_METHOD(
404       arc_bridge_service_->process(), RequestSystemProcessMemoryInfo);
405   if (!process_instance) {
406     LOG(ERROR) << "could not find method / get ProcessInstance";
407     return;
408   }
409   std::vector<uint32_t> nspids;
410   if (!arc::IsArcVmEnabled()) {
411     for (const auto& proc : procs)
412       nspids.push_back(proc.nspid());
413   }
414   // TODO(b/122992194): Fix this for ARCVM.
415   process_instance->RequestSystemProcessMemoryInfo(
416       nspids,
417       base::BindOnce(&ArcProcessService::OnReceiveMemoryInfo,
418                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
419 }
420 
OnConnectionReady()421 void ArcProcessService::OnConnectionReady() {
422   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
423   task_runner_->PostTask(FROM_HERE, base::BindOnce(&Reset, nspid_to_pid_));
424   connection_ready_ = true;
425 }
426 
OnConnectionClosed()427 void ArcProcessService::OnConnectionClosed() {
428   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
429   connection_ready_ = false;
430 }
431 
CanUseStaleProcessSnapshot() const432 bool ArcProcessService::CanUseStaleProcessSnapshot() const {
433   return base::Time::Now() - last_process_snapshot_time_ <=
434          kProcessSnapshotRefreshTime;
435 }
436 
MaybeStopObservingProcessSnapshots()437 void ArcProcessService::MaybeStopObservingProcessSnapshots() {
438   if (!is_observing_process_snapshot_)
439     return;
440 
441   // We can stop observing the ProcessSnapshotServer only if there are no more
442   // pending requests, and we have a recent enough |cached_process_snapshot_|.
443   const bool should_stop_observing =
444       pending_requests_.empty() && CanUseStaleProcessSnapshot();
445   if (!should_stop_observing)
446     return;
447 
448   ProcessSnapshotServer::Get()->RemoveObserver(this);
449   is_observing_process_snapshot_ = false;
450 }
451 
HandleRequest(base::OnceClosure request)452 void ArcProcessService::HandleRequest(base::OnceClosure request) {
453   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
454 
455   if (CanUseStaleProcessSnapshot()) {
456     // Handle the request immediately.
457     std::move(request).Run();
458     return;
459   }
460 
461   // We have a too stale |cached_process_snapshot_|, therefore request a fresher
462   // one by observing the ProcessSnapshotServer, and add |request| to the
463   // pending requests.
464   if (!is_observing_process_snapshot_) {
465     ProcessSnapshotServer::Get()->AddObserver(this);
466     is_observing_process_snapshot_ = true;
467   }
468 
469   pending_requests_.push(std::move(request));
470 }
471 
ContinueAppProcessListRequest(RequestProcessListCallback callback)472 void ArcProcessService::ContinueAppProcessListRequest(
473     RequestProcessListCallback callback) {
474   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
475   // Since several services call this class to get information about the ARC
476   // process list, it can produce a lot of logspam when the board is ARC-ready
477   // but the user has not opted into ARC. This redundant check avoids that
478   // logspam.
479   if (!connection_ready_) {
480     std::move(callback).Run(base::nullopt);
481     return;
482   }
483 
484   mojom::ProcessInstance* process_instance = ARC_GET_INSTANCE_FOR_METHOD(
485       arc_bridge_service_->process(), RequestProcessList);
486   if (!process_instance) {
487     std::move(callback).Run(base::nullopt);
488     return;
489   }
490 
491   process_instance->RequestProcessList(
492       base::BindOnce(&ArcProcessService::OnReceiveProcessList,
493                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
494 }
495 
ContinueSystemProcessListRequest(RequestProcessListCallback callback)496 void ArcProcessService::ContinueSystemProcessListRequest(
497     RequestProcessListCallback callback) {
498   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
499   base::PostTaskAndReplyWithResult(
500       task_runner_.get(), FROM_HERE,
501       base::BindOnce(&GetArcSystemProcessList, cached_process_snapshot_),
502       std::move(callback));
503 
504   MaybeStopObservingProcessSnapshots();
505 }
506 
ContinueAppMemoryInfoRequest(RequestMemoryInfoCallback callback)507 void ArcProcessService::ContinueAppMemoryInfoRequest(
508     RequestMemoryInfoCallback callback) {
509   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
510   if (!connection_ready_) {
511     std::move(callback).Run({});
512     return;
513   }
514 
515   mojom::ProcessInstance* process_instance = ARC_GET_INSTANCE_FOR_METHOD(
516       arc_bridge_service_->process(), RequestApplicationProcessMemoryInfo);
517   if (!process_instance) {
518     LOG(ERROR) << "could not find method / get ProcessInstance";
519     std::move(callback).Run({});
520     return;
521   }
522 
523   process_instance->RequestApplicationProcessMemoryInfo(
524       base::BindOnce(&ArcProcessService::OnReceiveMemoryInfo,
525                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
526   return;
527 }
528 
ContinueSystemMemoryInfoRequest(RequestMemoryInfoCallback callback)529 void ArcProcessService::ContinueSystemMemoryInfoRequest(
530     RequestMemoryInfoCallback callback) {
531   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
532   if (!connection_ready_) {
533     std::move(callback).Run({});
534     return;
535   }
536 
537   base::PostTaskAndReplyWithResult(
538       task_runner_.get(), FROM_HERE,
539       base::BindOnce(&GetArcSystemProcessList, cached_process_snapshot_),
540       base::BindOnce(&ArcProcessService::OnGetSystemProcessList,
541                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
542 }
543 
544 // -----------------------------------------------------------------------------
545 // ArcProcessService::NSPidToPidMap:
546 
547 inline ArcProcessService::NSPidToPidMap::NSPidToPidMap() = default;
548 
549 inline ArcProcessService::NSPidToPidMap::~NSPidToPidMap() = default;
550 
551 }  // namespace arc
552