blob: a1380707aa737d343f1d508a30e200628c2f5060 [file] [log] [blame]
[email protected]44013f682012-05-31 13:49:401// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]551707a2010-06-16 16:59:472// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]6d33da172011-11-22 03:56:095#include "chrome/browser/image_decoder.h"
[email protected]551707a2010-06-16 16:59:476
nya601d9702016-07-26 18:39:217#include <utility>
8
[email protected]31893772011-10-11 17:41:509#include "base/bind.h"
gabb15e19072016-05-11 20:45:4110#include "base/threading/thread_task_runner_handle.h"
avi6846aef2015-12-26 01:09:3811#include "build/build_config.h"
[email protected]551707a2010-06-16 16:59:4712#include "chrome/browser/browser_process.h"
amistry6f72f042016-04-05 20:42:0713#include "chrome/common/image_decoder.mojom.h"
thestige3d6b752015-04-07 21:58:4514#include "chrome/grit/generated_resources.h"
[email protected]c38831a12011-10-28 12:44:4915#include "content/public/browser/browser_thread.h"
[email protected]c4f883a2012-02-03 17:02:0716#include "content/public/browser/utility_process_host.h"
bend1dd50f52016-06-26 22:10:4817#include "services/shell/public/cpp/interface_provider.h"
amistry6f72f042016-04-05 20:42:0718#include "third_party/skia/include/core/SkBitmap.h"
thestige3d6b752015-04-07 21:58:4519#include "ui/base/l10n/l10n_util.h"
[email protected]551707a2010-06-16 16:59:4720
[email protected]631bb742011-11-02 11:29:3921using content::BrowserThread;
[email protected]c4f883a2012-02-03 17:02:0722using content::UtilityProcessHost;
[email protected]631bb742011-11-02 11:29:3923
twellingtona71414d2015-03-26 15:09:4524namespace {
25
26// static, Leaky to allow access from any thread.
27base::LazyInstance<ImageDecoder>::Leaky g_decoder = LAZY_INSTANCE_INITIALIZER;
28
29// How long to wait after the last request has been received before ending
30// batch mode.
31const int kBatchModeTimeoutSeconds = 5;
32
amistry6f72f042016-04-05 20:42:0733void OnDecodeImageDone(
34 base::Callback<void(int)> fail_callback,
35 base::Callback<void(const SkBitmap&, int)> success_callback,
mswb0123d12016-06-01 21:59:5436 int request_id,
37 const SkBitmap& image) {
amistry6f72f042016-04-05 20:42:0738 DCHECK_CURRENTLY_ON(BrowserThread::IO);
mswb0123d12016-06-01 21:59:5439 if (!image.isNull() && !image.empty())
40 success_callback.Run(image, request_id);
41 else
42 fail_callback.Run(request_id);
amistry6f72f042016-04-05 20:42:0743}
44
twellingtona71414d2015-03-26 15:09:4545} // namespace
46
47ImageDecoder::ImageDecoder()
thestigd3485b692015-04-30 09:47:3248 : image_request_id_counter_(0) {
twellingtona71414d2015-03-26 15:09:4549 // A single ImageDecoder instance should live for the life of the program.
50 // Explicitly add a reference so the object isn't deleted.
51 AddRef();
[email protected]551707a2010-06-16 16:59:4752}
53
twellingtona71414d2015-03-26 15:09:4554ImageDecoder::~ImageDecoder() {
pneubeck93871252015-01-20 11:26:3655}
56
thestigc5eeb9f362015-04-22 18:42:3257ImageDecoder::ImageRequest::ImageRequest()
58 : task_runner_(base::ThreadTaskRunnerHandle::Get()) {
59 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
60}
61
twellingtona71414d2015-03-26 15:09:4562ImageDecoder::ImageRequest::ImageRequest(
63 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
64 : task_runner_(task_runner) {
thestigc5eeb9f362015-04-22 18:42:3265 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
twellingtona71414d2015-03-26 15:09:4566}
[email protected]863e6d962011-05-15 19:39:3567
twellingtona71414d2015-03-26 15:09:4568ImageDecoder::ImageRequest::~ImageRequest() {
thestigc5eeb9f362015-04-22 18:42:3269 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
twellingtona71414d2015-03-26 15:09:4570 ImageDecoder::Cancel(this);
71}
72
73// static
74void ImageDecoder::Start(ImageRequest* image_request,
nya601d9702016-07-26 18:39:2175 std::vector<uint8_t> image_data) {
76 StartWithOptions(image_request, std::move(image_data), DEFAULT_CODEC, false);
77}
78
79// static
80void ImageDecoder::Start(ImageRequest* image_request,
twellingtona71414d2015-03-26 15:09:4581 const std::string& image_data) {
nya601d9702016-07-26 18:39:2182 Start(image_request,
83 std::vector<uint8_t>(image_data.begin(), image_data.end()));
84}
85
86// static
87void ImageDecoder::StartWithOptions(ImageRequest* image_request,
88 std::vector<uint8_t> image_data,
89 ImageCodec image_codec,
90 bool shrink_to_fit) {
91 g_decoder.Pointer()->StartWithOptionsImpl(image_request,
92 std::move(image_data),
93 image_codec, shrink_to_fit);
twellingtona71414d2015-03-26 15:09:4594}
95
96// static
97void ImageDecoder::StartWithOptions(ImageRequest* image_request,
98 const std::string& image_data,
99 ImageCodec image_codec,
100 bool shrink_to_fit) {
nya601d9702016-07-26 18:39:21101 StartWithOptions(image_request,
102 std::vector<uint8_t>(image_data.begin(), image_data.end()),
103 image_codec, shrink_to_fit);
thestigc5eeb9f362015-04-22 18:42:32104}
105
106void ImageDecoder::StartWithOptionsImpl(ImageRequest* image_request,
nya601d9702016-07-26 18:39:21107 std::vector<uint8_t> image_data,
thestigc5eeb9f362015-04-22 18:42:32108 ImageCodec image_codec,
109 bool shrink_to_fit) {
twellingtona71414d2015-03-26 15:09:45110 DCHECK(image_request);
111 DCHECK(image_request->task_runner());
thestigc5eeb9f362015-04-22 18:42:32112
113 int request_id;
114 {
115 base::AutoLock lock(map_lock_);
116 request_id = image_request_id_counter_++;
117 image_request_id_map_.insert(std::make_pair(request_id, image_request));
118 }
119
[email protected]cca169b52010-10-08 22:15:55120 BrowserThread::PostTask(
twellingtona71414d2015-03-26 15:09:45121 BrowserThread::IO, FROM_HERE,
122 base::Bind(
123 &ImageDecoder::DecodeImageInSandbox,
thestigc5eeb9f362015-04-22 18:42:32124 g_decoder.Pointer(), request_id,
nya601d9702016-07-26 18:39:21125 base::Passed(std::move(image_data)),
twellingtona71414d2015-03-26 15:09:45126 image_codec, shrink_to_fit));
[email protected]551707a2010-06-16 16:59:47127}
128
twellingtona71414d2015-03-26 15:09:45129// static
130void ImageDecoder::Cancel(ImageRequest* image_request) {
131 DCHECK(image_request);
132 g_decoder.Pointer()->CancelImpl(image_request);
133}
134
135void ImageDecoder::DecodeImageInSandbox(
thestigc5eeb9f362015-04-22 18:42:32136 int request_id,
nya601d9702016-07-26 18:39:21137 std::vector<uint8_t> image_data,
twellingtona71414d2015-03-26 15:09:45138 ImageCodec image_codec,
139 bool shrink_to_fit) {
140 DCHECK_CURRENTLY_ON(BrowserThread::IO);
thestigc5eeb9f362015-04-22 18:42:32141 base::AutoLock lock(map_lock_);
142 const auto it = image_request_id_map_.find(request_id);
143 if (it == image_request_id_map_.end())
144 return;
145
146 ImageRequest* image_request = it->second;
twellingtona71414d2015-03-26 15:09:45147 if (!utility_process_host_) {
148 StartBatchMode();
149 }
twellington612b9b62015-04-01 00:33:12150 if (!utility_process_host_) {
151 // Utility process failed to start; notify delegate and return.
152 // Without this check, we were seeing crashes on startup. Further
153 // investigation is needed to determine why the utility process
154 // is failing to start. See crbug.com/472272
155 image_request->task_runner()->PostTask(
thestigc5eeb9f362015-04-22 18:42:32156 FROM_HERE,
157 base::Bind(&ImageDecoder::RunOnDecodeImageFailed, this, request_id));
twellington612b9b62015-04-01 00:33:12158 return;
159 }
twellingtona71414d2015-03-26 15:09:45160
thestigd3485b692015-04-30 09:47:32161 if (!batch_mode_timer_) {
162 // Created here so it will call StopBatchMode() on the right thread.
danakj8c3eb802015-09-24 07:53:00163 batch_mode_timer_.reset(new base::DelayTimer(
164 FROM_HERE, base::TimeDelta::FromSeconds(kBatchModeTimeoutSeconds), this,
thestigd3485b692015-04-30 09:47:32165 &ImageDecoder::StopBatchMode));
166 }
167 batch_mode_timer_->Reset();
twellingtona71414d2015-03-26 15:09:45168
amistry6f72f042016-04-05 20:42:07169 mojom::ImageCodec mojo_codec = mojom::ImageCodec::DEFAULT;
edward.baker199f66b2015-05-07 19:13:30170#if defined(OS_CHROMEOS)
amistry6f72f042016-04-05 20:42:07171 if (image_codec == ROBUST_JPEG_CODEC)
172 mojo_codec = mojom::ImageCodec::ROBUST_JPEG;
173 if (image_codec == ROBUST_PNG_CODEC)
174 mojo_codec = mojom::ImageCodec::ROBUST_PNG;
edward.baker199f66b2015-05-07 19:13:30175#endif // defined(OS_CHROMEOS)
amistry6f72f042016-04-05 20:42:07176 decoder_->DecodeImage(
nya601d9702016-07-26 18:39:21177 mojo::Array<uint8_t>(std::move(image_data)),
amistry6f72f042016-04-05 20:42:07178 mojo_codec,
179 shrink_to_fit,
180 base::Bind(&OnDecodeImageDone,
181 base::Bind(&ImageDecoder::OnDecodeImageFailed, this),
182 base::Bind(&ImageDecoder::OnDecodeImageSucceeded, this),
183 request_id));
twellingtona71414d2015-03-26 15:09:45184}
185
186void ImageDecoder::CancelImpl(ImageRequest* image_request) {
187 base::AutoLock lock(map_lock_);
188 for (auto it = image_request_id_map_.begin();
189 it != image_request_id_map_.end();) {
190 if (it->second == image_request) {
191 image_request_id_map_.erase(it++);
192 } else {
193 ++it;
194 }
195 }
196}
197
198void ImageDecoder::StartBatchMode() {
199 DCHECK_CURRENTLY_ON(BrowserThread::IO);
200 utility_process_host_ =
pranay.kumar6a179252015-05-05 11:35:15201 UtilityProcessHost::Create(
202 this, base::ThreadTaskRunnerHandle::Get().get())->AsWeakPtr();
thestige3d6b752015-04-07 21:58:45203 utility_process_host_->SetName(l10n_util::GetStringUTF16(
204 IDS_UTILITY_PROCESS_IMAGE_DECODER_NAME));
amistry6f72f042016-04-05 20:42:07205 if (!utility_process_host_->Start()) {
206 delete utility_process_host_.get();
207 return;
twellington612b9b62015-04-01 00:33:12208 }
bend1dd50f52016-06-26 22:10:48209 utility_process_host_->GetRemoteInterfaces()->GetInterface(&decoder_);
twellingtona71414d2015-03-26 15:09:45210}
211
212void ImageDecoder::StopBatchMode() {
213 DCHECK_CURRENTLY_ON(BrowserThread::IO);
thestig3d8ebe3a2015-05-08 03:25:32214 {
215 // Check for outstanding requests and wait for them to finish.
216 base::AutoLock lock(map_lock_);
217 if (!image_request_id_map_.empty()) {
218 batch_mode_timer_->Reset();
219 return;
220 }
221 }
222
twellingtona71414d2015-03-26 15:09:45223 if (utility_process_host_) {
amistry6f72f042016-04-05 20:42:07224 // With Mojo, the utility process needs to be explicitly shut down by
225 // deleting the host.
226 delete utility_process_host_.get();
227 decoder_.reset();
twellingtona71414d2015-03-26 15:09:45228 utility_process_host_.reset();
229 }
amistryd59fe6b2015-04-30 23:50:30230}
231
232void ImageDecoder::FailAllRequests() {
233 RequestMap requests;
234 {
235 base::AutoLock lock(map_lock_);
236 requests = image_request_id_map_;
237 }
238
239 // Since |OnProcessCrashed| and |OnProcessLaunchFailed| are run asynchronously
240 // from the actual event, it's possible for a new utility process to have been
241 // created and sent requests by the time these functions are run. This results
242 // in failing requests that are unaffected by the crash. Although not ideal,
243 // this is valid and simpler than tracking which request is sent to which
244 // utility process, and whether the request has been sent at all.
245 for (const auto& request : requests)
246 OnDecodeImageFailed(request.first);
247}
248
249void ImageDecoder::OnProcessCrashed(int exit_code) {
250 DCHECK_CURRENTLY_ON(BrowserThread::IO);
251 FailAllRequests();
252}
253
wfh3adf87d2016-05-03 23:26:06254void ImageDecoder::OnProcessLaunchFailed(int error_code) {
amistryd59fe6b2015-04-30 23:50:30255 DCHECK_CURRENTLY_ON(BrowserThread::IO);
256 FailAllRequests();
twellingtona71414d2015-03-26 15:09:45257}
258
amistry6f72f042016-04-05 20:42:07259bool ImageDecoder::OnMessageReceived(const IPC::Message& message) {
260 return false;
[email protected]373c1062011-06-09 21:11:51261}
262
twellingtona71414d2015-03-26 15:09:45263void ImageDecoder::OnDecodeImageSucceeded(
264 const SkBitmap& decoded_image,
265 int request_id) {
266 DCHECK_CURRENTLY_ON(BrowserThread::IO);
267 base::AutoLock lock(map_lock_);
268 auto it = image_request_id_map_.find(request_id);
thestigc5eeb9f362015-04-22 18:42:32269 if (it == image_request_id_map_.end())
270 return;
twellingtona71414d2015-03-26 15:09:45271
thestigc5eeb9f362015-04-22 18:42:32272 ImageRequest* image_request = it->second;
273 image_request->task_runner()->PostTask(
274 FROM_HERE,
275 base::Bind(&ImageDecoder::RunOnImageDecoded,
276 this,
277 decoded_image,
278 request_id));
[email protected]928c0e712011-03-16 15:01:57279}
280
twellingtona71414d2015-03-26 15:09:45281void ImageDecoder::OnDecodeImageFailed(int request_id) {
282 DCHECK_CURRENTLY_ON(BrowserThread::IO);
283 base::AutoLock lock(map_lock_);
284 auto it = image_request_id_map_.find(request_id);
thestigc5eeb9f362015-04-22 18:42:32285 if (it == image_request_id_map_.end())
286 return;
[email protected]551707a2010-06-16 16:59:47287
thestigc5eeb9f362015-04-22 18:42:32288 ImageRequest* image_request = it->second;
289 image_request->task_runner()->PostTask(
290 FROM_HERE,
291 base::Bind(&ImageDecoder::RunOnDecodeImageFailed, this, request_id));
292}
293
294void ImageDecoder::RunOnImageDecoded(const SkBitmap& decoded_image,
295 int request_id) {
296 ImageRequest* image_request;
297 {
298 base::AutoLock lock(map_lock_);
299 auto it = image_request_id_map_.find(request_id);
300 if (it == image_request_id_map_.end())
301 return;
302 image_request = it->second;
twellingtona71414d2015-03-26 15:09:45303 image_request_id_map_.erase(it);
[email protected]11f16d102012-08-29 23:12:15304 }
thestigc5eeb9f362015-04-22 18:42:32305
306 DCHECK(image_request->task_runner()->RunsTasksOnCurrentThread());
307 image_request->OnImageDecoded(decoded_image);
308}
309
310void ImageDecoder::RunOnDecodeImageFailed(int request_id) {
311 ImageRequest* image_request;
312 {
313 base::AutoLock lock(map_lock_);
314 auto it = image_request_id_map_.find(request_id);
315 if (it == image_request_id_map_.end())
316 return;
317 image_request = it->second;
318 image_request_id_map_.erase(it);
319 }
320
321 DCHECK(image_request->task_runner()->RunsTasksOnCurrentThread());
322 image_request->OnDecodeImageFailed();
[email protected]551707a2010-06-16 16:59:47323}