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#ifndef COMPONENTS_STORAGE_MONITOR_STORAGE_MONITOR_H_
6#define COMPONENTS_STORAGE_MONITOR_STORAGE_MONITOR_H_
7
8#include <map>
9#include <string>
10#include <vector>
11
12#include "base/callback.h"
13#include "base/files/file_path.h"
14#include "base/memory/scoped_ptr.h"
15#include "base/observer_list_threadsafe.h"
16#include "base/strings/string16.h"
17#include "base/synchronization/lock.h"
18#include "base/threading/thread_checker.h"
19#include "components/storage_monitor/storage_info.h"
20
21class MediaFileSystemRegistryTest;
22class MediaGalleriesPlatformAppBrowserTest;
23class SystemStorageApiTest;
24class SystemStorageEjectApiTest;
25
26namespace device {
27class MediaTransferProtocolManager;
28}
29
30namespace storage_monitor {
31
32class RemovableStorageObserver;
33class TransientDeviceIds;
34
35// Base class for platform-specific instances watching for removable storage
36// attachments/detachments.
37// Lifecycle contracts: This class is created in the browser process
38// before the profile is initialized, so listeners can be
39// created during profile construction. The platform-specific initialization,
40// which can lead to calling registered listeners with notifications of
41// attached volumes, are done lazily at first use through the async
42// |EnsureInitialized()| method. That must be done before any of the registered
43// listeners will receive updates or calls to other API methods return
44// meaningful results.
45// A post-initialization |GetAttachedStorage()| call coupled with a
46// registered listener will receive a complete set, albeit potentially with
47// duplicates. This is because there's no tracking between when listeners were
48// registered and the state of initialization, and the fact that platforms
49// behave differently in how these notifications are provided.
50class StorageMonitor {
51 public:
52  // This interface is provided to generators of storage notifications.
53  class Receiver {
54   public:
55    virtual ~Receiver();
56
57    virtual void ProcessAttach(const StorageInfo& info) = 0;
58    virtual void ProcessDetach(const std::string& id) = 0;
59    virtual void MarkInitialized() = 0;
60  };
61
62  // Status codes for the result of an EjectDevice() call.
63  enum EjectStatus {
64    EJECT_OK,
65    EJECT_IN_USE,
66    EJECT_NO_SUCH_DEVICE,
67    EJECT_FAILURE
68  };
69
70  // Instantiates the StorageMonitor singleton. This function does not
71  // guarantee the complete initialization of the object. For that, see
72  // |EnsureInitialized|.
73  static void Create();
74
75  // Destroys the StorageMonitor singleton.
76  static void Destroy();
77
78  // Returns a pointer to an object owned by BrowserProcess, with lifetime
79  // starting before main message loop start, and ending after main message loop
80  // shutdown. Called outside it's lifetime (or with no browser process),
81  // returns NULL.
82  static StorageMonitor* GetInstance();
83
84  static void SetStorageMonitorForTesting(
85      scoped_ptr<StorageMonitor> storage_monitor);
86
87  virtual ~StorageMonitor();
88
89  // Ensures that the storage monitor is initialized. The provided callback, if
90  // non-null, will be called when initialization is complete. If initialization
91  // has already completed, this callback will be invoked within the calling
92  // stack. Before the callback is run, calls to |GetAllAvailableStorages| and
93  // |GetStorageInfoForPath| may not return the correct results. In addition,
94  // registered observers will not be notified on device attachment/detachment.
95  // Should be invoked on the UI thread; callbacks will be run on the UI thread.
96  void EnsureInitialized(base::Closure callback);
97
98  // Return true if the storage monitor has already been initialized.
99  bool IsInitialized() const;
100
101  // Finds the device that contains |path| and populates |device_info|.
102  // Should be able to handle any path on the local system, not just removable
103  // storage. Returns false if unable to find the device.
104  virtual bool GetStorageInfoForPath(
105      const base::FilePath& path,
106      StorageInfo* device_info) const = 0;
107
108// TODO(gbillock): make this either unnecessary (implementation-specific) or
109// platform-independent.
110#if defined(OS_WIN)
111  // Gets the MTP device storage information specified by |storage_device_id|.
112  // On success, returns true and fills in |device_location| with device
113  // interface details and |storage_object_id| with the string ID that
114  // uniquely identifies the object on the device. This ID need not be
115  // persistent across sessions.
116  virtual bool GetMTPStorageInfoFromDeviceId(
117      const std::string& storage_device_id,
118      base::string16* device_location,
119      base::string16* storage_object_id) const = 0;
120#endif
121
122#if defined(OS_LINUX)
123  virtual device::MediaTransferProtocolManager*
124      media_transfer_protocol_manager() = 0;
125#endif
126
127  // Returns information for all known storages on the system,
128  // including fixed and removable storages.
129  std::vector<StorageInfo> GetAllAvailableStorages() const;
130
131  void AddObserver(RemovableStorageObserver* obs);
132  void RemoveObserver(RemovableStorageObserver* obs);
133
134  std::string GetTransientIdForDeviceId(const std::string& device_id);
135  std::string GetDeviceIdForTransientId(const std::string& transient_id) const;
136
137  virtual void EjectDevice(
138      const std::string& device_id,
139      base::Callback<void(EjectStatus)> callback);
140
141 protected:
142  friend class ::MediaFileSystemRegistryTest;
143  friend class ::MediaGalleriesPlatformAppBrowserTest;
144  friend class ::SystemStorageApiTest;
145  friend class ::SystemStorageEjectApiTest;
146
147  StorageMonitor();
148
149  virtual Receiver* receiver() const;
150
151  // Called to initialize the storage monitor.
152  virtual void Init() = 0;
153
154  // Called by subclasses to mark the storage monitor as
155  // fully initialized. Must be called on the UI thread.
156  void MarkInitialized();
157
158 private:
159  // Internal method for creating platform specific StorageMonitor.
160  static StorageMonitor* CreateInternal();
161
162  class ReceiverImpl;
163  friend class ReceiverImpl;
164
165  // Key: device id.
166  typedef std::map<std::string, StorageInfo> StorageMap;
167
168  void ProcessAttach(const StorageInfo& storage);
169  void ProcessDetach(const std::string& id);
170
171  scoped_ptr<Receiver> receiver_;
172
173  scoped_refptr<ObserverListThreadSafe<RemovableStorageObserver> >
174      observer_list_;
175
176  // Used to make sure we call initialize from the same thread as creation.
177  base::ThreadChecker thread_checker_;
178
179  bool initializing_;
180  bool initialized_;
181  std::vector<base::Closure> on_initialize_callbacks_;
182
183  // For manipulating storage_map_ structure.
184  mutable base::Lock storage_lock_;
185
186  // Map of all known storage devices,including fixed and removable storages.
187  StorageMap storage_map_;
188
189  scoped_ptr<TransientDeviceIds> transient_device_ids_;
190};
191
192}  // namespace storage_monitor
193
194#endif  // COMPONENTS_STORAGE_MONITOR_STORAGE_MONITOR_H_
195