1// Copyright 2014 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 "components/storage_monitor/storage_monitor.h"
6
7#include "base/stl_util.h"
8#include "base/strings/utf_string_conversions.h"
9#include "components/storage_monitor/removable_storage_observer.h"
10#include "components/storage_monitor/transient_device_ids.h"
11
12namespace storage_monitor {
13
14namespace {
15
16StorageMonitor* g_storage_monitor = NULL;
17
18}  // namespace
19
20StorageMonitor::Receiver::~Receiver() {
21}
22
23class StorageMonitor::ReceiverImpl : public StorageMonitor::Receiver {
24 public:
25  explicit ReceiverImpl(StorageMonitor* notifications)
26      : notifications_(notifications) {}
27
28  virtual ~ReceiverImpl() {}
29
30  virtual void ProcessAttach(const StorageInfo& info) OVERRIDE;
31
32  virtual void ProcessDetach(const std::string& id) OVERRIDE;
33
34  virtual void MarkInitialized() OVERRIDE;
35
36 private:
37  StorageMonitor* notifications_;
38};
39
40void StorageMonitor::ReceiverImpl::ProcessAttach(const StorageInfo& info) {
41  notifications_->ProcessAttach(info);
42}
43
44void StorageMonitor::ReceiverImpl::ProcessDetach(const std::string& id) {
45  notifications_->ProcessDetach(id);
46}
47
48void StorageMonitor::ReceiverImpl::MarkInitialized() {
49  notifications_->MarkInitialized();
50}
51
52// static
53void StorageMonitor::Create() {
54  delete g_storage_monitor;
55  g_storage_monitor = CreateInternal();
56}
57
58// static
59void StorageMonitor::Destroy() {
60  delete g_storage_monitor;
61  g_storage_monitor = NULL;
62}
63
64StorageMonitor* StorageMonitor::GetInstance() {
65  return g_storage_monitor;
66}
67
68void StorageMonitor::SetStorageMonitorForTesting(
69    scoped_ptr<StorageMonitor> storage_monitor) {
70  delete g_storage_monitor;
71  g_storage_monitor = storage_monitor.release();
72}
73
74std::vector<StorageInfo> StorageMonitor::GetAllAvailableStorages() const {
75  std::vector<StorageInfo> results;
76
77  base::AutoLock lock(storage_lock_);
78  for (StorageMap::const_iterator it = storage_map_.begin();
79       it != storage_map_.end();
80       ++it) {
81    results.push_back(it->second);
82  }
83  return results;
84}
85
86void StorageMonitor::EnsureInitialized(base::Closure callback) {
87  DCHECK(thread_checker_.CalledOnValidThread());
88  if (initialized_) {
89    if (!callback.is_null())
90      callback.Run();
91    return;
92  }
93
94  if (!callback.is_null()) {
95    on_initialize_callbacks_.push_back(callback);
96  }
97
98  if (initializing_)
99    return;
100
101  initializing_ = true;
102  Init();
103}
104
105bool StorageMonitor::IsInitialized() const {
106  return initialized_;
107}
108
109void StorageMonitor::AddObserver(RemovableStorageObserver* obs) {
110  observer_list_->AddObserver(obs);
111}
112
113void StorageMonitor::RemoveObserver(
114    RemovableStorageObserver* obs) {
115  observer_list_->RemoveObserver(obs);
116}
117
118std::string StorageMonitor::GetTransientIdForDeviceId(
119    const std::string& device_id) {
120  return transient_device_ids_->GetTransientIdForDeviceId(device_id);
121}
122
123std::string StorageMonitor::GetDeviceIdForTransientId(
124    const std::string& transient_id) const {
125  return transient_device_ids_->DeviceIdFromTransientId(transient_id);
126}
127
128void StorageMonitor::EjectDevice(
129    const std::string& device_id,
130    base::Callback<void(EjectStatus)> callback) {
131  // Platform-specific implementations will override this method to
132  // perform actual device ejection.
133  callback.Run(EJECT_FAILURE);
134}
135
136StorageMonitor::StorageMonitor()
137    : observer_list_(new ObserverListThreadSafe<RemovableStorageObserver>()),
138      initializing_(false),
139      initialized_(false),
140      transient_device_ids_(new TransientDeviceIds) {
141  receiver_.reset(new ReceiverImpl(this));
142}
143
144StorageMonitor::~StorageMonitor() {
145}
146
147StorageMonitor::Receiver* StorageMonitor::receiver() const {
148  return receiver_.get();
149}
150
151void StorageMonitor::MarkInitialized() {
152  initialized_ = true;
153  for (std::vector<base::Closure>::iterator iter =
154           on_initialize_callbacks_.begin();
155       iter != on_initialize_callbacks_.end(); ++iter) {
156    iter->Run();
157  }
158  on_initialize_callbacks_.clear();
159}
160
161void StorageMonitor::ProcessAttach(const StorageInfo& info) {
162  {
163    base::AutoLock lock(storage_lock_);
164    if (ContainsKey(storage_map_, info.device_id())) {
165      // This can happen if our unique id scheme fails. Ignore the incoming
166      // non-unique attachment.
167      return;
168    }
169    storage_map_.insert(std::make_pair(info.device_id(), info));
170  }
171
172  DVLOG(1) << "StorageAttached id " << info.device_id();
173  if (StorageInfo::IsRemovableDevice(info.device_id())) {
174    observer_list_->Notify(
175        &RemovableStorageObserver::OnRemovableStorageAttached, info);
176  }
177}
178
179void StorageMonitor::ProcessDetach(const std::string& id) {
180  StorageInfo info;
181  {
182    base::AutoLock lock(storage_lock_);
183    StorageMap::iterator it = storage_map_.find(id);
184    if (it == storage_map_.end())
185      return;
186    info = it->second;
187    storage_map_.erase(it);
188  }
189
190  DVLOG(1) << "StorageDetached for id " << id;
191  if (StorageInfo::IsRemovableDevice(info.device_id())) {
192    observer_list_->Notify(
193        &RemovableStorageObserver::OnRemovableStorageDetached, info);
194  }
195}
196
197}  // namespace storage_monitor
198