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 62 BurnLibraryImpl::BurnLibraryImpl() { 63 if (CrosLibrary::Get()->EnsureLoaded()) { 64 Init(); 65 } else { 66 LOG(ERROR) << "Cros Library has not been loaded"; 67 } 68 } 69 70 BurnLibraryImpl::~BurnLibraryImpl() { 71 if (burn_status_connection_) { 72 DisconnectBurnStatus(burn_status_connection_); 73 } 74 } 75 76 void BurnLibraryImpl::AddObserver(Observer* observer) { 77 observers_.AddObserver(observer); 78 } 79 80 void BurnLibraryImpl::RemoveObserver(Observer* observer) { 81 observers_.RemoveObserver(observer); 82 } 83 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 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 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 127 void BurnLibraryImpl::Init() { 128 burn_status_connection_ = MonitorBurnStatus(&BurnStatusChangedHandler, this); 129 } 130 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 145 BurnLibraryTaskProxy::BurnLibraryTaskProxy( 146 const base::WeakPtr<BurnLibraryImpl>& library) 147 : library_(library) { 148 } 149 150 void BurnLibraryTaskProxy::BurnImage(const FilePath& from_path, 151 const FilePath& to_path) { 152 library_->BurnImage(from_path, to_path); 153 } 154 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: 164 BurnLibraryStubImpl() {} 165 virtual ~BurnLibraryStubImpl() {} 166 167 // BurnLibrary overrides. 168 virtual void AddObserver(Observer* observer) {} 169 virtual void RemoveObserver(Observer* observer) {} 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 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