| 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_);
|
|
|