1 // Copyright (c) 2011 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 "chrome/browser/chromeos/cros/burn_library.h"
6
7 #include <cstring>
8 #include "base/memory/linked_ptr.h"
9 #include "chrome/browser/chromeos/cros/cros_library.h"
10 #include "content/browser/browser_thread.h"
11
12 namespace chromeos {
13
14 class BurnLibraryImpl : public BurnLibrary,
15 public base::SupportsWeakPtr<BurnLibraryImpl> {
16 public:
17
18 BurnLibraryImpl();
19 virtual ~BurnLibraryImpl();
20
21 // BurnLibrary implementation.
22 virtual void AddObserver(Observer* observer);
23 virtual void RemoveObserver(Observer* observer);
24 virtual bool DoBurn(const FilePath& from_path, const FilePath& to_path);
25
26 bool BurnImage(const FilePath& from_path, const FilePath& to_path);
27 void UpdateBurnStatus(const ImageBurnStatus& status, BurnEventType evt);
28
29 private:
30 void Init();
31 static void BurnStatusChangedHandler(void* object,
32 const BurnStatus& status,
33 BurnEventType evt);
34
35 private:
36 ObserverList<BurnLibrary::Observer> observers_;
37 BurnStatusConnection burn_status_connection_;
38
39 // Holds a path that is currently being burnt to.
40 std::string target_path_;
41
42 DISALLOW_COPY_AND_ASSIGN(BurnLibraryImpl);
43 };
44
45 class BurnLibraryTaskProxy
46 : public base::RefCountedThreadSafe<BurnLibraryTaskProxy> {
47 public:
48 explicit BurnLibraryTaskProxy(const base::WeakPtr<BurnLibraryImpl>& library);
49
50 void BurnImage(const FilePath& from_path, const FilePath& to_path);
51
52 void UpdateBurnStatus(ImageBurnStatus* status, BurnEventType evt);
53
54 private:
55 base::WeakPtr<BurnLibraryImpl> library_;
56
57 friend class base::RefCountedThreadSafe<BurnLibraryTaskProxy>;
58
59 DISALLOW_COPY_AND_ASSIGN(BurnLibraryTaskProxy);
60 };
61
BurnLibraryImpl()62 BurnLibraryImpl::BurnLibraryImpl() {
63 if (CrosLibrary::Get()->EnsureLoaded()) {
64 Init();
65 } else {
66 LOG(ERROR) << "Cros Library has not been loaded";
67 }
68 }
69
~BurnLibraryImpl()70 BurnLibraryImpl::~BurnLibraryImpl() {
71 if (burn_status_connection_) {
72 DisconnectBurnStatus(burn_status_connection_);
73 }
74 }
75
AddObserver(Observer * observer)76 void BurnLibraryImpl::AddObserver(Observer* observer) {
77 observers_.AddObserver(observer);
78 }
79
RemoveObserver(Observer * observer)80 void BurnLibraryImpl::RemoveObserver(Observer* observer) {
81 observers_.RemoveObserver(observer);
82 }
83
DoBurn(const FilePath & from_path,const FilePath & to_path)84 bool BurnLibraryImpl::DoBurn(const FilePath& from_path,
85 const FilePath& to_path) {
86 BurnLibraryTaskProxy* task = new BurnLibraryTaskProxy(AsWeakPtr());
87 task->AddRef();
88 task->BurnImage(from_path, to_path);
89 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
90 NewRunnableMethod(task, &BurnLibraryTaskProxy::BurnImage,
91 from_path, to_path));
92 return true;
93 }
94
BurnImage(const FilePath & from_path,const FilePath & to_path)95 bool BurnLibraryImpl::BurnImage(const FilePath& from_path,
96 const FilePath& to_path) {
97 // Make sure we run on file thread.
98 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
99
100 // Check if there is a target path already being burnt to.
101 if (target_path_ == "") {
102 target_path_ = to_path.value();
103 } else {
104 return false;
105 }
106
107 StartBurn(from_path.value().c_str(), to_path.value().c_str(),
108 burn_status_connection_);
109 return true;
110 }
111
BurnStatusChangedHandler(void * object,const BurnStatus & status,BurnEventType evt)112 void BurnLibraryImpl::BurnStatusChangedHandler(void* object,
113 const BurnStatus& status,
114 BurnEventType evt) {
115 BurnLibraryImpl* burn = static_cast<BurnLibraryImpl*>(object);
116
117 // Copy burn status because it will be freed after returning from this method.
118 ImageBurnStatus* status_copy = new ImageBurnStatus(status);
119
120 BurnLibraryTaskProxy* task = new BurnLibraryTaskProxy(burn->AsWeakPtr());
121 task->AddRef();
122 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
123 NewRunnableMethod(task, &BurnLibraryTaskProxy::UpdateBurnStatus,
124 status_copy, evt));
125 }
126
Init()127 void BurnLibraryImpl::Init() {
128 burn_status_connection_ = MonitorBurnStatus(&BurnStatusChangedHandler, this);
129 }
130
UpdateBurnStatus(const ImageBurnStatus & status,BurnEventType evt)131 void BurnLibraryImpl::UpdateBurnStatus(const ImageBurnStatus& status,
132 BurnEventType evt) {
133 // Make sure we run on UI thread.
134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
135
136 // If burn is finished, remove target paths from paths being burnt to.
137 // This has to be done in thread-safe way, hence using task proxy class.
138 if ((evt == BURN_CANCELED || evt == BURN_COMPLETE) &&
139 target_path_ == status.target_path)
140 target_path_ = "";
141
142 FOR_EACH_OBSERVER(Observer, observers_, ProgressUpdated(this, evt, status));
143 }
144
BurnLibraryTaskProxy(const base::WeakPtr<BurnLibraryImpl> & library)145 BurnLibraryTaskProxy::BurnLibraryTaskProxy(
146 const base::WeakPtr<BurnLibraryImpl>& library)
147 : library_(library) {
148 }
149
BurnImage(const FilePath & from_path,const FilePath & to_path)150 void BurnLibraryTaskProxy::BurnImage(const FilePath& from_path,
151 const FilePath& to_path) {
152 library_->BurnImage(from_path, to_path);
153 }
154
UpdateBurnStatus(ImageBurnStatus * status,BurnEventType evt)155 void BurnLibraryTaskProxy::UpdateBurnStatus(ImageBurnStatus* status,
156 BurnEventType evt) {
157 library_->UpdateBurnStatus(*status, evt);
158 delete status;
159 }
160
161
162 class BurnLibraryStubImpl : public BurnLibrary {
163 public:
BurnLibraryStubImpl()164 BurnLibraryStubImpl() {}
~BurnLibraryStubImpl()165 virtual ~BurnLibraryStubImpl() {}
166
167 // BurnLibrary overrides.
AddObserver(Observer * observer)168 virtual void AddObserver(Observer* observer) {}
RemoveObserver(Observer * observer)169 virtual void RemoveObserver(Observer* observer) {}
DoBurn(const FilePath & from_path,const FilePath & to_path)170 virtual bool DoBurn(const FilePath& from_path, const FilePath& to_path) {
171 return false;
172 }
173
174 DISALLOW_COPY_AND_ASSIGN(BurnLibraryStubImpl);
175 };
176
177 // static
GetImpl(bool stub)178 BurnLibrary* BurnLibrary::GetImpl(bool stub) {
179 if (stub)
180 return new BurnLibraryStubImpl();
181 else
182 return new BurnLibraryImpl();
183 }
184
185 } // namespace chromeos
186
187 // Allows InvokeLater without adding refcounting. This class is a Singleton and
188 // won't be deleted until it's last InvokeLater is run.
189 DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::BurnLibraryImpl);
190
191