1// Copyright 2014 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 "base/bind.h"
6#include "base/message_loop/message_loop.h"
7#include "chrome/browser/browser_process.h"
8#include "chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h"
9#include "chrome/common/extensions/chrome_utility_extensions_messages.h"
10#include "content/public/browser/browser_thread.h"
11
12using content::BrowserThread;
13
14ImageWriterUtilityClient::ImageWriterUtilityClient()
15    : message_loop_proxy_(base::MessageLoopProxy::current()) {}
16ImageWriterUtilityClient::~ImageWriterUtilityClient() {}
17
18void ImageWriterUtilityClient::Write(const ProgressCallback& progress_callback,
19                                     const SuccessCallback& success_callback,
20                                     const ErrorCallback& error_callback,
21                                     const base::FilePath& source,
22                                     const base::FilePath& target) {
23  DCHECK_CURRENTLY_ON(BrowserThread::IO);
24
25  StartHost();
26
27  progress_callback_ = progress_callback;
28  success_callback_ = success_callback;
29  error_callback_ = error_callback;
30
31  if (!Send(new ChromeUtilityMsg_ImageWriter_Write(source, target))) {
32    DLOG(ERROR) << "Unable to send Write message to Utility Process.";
33    message_loop_proxy_->PostTask(
34        FROM_HERE, base::Bind(error_callback_, "IPC communication failed"));
35  }
36}
37
38void ImageWriterUtilityClient::Verify(const ProgressCallback& progress_callback,
39                                      const SuccessCallback& success_callback,
40                                      const ErrorCallback& error_callback,
41                                      const base::FilePath& source,
42                                      const base::FilePath& target) {
43  DCHECK_CURRENTLY_ON(BrowserThread::IO);
44
45  StartHost();
46
47  progress_callback_ = progress_callback;
48  success_callback_ = success_callback;
49  error_callback_ = error_callback;
50
51  if (!Send(new ChromeUtilityMsg_ImageWriter_Verify(source, target))) {
52    DLOG(ERROR) << "Unable to send Verify message to Utility Process.";
53    message_loop_proxy_->PostTask(
54        FROM_HERE, base::Bind(error_callback_, "IPC communication failed"));
55  }
56}
57
58void ImageWriterUtilityClient::Cancel(const CancelCallback& cancel_callback) {
59  DCHECK_CURRENTLY_ON(BrowserThread::IO);
60
61  if (!utility_process_host_) {
62    // If we haven't connected, there is nothing to cancel.
63    message_loop_proxy_->PostTask(FROM_HERE, cancel_callback);
64    return;
65  }
66
67  cancel_callback_ = cancel_callback;
68
69  if (!Send(new ChromeUtilityMsg_ImageWriter_Cancel())) {
70    DLOG(ERROR) << "Unable to send Cancel message to Utility Process.";
71  }
72}
73
74void ImageWriterUtilityClient::Shutdown() {
75  if (utility_process_host_ &&
76      Send(new ChromeUtilityMsg_ImageWriter_Cancel())) {
77    utility_process_host_->EndBatchMode();
78  }
79
80  // Clear handlers to not hold any reference to the caller.
81  success_callback_ = base::Closure();
82  progress_callback_ = base::Callback<void(int64)>();
83  error_callback_ = base::Callback<void(const std::string&)>();
84  cancel_callback_ = base::Closure();
85}
86
87void ImageWriterUtilityClient::StartHost() {
88  if (!utility_process_host_) {
89    scoped_refptr<base::SequencedTaskRunner> task_runner =
90        base::MessageLoop::current()->message_loop_proxy();
91    utility_process_host_ = content::UtilityProcessHost::Create(
92                                this, task_runner.get())->AsWeakPtr();
93
94#if defined(OS_WIN)
95    utility_process_host_->ElevatePrivileges();
96#else
97    utility_process_host_->DisableSandbox();
98#endif
99    utility_process_host_->StartBatchMode();
100  }
101}
102
103void ImageWriterUtilityClient::OnProcessCrashed(int exit_code) {
104  message_loop_proxy_->PostTask(
105      FROM_HERE, base::Bind(error_callback_, "Utility process crashed."));
106}
107
108void ImageWriterUtilityClient::OnProcessLaunchFailed() {
109  message_loop_proxy_->PostTask(
110      FROM_HERE, base::Bind(error_callback_, "Process launch failed."));
111}
112
113bool ImageWriterUtilityClient::OnMessageReceived(const IPC::Message& message) {
114  bool handled = true;
115  IPC_BEGIN_MESSAGE_MAP(ImageWriterUtilityClient, message)
116  IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ImageWriter_Succeeded,
117                      OnWriteImageSucceeded)
118  IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ImageWriter_Cancelled,
119                      OnWriteImageCancelled)
120  IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ImageWriter_Failed,
121                      OnWriteImageFailed)
122  IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ImageWriter_Progress,
123                      OnWriteImageProgress)
124  IPC_MESSAGE_UNHANDLED(handled = false)
125  IPC_END_MESSAGE_MAP()
126  return handled;
127}
128
129bool ImageWriterUtilityClient::Send(IPC::Message* msg) {
130  return utility_process_host_ && utility_process_host_->Send(msg);
131}
132
133void ImageWriterUtilityClient::OnWriteImageSucceeded() {
134  if (!success_callback_.is_null()) {
135    message_loop_proxy_->PostTask(FROM_HERE, success_callback_);
136  }
137}
138
139void ImageWriterUtilityClient::OnWriteImageCancelled() {
140  if (!cancel_callback_.is_null()) {
141    message_loop_proxy_->PostTask(FROM_HERE, cancel_callback_);
142  }
143}
144
145void ImageWriterUtilityClient::OnWriteImageFailed(const std::string& message) {
146  if (!error_callback_.is_null()) {
147    message_loop_proxy_->PostTask(FROM_HERE,
148                                  base::Bind(error_callback_, message));
149  }
150}
151
152void ImageWriterUtilityClient::OnWriteImageProgress(int64 progress) {
153  if (!progress_callback_.is_null()) {
154    message_loop_proxy_->PostTask(FROM_HERE,
155                                  base::Bind(progress_callback_, progress));
156  }
157}
158