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.
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"
23 namespace image_writer_api
= extensions::api::image_writer_private
;
25 namespace extensions
{
26 namespace image_writer
{
28 using content::BrowserThread
;
30 OperationManager::OperationManager(content::BrowserContext
* context
)
31 : browser_context_(context
),
32 extension_registry_observer_(this),
34 extension_registry_observer_
.Add(ExtensionRegistry::Get(browser_context_
));
35 Profile
* profile
= Profile::FromBrowserContext(browser_context_
);
37 extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED
,
38 content::Source
<Profile
>(profile
));
40 extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE
,
41 content::Source
<Profile
>(profile
));
43 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED
,
44 content::Source
<Profile
>(profile
));
47 OperationManager::~OperationManager() {
50 void OperationManager::Shutdown() {
51 for (OperationMap::iterator iter
= operations_
.begin();
52 iter
!= operations_
.end();
54 BrowserThread::PostTask(BrowserThread::FILE,
56 base::Bind(&Operation::Abort
,
61 void OperationManager::StartWriteFromUrl(
62 const ExtensionId
& extension_id
,
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) {
71 OperationMap::iterator existing_operation
= operations_
.find(extension_id
);
73 if (existing_operation
!= operations_
.end()) {
75 return callback
.Run(false, error::kOperationAlreadyInProgress
);
78 scoped_refptr
<Operation
> operation(
79 new WriteFromUrlOperation(weak_factory_
.GetWeakPtr(),
81 browser_context_
->GetRequestContext(),
85 operations_
[extension_id
] = operation
;
86 BrowserThread::PostTask(BrowserThread::FILE,
88 base::Bind(&Operation::Start
, operation
));
89 callback
.Run(true, "");
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) {
101 OperationMap::iterator existing_operation
= operations_
.find(extension_id
);
103 if (existing_operation
!= operations_
.end()) {
105 return callback
.Run(false, error::kOperationAlreadyInProgress
);
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,
113 base::Bind(&Operation::Start
, operation
));
114 callback
.Run(true, "");
117 void OperationManager::CancelWrite(
118 const ExtensionId
& extension_id
,
119 const Operation::CancelWriteCallback
& callback
) {
120 Operation
* existing_operation
= GetOperation(extension_id
);
122 if (existing_operation
== NULL
) {
123 callback
.Run(false, error::kNoOperationInProgress
);
125 BrowserThread::PostTask(BrowserThread::FILE,
127 base::Bind(&Operation::Cancel
, existing_operation
));
128 DeleteOperation(extension_id
);
129 callback
.Run(true, "");
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
);
139 if (existing_operation
!= operations_
.end()) {
140 return callback
.Run(false, error::kOperationAlreadyInProgress
);
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,
148 base::Bind(&Operation::Start
, operation
));
149 callback
.Run(true, "");
152 void OperationManager::OnProgress(const ExtensionId
& extension_id
,
153 image_writer_api::Stage stage
,
155 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
157 image_writer_api::ProgressInfo info
;
159 info
.percent_complete
= progress
;
161 scoped_ptr
<base::ListValue
> args(
162 image_writer_api::OnWriteProgress::Create(info
));
163 scoped_ptr
<Event
> event(
164 new Event(events::IMAGE_WRITER_PRIVATE_ON_WRITE_PROGRESS
,
165 image_writer_api::OnWriteProgress::kEventName
, args
.Pass()));
167 EventRouter::Get(browser_context_
)
168 ->DispatchEventToExtension(extension_id
, event
.Pass());
171 void OperationManager::OnComplete(const ExtensionId
& extension_id
) {
172 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
174 scoped_ptr
<base::ListValue
> args(image_writer_api::OnWriteComplete::Create());
175 scoped_ptr
<Event
> event(
176 new Event(events::IMAGE_WRITER_PRIVATE_ON_WRITE_COMPLETE
,
177 image_writer_api::OnWriteComplete::kEventName
, args
.Pass()));
179 EventRouter::Get(browser_context_
)
180 ->DispatchEventToExtension(extension_id
, event
.Pass());
182 DeleteOperation(extension_id
);
185 void OperationManager::OnError(const ExtensionId
& extension_id
,
186 image_writer_api::Stage stage
,
188 const std::string
& error_message
) {
189 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
190 image_writer_api::ProgressInfo info
;
192 DLOG(ERROR
) << "ImageWriter error: " << error_message
;
195 info
.percent_complete
= progress
;
197 scoped_ptr
<base::ListValue
> args(
198 image_writer_api::OnWriteError::Create(info
, error_message
));
199 scoped_ptr
<Event
> event(new Event(events::IMAGE_WRITER_PRIVATE_ON_WRITE_ERROR
,
200 image_writer_api::OnWriteError::kEventName
,
203 EventRouter::Get(browser_context_
)
204 ->DispatchEventToExtension(extension_id
, event
.Pass());
206 DeleteOperation(extension_id
);
209 Operation
* OperationManager::GetOperation(const ExtensionId
& extension_id
) {
210 OperationMap::iterator existing_operation
= operations_
.find(extension_id
);
212 if (existing_operation
== operations_
.end())
214 return existing_operation
->second
.get();
217 void OperationManager::DeleteOperation(const ExtensionId
& extension_id
) {
218 OperationMap::iterator existing_operation
= operations_
.find(extension_id
);
219 if (existing_operation
!= operations_
.end()) {
220 operations_
.erase(existing_operation
);
224 void OperationManager::OnExtensionUnloaded(
225 content::BrowserContext
* browser_context
,
226 const Extension
* extension
,
227 UnloadedExtensionInfo::Reason reason
) {
228 DeleteOperation(extension
->id());
231 void OperationManager::Observe(int type
,
232 const content::NotificationSource
& source
,
233 const content::NotificationDetails
& details
) {
235 case extensions::NOTIFICATION_EXTENSION_PROCESS_TERMINATED
: {
236 DeleteOperation(content::Details
<const Extension
>(details
).ptr()->id());
239 case extensions::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE
: {
241 content::Details
<ExtensionHost
>(details
)->extension()->id());
244 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED
: {
246 content::Details
<ExtensionHost
>(details
)->extension()->id());
256 OperationManager
* OperationManager::Get(content::BrowserContext
* context
) {
257 return BrowserContextKeyedAPIFactory
<OperationManager
>::Get(context
);
260 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<OperationManager
> >
261 g_factory
= LAZY_INSTANCE_INITIALIZER
;
263 BrowserContextKeyedAPIFactory
<OperationManager
>*
264 OperationManager::GetFactoryInstance() {
265 return g_factory
.Pointer();
269 } // namespace image_writer
270 } // namespace extensions