Index: chrome/browser/image_decoder.cc |
diff --git a/chrome/browser/image_decoder.cc b/chrome/browser/image_decoder.cc |
index 3815f26dc922621713773dbb4ee634ea70e37626..93360b7007c11ba8359abb1cd4186281aa08bcd8 100644 |
--- a/chrome/browser/image_decoder.cc |
+++ b/chrome/browser/image_decoder.cc |
@@ -7,53 +7,78 @@ |
#include <utility> |
#include "base/bind.h" |
+#include "base/callback.h" |
+#include "base/lazy_instance.h" |
#include "base/threading/thread_task_runner_handle.h" |
#include "build/build_config.h" |
-#include "chrome/browser/browser_process.h" |
-#include "chrome/common/image_decoder.mojom.h" |
-#include "chrome/grit/generated_resources.h" |
#include "content/public/browser/browser_thread.h" |
-#include "content/public/browser/utility_process_host.h" |
-#include "services/service_manager/public/cpp/interface_provider.h" |
+#include "content/public/common/service_manager_connection.h" |
+#include "ipc/ipc_channel.h" |
+#include "services/image_decoder/public/cpp/decode.h" |
+#include "services/service_manager/public/cpp/connector.h" |
#include "third_party/skia/include/core/SkBitmap.h" |
-#include "ui/base/l10n/l10n_util.h" |
- |
-using content::BrowserThread; |
-using content::UtilityProcessHost; |
namespace { |
// static, Leaky to allow access from any thread. |
base::LazyInstance<ImageDecoder>::Leaky g_decoder = LAZY_INSTANCE_INITIALIZER; |
-// How long to wait after the last request has been received before ending |
-// batch mode. |
-const int kBatchModeTimeoutSeconds = 5; |
+const int64_t kMaxImageSizeInBytes = |
+ static_cast<int64_t>(IPC::Channel::kMaximumMessageSize); |
+// Note that this is always called on the thread which initiated the |
+// corresponding image_decoder::Decode request. |
void OnDecodeImageDone( |
base::Callback<void(int)> fail_callback, |
base::Callback<void(const SkBitmap&, int)> success_callback, |
int request_id, |
const SkBitmap& image) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
if (!image.isNull() && !image.empty()) |
success_callback.Run(image, request_id); |
else |
fail_callback.Run(request_id); |
} |
-} // namespace |
+void BindToBrowserConnector(service_manager::mojom::ConnectorRequest request) { |
+ if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::UI, FROM_HERE, |
+ base::Bind(&BindToBrowserConnector, base::Passed(&request))); |
+ return; |
+ } |
+ |
+ content::ServiceManagerConnection::GetForProcess()->GetConnector() |
+ ->BindRequest(std::move(request)); |
+} |
-ImageDecoder::ImageDecoder() |
- : image_request_id_counter_(0) { |
- // A single ImageDecoder instance should live for the life of the program. |
- // Explicitly add a reference so the object isn't deleted. |
- AddRef(); |
+void RunDecodeCallbackOnTaskRunner( |
+ const image_decoder::mojom::ImageDecoder::DecodeImageCallback& callback, |
+ scoped_refptr<base::SequencedTaskRunner> task_runner, |
+ const SkBitmap& image) { |
+ task_runner->PostTask(FROM_HERE, base::Bind(callback, image)); |
} |
-ImageDecoder::~ImageDecoder() { |
+void DecodeImage( |
+ std::vector<uint8_t> image_data, |
+ image_decoder::mojom::ImageCodec codec, |
+ bool shrink_to_fit, |
+ const image_decoder::mojom::ImageDecoder::DecodeImageCallback& callback, |
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
+ |
+ service_manager::mojom::ConnectorRequest connector_request; |
+ std::unique_ptr<service_manager::Connector> connector = |
+ service_manager::Connector::Create(&connector_request); |
+ BindToBrowserConnector(std::move(connector_request)); |
+ |
+ image_decoder::Decode(connector.get(), image_data, codec, shrink_to_fit, |
+ kMaxImageSizeInBytes, |
+ base::Bind(&RunDecodeCallbackOnTaskRunner, |
+ callback, callback_task_runner)); |
} |
+} // namespace |
+ |
ImageDecoder::ImageRequest::ImageRequest() |
: task_runner_(base::ThreadTaskRunnerHandle::Get()) { |
DCHECK(sequence_checker_.CalledOnValidSequence()); |
@@ -70,6 +95,10 @@ ImageDecoder::ImageRequest::~ImageRequest() { |
ImageDecoder::Cancel(this); |
} |
+ImageDecoder::ImageDecoder() : image_request_id_counter_(0) {} |
+ |
+ImageDecoder::~ImageDecoder() {} |
+ |
// static |
void ImageDecoder::Start(ImageRequest* image_request, |
std::vector<uint8_t> image_data) { |
@@ -88,9 +117,8 @@ void ImageDecoder::StartWithOptions(ImageRequest* image_request, |
std::vector<uint8_t> image_data, |
ImageCodec image_codec, |
bool shrink_to_fit) { |
- g_decoder.Pointer()->StartWithOptionsImpl(image_request, |
- std::move(image_data), |
- image_codec, shrink_to_fit); |
+ g_decoder.Get().StartWithOptionsImpl(image_request, std::move(image_data), |
+ image_codec, shrink_to_fit); |
} |
// static |
@@ -117,68 +145,35 @@ void ImageDecoder::StartWithOptionsImpl(ImageRequest* image_request, |
image_request_id_map_.insert(std::make_pair(request_id, image_request)); |
} |
- BrowserThread::PostTask( |
- BrowserThread::IO, FROM_HERE, |
- base::Bind( |
- &ImageDecoder::DecodeImageInSandbox, |
- g_decoder.Pointer(), request_id, |
- base::Passed(std::move(image_data)), |
- image_codec, shrink_to_fit)); |
+ image_decoder::mojom::ImageCodec codec = |
+ image_decoder::mojom::ImageCodec::DEFAULT; |
+#if defined(OS_CHROMEOS) |
+ if (image_codec == ROBUST_JPEG_CODEC) |
+ codec = image_decoder::mojom::ImageCodec::ROBUST_JPEG; |
+ if (image_codec == ROBUST_PNG_CODEC) |
+ codec = image_decoder::mojom::ImageCodec::ROBUST_PNG; |
+#endif // defined(OS_CHROMEOS) |
+ |
+ auto callback = base::Bind( |
+ &OnDecodeImageDone, |
+ base::Bind(&ImageDecoder::OnDecodeImageFailed, base::Unretained(this)), |
+ base::Bind(&ImageDecoder::OnDecodeImageSucceeded, base::Unretained(this)), |
+ request_id); |
+ |
+ // NOTE: There exist ImageDecoder consumers which implicitly rely on this |
+ // operation happening on a thread which always has a ThreadTaskRunnerHandle. |
+ // We arbitrarily use the IO thread here to match details of the legacy |
+ // implementation. |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::IO, FROM_HERE, |
+ base::Bind(&DecodeImage, base::Passed(&image_data), codec, shrink_to_fit, |
+ callback, make_scoped_refptr(image_request->task_runner()))); |
} |
// static |
void ImageDecoder::Cancel(ImageRequest* image_request) { |
DCHECK(image_request); |
- g_decoder.Pointer()->CancelImpl(image_request); |
-} |
- |
-void ImageDecoder::DecodeImageInSandbox( |
- int request_id, |
- std::vector<uint8_t> image_data, |
- ImageCodec image_codec, |
- bool shrink_to_fit) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- base::AutoLock lock(map_lock_); |
- const auto it = image_request_id_map_.find(request_id); |
- if (it == image_request_id_map_.end()) |
- return; |
- |
- ImageRequest* image_request = it->second; |
- if (!utility_process_host_) { |
- StartBatchMode(); |
- } |
- if (!utility_process_host_) { |
- // Utility process failed to start; notify delegate and return. |
- // Without this check, we were seeing crashes on startup. Further |
- // investigation is needed to determine why the utility process |
- // is failing to start. See crbug.com/472272 |
- image_request->task_runner()->PostTask( |
- FROM_HERE, |
- base::Bind(&ImageDecoder::RunOnDecodeImageFailed, this, request_id)); |
- return; |
- } |
- |
- if (!batch_mode_timer_) { |
- // Created here so it will call StopBatchMode() on the right thread. |
- batch_mode_timer_.reset(new base::DelayTimer( |
- FROM_HERE, base::TimeDelta::FromSeconds(kBatchModeTimeoutSeconds), this, |
- &ImageDecoder::StopBatchMode)); |
- } |
- batch_mode_timer_->Reset(); |
- |
- mojom::ImageCodec mojo_codec = mojom::ImageCodec::DEFAULT; |
-#if defined(OS_CHROMEOS) |
- if (image_codec == ROBUST_JPEG_CODEC) |
- mojo_codec = mojom::ImageCodec::ROBUST_JPEG; |
- if (image_codec == ROBUST_PNG_CODEC) |
- mojo_codec = mojom::ImageCodec::ROBUST_PNG; |
-#endif // defined(OS_CHROMEOS) |
- decoder_->DecodeImage( |
- image_data, mojo_codec, shrink_to_fit, |
- base::Bind(&OnDecodeImageDone, |
- base::Bind(&ImageDecoder::OnDecodeImageFailed, this), |
- base::Bind(&ImageDecoder::OnDecodeImageSucceeded, this), |
- request_id)); |
+ g_decoder.Get().CancelImpl(image_request); |
} |
void ImageDecoder::CancelImpl(ImageRequest* image_request) { |
@@ -193,104 +188,9 @@ void ImageDecoder::CancelImpl(ImageRequest* image_request) { |
} |
} |
-void ImageDecoder::StartBatchMode() { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- utility_process_host_ = |
- UtilityProcessHost::Create( |
- this, base::ThreadTaskRunnerHandle::Get().get())->AsWeakPtr(); |
- utility_process_host_->SetName(l10n_util::GetStringUTF16( |
- IDS_UTILITY_PROCESS_IMAGE_DECODER_NAME)); |
- if (!utility_process_host_->Start()) { |
- delete utility_process_host_.get(); |
- return; |
- } |
- utility_process_host_->GetRemoteInterfaces()->GetInterface(&decoder_); |
-} |
- |
-void ImageDecoder::StopBatchMode() { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- { |
- // Check for outstanding requests and wait for them to finish. |
- base::AutoLock lock(map_lock_); |
- if (!image_request_id_map_.empty()) { |
- batch_mode_timer_->Reset(); |
- return; |
- } |
- } |
- |
- if (utility_process_host_) { |
- // With Mojo, the utility process needs to be explicitly shut down by |
- // deleting the host. |
- delete utility_process_host_.get(); |
- decoder_.reset(); |
- utility_process_host_.reset(); |
- } |
-} |
- |
-void ImageDecoder::FailAllRequests() { |
- RequestMap requests; |
- { |
- base::AutoLock lock(map_lock_); |
- requests = image_request_id_map_; |
- } |
- |
- // Since |OnProcessCrashed| and |OnProcessLaunchFailed| are run asynchronously |
- // from the actual event, it's possible for a new utility process to have been |
- // created and sent requests by the time these functions are run. This results |
- // in failing requests that are unaffected by the crash. Although not ideal, |
- // this is valid and simpler than tracking which request is sent to which |
- // utility process, and whether the request has been sent at all. |
- for (const auto& request : requests) |
- OnDecodeImageFailed(request.first); |
-} |
- |
-void ImageDecoder::OnProcessCrashed(int exit_code) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- FailAllRequests(); |
-} |
- |
-void ImageDecoder::OnProcessLaunchFailed(int error_code) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- FailAllRequests(); |
-} |
- |
-bool ImageDecoder::OnMessageReceived(const IPC::Message& message) { |
- return false; |
-} |
- |
void ImageDecoder::OnDecodeImageSucceeded( |
const SkBitmap& decoded_image, |
int request_id) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- base::AutoLock lock(map_lock_); |
- auto it = image_request_id_map_.find(request_id); |
- if (it == image_request_id_map_.end()) |
- return; |
- |
- ImageRequest* image_request = it->second; |
- image_request->task_runner()->PostTask( |
- FROM_HERE, |
- base::Bind(&ImageDecoder::RunOnImageDecoded, |
- this, |
- decoded_image, |
- request_id)); |
-} |
- |
-void ImageDecoder::OnDecodeImageFailed(int request_id) { |
- DCHECK_CURRENTLY_ON(BrowserThread::IO); |
- base::AutoLock lock(map_lock_); |
- auto it = image_request_id_map_.find(request_id); |
- if (it == image_request_id_map_.end()) |
- return; |
- |
- ImageRequest* image_request = it->second; |
- image_request->task_runner()->PostTask( |
- FROM_HERE, |
- base::Bind(&ImageDecoder::RunOnDecodeImageFailed, this, request_id)); |
-} |
- |
-void ImageDecoder::RunOnImageDecoded(const SkBitmap& decoded_image, |
- int request_id) { |
ImageRequest* image_request; |
{ |
base::AutoLock lock(map_lock_); |
@@ -305,7 +205,7 @@ void ImageDecoder::RunOnImageDecoded(const SkBitmap& decoded_image, |
image_request->OnImageDecoded(decoded_image); |
} |
-void ImageDecoder::RunOnDecodeImageFailed(int request_id) { |
+void ImageDecoder::OnDecodeImageFailed(int request_id) { |
ImageRequest* image_request; |
{ |
base::AutoLock lock(map_lock_); |