1 // Copyright 2019 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 <memory>
6 #include <string>
7 #include <utility>
8 
9 #include "base/macros.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/no_destructor.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/synchronization/lock.h"
14 #include "content/browser/utility_process_host.h"
15 #include "content/common/child_process.mojom.h"
16 #include "content/public/browser/browser_task_traits.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/service_process_host.h"
19 #include "mojo/public/cpp/bindings/generic_pending_receiver.h"
20 #include "mojo/public/cpp/bindings/remote.h"
21 
22 namespace content {
23 
24 namespace {
25 
26 // Internal helper to track running service processes. Usage of this class is
27 // split across the IO thread and UI thread.
28 class ServiceProcessTracker {
29  public:
ServiceProcessTracker()30   ServiceProcessTracker() : ui_task_runner_(GetUIThreadTaskRunner({})) {}
31   ~ServiceProcessTracker() = default;
32 
AddProcess(const base::Process & process,const std::string & service_interface_name)33   ServiceProcessInfo AddProcess(const base::Process& process,
34                                 const std::string& service_interface_name) {
35     DCHECK_CURRENTLY_ON(BrowserThread::IO);
36     base::AutoLock lock(processes_lock_);
37     auto id = GenerateNextId();
38     ServiceProcessInfo& info = processes_[id];
39     info.service_process_id = id;
40     info.pid = process.Pid();
41     info.service_interface_name = service_interface_name;
42     ui_task_runner_->PostTask(
43         FROM_HERE,
44         base::BindOnce(&ServiceProcessTracker::NotifyLaunchOnUIThread,
45                        base::Unretained(this), info));
46     return info;
47   }
48 
NotifyTerminated(ServiceProcessId id)49   void NotifyTerminated(ServiceProcessId id) {
50     DCHECK_CURRENTLY_ON(BrowserThread::IO);
51     base::AutoLock lock(processes_lock_);
52     auto iter = processes_.find(id);
53     DCHECK(iter != processes_.end());
54     ui_task_runner_->PostTask(
55         FROM_HERE,
56         base::BindOnce(&ServiceProcessTracker::NotifyTerminatedOnUIThread,
57                        base::Unretained(this), iter->second));
58     processes_.erase(iter);
59   }
60 
NotifyCrashed(ServiceProcessId id)61   void NotifyCrashed(ServiceProcessId id) {
62     DCHECK_CURRENTLY_ON(BrowserThread::IO);
63     base::AutoLock lock(processes_lock_);
64     auto iter = processes_.find(id);
65     DCHECK(iter != processes_.end());
66     ui_task_runner_->PostTask(
67         FROM_HERE,
68         base::BindOnce(&ServiceProcessTracker::NotifyCrashedOnUIThread,
69                        base::Unretained(this), iter->second));
70     processes_.erase(iter);
71   }
72 
AddObserver(ServiceProcessHost::Observer * observer)73   void AddObserver(ServiceProcessHost::Observer* observer) {
74     DCHECK_CURRENTLY_ON(BrowserThread::UI);
75     observers_.AddObserver(observer);
76   }
77 
RemoveObserver(ServiceProcessHost::Observer * observer)78   void RemoveObserver(ServiceProcessHost::Observer* observer) {
79     // NOTE: Some tests may remove observers after BrowserThreads are shut down.
80     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
81            !BrowserThread::IsThreadInitialized(BrowserThread::UI));
82     observers_.RemoveObserver(observer);
83   }
84 
GetProcesses()85   std::vector<ServiceProcessInfo> GetProcesses() {
86     DCHECK_CURRENTLY_ON(BrowserThread::UI);
87     base::AutoLock lock(processes_lock_);
88     std::vector<ServiceProcessInfo> processes;
89     for (const auto& entry : processes_)
90       processes.push_back(entry.second);
91     return processes;
92   }
93 
94  private:
NotifyLaunchOnUIThread(const content::ServiceProcessInfo & info)95   void NotifyLaunchOnUIThread(const content::ServiceProcessInfo& info) {
96     for (auto& observer : observers_)
97       observer.OnServiceProcessLaunched(info);
98   }
99 
NotifyTerminatedOnUIThread(const content::ServiceProcessInfo & info)100   void NotifyTerminatedOnUIThread(const content::ServiceProcessInfo& info) {
101     for (auto& observer : observers_)
102       observer.OnServiceProcessTerminatedNormally(info);
103   }
104 
NotifyCrashedOnUIThread(const content::ServiceProcessInfo & info)105   void NotifyCrashedOnUIThread(const content::ServiceProcessInfo& info) {
106     for (auto& observer : observers_)
107       observer.OnServiceProcessCrashed(info);
108   }
109 
GenerateNextId()110   ServiceProcessId GenerateNextId() {
111     DCHECK_CURRENTLY_ON(BrowserThread::IO);
112     return service_process_id_generator_.GenerateNextId();
113   }
114 
115   const scoped_refptr<base::TaskRunner> ui_task_runner_;
116   ServiceProcessId::Generator service_process_id_generator_;
117 
118   base::Lock processes_lock_;
119   std::map<ServiceProcessId, ServiceProcessInfo> processes_;
120 
121   // Observers are owned and used exclusively on the UI thread.
122   base::ObserverList<ServiceProcessHost::Observer> observers_;
123 
124   DISALLOW_COPY_AND_ASSIGN(ServiceProcessTracker);
125 };
126 
GetServiceProcessTracker()127 ServiceProcessTracker& GetServiceProcessTracker() {
128   static base::NoDestructor<ServiceProcessTracker> tracker;
129   return *tracker;
130 }
131 
132 // Helper to bridge UtilityProcessHost IO thread events to the
133 // ServiceProcessTracker. Every UtilityProcessHost created for a service process
134 // has a unique instance of this class associated with it.
135 class UtilityProcessClient : public UtilityProcessHost::Client {
136  public:
UtilityProcessClient(const std::string & service_interface_name)137   explicit UtilityProcessClient(const std::string& service_interface_name)
138       : service_interface_name_(service_interface_name) {}
139   ~UtilityProcessClient() override = default;
140 
141   // UtilityProcessHost::Client:
OnProcessLaunched(const base::Process & process)142   void OnProcessLaunched(const base::Process& process) override {
143     process_info_ =
144         GetServiceProcessTracker().AddProcess(process, service_interface_name_);
145   }
146 
OnProcessTerminatedNormally()147   void OnProcessTerminatedNormally() override {
148     GetServiceProcessTracker().NotifyTerminated(
149         process_info_->service_process_id);
150   }
151 
OnProcessCrashed()152   void OnProcessCrashed() override {
153     // TODO(https://crbug.com/1016027): It is unclear how we can observe
154     // |OnProcessCrashed()| without observing |OnProcessLaunched()| first, but
155     // it can happen on Android. Ignore the notification in this case.
156     if (!process_info_)
157       return;
158 
159     GetServiceProcessTracker().NotifyCrashed(process_info_->service_process_id);
160   }
161 
162  private:
163   const std::string service_interface_name_;
164   base::Optional<ServiceProcessInfo> process_info_;
165 
166   DISALLOW_COPY_AND_ASSIGN(UtilityProcessClient);
167 };
168 
169 // TODO(crbug.com/977637): Once UtilityProcessHost is used only by service
170 // processes, its logic can be inlined here.
LaunchServiceProcessOnIOThread(mojo::GenericPendingReceiver receiver,ServiceProcessHost::Options options)171 void LaunchServiceProcessOnIOThread(mojo::GenericPendingReceiver receiver,
172                                     ServiceProcessHost::Options options) {
173   UtilityProcessHost* host = new UtilityProcessHost(
174       std::make_unique<UtilityProcessClient>(*receiver.interface_name()));
175   host->SetName(!options.display_name.empty()
176                     ? options.display_name
177                     : base::UTF8ToUTF16(*receiver.interface_name()));
178   host->SetMetricsName(*receiver.interface_name());
179   host->SetSandboxType(options.sandbox_type);
180   host->SetExtraCommandLineSwitches(std::move(options.extra_switches));
181   if (options.child_flags)
182     host->set_child_flags(*options.child_flags);
183   host->Start();
184   host->GetChildProcess()->BindServiceInterface(std::move(receiver));
185 }
186 
187 }  // namespace
188 
189 // static
GetRunningProcessInfo()190 std::vector<ServiceProcessInfo> ServiceProcessHost::GetRunningProcessInfo() {
191   return GetServiceProcessTracker().GetProcesses();
192 }
193 
194 // static
AddObserver(Observer * observer)195 void ServiceProcessHost::AddObserver(Observer* observer) {
196   GetServiceProcessTracker().AddObserver(observer);
197 }
198 
199 // static
RemoveObserver(Observer * observer)200 void ServiceProcessHost::RemoveObserver(Observer* observer) {
201   GetServiceProcessTracker().RemoveObserver(observer);
202 }
203 
204 // static
Launch(mojo::GenericPendingReceiver receiver,Options options)205 void ServiceProcessHost::Launch(mojo::GenericPendingReceiver receiver,
206                                 Options options) {
207   DCHECK(receiver.interface_name().has_value());
208   GetIOThreadTaskRunner({})->PostTask(
209       FROM_HERE, base::BindOnce(&LaunchServiceProcessOnIOThread,
210                                 std::move(receiver), std::move(options)));
211 }
212 
213 }  // namespace content
214