Bluetooth: add Device events, and cleanup JS API
[chromium-blink-merge.git] / chrome / service / service_utility_process_host.cc
blob3054adc3e16abb5408f5639f08c2e5214a6da03d
1 // Copyright (c) 2012 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.
5 #include "chrome/service/service_utility_process_host.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/metrics/histogram.h"
15 #include "base/process/kill.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/common/chrome_utility_messages.h"
19 #include "content/public/common/child_process_host.h"
20 #include "content/public/common/result_codes.h"
21 #include "content/public/common/sandbox_init.h"
22 #include "ipc/ipc_switches.h"
23 #include "printing/page_range.h"
24 #include "ui/base/ui_base_switches.h"
25 #include "ui/gfx/rect.h"
27 #if defined(OS_WIN)
28 #include "base/files/file_path.h"
29 #include "base/memory/scoped_ptr.h"
30 #include "base/process/launch.h"
31 #include "base/win/scoped_handle.h"
32 #include "content/public/common/sandbox_init.h"
33 #include "content/public/common/sandboxed_process_launcher_delegate.h"
34 #include "printing/emf_win.h"
36 namespace {
38 // NOTE: changes to this class need to be reviewed by the security team.
39 class ServiceSandboxedProcessLauncherDelegate
40 : public content::SandboxedProcessLauncherDelegate {
41 public:
42 explicit ServiceSandboxedProcessLauncherDelegate(
43 const base::FilePath& exposed_dir)
44 : exposed_dir_(exposed_dir) {
47 virtual void PreSandbox(bool* disable_default_policy,
48 base::FilePath* exposed_dir) OVERRIDE {
49 *exposed_dir = exposed_dir_;
52 private:
53 base::FilePath exposed_dir_;
56 } // namespace
58 #endif // OS_WIN
60 using content::ChildProcessHost;
62 namespace {
63 enum ServiceUtilityProcessHostEvent {
64 SERVICE_UTILITY_STARTED,
65 SERVICE_UTILITY_DISCONNECTED,
66 SERVICE_UTILITY_METAFILE_REQUEST,
67 SERVICE_UTILITY_METAFILE_SUCCEEDED,
68 SERVICE_UTILITY_METAFILE_FAILED,
69 SERVICE_UTILITY_CAPS_REQUEST,
70 SERVICE_UTILITY_CAPS_SUCCEEDED,
71 SERVICE_UTILITY_CAPS_FAILED,
72 SERVICE_UTILITY_SEMANTIC_CAPS_REQUEST,
73 SERVICE_UTILITY_SEMANTIC_CAPS_SUCCEEDED,
74 SERVICE_UTILITY_SEMANTIC_CAPS_FAILED,
75 SERVICE_UTILITY_EVENT_MAX,
77 } // namespace
79 ServiceUtilityProcessHost::ServiceUtilityProcessHost(
80 Client* client, base::MessageLoopProxy* client_message_loop_proxy)
81 : handle_(base::kNullProcessHandle),
82 client_(client),
83 client_message_loop_proxy_(client_message_loop_proxy),
84 waiting_for_reply_(false) {
85 child_process_host_.reset(ChildProcessHost::Create(this));
88 ServiceUtilityProcessHost::~ServiceUtilityProcessHost() {
89 // We need to kill the child process when the host dies.
90 base::KillProcess(handle_, content::RESULT_CODE_NORMAL_EXIT, false);
93 bool ServiceUtilityProcessHost::StartRenderPDFPagesToMetafile(
94 const base::FilePath& pdf_path,
95 const printing::PdfRenderSettings& render_settings,
96 const std::vector<printing::PageRange>& page_ranges) {
97 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
98 SERVICE_UTILITY_METAFILE_REQUEST,
99 SERVICE_UTILITY_EVENT_MAX);
100 start_time_ = base::Time::Now();
101 #if !defined(OS_WIN)
102 // This is only implemented on Windows (because currently it is only needed
103 // on Windows). Will add implementations on other platforms when needed.
104 NOTIMPLEMENTED();
105 return false;
106 #else // !defined(OS_WIN)
107 scratch_metafile_dir_.reset(new base::ScopedTempDir);
108 if (!scratch_metafile_dir_->CreateUniqueTempDir())
109 return false;
110 if (!base::CreateTemporaryFileInDir(scratch_metafile_dir_->path(),
111 &metafile_path_)) {
112 return false;
115 if (!StartProcess(false, scratch_metafile_dir_->path()))
116 return false;
118 base::win::ScopedHandle pdf_file(
119 ::CreateFile(pdf_path.value().c_str(),
120 GENERIC_READ,
121 FILE_SHARE_READ | FILE_SHARE_WRITE,
122 NULL,
123 OPEN_EXISTING,
124 FILE_ATTRIBUTE_NORMAL,
125 NULL));
126 if (pdf_file == INVALID_HANDLE_VALUE)
127 return false;
128 HANDLE pdf_file_in_utility_process = NULL;
129 ::DuplicateHandle(::GetCurrentProcess(), pdf_file, handle(),
130 &pdf_file_in_utility_process, 0, false,
131 DUPLICATE_SAME_ACCESS);
132 if (!pdf_file_in_utility_process)
133 return false;
134 DCHECK(!waiting_for_reply_);
135 waiting_for_reply_ = true;
136 return child_process_host_->Send(
137 new ChromeUtilityMsg_RenderPDFPagesToMetafile(
138 pdf_file_in_utility_process,
139 metafile_path_,
140 render_settings,
141 page_ranges));
142 #endif // !defined(OS_WIN)
145 bool ServiceUtilityProcessHost::StartGetPrinterCapsAndDefaults(
146 const std::string& printer_name) {
147 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
148 SERVICE_UTILITY_CAPS_REQUEST,
149 SERVICE_UTILITY_EVENT_MAX);
150 start_time_ = base::Time::Now();
151 base::FilePath exposed_path;
152 if (!StartProcess(true, exposed_path))
153 return false;
154 DCHECK(!waiting_for_reply_);
155 waiting_for_reply_ = true;
156 return child_process_host_->Send(
157 new ChromeUtilityMsg_GetPrinterCapsAndDefaults(printer_name));
160 bool ServiceUtilityProcessHost::StartGetPrinterSemanticCapsAndDefaults(
161 const std::string& printer_name) {
162 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
163 SERVICE_UTILITY_SEMANTIC_CAPS_REQUEST,
164 SERVICE_UTILITY_EVENT_MAX);
165 start_time_ = base::Time::Now();
166 base::FilePath exposed_path;
167 if (!StartProcess(true, exposed_path))
168 return false;
169 DCHECK(!waiting_for_reply_);
170 waiting_for_reply_ = true;
171 return child_process_host_->Send(
172 new ChromeUtilityMsg_GetPrinterSemanticCapsAndDefaults(printer_name));
175 bool ServiceUtilityProcessHost::StartProcess(
176 bool no_sandbox,
177 const base::FilePath& exposed_dir) {
178 std::string channel_id = child_process_host_->CreateChannel();
179 if (channel_id.empty())
180 return false;
182 base::FilePath exe_path = GetUtilityProcessCmd();
183 if (exe_path.empty()) {
184 NOTREACHED() << "Unable to get utility process binary name.";
185 return false;
188 CommandLine cmd_line(exe_path);
189 cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kUtilityProcess);
190 cmd_line.AppendSwitchASCII(switches::kProcessChannelID, channel_id);
191 cmd_line.AppendSwitch(switches::kLang);
193 if (Launch(&cmd_line, no_sandbox, exposed_dir)) {
194 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
195 SERVICE_UTILITY_STARTED,
196 SERVICE_UTILITY_EVENT_MAX);
197 return true;
199 return false;
202 bool ServiceUtilityProcessHost::Launch(CommandLine* cmd_line,
203 bool no_sandbox,
204 const base::FilePath& exposed_dir) {
205 #if !defined(OS_WIN)
206 // TODO(sanjeevr): Implement for non-Windows OSes.
207 NOTIMPLEMENTED();
208 return false;
209 #else // !defined(OS_WIN)
211 if (no_sandbox) {
212 base::ProcessHandle process = base::kNullProcessHandle;
213 cmd_line->AppendSwitch(switches::kNoSandbox);
214 base::LaunchProcess(*cmd_line, base::LaunchOptions(), &handle_);
215 } else {
216 ServiceSandboxedProcessLauncherDelegate delegate(exposed_dir);
217 handle_ = content::StartSandboxedProcess(&delegate, cmd_line);
219 return (handle_ != base::kNullProcessHandle);
220 #endif // !defined(OS_WIN)
223 base::FilePath ServiceUtilityProcessHost::GetUtilityProcessCmd() {
224 #if defined(OS_LINUX)
225 int flags = ChildProcessHost::CHILD_ALLOW_SELF;
226 #else
227 int flags = ChildProcessHost::CHILD_NORMAL;
228 #endif
229 return ChildProcessHost::GetChildPath(flags);
232 void ServiceUtilityProcessHost::OnChildDisconnected() {
233 if (waiting_for_reply_) {
234 // If we are yet to receive a reply then notify the client that the
235 // child died.
236 client_message_loop_proxy_->PostTask(
237 FROM_HERE, base::Bind(&Client::OnChildDied, client_.get()));
238 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
239 SERVICE_UTILITY_DISCONNECTED,
240 SERVICE_UTILITY_EVENT_MAX);
241 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityDisconnectTime",
242 base::Time::Now() - start_time_);
244 delete this;
247 bool ServiceUtilityProcessHost::OnMessageReceived(const IPC::Message& message) {
248 bool handled = true;
249 IPC_BEGIN_MESSAGE_MAP(ServiceUtilityProcessHost, message)
250 IPC_MESSAGE_HANDLER(
251 ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Succeeded,
252 OnRenderPDFPagesToMetafileSucceeded)
253 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafile_Failed,
254 OnRenderPDFPagesToMetafileFailed)
255 IPC_MESSAGE_HANDLER(
256 ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded,
257 OnGetPrinterCapsAndDefaultsSucceeded)
258 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Failed,
259 OnGetPrinterCapsAndDefaultsFailed)
260 IPC_MESSAGE_HANDLER(
261 ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Succeeded,
262 OnGetPrinterSemanticCapsAndDefaultsSucceeded)
263 IPC_MESSAGE_HANDLER(
264 ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Failed,
265 OnGetPrinterSemanticCapsAndDefaultsFailed)
266 IPC_MESSAGE_UNHANDLED(handled = false)
267 IPC_END_MESSAGE_MAP()
268 return handled;
271 base::ProcessHandle ServiceUtilityProcessHost::GetHandle() const {
272 return handle_;
275 void ServiceUtilityProcessHost::OnRenderPDFPagesToMetafileSucceeded(
276 int highest_rendered_page_number,
277 double scale_factor) {
278 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
279 SERVICE_UTILITY_METAFILE_SUCCEEDED,
280 SERVICE_UTILITY_EVENT_MAX);
281 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityMetafileTime",
282 base::Time::Now() - start_time_);
283 DCHECK(waiting_for_reply_);
284 waiting_for_reply_ = false;
285 // If the metafile was successfully created, we need to take our hands off the
286 // scratch metafile directory. The client will delete it when it is done with
287 // metafile.
288 scratch_metafile_dir_->Take();
289 client_message_loop_proxy_->PostTask(
290 FROM_HERE,
291 base::Bind(&Client::MetafileAvailable, client_.get(), metafile_path_,
292 highest_rendered_page_number, scale_factor));
295 void ServiceUtilityProcessHost::OnRenderPDFPagesToMetafileFailed() {
296 DCHECK(waiting_for_reply_);
297 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
298 SERVICE_UTILITY_METAFILE_FAILED,
299 SERVICE_UTILITY_EVENT_MAX);
300 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityMetafileFailTime",
301 base::Time::Now() - start_time_);
302 waiting_for_reply_ = false;
303 client_message_loop_proxy_->PostTask(
304 FROM_HERE,
305 base::Bind(&Client::OnRenderPDFPagesToMetafileFailed, client_.get()));
308 void ServiceUtilityProcessHost::OnGetPrinterCapsAndDefaultsSucceeded(
309 const std::string& printer_name,
310 const printing::PrinterCapsAndDefaults& caps_and_defaults) {
311 DCHECK(waiting_for_reply_);
312 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
313 SERVICE_UTILITY_CAPS_SUCCEEDED,
314 SERVICE_UTILITY_EVENT_MAX);
315 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityCapsTime",
316 base::Time::Now() - start_time_);
317 waiting_for_reply_ = false;
318 client_message_loop_proxy_->PostTask(
319 FROM_HERE,
320 base::Bind(&Client::OnGetPrinterCapsAndDefaults, client_.get(), true,
321 printer_name, caps_and_defaults));
324 void ServiceUtilityProcessHost::OnGetPrinterSemanticCapsAndDefaultsSucceeded(
325 const std::string& printer_name,
326 const printing::PrinterSemanticCapsAndDefaults& caps_and_defaults) {
327 DCHECK(waiting_for_reply_);
328 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
329 SERVICE_UTILITY_SEMANTIC_CAPS_SUCCEEDED,
330 SERVICE_UTILITY_EVENT_MAX);
331 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilitySemanticCapsTime",
332 base::Time::Now() - start_time_);
333 waiting_for_reply_ = false;
334 client_message_loop_proxy_->PostTask(
335 FROM_HERE,
336 base::Bind(&Client::OnGetPrinterSemanticCapsAndDefaults, client_.get(),
337 true, printer_name, caps_and_defaults));
340 void ServiceUtilityProcessHost::OnGetPrinterCapsAndDefaultsFailed(
341 const std::string& printer_name) {
342 DCHECK(waiting_for_reply_);
343 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
344 SERVICE_UTILITY_CAPS_FAILED,
345 SERVICE_UTILITY_EVENT_MAX);
346 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityCapsFailTime",
347 base::Time::Now() - start_time_);
348 waiting_for_reply_ = false;
349 client_message_loop_proxy_->PostTask(
350 FROM_HERE,
351 base::Bind(&Client::OnGetPrinterCapsAndDefaults, client_.get(), false,
352 printer_name, printing::PrinterCapsAndDefaults()));
355 void ServiceUtilityProcessHost::OnGetPrinterSemanticCapsAndDefaultsFailed(
356 const std::string& printer_name) {
357 DCHECK(waiting_for_reply_);
358 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
359 SERVICE_UTILITY_SEMANTIC_CAPS_FAILED,
360 SERVICE_UTILITY_EVENT_MAX);
361 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilitySemanticCapsFailTime",
362 base::Time::Now() - start_time_);
363 waiting_for_reply_ = false;
364 client_message_loop_proxy_->PostTask(
365 FROM_HERE,
366 base::Bind(&Client::OnGetPrinterSemanticCapsAndDefaults,
367 client_.get(), false, printer_name,
368 printing::PrinterSemanticCapsAndDefaults()));
371 void ServiceUtilityProcessHost::Client::MetafileAvailable(
372 const base::FilePath& metafile_path,
373 int highest_rendered_page_number,
374 double scale_factor) {
375 // The metafile was created in a temp folder which needs to get deleted after
376 // we have processed it.
377 base::ScopedTempDir scratch_metafile_dir;
378 if (!scratch_metafile_dir.Set(metafile_path.DirName()))
379 LOG(WARNING) << "Unable to set scratch metafile directory";
380 #if defined(OS_WIN)
381 // It's important that metafile is declared after scratch_metafile_dir so
382 // that the metafile destructor closes the file before the base::ScopedTempDir
383 // destructor tries to remove the directory.
384 printing::Emf metafile;
385 if (!metafile.InitFromFile(metafile_path)) {
386 OnRenderPDFPagesToMetafileFailed();
387 } else {
388 OnRenderPDFPagesToMetafileSucceeded(metafile,
389 highest_rendered_page_number,
390 scale_factor);
392 #endif // defined(OS_WIN)