Home | History | Annotate | Download | only in image_writer_private
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/lazy_instance.h"
      6 #include "chrome/browser/browser_process.h"
      7 #include "chrome/browser/extensions/api/image_writer_private/destroy_partitions_operation.h"
      8 #include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
      9 #include "chrome/browser/extensions/api/image_writer_private/operation.h"
     10 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h"
     11 #include "chrome/browser/extensions/api/image_writer_private/write_from_file_operation.h"
     12 #include "chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h"
     13 #include "chrome/browser/extensions/event_router_forwarder.h"
     14 #include "chrome/browser/extensions/extension_service.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "content/public/browser/browser_thread.h"
     17 #include "content/public/browser/notification_service.h"
     18 #include "extensions/browser/event_router.h"
     19 #include "extensions/browser/extension_host.h"
     20 #include "extensions/browser/extension_registry.h"
     21 #include "extensions/browser/notification_types.h"
     22 
     23 namespace image_writer_api = extensions::api::image_writer_private;
     24 
     25 namespace extensions {
     26 namespace image_writer {
     27 
     28 using content::BrowserThread;
     29 
     30 OperationManager::OperationManager(content::BrowserContext* context)
     31     : browser_context_(context),
     32       extension_registry_observer_(this),
     33       weak_factory_(this) {
     34   extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
     35   Profile* profile = Profile::FromBrowserContext(browser_context_);
     36   registrar_.Add(this,
     37                  extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
     38                  content::Source<Profile>(profile));
     39   registrar_.Add(this,
     40                  extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
     41                  content::Source<Profile>(profile));
     42   registrar_.Add(this,
     43                  extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
     44                  content::Source<Profile>(profile));
     45 }
     46 
     47 OperationManager::~OperationManager() {
     48 }
     49 
     50 void OperationManager::Shutdown() {
     51   for (OperationMap::iterator iter = operations_.begin();
     52        iter != operations_.end();
     53        iter++) {
     54     BrowserThread::PostTask(BrowserThread::FILE,
     55                             FROM_HERE,
     56                             base::Bind(&Operation::Abort,
     57                                        iter->second));
     58   }
     59 }
     60 
     61 void OperationManager::StartWriteFromUrl(
     62     const ExtensionId& extension_id,
     63     GURL url,
     64     const std::string& hash,
     65     const std::string& device_path,
     66     const Operation::StartWriteCallback& callback) {
     67 #if defined(OS_CHROMEOS)
     68   // Chrome OS can only support a single operation at a time.
     69   if (operations_.size() > 0) {
     70 #else
     71   OperationMap::iterator existing_operation = operations_.find(extension_id);
     72 
     73   if (existing_operation != operations_.end()) {
     74 #endif
     75     return callback.Run(false, error::kOperationAlreadyInProgress);
     76   }
     77 
     78   scoped_refptr<Operation> operation(
     79       new WriteFromUrlOperation(weak_factory_.GetWeakPtr(),
     80                                 extension_id,
     81                                 browser_context_->GetRequestContext(),
     82                                 url,
     83                                 hash,
     84                                 device_path));
     85   operations_[extension_id] = operation;
     86   BrowserThread::PostTask(BrowserThread::FILE,
     87                           FROM_HERE,
     88                           base::Bind(&Operation::Start, operation));
     89   callback.Run(true, "");
     90 }
     91 
     92 void OperationManager::StartWriteFromFile(
     93     const ExtensionId& extension_id,
     94     const base::FilePath& path,
     95     const std::string& device_path,
     96     const Operation::StartWriteCallback& callback) {
     97 #if defined(OS_CHROMEOS)
     98   // Chrome OS can only support a single operation at a time.
     99   if (operations_.size() > 0) {
    100 #else
    101   OperationMap::iterator existing_operation = operations_.find(extension_id);
    102 
    103   if (existing_operation != operations_.end()) {
    104 #endif
    105     return callback.Run(false, error::kOperationAlreadyInProgress);
    106   }
    107 
    108   scoped_refptr<Operation> operation(new WriteFromFileOperation(
    109       weak_factory_.GetWeakPtr(), extension_id, path, device_path));
    110   operations_[extension_id] = operation;
    111   BrowserThread::PostTask(BrowserThread::FILE,
    112                           FROM_HERE,
    113                           base::Bind(&Operation::Start, operation));
    114   callback.Run(true, "");
    115 }
    116 
    117 void OperationManager::CancelWrite(
    118     const ExtensionId& extension_id,
    119     const Operation::CancelWriteCallback& callback) {
    120   Operation* existing_operation = GetOperation(extension_id);
    121 
    122   if (existing_operation == NULL) {
    123     callback.Run(false, error::kNoOperationInProgress);
    124   } else {
    125     BrowserThread::PostTask(BrowserThread::FILE,
    126                             FROM_HERE,
    127                             base::Bind(&Operation::Cancel, existing_operation));
    128     DeleteOperation(extension_id);
    129     callback.Run(true, "");
    130   }
    131 }
    132 
    133 void OperationManager::DestroyPartitions(
    134     const ExtensionId& extension_id,
    135     const std::string& device_path,
    136     const Operation::StartWriteCallback& callback) {
    137   OperationMap::iterator existing_operation = operations_.find(extension_id);
    138 
    139   if (existing_operation != operations_.end()) {
    140     return callback.Run(false, error::kOperationAlreadyInProgress);
    141   }
    142 
    143   scoped_refptr<Operation> operation(new DestroyPartitionsOperation(
    144       weak_factory_.GetWeakPtr(), extension_id, device_path));
    145   operations_[extension_id] = operation;
    146   BrowserThread::PostTask(BrowserThread::FILE,
    147                           FROM_HERE,
    148                           base::Bind(&Operation::Start, operation));
    149   callback.Run(true, "");
    150 }
    151 
    152 void OperationManager::OnProgress(const ExtensionId& extension_id,
    153                                   image_writer_api::Stage stage,
    154                                   int progress) {
    155   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    156 
    157   image_writer_api::ProgressInfo info;
    158   info.stage = stage;
    159   info.percent_complete = progress;
    160 
    161   scoped_ptr<base::ListValue> args(
    162       image_writer_api::OnWriteProgress::Create(info));
    163   scoped_ptr<Event> event(new Event(
    164       image_writer_api::OnWriteProgress::kEventName, args.Pass()));
    165 
    166   EventRouter::Get(browser_context_)
    167       ->DispatchEventToExtension(extension_id, event.Pass());
    168 }
    169 
    170 void OperationManager::OnComplete(const ExtensionId& extension_id) {
    171   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    172 
    173   scoped_ptr<base::ListValue> args(image_writer_api::OnWriteComplete::Create());
    174   scoped_ptr<Event> event(new Event(
    175       image_writer_api::OnWriteComplete::kEventName, args.Pass()));
    176 
    177   EventRouter::Get(browser_context_)
    178       ->DispatchEventToExtension(extension_id, event.Pass());
    179 
    180   DeleteOperation(extension_id);
    181 }
    182 
    183 void OperationManager::OnError(const ExtensionId& extension_id,
    184                                image_writer_api::Stage stage,
    185                                int progress,
    186                                const std::string& error_message) {
    187   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    188   image_writer_api::ProgressInfo info;
    189 
    190   DLOG(ERROR) << "ImageWriter error: " << error_message;
    191 
    192   info.stage = stage;
    193   info.percent_complete = progress;
    194 
    195   scoped_ptr<base::ListValue> args(
    196       image_writer_api::OnWriteError::Create(info, error_message));
    197   scoped_ptr<Event> event(new Event(
    198       image_writer_api::OnWriteError::kEventName, args.Pass()));
    199 
    200   EventRouter::Get(browser_context_)
    201       ->DispatchEventToExtension(extension_id, event.Pass());
    202 
    203   DeleteOperation(extension_id);
    204 }
    205 
    206 Operation* OperationManager::GetOperation(const ExtensionId& extension_id) {
    207   OperationMap::iterator existing_operation = operations_.find(extension_id);
    208 
    209   if (existing_operation == operations_.end())
    210     return NULL;
    211   return existing_operation->second.get();
    212 }
    213 
    214 void OperationManager::DeleteOperation(const ExtensionId& extension_id) {
    215   OperationMap::iterator existing_operation = operations_.find(extension_id);
    216   if (existing_operation != operations_.end()) {
    217     operations_.erase(existing_operation);
    218   }
    219 }
    220 
    221 void OperationManager::OnExtensionUnloaded(
    222     content::BrowserContext* browser_context,
    223     const Extension* extension,
    224     UnloadedExtensionInfo::Reason reason) {
    225   DeleteOperation(extension->id());
    226 }
    227 
    228 void OperationManager::Observe(int type,
    229                                const content::NotificationSource& source,
    230                                const content::NotificationDetails& details) {
    231   switch (type) {
    232     case extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: {
    233       DeleteOperation(content::Details<const Extension>(details).ptr()->id());
    234       break;
    235     }
    236     case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: {
    237       DeleteOperation(
    238         content::Details<ExtensionHost>(details)->extension()->id());
    239       break;
    240     }
    241     case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
    242       DeleteOperation(
    243         content::Details<ExtensionHost>(details)->extension()->id());
    244       break;
    245     }
    246     default: {
    247       NOTREACHED();
    248       break;
    249     }
    250   }
    251 }
    252 
    253 OperationManager* OperationManager::Get(content::BrowserContext* context) {
    254   return BrowserContextKeyedAPIFactory<OperationManager>::Get(context);
    255 }
    256 
    257 static base::LazyInstance<BrowserContextKeyedAPIFactory<OperationManager> >
    258     g_factory = LAZY_INSTANCE_INITIALIZER;
    259 
    260 BrowserContextKeyedAPIFactory<OperationManager>*
    261 OperationManager::GetFactoryInstance() {
    262   return g_factory.Pointer();
    263 }
    264 
    265 
    266 }  // namespace image_writer
    267 }  // namespace extensions
    268