普通文本  |  191行  |  5.84 KB

// 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);