// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/cros/burn_library.h" #include <cstring> #include "base/memory/linked_ptr.h" #include "chrome/browser/chromeos/cros/cros_library.h" #include "content/browser/browser_thread.h" namespace chromeos { class BurnLibraryImpl : public BurnLibrary, public base::SupportsWeakPtr<BurnLibraryImpl> { public: BurnLibraryImpl(); virtual ~BurnLibraryImpl(); // BurnLibrary implementation. virtual void AddObserver(Observer* observer); virtual void RemoveObserver(Observer* observer); virtual bool DoBurn(const FilePath& from_path, const FilePath& to_path); bool BurnImage(const FilePath& from_path, const FilePath& to_path); void UpdateBurnStatus(const ImageBurnStatus& status, BurnEventType evt); private: void Init(); static void BurnStatusChangedHandler(void* object, const BurnStatus& status, BurnEventType evt); private: ObserverList<BurnLibrary::Observer> observers_; BurnStatusConnection burn_status_connection_; // Holds a path that is currently being burnt to. std::string target_path_; DISALLOW_COPY_AND_ASSIGN(BurnLibraryImpl); }; class BurnLibraryTaskProxy : public base::RefCountedThreadSafe<BurnLibraryTaskProxy> { public: explicit BurnLibraryTaskProxy(const base::WeakPtr<BurnLibraryImpl>& library); void BurnImage(const FilePath& from_path, const FilePath& to_path); void UpdateBurnStatus(ImageBurnStatus* status, BurnEventType evt); private: base::WeakPtr<BurnLibraryImpl> library_; friend class base::RefCountedThreadSafe<BurnLibraryTaskProxy>; DISALLOW_COPY_AND_ASSIGN(BurnLibraryTaskProxy); }; BurnLibraryImpl::BurnLibraryImpl() { if (CrosLibrary::Get()->EnsureLoaded()) { Init(); } else { LOG(ERROR) << "Cros Library has not been loaded"; } } BurnLibraryImpl::~BurnLibraryImpl() { if (burn_status_connection_) { DisconnectBurnStatus(burn_status_connection_); } } void BurnLibraryImpl::AddObserver(Observer* observer) { observers_.AddObserver(observer); } void BurnLibraryImpl::RemoveObserver(Observer* observer) { observers_.RemoveObserver(observer); } bool BurnLibraryImpl::DoBurn(const FilePath& from_path, const FilePath& to_path) { BurnLibraryTaskProxy* task = new BurnLibraryTaskProxy(AsWeakPtr()); task->AddRef(); task->BurnImage(from_path, to_path); BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, NewRunnableMethod(task, &BurnLibraryTaskProxy::BurnImage, from_path, to_path)); return true; } bool BurnLibraryImpl::BurnImage(const FilePath& from_path, const FilePath& to_path) { // Make sure we run on file thread. DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); // Check if there is a target path already being burnt to. if (target_path_ == "") { target_path_ = to_path.value(); } else { return false; } StartBurn(from_path.value().c_str(), to_path.value().c_str(), burn_status_connection_); return true; } void BurnLibraryImpl::BurnStatusChangedHandler(void* object, const BurnStatus& status, BurnEventType evt) { BurnLibraryImpl* burn = static_cast<BurnLibraryImpl*>(object); // Copy burn status because it will be freed after returning from this method. ImageBurnStatus* status_copy = new ImageBurnStatus(status); BurnLibraryTaskProxy* task = new BurnLibraryTaskProxy(burn->AsWeakPtr()); task->AddRef(); BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(task, &BurnLibraryTaskProxy::UpdateBurnStatus, status_copy, evt)); } void BurnLibraryImpl::Init() { burn_status_connection_ = MonitorBurnStatus(&BurnStatusChangedHandler, this); } void BurnLibraryImpl::UpdateBurnStatus(const ImageBurnStatus& status, BurnEventType evt) { // Make sure we run on UI thread. DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // If burn is finished, remove target paths from paths being burnt to. // This has to be done in thread-safe way, hence using task proxy class. if ((evt == BURN_CANCELED || evt == BURN_COMPLETE) && target_path_ == status.target_path) target_path_ = ""; FOR_EACH_OBSERVER(Observer, observers_, ProgressUpdated(this, evt, status)); } BurnLibraryTaskProxy::BurnLibraryTaskProxy( const base::WeakPtr<BurnLibraryImpl>& library) : library_(library) { } void BurnLibraryTaskProxy::BurnImage(const FilePath& from_path, const FilePath& to_path) { library_->BurnImage(from_path, to_path); } void BurnLibraryTaskProxy::UpdateBurnStatus(ImageBurnStatus* status, BurnEventType evt) { library_->UpdateBurnStatus(*status, evt); delete status; } class BurnLibraryStubImpl : public BurnLibrary { public: BurnLibraryStubImpl() {} virtual ~BurnLibraryStubImpl() {} // BurnLibrary overrides. virtual void AddObserver(Observer* observer) {} virtual void RemoveObserver(Observer* observer) {} virtual bool DoBurn(const FilePath& from_path, const FilePath& to_path) { return false; } DISALLOW_COPY_AND_ASSIGN(BurnLibraryStubImpl); }; // static BurnLibrary* BurnLibrary::GetImpl(bool stub) { if (stub) return new BurnLibraryStubImpl(); else return new BurnLibraryImpl(); } } // namespace chromeos // Allows InvokeLater without adding refcounting. This class is a Singleton and // won't be deleted until it's last InvokeLater is run. DISABLE_RUNNABLE_METHOD_REFCOUNT(chromeos::BurnLibraryImpl);