blob: cb758e585e3403b2876e324ca7a562ea54ff5188 [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"
thestigc5eeb9f362015-04-22 18:42:328#include "base/thread_task_runner_handle.h"
[email protected]551707a2010-06-16 16:59:479#include "chrome/browser/browser_process.h"
[email protected]373c1062011-06-09 21:11:5110#include "chrome/common/chrome_utility_messages.h"
thestige3d6b752015-04-07 21:58:4511#include "chrome/grit/generated_resources.h"
[email protected]c38831a12011-10-28 12:44:4912#include "content/public/browser/browser_thread.h"
[email protected]c4f883a2012-02-03 17:02:0713#include "content/public/browser/utility_process_host.h"
thestige3d6b752015-04-07 21:58:4514#include "ui/base/l10n/l10n_util.h"
[email protected]551707a2010-06-16 16:59:4715
[email protected]631bb742011-11-02 11:29:3916using content::BrowserThread;
[email protected]c4f883a2012-02-03 17:02:0717using content::UtilityProcessHost;
[email protected]631bb742011-11-02 11:29:3918
twellingtona71414d2015-03-26 15:09:4519namespace {
20
21// static, Leaky to allow access from any thread.
22base::LazyInstance<ImageDecoder>::Leaky g_decoder = LAZY_INSTANCE_INITIALIZER;
23
24// How long to wait after the last request has been received before ending
25// batch mode.
26const int kBatchModeTimeoutSeconds = 5;
27
28} // namespace
29
30ImageDecoder::ImageDecoder()
thestigd3485b692015-04-30 09:47:3231 : image_request_id_counter_(0) {
twellingtona71414d2015-03-26 15:09:4532 // A single ImageDecoder instance should live for the life of the program.
33 // Explicitly add a reference so the object isn't deleted.
34 AddRef();
[email protected]551707a2010-06-16 16:59:4735}
36
twellingtona71414d2015-03-26 15:09:4537ImageDecoder::~ImageDecoder() {
pneubeck93871252015-01-20 11:26:3638}
39
thestigc5eeb9f362015-04-22 18:42:3240ImageDecoder::ImageRequest::ImageRequest()
41 : task_runner_(base::ThreadTaskRunnerHandle::Get()) {
42 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
43}
44
twellingtona71414d2015-03-26 15:09:4545ImageDecoder::ImageRequest::ImageRequest(
46 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
47 : task_runner_(task_runner) {
thestigc5eeb9f362015-04-22 18:42:3248 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
twellingtona71414d2015-03-26 15:09:4549}
[email protected]863e6d962011-05-15 19:39:3550
twellingtona71414d2015-03-26 15:09:4551ImageDecoder::ImageRequest::~ImageRequest() {
thestigc5eeb9f362015-04-22 18:42:3252 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
twellingtona71414d2015-03-26 15:09:4553 ImageDecoder::Cancel(this);
54}
55
56// static
57void ImageDecoder::Start(ImageRequest* image_request,
58 const std::string& image_data) {
59 StartWithOptions(image_request, image_data, DEFAULT_CODEC, false);
60}
61
62// static
63void ImageDecoder::StartWithOptions(ImageRequest* image_request,
64 const std::string& image_data,
65 ImageCodec image_codec,
66 bool shrink_to_fit) {
thestigc5eeb9f362015-04-22 18:42:3267 g_decoder.Pointer()->StartWithOptionsImpl(image_request, image_data,
68 image_codec, shrink_to_fit);
69}
70
71void ImageDecoder::StartWithOptionsImpl(ImageRequest* image_request,
72 const std::string& image_data,
73 ImageCodec image_codec,
74 bool shrink_to_fit) {
twellingtona71414d2015-03-26 15:09:4575 DCHECK(image_request);
76 DCHECK(image_request->task_runner());
thestigc5eeb9f362015-04-22 18:42:3277
78 int request_id;
79 {
80 base::AutoLock lock(map_lock_);
81 request_id = image_request_id_counter_++;
82 image_request_id_map_.insert(std::make_pair(request_id, image_request));
83 }
84
[email protected]cca169b52010-10-08 22:15:5585 BrowserThread::PostTask(
twellingtona71414d2015-03-26 15:09:4586 BrowserThread::IO, FROM_HERE,
87 base::Bind(
88 &ImageDecoder::DecodeImageInSandbox,
thestigc5eeb9f362015-04-22 18:42:3289 g_decoder.Pointer(), request_id,
twellingtona71414d2015-03-26 15:09:4590 std::vector<unsigned char>(image_data.begin(), image_data.end()),
91 image_codec, shrink_to_fit));
[email protected]551707a2010-06-16 16:59:4792}
93
twellingtona71414d2015-03-26 15:09:4594// static
95void ImageDecoder::Cancel(ImageRequest* image_request) {
96 DCHECK(image_request);
97 g_decoder.Pointer()->CancelImpl(image_request);
98}
99
100void ImageDecoder::DecodeImageInSandbox(
thestigc5eeb9f362015-04-22 18:42:32101 int request_id,
twellingtona71414d2015-03-26 15:09:45102 const std::vector<unsigned char>& image_data,
103 ImageCodec image_codec,
104 bool shrink_to_fit) {
105 DCHECK_CURRENTLY_ON(BrowserThread::IO);
thestigc5eeb9f362015-04-22 18:42:32106 base::AutoLock lock(map_lock_);
107 const auto it = image_request_id_map_.find(request_id);
108 if (it == image_request_id_map_.end())
109 return;
110
111 ImageRequest* image_request = it->second;
twellingtona71414d2015-03-26 15:09:45112 if (!utility_process_host_) {
113 StartBatchMode();
114 }
twellington612b9b62015-04-01 00:33:12115 if (!utility_process_host_) {
116 // Utility process failed to start; notify delegate and return.
117 // Without this check, we were seeing crashes on startup. Further
118 // investigation is needed to determine why the utility process
119 // is failing to start. See crbug.com/472272
120 image_request->task_runner()->PostTask(
thestigc5eeb9f362015-04-22 18:42:32121 FROM_HERE,
122 base::Bind(&ImageDecoder::RunOnDecodeImageFailed, this, request_id));
twellington612b9b62015-04-01 00:33:12123 return;
124 }
twellingtona71414d2015-03-26 15:09:45125
thestigd3485b692015-04-30 09:47:32126 if (!batch_mode_timer_) {
127 // Created here so it will call StopBatchMode() on the right thread.
128 batch_mode_timer_.reset(new base::DelayTimer<ImageDecoder>(
129 FROM_HERE,
130 base::TimeDelta::FromSeconds(kBatchModeTimeoutSeconds),
131 this,
132 &ImageDecoder::StopBatchMode));
133 }
134 batch_mode_timer_->Reset();
twellingtona71414d2015-03-26 15:09:45135
136 switch (image_codec) {
137 case ROBUST_JPEG_CODEC:
138 utility_process_host_->Send(new ChromeUtilityMsg_RobustJPEGDecodeImage(
thestigc5eeb9f362015-04-22 18:42:32139 image_data, request_id));
twellingtona71414d2015-03-26 15:09:45140 break;
141 case DEFAULT_CODEC:
142 utility_process_host_->Send(new ChromeUtilityMsg_DecodeImage(
thestigc5eeb9f362015-04-22 18:42:32143 image_data, shrink_to_fit, request_id));
twellingtona71414d2015-03-26 15:09:45144 break;
145 }
twellingtona71414d2015-03-26 15:09:45146}
147
148void ImageDecoder::CancelImpl(ImageRequest* image_request) {
149 base::AutoLock lock(map_lock_);
150 for (auto it = image_request_id_map_.begin();
151 it != image_request_id_map_.end();) {
152 if (it->second == image_request) {
153 image_request_id_map_.erase(it++);
154 } else {
155 ++it;
156 }
157 }
158}
159
160void ImageDecoder::StartBatchMode() {
161 DCHECK_CURRENTLY_ON(BrowserThread::IO);
162 utility_process_host_ =
pranay.kumar6a179252015-05-05 11:35:15163 UtilityProcessHost::Create(
164 this, base::ThreadTaskRunnerHandle::Get().get())->AsWeakPtr();
thestige3d6b752015-04-07 21:58:45165 utility_process_host_->SetName(l10n_util::GetStringUTF16(
166 IDS_UTILITY_PROCESS_IMAGE_DECODER_NAME));
twellington612b9b62015-04-01 00:33:12167 if (!utility_process_host_->StartBatchMode()) {
168 utility_process_host_.reset();
169 return;
170 }
twellingtona71414d2015-03-26 15:09:45171}
172
173void ImageDecoder::StopBatchMode() {
174 DCHECK_CURRENTLY_ON(BrowserThread::IO);
twellingtona71414d2015-03-26 15:09:45175 if (utility_process_host_) {
176 utility_process_host_->EndBatchMode();
177 utility_process_host_.reset();
178 }
amistryd59fe6b2015-04-30 23:50:30179
180 // There could be outstanding request that are taking too long. Fail these so
181 // that there aren't any dangling requests.
182 FailAllRequests();
183}
184
185void ImageDecoder::FailAllRequests() {
186 RequestMap requests;
187 {
188 base::AutoLock lock(map_lock_);
189 requests = image_request_id_map_;
190 }
191
192 // Since |OnProcessCrashed| and |OnProcessLaunchFailed| are run asynchronously
193 // from the actual event, it's possible for a new utility process to have been
194 // created and sent requests by the time these functions are run. This results
195 // in failing requests that are unaffected by the crash. Although not ideal,
196 // this is valid and simpler than tracking which request is sent to which
197 // utility process, and whether the request has been sent at all.
198 for (const auto& request : requests)
199 OnDecodeImageFailed(request.first);
200}
201
202void ImageDecoder::OnProcessCrashed(int exit_code) {
203 DCHECK_CURRENTLY_ON(BrowserThread::IO);
204 FailAllRequests();
205}
206
207void ImageDecoder::OnProcessLaunchFailed() {
208 DCHECK_CURRENTLY_ON(BrowserThread::IO);
209 FailAllRequests();
twellingtona71414d2015-03-26 15:09:45210}
211
212bool ImageDecoder::OnMessageReceived(
213 const IPC::Message& message) {
[email protected]373c1062011-06-09 21:11:51214 bool handled = true;
215 IPC_BEGIN_MESSAGE_MAP(ImageDecoder, message)
[email protected]2ccf45c2011-08-19 23:35:50216 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Succeeded,
[email protected]373c1062011-06-09 21:11:51217 OnDecodeImageSucceeded)
[email protected]2ccf45c2011-08-19 23:35:50218 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DecodeImage_Failed,
219 OnDecodeImageFailed)
[email protected]373c1062011-06-09 21:11:51220 IPC_MESSAGE_UNHANDLED(handled = false)
[email protected]1f946bc2011-11-17 00:52:30221 IPC_END_MESSAGE_MAP()
[email protected]373c1062011-06-09 21:11:51222 return handled;
223}
224
twellingtona71414d2015-03-26 15:09:45225void ImageDecoder::OnDecodeImageSucceeded(
226 const SkBitmap& decoded_image,
227 int request_id) {
228 DCHECK_CURRENTLY_ON(BrowserThread::IO);
229 base::AutoLock lock(map_lock_);
230 auto it = image_request_id_map_.find(request_id);
thestigc5eeb9f362015-04-22 18:42:32231 if (it == image_request_id_map_.end())
232 return;
twellingtona71414d2015-03-26 15:09:45233
thestigc5eeb9f362015-04-22 18:42:32234 ImageRequest* image_request = it->second;
235 image_request->task_runner()->PostTask(
236 FROM_HERE,
237 base::Bind(&ImageDecoder::RunOnImageDecoded,
238 this,
239 decoded_image,
240 request_id));
[email protected]928c0e712011-03-16 15:01:57241}
242
twellingtona71414d2015-03-26 15:09:45243void ImageDecoder::OnDecodeImageFailed(int request_id) {
244 DCHECK_CURRENTLY_ON(BrowserThread::IO);
245 base::AutoLock lock(map_lock_);
246 auto it = image_request_id_map_.find(request_id);
thestigc5eeb9f362015-04-22 18:42:32247 if (it == image_request_id_map_.end())
248 return;
[email protected]551707a2010-06-16 16:59:47249
thestigc5eeb9f362015-04-22 18:42:32250 ImageRequest* image_request = it->second;
251 image_request->task_runner()->PostTask(
252 FROM_HERE,
253 base::Bind(&ImageDecoder::RunOnDecodeImageFailed, this, request_id));
254}
255
256void ImageDecoder::RunOnImageDecoded(const SkBitmap& decoded_image,
257 int request_id) {
258 ImageRequest* image_request;
259 {
260 base::AutoLock lock(map_lock_);
261 auto it = image_request_id_map_.find(request_id);
262 if (it == image_request_id_map_.end())
263 return;
264 image_request = it->second;
twellingtona71414d2015-03-26 15:09:45265 image_request_id_map_.erase(it);
[email protected]11f16d102012-08-29 23:12:15266 }
thestigc5eeb9f362015-04-22 18:42:32267
268 DCHECK(image_request->task_runner()->RunsTasksOnCurrentThread());
269 image_request->OnImageDecoded(decoded_image);
270}
271
272void ImageDecoder::RunOnDecodeImageFailed(int request_id) {
273 ImageRequest* image_request;
274 {
275 base::AutoLock lock(map_lock_);
276 auto it = image_request_id_map_.find(request_id);
277 if (it == image_request_id_map_.end())
278 return;
279 image_request = it->second;
280 image_request_id_map_.erase(it);
281 }
282
283 DCHECK(image_request->task_runner()->RunsTasksOnCurrentThread());
284 image_request->OnDecodeImageFailed();
[email protected]551707a2010-06-16 16:59:47285}