// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h" #include #include "base/lazy_instance.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/api/image_writer_private/destroy_partitions_operation.h" #include "chrome/browser/extensions/api/image_writer_private/error_messages.h" #include "chrome/browser/extensions/api/image_writer_private/operation.h" #include "chrome/browser/extensions/api/image_writer_private/write_from_file_operation.h" #include "chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h" #include "chrome/browser/extensions/event_router_forwarder.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "extensions/browser/event_router.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/notification_types.h" namespace image_writer_api = extensions::api::image_writer_private; namespace extensions { namespace image_writer { using content::BrowserThread; OperationManager::OperationManager(content::BrowserContext* context) : browser_context_(context), extension_registry_observer_(this), weak_factory_(this) { extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); Profile* profile = Profile::FromBrowserContext(browser_context_); registrar_.Add(this, extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, content::Source(profile)); registrar_.Add(this, extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, content::Source(profile)); registrar_.Add(this, extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, content::Source(profile)); } OperationManager::~OperationManager() { } void OperationManager::Shutdown() { for (OperationMap::iterator iter = operations_.begin(); iter != operations_.end(); iter++) { BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(&Operation::Abort, iter->second)); } } void OperationManager::StartWriteFromUrl( const ExtensionId& extension_id, GURL url, const std::string& hash, const std::string& device_path, const Operation::StartWriteCallback& callback) { #if defined(OS_CHROMEOS) // Chrome OS can only support a single operation at a time. if (operations_.size() > 0) { #else OperationMap::iterator existing_operation = operations_.find(extension_id); if (existing_operation != operations_.end()) { #endif return callback.Run(false, error::kOperationAlreadyInProgress); } scoped_refptr operation( new WriteFromUrlOperation(weak_factory_.GetWeakPtr(), extension_id, browser_context_->GetRequestContext(), url, hash, device_path)); operations_[extension_id] = operation; BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(&Operation::Start, operation)); callback.Run(true, ""); } void OperationManager::StartWriteFromFile( const ExtensionId& extension_id, const base::FilePath& path, const std::string& device_path, const Operation::StartWriteCallback& callback) { #if defined(OS_CHROMEOS) // Chrome OS can only support a single operation at a time. if (operations_.size() > 0) { #else OperationMap::iterator existing_operation = operations_.find(extension_id); if (existing_operation != operations_.end()) { #endif return callback.Run(false, error::kOperationAlreadyInProgress); } scoped_refptr operation(new WriteFromFileOperation( weak_factory_.GetWeakPtr(), extension_id, path, device_path)); operations_[extension_id] = operation; BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(&Operation::Start, operation)); callback.Run(true, ""); } void OperationManager::CancelWrite( const ExtensionId& extension_id, const Operation::CancelWriteCallback& callback) { Operation* existing_operation = GetOperation(extension_id); if (existing_operation == NULL) { callback.Run(false, error::kNoOperationInProgress); } else { BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(&Operation::Cancel, existing_operation)); DeleteOperation(extension_id); callback.Run(true, ""); } } void OperationManager::DestroyPartitions( const ExtensionId& extension_id, const std::string& device_path, const Operation::StartWriteCallback& callback) { OperationMap::iterator existing_operation = operations_.find(extension_id); if (existing_operation != operations_.end()) { return callback.Run(false, error::kOperationAlreadyInProgress); } scoped_refptr operation(new DestroyPartitionsOperation( weak_factory_.GetWeakPtr(), extension_id, device_path)); operations_[extension_id] = operation; BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(&Operation::Start, operation)); callback.Run(true, ""); } void OperationManager::OnProgress(const ExtensionId& extension_id, image_writer_api::Stage stage, int progress) { DCHECK_CURRENTLY_ON(BrowserThread::UI); image_writer_api::ProgressInfo info; info.stage = stage; info.percent_complete = progress; scoped_ptr args( image_writer_api::OnWriteProgress::Create(info)); scoped_ptr event(new Event( events::IMAGE_WRITER_PRIVATE_ON_WRITE_PROGRESS, image_writer_api::OnWriteProgress::kEventName, std::move(args))); EventRouter::Get(browser_context_) ->DispatchEventToExtension(extension_id, std::move(event)); } void OperationManager::OnComplete(const ExtensionId& extension_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); scoped_ptr args(image_writer_api::OnWriteComplete::Create()); scoped_ptr event(new Event( events::IMAGE_WRITER_PRIVATE_ON_WRITE_COMPLETE, image_writer_api::OnWriteComplete::kEventName, std::move(args))); EventRouter::Get(browser_context_) ->DispatchEventToExtension(extension_id, std::move(event)); DeleteOperation(extension_id); } void OperationManager::OnError(const ExtensionId& extension_id, image_writer_api::Stage stage, int progress, const std::string& error_message) { DCHECK_CURRENTLY_ON(BrowserThread::UI); image_writer_api::ProgressInfo info; DLOG(ERROR) << "ImageWriter error: " << error_message; info.stage = stage; info.percent_complete = progress; scoped_ptr args( image_writer_api::OnWriteError::Create(info, error_message)); scoped_ptr event(new Event(events::IMAGE_WRITER_PRIVATE_ON_WRITE_ERROR, image_writer_api::OnWriteError::kEventName, std::move(args))); EventRouter::Get(browser_context_) ->DispatchEventToExtension(extension_id, std::move(event)); DeleteOperation(extension_id); } Operation* OperationManager::GetOperation(const ExtensionId& extension_id) { OperationMap::iterator existing_operation = operations_.find(extension_id); if (existing_operation == operations_.end()) return NULL; return existing_operation->second.get(); } void OperationManager::DeleteOperation(const ExtensionId& extension_id) { OperationMap::iterator existing_operation = operations_.find(extension_id); if (existing_operation != operations_.end()) { operations_.erase(existing_operation); } } void OperationManager::OnExtensionUnloaded( content::BrowserContext* browser_context, const Extension* extension, UnloadedExtensionInfo::Reason reason) { DeleteOperation(extension->id()); } void OperationManager::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { case extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: { DeleteOperation(content::Details(details).ptr()->id()); break; } case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: { DeleteOperation( content::Details(details)->extension()->id()); break; } case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: { DeleteOperation( content::Details(details)->extension()->id()); break; } default: { NOTREACHED(); break; } } } OperationManager* OperationManager::Get(content::BrowserContext* context) { return BrowserContextKeyedAPIFactory::Get(context); } static base::LazyInstance > g_factory = LAZY_INSTANCE_INITIALIZER; BrowserContextKeyedAPIFactory* OperationManager::GetFactoryInstance() { return g_factory.Pointer(); } } // namespace image_writer } // namespace extensions