Telemetry media_measurement plus play action and tests.
[chromium-blink-merge.git] / device / media_transfer_protocol / media_transfer_protocol_manager.cc
blob9bcf5be28ace725bcbe0abb31d91bbba80fcec09
1 // Copyright (c) 2012 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.
5 #include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
7 #include <map>
8 #include <queue>
9 #include <set>
10 #include <utility>
12 #include "base/bind.h"
13 #include "base/command_line.h"
14 #include "base/location.h"
15 #include "base/memory/weak_ptr.h"
16 #include "base/observer_list.h"
17 #include "base/sequenced_task_runner.h"
18 #include "base/stl_util.h"
19 #include "base/threading/thread_checker.h"
20 #include "dbus/bus.h"
21 #include "device/media_transfer_protocol/media_transfer_protocol_daemon_client.h"
22 #include "device/media_transfer_protocol/mtp_file_entry.pb.h"
23 #include "device/media_transfer_protocol/mtp_storage_info.pb.h"
24 #include "third_party/cros_system_api/dbus/service_constants.h"
26 #if defined(OS_CHROMEOS)
27 #include "chromeos/dbus/dbus_thread_manager.h"
28 #endif
30 namespace device {
32 namespace {
34 MediaTransferProtocolManager* g_media_transfer_protocol_manager = NULL;
36 // The MediaTransferProtocolManager implementation.
37 class MediaTransferProtocolManagerImpl : public MediaTransferProtocolManager {
38 public:
39 explicit MediaTransferProtocolManagerImpl(
40 scoped_refptr<base::SequencedTaskRunner> task_runner)
41 : weak_ptr_factory_(this) {
42 #if defined(OS_CHROMEOS)
43 DCHECK(!task_runner.get());
44 #else
45 DCHECK(task_runner.get());
46 dbus::Bus::Options options;
47 options.bus_type = dbus::Bus::SYSTEM;
48 options.connection_type = dbus::Bus::PRIVATE;
49 options.dbus_task_runner = task_runner;
50 session_bus_ = new dbus::Bus(options);
51 #endif
53 // Listen for future mtpd service owner changes, in case it is not
54 // available right now. There is no guarantee on Linux or ChromeOS that
55 // mtpd is running already.
56 mtpd_owner_changed_callback_ =
57 base::Bind(&MediaTransferProtocolManagerImpl::FinishSetupOnOriginThread,
58 weak_ptr_factory_.GetWeakPtr());
59 GetBus()->ListenForServiceOwnerChange(mtpd::kMtpdServiceName,
60 mtpd_owner_changed_callback_);
61 GetBus()->GetServiceOwner(mtpd::kMtpdServiceName,
62 mtpd_owner_changed_callback_);
65 virtual ~MediaTransferProtocolManagerImpl() {
66 DCHECK(g_media_transfer_protocol_manager);
67 g_media_transfer_protocol_manager = NULL;
68 GetBus()->UnlistenForServiceOwnerChange(mtpd::kMtpdServiceName,
69 mtpd_owner_changed_callback_);
71 #if !defined(OS_CHROMEOS)
72 session_bus_->PostTaskToDBusThread(
73 FROM_HERE, base::Bind(&dbus::Bus::ShutdownAndBlock, session_bus_));
74 #endif
76 VLOG(1) << "MediaTransferProtocolManager Shutdown completed";
79 // MediaTransferProtocolManager override.
80 virtual void AddObserver(Observer* observer) OVERRIDE {
81 observers_.AddObserver(observer);
84 // MediaTransferProtocolManager override.
85 virtual void RemoveObserver(Observer* observer) OVERRIDE {
86 observers_.RemoveObserver(observer);
89 // MediaTransferProtocolManager override.
90 virtual const std::vector<std::string> GetStorages() const OVERRIDE {
91 DCHECK(thread_checker_.CalledOnValidThread());
92 std::vector<std::string> storages;
93 for (StorageInfoMap::const_iterator it = storage_info_map_.begin();
94 it != storage_info_map_.end();
95 ++it) {
96 storages.push_back(it->first);
98 return storages;
101 // MediaTransferProtocolManager override.
102 virtual const MtpStorageInfo* GetStorageInfo(
103 const std::string& storage_name) const OVERRIDE {
104 DCHECK(thread_checker_.CalledOnValidThread());
105 StorageInfoMap::const_iterator it = storage_info_map_.find(storage_name);
106 return it != storage_info_map_.end() ? &it->second : NULL;
109 // MediaTransferProtocolManager override.
110 virtual void OpenStorage(const std::string& storage_name,
111 const std::string& mode,
112 const OpenStorageCallback& callback) OVERRIDE {
113 DCHECK(thread_checker_.CalledOnValidThread());
114 if (!ContainsKey(storage_info_map_, storage_name) || !mtp_client_) {
115 callback.Run(std::string(), true);
116 return;
118 open_storage_callbacks_.push(callback);
119 mtp_client_->OpenStorage(
120 storage_name,
121 mode,
122 base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorage,
123 weak_ptr_factory_.GetWeakPtr()),
124 base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorageError,
125 weak_ptr_factory_.GetWeakPtr()));
128 // MediaTransferProtocolManager override.
129 virtual void CloseStorage(const std::string& storage_handle,
130 const CloseStorageCallback& callback) OVERRIDE {
131 DCHECK(thread_checker_.CalledOnValidThread());
132 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
133 callback.Run(true);
134 return;
136 close_storage_callbacks_.push(std::make_pair(callback, storage_handle));
137 mtp_client_->CloseStorage(
138 storage_handle,
139 base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorage,
140 weak_ptr_factory_.GetWeakPtr()),
141 base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorageError,
142 weak_ptr_factory_.GetWeakPtr()));
145 // MediaTransferProtocolManager override.
146 virtual void ReadDirectoryByPath(
147 const std::string& storage_handle,
148 const std::string& path,
149 const ReadDirectoryCallback& callback) OVERRIDE {
150 DCHECK(thread_checker_.CalledOnValidThread());
151 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
152 callback.Run(std::vector<MtpFileEntry>(), true);
153 return;
155 read_directory_callbacks_.push(callback);
156 mtp_client_->ReadDirectoryByPath(
157 storage_handle,
158 path,
159 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory,
160 weak_ptr_factory_.GetWeakPtr()),
161 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
162 weak_ptr_factory_.GetWeakPtr()));
165 // MediaTransferProtocolManager override.
166 virtual void ReadDirectoryById(
167 const std::string& storage_handle,
168 uint32 file_id,
169 const ReadDirectoryCallback& callback) OVERRIDE {
170 DCHECK(thread_checker_.CalledOnValidThread());
171 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
172 callback.Run(std::vector<MtpFileEntry>(), true);
173 return;
175 read_directory_callbacks_.push(callback);
176 mtp_client_->ReadDirectoryById(
177 storage_handle,
178 file_id,
179 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory,
180 weak_ptr_factory_.GetWeakPtr()),
181 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
182 weak_ptr_factory_.GetWeakPtr()));
185 // MediaTransferProtocolManager override.
186 virtual void ReadFileChunkByPath(const std::string& storage_handle,
187 const std::string& path,
188 uint32 offset,
189 uint32 count,
190 const ReadFileCallback& callback) OVERRIDE {
191 DCHECK(thread_checker_.CalledOnValidThread());
192 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
193 callback.Run(std::string(), true);
194 return;
196 read_file_callbacks_.push(callback);
197 mtp_client_->ReadFileChunkByPath(
198 storage_handle, path, offset, count,
199 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile,
200 weak_ptr_factory_.GetWeakPtr()),
201 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError,
202 weak_ptr_factory_.GetWeakPtr()));
205 // MediaTransferProtocolManager override.
206 virtual void ReadFileChunkById(const std::string& storage_handle,
207 uint32 file_id,
208 uint32 offset,
209 uint32 count,
210 const ReadFileCallback& callback) OVERRIDE {
211 DCHECK(thread_checker_.CalledOnValidThread());
212 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
213 callback.Run(std::string(), true);
214 return;
216 read_file_callbacks_.push(callback);
217 mtp_client_->ReadFileChunkById(
218 storage_handle, file_id, offset, count,
219 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile,
220 weak_ptr_factory_.GetWeakPtr()),
221 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError,
222 weak_ptr_factory_.GetWeakPtr()));
225 virtual void GetFileInfoByPath(const std::string& storage_handle,
226 const std::string& path,
227 const GetFileInfoCallback& callback) OVERRIDE {
228 DCHECK(thread_checker_.CalledOnValidThread());
229 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
230 callback.Run(MtpFileEntry(), true);
231 return;
233 get_file_info_callbacks_.push(callback);
234 mtp_client_->GetFileInfoByPath(
235 storage_handle,
236 path,
237 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo,
238 weak_ptr_factory_.GetWeakPtr()),
239 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError,
240 weak_ptr_factory_.GetWeakPtr()));
243 virtual void GetFileInfoById(const std::string& storage_handle,
244 uint32 file_id,
245 const GetFileInfoCallback& callback) OVERRIDE {
246 DCHECK(thread_checker_.CalledOnValidThread());
247 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
248 callback.Run(MtpFileEntry(), true);
249 return;
251 get_file_info_callbacks_.push(callback);
252 mtp_client_->GetFileInfoById(
253 storage_handle,
254 file_id,
255 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo,
256 weak_ptr_factory_.GetWeakPtr()),
257 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError,
258 weak_ptr_factory_.GetWeakPtr()));
261 private:
262 // Map of storage names to storage info.
263 typedef std::map<std::string, MtpStorageInfo> StorageInfoMap;
264 // Callback queues - DBus communication is in-order, thus callbacks are
265 // received in the same order as the requests.
266 typedef std::queue<OpenStorageCallback> OpenStorageCallbackQueue;
267 // (callback, handle)
268 typedef std::queue<std::pair<CloseStorageCallback, std::string>
269 > CloseStorageCallbackQueue;
270 typedef std::queue<ReadDirectoryCallback> ReadDirectoryCallbackQueue;
271 typedef std::queue<ReadFileCallback> ReadFileCallbackQueue;
272 typedef std::queue<GetFileInfoCallback> GetFileInfoCallbackQueue;
274 void OnStorageChanged(bool is_attach, const std::string& storage_name) {
275 DCHECK(thread_checker_.CalledOnValidThread());
276 DCHECK(mtp_client_);
277 if (is_attach) {
278 mtp_client_->GetStorageInfo(
279 storage_name,
280 base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo,
281 weak_ptr_factory_.GetWeakPtr()),
282 base::Bind(&base::DoNothing));
283 return;
286 // Detach case.
287 StorageInfoMap::iterator it = storage_info_map_.find(storage_name);
288 if (it == storage_info_map_.end()) {
289 // This might happen during initialization when |storage_info_map_| has
290 // not been fully populated yet?
291 return;
293 storage_info_map_.erase(it);
294 FOR_EACH_OBSERVER(Observer,
295 observers_,
296 StorageChanged(false /* detach */, storage_name));
299 void OnEnumerateStorages(const std::vector<std::string>& storage_names) {
300 DCHECK(thread_checker_.CalledOnValidThread());
301 DCHECK(mtp_client_);
302 for (size_t i = 0; i < storage_names.size(); ++i) {
303 mtp_client_->GetStorageInfo(
304 storage_names[i],
305 base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo,
306 weak_ptr_factory_.GetWeakPtr()),
307 base::Bind(&base::DoNothing));
311 void OnGetStorageInfo(const MtpStorageInfo& storage_info) {
312 DCHECK(thread_checker_.CalledOnValidThread());
313 const std::string& storage_name = storage_info.storage_name();
314 if (ContainsKey(storage_info_map_, storage_name)) {
315 // This should not happen, since MediaTransferProtocolManagerImpl should
316 // only call EnumerateStorages() once, which populates |storage_info_map_|
317 // with the already-attached devices.
318 // After that, all incoming signals are either for new storage
319 // attachments, which should not be in |storage_info_map_|, or for
320 // storage detachements, which do not add to |storage_info_map_|.
321 NOTREACHED();
322 return;
325 // New storage. Add it and let the observers know.
326 storage_info_map_.insert(std::make_pair(storage_name, storage_info));
327 FOR_EACH_OBSERVER(Observer,
328 observers_,
329 StorageChanged(true /* is attach */, storage_name));
332 void OnOpenStorage(const std::string& handle) {
333 DCHECK(thread_checker_.CalledOnValidThread());
334 if (!ContainsKey(handles_, handle)) {
335 handles_.insert(handle);
336 open_storage_callbacks_.front().Run(handle, false);
337 } else {
338 NOTREACHED();
339 open_storage_callbacks_.front().Run(std::string(), true);
341 open_storage_callbacks_.pop();
344 void OnOpenStorageError() {
345 open_storage_callbacks_.front().Run(std::string(), true);
346 open_storage_callbacks_.pop();
349 void OnCloseStorage() {
350 DCHECK(thread_checker_.CalledOnValidThread());
351 const std::string& handle = close_storage_callbacks_.front().second;
352 if (ContainsKey(handles_, handle)) {
353 handles_.erase(handle);
354 close_storage_callbacks_.front().first.Run(false);
355 } else {
356 NOTREACHED();
357 close_storage_callbacks_.front().first.Run(true);
359 close_storage_callbacks_.pop();
362 void OnCloseStorageError() {
363 DCHECK(thread_checker_.CalledOnValidThread());
364 close_storage_callbacks_.front().first.Run(true);
365 close_storage_callbacks_.pop();
368 void OnReadDirectory(const std::vector<MtpFileEntry>& file_entries) {
369 DCHECK(thread_checker_.CalledOnValidThread());
370 read_directory_callbacks_.front().Run(file_entries, false);
371 read_directory_callbacks_.pop();
374 void OnReadDirectoryError() {
375 DCHECK(thread_checker_.CalledOnValidThread());
376 read_directory_callbacks_.front().Run(std::vector<MtpFileEntry>(), true);
377 read_directory_callbacks_.pop();
380 void OnReadFile(const std::string& data) {
381 DCHECK(thread_checker_.CalledOnValidThread());
382 read_file_callbacks_.front().Run(data, false);
383 read_file_callbacks_.pop();
386 void OnReadFileError() {
387 DCHECK(thread_checker_.CalledOnValidThread());
388 read_file_callbacks_.front().Run(std::string(), true);
389 read_file_callbacks_.pop();
392 void OnGetFileInfo(const MtpFileEntry& entry) {
393 DCHECK(thread_checker_.CalledOnValidThread());
394 get_file_info_callbacks_.front().Run(entry, false);
395 get_file_info_callbacks_.pop();
398 void OnGetFileInfoError() {
399 DCHECK(thread_checker_.CalledOnValidThread());
400 get_file_info_callbacks_.front().Run(MtpFileEntry(), true);
401 get_file_info_callbacks_.pop();
404 // Get the Bus object used to communicate with mtpd.
405 dbus::Bus* GetBus() {
406 DCHECK(thread_checker_.CalledOnValidThread());
407 #if defined(OS_CHROMEOS)
408 return chromeos::DBusThreadManager::Get()->GetSystemBus();
409 #else
410 return session_bus_.get();
411 #endif
414 // Callback to finish initialization after figuring out if the mtp service
415 // has an owner, or if the service owner has changed.
416 // |mtpd_service_owner| contains the name of the current owner, if any.
417 void FinishSetupOnOriginThread(const std::string& mtpd_service_owner) {
418 DCHECK(thread_checker_.CalledOnValidThread());
420 if (mtpd_service_owner == current_mtpd_owner_)
421 return;
423 if (mtpd_service_owner.empty()) {
424 current_mtpd_owner_.clear();
425 mtp_client_.reset();
426 return;
429 current_mtpd_owner_ = mtpd_service_owner;
431 mtp_client_.reset(
432 MediaTransferProtocolDaemonClient::Create(GetBus(),
433 false /* not stub */));
435 // Set up signals and start initializing |storage_info_map_|.
436 mtp_client_->SetUpConnections(
437 base::Bind(&MediaTransferProtocolManagerImpl::OnStorageChanged,
438 weak_ptr_factory_.GetWeakPtr()));
439 mtp_client_->EnumerateStorages(
440 base::Bind(&MediaTransferProtocolManagerImpl::OnEnumerateStorages,
441 weak_ptr_factory_.GetWeakPtr()),
442 base::Bind(&base::DoNothing));
445 // Mtpd DBus client.
446 scoped_ptr<MediaTransferProtocolDaemonClient> mtp_client_;
448 #if !defined(OS_CHROMEOS)
449 // And a D-Bus session for talking to mtpd.
450 scoped_refptr<dbus::Bus> session_bus_;
451 #endif
453 // Device attachment / detachment observers.
454 ObserverList<Observer> observers_;
456 base::WeakPtrFactory<MediaTransferProtocolManagerImpl> weak_ptr_factory_;
458 // Everything below is only accessed on the UI thread.
460 // Map to keep track of attached storages by name.
461 StorageInfoMap storage_info_map_;
463 // Set of open storage handles.
464 std::set<std::string> handles_;
466 dbus::Bus::GetServiceOwnerCallback mtpd_owner_changed_callback_;
468 std::string current_mtpd_owner_;
470 // Queued callbacks.
471 OpenStorageCallbackQueue open_storage_callbacks_;
472 CloseStorageCallbackQueue close_storage_callbacks_;
473 ReadDirectoryCallbackQueue read_directory_callbacks_;
474 ReadFileCallbackQueue read_file_callbacks_;
475 GetFileInfoCallbackQueue get_file_info_callbacks_;
477 base::ThreadChecker thread_checker_;
479 DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolManagerImpl);
482 } // namespace
484 // static
485 MediaTransferProtocolManager* MediaTransferProtocolManager::Initialize(
486 scoped_refptr<base::SequencedTaskRunner> task_runner) {
487 DCHECK(!g_media_transfer_protocol_manager);
489 g_media_transfer_protocol_manager =
490 new MediaTransferProtocolManagerImpl(task_runner);
491 VLOG(1) << "MediaTransferProtocolManager initialized";
493 return g_media_transfer_protocol_manager;
496 } // namespace device