blob: adb15c3fcb7784a4c870da9164d4d9e42fd94d9d [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
[email protected]31893772011-10-11 17:41:507#include "base/bind.h"
gabb15e19072016-05-11 20:45:418#include "base/threading/thread_task_runner_handle.h"
avi6846aef2015-12-26 01:09:389#include "build/build_config.h"
[email protected]551707a2010-06-16 16:59:4710#include "chrome/browser/browser_process.h"
amistry6f72f042016-04-05 20:42:0711#include "chrome/common/image_decoder.mojom.h"
thestige3d6b752015-04-07 21:58:4512#include "chrome/grit/generated_resources.h"
[email protected]c38831a12011-10-28 12:44:4913#include "content/public/browser/browser_thread.h"
[email protected]c4f883a2012-02-03 17:02:0714#include "content/public/browser/utility_process_host.h"
amistry6f72f042016-04-05 20:42:0715#include "content/public/common/service_registry.h"
amistry6f72f042016-04-05 20:42:0716#include "third_party/skia/include/core/SkBitmap.h"
thestige3d6b752015-04-07 21:58:4517#include "ui/base/l10n/l10n_util.h"
[email protected]551707a2010-06-16 16:59:4718
[email protected]631bb742011-11-02 11:29:3919using content::BrowserThread;
[email protected]c4f883a2012-02-03 17:02:0720using content::UtilityProcessHost;
[email protected]631bb742011-11-02 11:29:3921
twellingtona71414d2015-03-26 15:09:4522namespace {
23
24// static, Leaky to allow access from any thread.
25base::LazyInstance<ImageDecoder>::Leaky g_decoder = LAZY_INSTANCE_INITIALIZER;
26
27// How long to wait after the last request has been received before ending
28// batch mode.
29const int kBatchModeTimeoutSeconds = 5;
30
amistry6f72f042016-04-05 20:42:0731void OnDecodeImageDone(
32 base::Callback<void(int)> fail_callback,
33 base::Callback<void(const SkBitmap&, int)> success_callback,
mswb0123d12016-06-01 21:59:5434 int request_id,
35 const SkBitmap& image) {
amistry6f72f042016-04-05 20:42:0736 DCHECK_CURRENTLY_ON(BrowserThread::IO);
mswb0123d12016-06-01 21:59:5437 if (!image.isNull() && !image.empty())
38 success_callback.Run(image, request_id);
39 else
40 fail_callback.Run(request_id);
amistry6f72f042016-04-05 20:42:0741}
42
twellingtona71414d2015-03-26 15:09:4543} // namespace
44
45ImageDecoder::ImageDecoder()
thestigd3485b692015-04-30 09:47:3246 : image_request_id_counter_(0) {
twellingtona71414d2015-03-26 15:09:4547 // A single ImageDecoder instance should live for the life of the program.
48 // Explicitly add a reference so the object isn't deleted.
49 AddRef();
[email protected]551707a2010-06-16 16:59:4750}
51
twellingtona71414d2015-03-26 15:09:4552ImageDecoder::~ImageDecoder() {
pneubeck93871252015-01-20 11:26:3653}
54
thestigc5eeb9f362015-04-22 18:42:3255ImageDecoder::ImageRequest::ImageRequest()
56 : task_runner_(base::ThreadTaskRunnerHandle::Get()) {
57 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
58}
59
twellingtona71414d2015-03-26 15:09:4560ImageDecoder::ImageRequest::ImageRequest(
61 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
62 : task_runner_(task_runner) {
thestigc5eeb9f362015-04-22 18:42:3263 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
twellingtona71414d2015-03-26 15:09:4564}
[email protected]863e6d962011-05-15 19:39:3565
twellingtona71414d2015-03-26 15:09:4566ImageDecoder::ImageRequest::~ImageRequest() {
thestigc5eeb9f362015-04-22 18:42:3267 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
twellingtona71414d2015-03-26 15:09:4568 ImageDecoder::Cancel(this);
69}
70
71// static
72void ImageDecoder::Start(ImageRequest* image_request,
73 const std::string& image_data) {
74 StartWithOptions(image_request, image_data, DEFAULT_CODEC, false);
75}
76
77// static
78void ImageDecoder::StartWithOptions(ImageRequest* image_request,
79 const std::string& image_data,
80 ImageCodec image_codec,
81 bool shrink_to_fit) {
thestigc5eeb9f362015-04-22 18:42:3282 g_decoder.Pointer()->StartWithOptionsImpl(image_request, image_data,
83 image_codec, shrink_to_fit);
84}
85
86void ImageDecoder::StartWithOptionsImpl(ImageRequest* image_request,
87 const std::string& image_data,
88 ImageCodec image_codec,
89 bool shrink_to_fit) {
twellingtona71414d2015-03-26 15:09:4590 DCHECK(image_request);
91 DCHECK(image_request->task_runner());
thestigc5eeb9f362015-04-22 18:42:3292
93 int request_id;
94 {
95 base::AutoLock lock(map_lock_);
96 request_id = image_request_id_counter_++;
97 image_request_id_map_.insert(std::make_pair(request_id, image_request));
98 }
99
[email protected]cca169b52010-10-08 22:15:55100 BrowserThread::PostTask(
twellingtona71414d2015-03-26 15:09:45101 BrowserThread::IO, FROM_HERE,
102 base::Bind(
103 &ImageDecoder::DecodeImageInSandbox,
thestigc5eeb9f362015-04-22 18:42:32104 g_decoder.Pointer(), request_id,
twellingtona71414d2015-03-26 15:09:45105 std::vector<unsigned char>(image_data.begin(), image_data.end()),
106 image_codec, shrink_to_fit));
[email protected]551707a2010-06-16 16:59:47107}
108
twellingtona71414d2015-03-26 15:09:45109// static
110void ImageDecoder::Cancel(ImageRequest* image_request) {
111 DCHECK(image_request);
112 g_decoder.Pointer()->CancelImpl(image_request);
113}
114
115void ImageDecoder::DecodeImageInSandbox(
thestigc5eeb9f362015-04-22 18:42:32116 int request_id,
twellingtona71414d2015-03-26 15:09:45117 const std::vector<unsigned char>& image_data,
118 ImageCodec image_codec,
119 bool shrink_to_fit) {
120 DCHECK_CURRENTLY_ON(BrowserThread::IO);
thestigc5eeb9f362015-04-22 18:42:32121 base::AutoLock lock(map_lock_);
122 const auto it = image_request_id_map_.find(request_id);
123 if (it == image_request_id_map_.end())
124 return;
125
126 ImageRequest* image_request = it->second;
twellingtona71414d2015-03-26 15:09:45127 if (!utility_process_host_) {
128 StartBatchMode();
129 }
twellington612b9b62015-04-01 00:33:12130 if (!utility_process_host_) {
131 // Utility process failed to start; notify delegate and return.
132 // Without this check, we were seeing crashes on startup. Further
133 // investigation is needed to determine why the utility process
134 // is failing to start. See crbug.com/472272
135 image_request->task_runner()->PostTask(
thestigc5eeb9f362015-04-22 18:42:32136 FROM_HERE,
137 base::Bind(&ImageDecoder::RunOnDecodeImageFailed, this, request_id));
twellington612b9b62015-04-01 00:33:12138 return;
139 }
twellingtona71414d2015-03-26 15:09:45140
thestigd3485b692015-04-30 09:47:32141 if (!batch_mode_timer_) {
142 // Created here so it will call StopBatchMode() on the right thread.
danakj8c3eb802015-09-24 07:53:00143 batch_mode_timer_.reset(new base::DelayTimer(
144 FROM_HERE, base::TimeDelta::FromSeconds(kBatchModeTimeoutSeconds), this,
thestigd3485b692015-04-30 09:47:32145 &ImageDecoder::StopBatchMode));
146 }
147 batch_mode_timer_->Reset();
twellingtona71414d2015-03-26 15:09:45148
amistry6f72f042016-04-05 20:42:07149 mojom::ImageCodec mojo_codec = mojom::ImageCodec::DEFAULT;
edward.baker199f66b2015-05-07 19:13:30150#if defined(OS_CHROMEOS)
amistry6f72f042016-04-05 20:42:07151 if (image_codec == ROBUST_JPEG_CODEC)
152 mojo_codec = mojom::ImageCodec::ROBUST_JPEG;
153 if (image_codec == ROBUST_PNG_CODEC)
154 mojo_codec = mojom::ImageCodec::ROBUST_PNG;
edward.baker199f66b2015-05-07 19:13:30155#endif // defined(OS_CHROMEOS)
amistry6f72f042016-04-05 20:42:07156 decoder_->DecodeImage(
157 mojo::Array<uint8_t>::From(image_data),
158 mojo_codec,
159 shrink_to_fit,
160 base::Bind(&OnDecodeImageDone,
161 base::Bind(&ImageDecoder::OnDecodeImageFailed, this),
162 base::Bind(&ImageDecoder::OnDecodeImageSucceeded, this),
163 request_id));
twellingtona71414d2015-03-26 15:09:45164}
165
166void ImageDecoder::CancelImpl(ImageRequest* image_request) {
167 base::AutoLock lock(map_lock_);
168 for (auto it = image_request_id_map_.begin();
169 it != image_request_id_map_.end();) {
170 if (it->second == image_request) {
171 image_request_id_map_.erase(it++);
172 } else {
173 ++it;
174 }
175 }
176}
177
178void ImageDecoder::StartBatchMode() {
179 DCHECK_CURRENTLY_ON(BrowserThread::IO);
180 utility_process_host_ =
pranay.kumar6a179252015-05-05 11:35:15181 UtilityProcessHost::Create(
182 this, base::ThreadTaskRunnerHandle::Get().get())->AsWeakPtr();
thestige3d6b752015-04-07 21:58:45183 utility_process_host_->SetName(l10n_util::GetStringUTF16(
184 IDS_UTILITY_PROCESS_IMAGE_DECODER_NAME));
amistry6f72f042016-04-05 20:42:07185 if (!utility_process_host_->Start()) {
186 delete utility_process_host_.get();
187 return;
twellington612b9b62015-04-01 00:33:12188 }
amistry6f72f042016-04-05 20:42:07189 content::ServiceRegistry* service_registry =
190 utility_process_host_->GetServiceRegistry();
191 service_registry->ConnectToRemoteService(mojo::GetProxy(&decoder_));
twellingtona71414d2015-03-26 15:09:45192}
193
194void ImageDecoder::StopBatchMode() {
195 DCHECK_CURRENTLY_ON(BrowserThread::IO);
thestig3d8ebe3a2015-05-08 03:25:32196 {
197 // Check for outstanding requests and wait for them to finish.
198 base::AutoLock lock(map_lock_);
199 if (!image_request_id_map_.empty()) {
200 batch_mode_timer_->Reset();
201 return;
202 }
203 }
204
twellingtona71414d2015-03-26 15:09:45205 if (utility_process_host_) {
amistry6f72f042016-04-05 20:42:07206 // With Mojo, the utility process needs to be explicitly shut down by
207 // deleting the host.
208 delete utility_process_host_.get();
209 decoder_.reset();
twellingtona71414d2015-03-26 15:09:45210 utility_process_host_.reset();
211 }
amistryd59fe6b2015-04-30 23:50:30212}
213
214void ImageDecoder::FailAllRequests() {
215 RequestMap requests;
216 {
217 base::AutoLock lock(map_lock_);
218 requests = image_request_id_map_;
219 }
220
221 // Since |OnProcessCrashed| and |OnProcessLaunchFailed| are run asynchronously
222 // from the actual event, it's possible for a new utility process to have been
223 // created and sent requests by the time these functions are run. This results
224 // in failing requests that are unaffected by the crash. Although not ideal,
225 // this is valid and simpler than tracking which request is sent to which
226 // utility process, and whether the request has been sent at all.
227 for (const auto& request : requests)
228 OnDecodeImageFailed(request.first);
229}
230
231void ImageDecoder::OnProcessCrashed(int exit_code) {
232 DCHECK_CURRENTLY_ON(BrowserThread::IO);
233 FailAllRequests();
234}
235
wfh3adf87d2016-05-03 23:26:06236void ImageDecoder::OnProcessLaunchFailed(int error_code) {
amistryd59fe6b2015-04-30 23:50:30237 DCHECK_CURRENTLY_ON(BrowserThread::IO);
238 FailAllRequests();
twellingtona71414d2015-03-26 15:09:45239}
240
amistry6f72f042016-04-05 20:42:07241bool ImageDecoder::OnMessageReceived(const IPC::Message& message) {
242 return false;
[email protected]373c1062011-06-09 21:11:51243}
244
twellingtona71414d2015-03-26 15:09:45245void ImageDecoder::OnDecodeImageSucceeded(
246 const SkBitmap& decoded_image,
247 int request_id) {
248 DCHECK_CURRENTLY_ON(BrowserThread::IO);
249 base::AutoLock lock(map_lock_);
250 auto it = image_request_id_map_.find(request_id);
thestigc5eeb9f362015-04-22 18:42:32251 if (it == image_request_id_map_.end())
252 return;
twellingtona71414d2015-03-26 15:09:45253
thestigc5eeb9f362015-04-22 18:42:32254 ImageRequest* image_request = it->second;
255 image_request->task_runner()->PostTask(
256 FROM_HERE,
257 base::Bind(&ImageDecoder::RunOnImageDecoded,
258 this,
259 decoded_image,
260 request_id));
[email protected]928c0e712011-03-16 15:01:57261}
262
twellingtona71414d2015-03-26 15:09:45263void ImageDecoder::OnDecodeImageFailed(int request_id) {
264 DCHECK_CURRENTLY_ON(BrowserThread::IO);
265 base::AutoLock lock(map_lock_);
266 auto it = image_request_id_map_.find(request_id);
thestigc5eeb9f362015-04-22 18:42:32267 if (it == image_request_id_map_.end())
268 return;
[email protected]551707a2010-06-16 16:59:47269
thestigc5eeb9f362015-04-22 18:42:32270 ImageRequest* image_request = it->second;
271 image_request->task_runner()->PostTask(
272 FROM_HERE,
273 base::Bind(&ImageDecoder::RunOnDecodeImageFailed, this, request_id));
274}
275
276void ImageDecoder::RunOnImageDecoded(const SkBitmap& decoded_image,
277 int request_id) {
278 ImageRequest* image_request;
279 {
280 base::AutoLock lock(map_lock_);
281 auto it = image_request_id_map_.find(request_id);
282 if (it == image_request_id_map_.end())
283 return;
284 image_request = it->second;
twellingtona71414d2015-03-26 15:09:45285 image_request_id_map_.erase(it);
[email protected]11f16d102012-08-29 23:12:15286 }
thestigc5eeb9f362015-04-22 18:42:32287
288 DCHECK(image_request->task_runner()->RunsTasksOnCurrentThread());
289 image_request->OnImageDecoded(decoded_image);
290}
291
292void ImageDecoder::RunOnDecodeImageFailed(int request_id) {
293 ImageRequest* image_request;
294 {
295 base::AutoLock lock(map_lock_);
296 auto it = image_request_id_map_.find(request_id);
297 if (it == image_request_id_map_.end())
298 return;
299 image_request = it->second;
300 image_request_id_map_.erase(it);
301 }
302
303 DCHECK(image_request->task_runner()->RunsTasksOnCurrentThread());
304 image_request->OnDecodeImageFailed();
[email protected]551707a2010-06-16 16:59:47305}