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