• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
OperationManager(content::BrowserContext * context)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 
~OperationManager()47 OperationManager::~OperationManager() {
48 }
49 
Shutdown()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 
StartWriteFromUrl(const ExtensionId & extension_id,GURL url,const std::string & hash,const std::string & device_path,const Operation::StartWriteCallback & callback)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