Revert of Enabling audio quality test on mac. (patchset #1 id:1 of https://codereview...
[chromium-blink-merge.git] / chrome / service / service_utility_process_host.cc
blob88240fa59cc5059b3ce217fcded6ed97d37d060a
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 <queue>
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/files/file.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/logging.h"
16 #include "base/message_loop/message_loop_proxy.h"
17 #include "base/metrics/histogram.h"
18 #include "base/process/kill.h"
19 #include "base/process/launch.h"
20 #include "base/task_runner_util.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/chrome_utility_printing_messages.h"
23 #include "content/public/common/child_process_host.h"
24 #include "content/public/common/result_codes.h"
25 #include "content/public/common/sandbox_init.h"
26 #include "content/public/common/sandboxed_process_launcher_delegate.h"
27 #include "ipc/ipc_switches.h"
28 #include "printing/emf_win.h"
29 #include "sandbox/win/src/sandbox_policy_base.h"
30 #include "ui/base/ui_base_switches.h"
32 namespace {
34 using content::ChildProcessHost;
36 enum ServiceUtilityProcessHostEvent {
37 SERVICE_UTILITY_STARTED,
38 SERVICE_UTILITY_DISCONNECTED,
39 SERVICE_UTILITY_METAFILE_REQUEST,
40 SERVICE_UTILITY_METAFILE_SUCCEEDED,
41 SERVICE_UTILITY_METAFILE_FAILED,
42 SERVICE_UTILITY_CAPS_REQUEST,
43 SERVICE_UTILITY_CAPS_SUCCEEDED,
44 SERVICE_UTILITY_CAPS_FAILED,
45 SERVICE_UTILITY_SEMANTIC_CAPS_REQUEST,
46 SERVICE_UTILITY_SEMANTIC_CAPS_SUCCEEDED,
47 SERVICE_UTILITY_SEMANTIC_CAPS_FAILED,
48 SERVICE_UTILITY_FAILED_TO_START,
49 SERVICE_UTILITY_EVENT_MAX,
52 void ReportUmaEvent(ServiceUtilityProcessHostEvent id) {
53 UMA_HISTOGRAM_ENUMERATION("CloudPrint.ServiceUtilityProcessHostEvent",
54 id,
55 SERVICE_UTILITY_EVENT_MAX);
58 // NOTE: changes to this class need to be reviewed by the security team.
59 class ServiceSandboxedProcessLauncherDelegate
60 : public content::SandboxedProcessLauncherDelegate {
61 public:
62 ServiceSandboxedProcessLauncherDelegate() {}
64 virtual void PreSpawnTarget(sandbox::TargetPolicy* policy,
65 bool* success) OVERRIDE {
66 // Service process may run as windows service and it fails to create a
67 // window station.
68 policy->SetAlternateDesktop(false);
71 private:
72 DISALLOW_COPY_AND_ASSIGN(ServiceSandboxedProcessLauncherDelegate);
75 } // namespace
77 class ServiceUtilityProcessHost::PdfToEmfState {
78 public:
79 explicit PdfToEmfState(ServiceUtilityProcessHost* host)
80 : host_(host), page_count_(0), current_page_(0), pages_in_progress_(0) {}
81 ~PdfToEmfState() { Stop(); }
83 bool Start(base::File pdf_file,
84 const printing::PdfRenderSettings& conversion_settings) {
85 if (!temp_dir_.CreateUniqueTempDir())
86 return false;
87 return host_->Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles(
88 IPC::TakeFileHandleForProcess(pdf_file.Pass(), host_->handle()),
89 conversion_settings));
92 void GetMorePages() {
93 const int kMaxNumberOfTempFilesPerDocument = 3;
94 while (pages_in_progress_ < kMaxNumberOfTempFilesPerDocument &&
95 current_page_ < page_count_) {
96 ++pages_in_progress_;
97 emf_files_.push(CreateTempFile());
98 host_->Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_GetPage(
99 current_page_++,
100 IPC::GetFileHandleForProcess(
101 emf_files_.back().GetPlatformFile(), host_->handle(), false)));
105 // Returns true if all pages processed and client should not expect more
106 // results.
107 bool OnPageProcessed() {
108 --pages_in_progress_;
109 GetMorePages();
110 if (pages_in_progress_ || current_page_ < page_count_)
111 return false;
112 Stop();
113 return true;
116 base::File TakeNextFile() {
117 DCHECK(!emf_files_.empty());
118 base::File file;
119 if (!emf_files_.empty())
120 file = emf_files_.front().Pass();
121 emf_files_.pop();
122 return file.Pass();
125 void set_page_count(int page_count) { page_count_ = page_count; }
126 bool has_page_count() { return page_count_ > 0; }
128 private:
129 void Stop() {
130 host_->Send(new ChromeUtilityMsg_RenderPDFPagesToMetafiles_Stop());
133 base::File CreateTempFile() {
134 base::FilePath path;
135 if (!base::CreateTemporaryFileInDir(temp_dir_.path(), &path))
136 return base::File();
137 return base::File(path,
138 base::File::FLAG_CREATE_ALWAYS |
139 base::File::FLAG_WRITE |
140 base::File::FLAG_READ |
141 base::File::FLAG_DELETE_ON_CLOSE |
142 base::File::FLAG_TEMPORARY);
145 base::ScopedTempDir temp_dir_;
146 ServiceUtilityProcessHost* host_;
147 std::queue<base::File> emf_files_;
148 int page_count_;
149 int current_page_;
150 int pages_in_progress_;
153 ServiceUtilityProcessHost::ServiceUtilityProcessHost(
154 Client* client,
155 base::MessageLoopProxy* client_message_loop_proxy)
156 : handle_(base::kNullProcessHandle),
157 client_(client),
158 client_message_loop_proxy_(client_message_loop_proxy),
159 waiting_for_reply_(false),
160 weak_ptr_factory_(this) {
161 child_process_host_.reset(ChildProcessHost::Create(this));
164 ServiceUtilityProcessHost::~ServiceUtilityProcessHost() {
165 // We need to kill the child process when the host dies.
166 base::KillProcess(handle_, content::RESULT_CODE_NORMAL_EXIT, false);
169 bool ServiceUtilityProcessHost::StartRenderPDFPagesToMetafile(
170 const base::FilePath& pdf_path,
171 const printing::PdfRenderSettings& render_settings) {
172 ReportUmaEvent(SERVICE_UTILITY_METAFILE_REQUEST);
173 start_time_ = base::Time::Now();
174 base::File pdf_file(pdf_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
175 if (!pdf_file.IsValid() || !StartProcess(false))
176 return false;
178 DCHECK(!waiting_for_reply_);
179 waiting_for_reply_ = true;
181 pdf_to_emf_state_.reset(new PdfToEmfState(this));
182 return pdf_to_emf_state_->Start(pdf_file.Pass(), render_settings);
185 bool ServiceUtilityProcessHost::StartGetPrinterCapsAndDefaults(
186 const std::string& printer_name) {
187 ReportUmaEvent(SERVICE_UTILITY_CAPS_REQUEST);
188 start_time_ = base::Time::Now();
189 if (!StartProcess(true))
190 return false;
191 DCHECK(!waiting_for_reply_);
192 waiting_for_reply_ = true;
193 return Send(new ChromeUtilityMsg_GetPrinterCapsAndDefaults(printer_name));
196 bool ServiceUtilityProcessHost::StartGetPrinterSemanticCapsAndDefaults(
197 const std::string& printer_name) {
198 ReportUmaEvent(SERVICE_UTILITY_SEMANTIC_CAPS_REQUEST);
199 start_time_ = base::Time::Now();
200 if (!StartProcess(true))
201 return false;
202 DCHECK(!waiting_for_reply_);
203 waiting_for_reply_ = true;
204 return Send(
205 new ChromeUtilityMsg_GetPrinterSemanticCapsAndDefaults(printer_name));
208 bool ServiceUtilityProcessHost::StartProcess(bool no_sandbox) {
209 std::string channel_id = child_process_host_->CreateChannel();
210 if (channel_id.empty())
211 return false;
213 base::FilePath exe_path = GetUtilityProcessCmd();
214 if (exe_path.empty()) {
215 NOTREACHED() << "Unable to get utility process binary name.";
216 return false;
219 base::CommandLine cmd_line(exe_path);
220 cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kUtilityProcess);
221 cmd_line.AppendSwitchASCII(switches::kProcessChannelID, channel_id);
222 cmd_line.AppendSwitch(switches::kLang);
224 if (Launch(&cmd_line, no_sandbox)) {
225 ReportUmaEvent(SERVICE_UTILITY_STARTED);
226 return true;
228 ReportUmaEvent(SERVICE_UTILITY_FAILED_TO_START);
229 return false;
232 bool ServiceUtilityProcessHost::Launch(base::CommandLine* cmd_line,
233 bool no_sandbox) {
234 if (no_sandbox) {
235 base::ProcessHandle process = base::kNullProcessHandle;
236 cmd_line->AppendSwitch(switches::kNoSandbox);
237 base::LaunchProcess(*cmd_line, base::LaunchOptions(), &handle_);
238 } else {
239 ServiceSandboxedProcessLauncherDelegate delegate;
240 handle_ = content::StartSandboxedProcess(&delegate, cmd_line);
242 return (handle_ != base::kNullProcessHandle);
245 bool ServiceUtilityProcessHost::Send(IPC::Message* msg) {
246 if (child_process_host_)
247 return child_process_host_->Send(msg);
248 delete msg;
249 return false;
252 base::FilePath ServiceUtilityProcessHost::GetUtilityProcessCmd() {
253 #if defined(OS_LINUX)
254 int flags = ChildProcessHost::CHILD_ALLOW_SELF;
255 #else
256 int flags = ChildProcessHost::CHILD_NORMAL;
257 #endif
258 return ChildProcessHost::GetChildPath(flags);
261 void ServiceUtilityProcessHost::OnChildDisconnected() {
262 if (waiting_for_reply_) {
263 // If we are yet to receive a reply then notify the client that the
264 // child died.
265 client_message_loop_proxy_->PostTask(
266 FROM_HERE, base::Bind(&Client::OnChildDied, client_.get()));
267 ReportUmaEvent(SERVICE_UTILITY_DISCONNECTED);
268 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityDisconnectTime",
269 base::Time::Now() - start_time_);
271 delete this;
274 bool ServiceUtilityProcessHost::OnMessageReceived(const IPC::Message& message) {
275 bool handled = true;
276 IPC_BEGIN_MESSAGE_MAP(ServiceUtilityProcessHost, message)
277 IPC_MESSAGE_HANDLER(
278 ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageCount,
279 OnRenderPDFPagesToMetafilesPageCount)
280 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_RenderPDFPagesToMetafiles_PageDone,
281 OnRenderPDFPagesToMetafilesPageDone)
282 IPC_MESSAGE_HANDLER(
283 ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Succeeded,
284 OnGetPrinterCapsAndDefaultsSucceeded)
285 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_GetPrinterCapsAndDefaults_Failed,
286 OnGetPrinterCapsAndDefaultsFailed)
287 IPC_MESSAGE_HANDLER(
288 ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Succeeded,
289 OnGetPrinterSemanticCapsAndDefaultsSucceeded)
290 IPC_MESSAGE_HANDLER(
291 ChromeUtilityHostMsg_GetPrinterSemanticCapsAndDefaults_Failed,
292 OnGetPrinterSemanticCapsAndDefaultsFailed)
293 IPC_MESSAGE_UNHANDLED(handled = false)
294 IPC_END_MESSAGE_MAP()
295 return handled;
298 base::ProcessHandle ServiceUtilityProcessHost::GetHandle() const {
299 return handle_;
302 void ServiceUtilityProcessHost::OnMetafileSpooled(bool success) {
303 if (!success || pdf_to_emf_state_->OnPageProcessed())
304 OnPDFToEmfFinished(success);
307 void ServiceUtilityProcessHost::OnRenderPDFPagesToMetafilesPageCount(
308 int page_count) {
309 DCHECK(waiting_for_reply_);
310 if (!pdf_to_emf_state_ || page_count <= 0 ||
311 pdf_to_emf_state_->has_page_count()) {
312 return OnPDFToEmfFinished(false);
314 pdf_to_emf_state_->set_page_count(page_count);
315 pdf_to_emf_state_->GetMorePages();
318 void ServiceUtilityProcessHost::OnRenderPDFPagesToMetafilesPageDone(
319 bool success,
320 double scale_factor) {
321 DCHECK(waiting_for_reply_);
322 if (!pdf_to_emf_state_ || !success)
323 return OnPDFToEmfFinished(false);
324 base::File emf_file = pdf_to_emf_state_->TakeNextFile();
325 base::PostTaskAndReplyWithResult(
326 client_message_loop_proxy_,
327 FROM_HERE,
328 base::Bind(&Client::MetafileAvailable,
329 client_.get(),
330 scale_factor,
331 base::Passed(&emf_file)),
332 base::Bind(&ServiceUtilityProcessHost::OnMetafileSpooled,
333 weak_ptr_factory_.GetWeakPtr()));
336 void ServiceUtilityProcessHost::OnPDFToEmfFinished(bool success) {
337 if (!waiting_for_reply_)
338 return;
339 waiting_for_reply_ = false;
340 if (success) {
341 ReportUmaEvent(SERVICE_UTILITY_METAFILE_SUCCEEDED);
342 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityMetafileTime",
343 base::Time::Now() - start_time_);
344 } else {
345 ReportUmaEvent(SERVICE_UTILITY_METAFILE_FAILED);
346 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityMetafileFailTime",
347 base::Time::Now() - start_time_);
349 client_message_loop_proxy_->PostTask(
350 FROM_HERE,
351 base::Bind(
352 &Client::OnRenderPDFPagesToMetafileDone, client_.get(), success));
353 pdf_to_emf_state_.reset();
356 void ServiceUtilityProcessHost::OnGetPrinterCapsAndDefaultsSucceeded(
357 const std::string& printer_name,
358 const printing::PrinterCapsAndDefaults& caps_and_defaults) {
359 DCHECK(waiting_for_reply_);
360 ReportUmaEvent(SERVICE_UTILITY_CAPS_SUCCEEDED);
361 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityCapsTime",
362 base::Time::Now() - start_time_);
363 waiting_for_reply_ = false;
364 client_message_loop_proxy_->PostTask(
365 FROM_HERE,
366 base::Bind(&Client::OnGetPrinterCapsAndDefaults, client_.get(), true,
367 printer_name, caps_and_defaults));
370 void ServiceUtilityProcessHost::OnGetPrinterSemanticCapsAndDefaultsSucceeded(
371 const std::string& printer_name,
372 const printing::PrinterSemanticCapsAndDefaults& caps_and_defaults) {
373 DCHECK(waiting_for_reply_);
374 ReportUmaEvent(SERVICE_UTILITY_SEMANTIC_CAPS_SUCCEEDED);
375 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilitySemanticCapsTime",
376 base::Time::Now() - start_time_);
377 waiting_for_reply_ = false;
378 client_message_loop_proxy_->PostTask(
379 FROM_HERE,
380 base::Bind(&Client::OnGetPrinterSemanticCapsAndDefaults, client_.get(),
381 true, printer_name, caps_and_defaults));
384 void ServiceUtilityProcessHost::OnGetPrinterCapsAndDefaultsFailed(
385 const std::string& printer_name) {
386 DCHECK(waiting_for_reply_);
387 ReportUmaEvent(SERVICE_UTILITY_CAPS_FAILED);
388 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilityCapsFailTime",
389 base::Time::Now() - start_time_);
390 waiting_for_reply_ = false;
391 client_message_loop_proxy_->PostTask(
392 FROM_HERE,
393 base::Bind(&Client::OnGetPrinterCapsAndDefaults, client_.get(), false,
394 printer_name, printing::PrinterCapsAndDefaults()));
397 void ServiceUtilityProcessHost::OnGetPrinterSemanticCapsAndDefaultsFailed(
398 const std::string& printer_name) {
399 DCHECK(waiting_for_reply_);
400 ReportUmaEvent(SERVICE_UTILITY_SEMANTIC_CAPS_FAILED);
401 UMA_HISTOGRAM_TIMES("CloudPrint.ServiceUtilitySemanticCapsFailTime",
402 base::Time::Now() - start_time_);
403 waiting_for_reply_ = false;
404 client_message_loop_proxy_->PostTask(
405 FROM_HERE,
406 base::Bind(&Client::OnGetPrinterSemanticCapsAndDefaults,
407 client_.get(), false, printer_name,
408 printing::PrinterSemanticCapsAndDefaults()));
411 bool ServiceUtilityProcessHost::Client::MetafileAvailable(double scale_factor,
412 base::File file) {
413 file.Seek(base::File::FROM_BEGIN, 0);
414 int64 size = file.GetLength();
415 if (size <= 0) {
416 OnRenderPDFPagesToMetafileDone(false);
417 return false;
419 std::vector<char> data(size);
420 if (file.ReadAtCurrentPos(data.data(), data.size()) != size) {
421 OnRenderPDFPagesToMetafileDone(false);
422 return false;
424 printing::Emf emf;
425 if (!emf.InitFromData(data.data(), data.size())) {
426 OnRenderPDFPagesToMetafileDone(false);
427 return false;
429 OnRenderPDFPagesToMetafilePageDone(scale_factor, emf);
430 return true;