summaryrefslogtreecommitdiffstats
path: root/components/storage_monitor/storage_monitor.h
blob: c3a2d9a2d7a380f78e75a03117f5bfbacece1831 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// Copyright 2014 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.

#ifndef COMPONENTS_STORAGE_MONITOR_STORAGE_MONITOR_H_
#define COMPONENTS_STORAGE_MONITOR_STORAGE_MONITOR_H_

#include <map>
#include <string>
#include <vector>

#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list_threadsafe.h"
#include "base/strings/string16.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "build/build_config.h"
#include "components/storage_monitor/storage_info.h"

class MediaFileSystemRegistryTest;
class MediaGalleriesPlatformAppBrowserTest;
class SystemStorageApiTest;
class SystemStorageEjectApiTest;

namespace device {
class MediaTransferProtocolManager;
}

namespace storage_monitor {

class RemovableStorageObserver;
class TransientDeviceIds;

// Base class for platform-specific instances watching for removable storage
// attachments/detachments.
// Lifecycle contracts: This class is created in the browser process
// before the profile is initialized, so listeners can be
// created during profile construction. The platform-specific initialization,
// which can lead to calling registered listeners with notifications of
// attached volumes, are done lazily at first use through the async
// |EnsureInitialized()| method. That must be done before any of the registered
// listeners will receive updates or calls to other API methods return
// meaningful results.
// A post-initialization |GetAttachedStorage()| call coupled with a
// registered listener will receive a complete set, albeit potentially with
// duplicates. This is because there's no tracking between when listeners were
// registered and the state of initialization, and the fact that platforms
// behave differently in how these notifications are provided.
class StorageMonitor {
 public:
  // This interface is provided to generators of storage notifications.
  class Receiver {
   public:
    virtual ~Receiver();

    virtual void ProcessAttach(const StorageInfo& info) = 0;
    virtual void ProcessDetach(const std::string& id) = 0;
    virtual void MarkInitialized() = 0;
  };

  // Status codes for the result of an EjectDevice() call.
  enum EjectStatus {
    EJECT_OK,
    EJECT_IN_USE,
    EJECT_NO_SUCH_DEVICE,
    EJECT_FAILURE
  };

  // Instantiates the StorageMonitor singleton. This function does not
  // guarantee the complete initialization of the object. For that, see
  // |EnsureInitialized|.
  static void Create();

  // Destroys the StorageMonitor singleton.
  static void Destroy();

  // Returns a pointer to an object owned by BrowserProcess, with lifetime
  // starting before main message loop start, and ending after main message loop
  // shutdown. Called outside it's lifetime (or with no browser process),
  // returns NULL.
  static StorageMonitor* GetInstance();

  static void SetStorageMonitorForTesting(
      scoped_ptr<StorageMonitor> storage_monitor);

  virtual ~StorageMonitor();

  // Ensures that the storage monitor is initialized. The provided callback, if
  // non-null, will be called when initialization is complete. If initialization
  // has already completed, this callback will be invoked within the calling
  // stack. Before the callback is run, calls to |GetAllAvailableStorages| and
  // |GetStorageInfoForPath| may not return the correct results. In addition,
  // registered observers will not be notified on device attachment/detachment.
  // Should be invoked on the UI thread; callbacks will be run on the UI thread.
  void EnsureInitialized(base::Closure callback);

  // Return true if the storage monitor has already been initialized.
  bool IsInitialized() const;

  // Finds the device that contains |path| and populates |device_info|.
  // Should be able to handle any path on the local system, not just removable
  // storage. Returns false if unable to find the device.
  virtual bool GetStorageInfoForPath(
      const base::FilePath& path,
      StorageInfo* device_info) const = 0;

// TODO(gbillock): make this either unnecessary (implementation-specific) or
// platform-independent.
#if defined(OS_WIN)
  // Gets the MTP device storage information specified by |storage_device_id|.
  // On success, returns true and fills in |device_location| with device
  // interface details and |storage_object_id| with the string ID that
  // uniquely identifies the object on the device. This ID need not be
  // persistent across sessions.
  virtual bool GetMTPStorageInfoFromDeviceId(
      const std::string& storage_device_id,
      base::string16* device_location,
      base::string16* storage_object_id) const = 0;
#endif

#if defined(OS_LINUX)
  virtual device::MediaTransferProtocolManager*
      media_transfer_protocol_manager() = 0;
#endif

  // Returns information for all known storages on the system,
  // including fixed and removable storages.
  std::vector<StorageInfo> GetAllAvailableStorages() const;

  void AddObserver(RemovableStorageObserver* obs);
  void RemoveObserver(RemovableStorageObserver* obs);

  std::string GetTransientIdForDeviceId(const std::string& device_id);
  std::string GetDeviceIdForTransientId(const std::string& transient_id) const;

  virtual void EjectDevice(
      const std::string& device_id,
      base::Callback<void(EjectStatus)> callback);

 protected:
  friend class ::MediaFileSystemRegistryTest;
  friend class ::MediaGalleriesPlatformAppBrowserTest;
  friend class ::SystemStorageApiTest;
  friend class ::SystemStorageEjectApiTest;

  StorageMonitor();

  virtual Receiver* receiver() const;

  // Called to initialize the storage monitor.
  virtual void Init() = 0;

  // Called by subclasses to mark the storage monitor as
  // fully initialized. Must be called on the UI thread.
  void MarkInitialized();

 private:
  // Internal method for creating platform specific StorageMonitor.
  static StorageMonitor* CreateInternal();

  class ReceiverImpl;
  friend class ReceiverImpl;

  // Key: device id.
  typedef std::map<std::string, StorageInfo> StorageMap;

  void ProcessAttach(const StorageInfo& storage);
  void ProcessDetach(const std::string& id);

  scoped_ptr<Receiver> receiver_;

  scoped_refptr<base::ObserverListThreadSafe<RemovableStorageObserver>>
      observer_list_;

  // Used to make sure we call initialize from the same thread as creation.
  base::ThreadChecker thread_checker_;

  bool initializing_;
  bool initialized_;
  std::vector<base::Closure> on_initialize_callbacks_;

  // For manipulating storage_map_ structure.
  mutable base::Lock storage_lock_;

  // Map of all known storage devices,including fixed and removable storages.
  StorageMap storage_map_;

  scoped_ptr<TransientDeviceIds> transient_device_ids_;
};

}  // namespace storage_monitor

#endif  // COMPONENTS_STORAGE_MONITOR_STORAGE_MONITOR_H_