mac: Let IPhotoDataProvider::GetAlbumNames() return albums in a deterministic order.
[chromium-blink-merge.git] / device / media_transfer_protocol / media_transfer_protocol_manager.cc
blob898b3932f7cdff5a3d07a0accfae8a5f279aedcb
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 <algorithm>
8 #include <map>
9 #include <queue>
10 #include <set>
11 #include <utility>
13 #include "base/bind.h"
14 #include "base/command_line.h"
15 #include "base/location.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/observer_list.h"
18 #include "base/sequenced_task_runner.h"
19 #include "base/stl_util.h"
20 #include "base/threading/thread_checker.h"
21 #include "dbus/bus.h"
22 #include "device/media_transfer_protocol/media_transfer_protocol_daemon_client.h"
23 #include "device/media_transfer_protocol/mtp_file_entry.pb.h"
24 #include "device/media_transfer_protocol/mtp_storage_info.pb.h"
25 #include "third_party/cros_system_api/dbus/service_constants.h"
27 #if defined(OS_CHROMEOS)
28 #include "chromeos/dbus/dbus_thread_manager.h"
29 #endif
31 namespace device {
33 namespace {
35 MediaTransferProtocolManager* g_media_transfer_protocol_manager = NULL;
37 // When reading directory entries, this is the number of entries for
38 // GetFileInfo() to read in one operation. If set too low, efficiency goes down
39 // slightly due to the overhead of D-Bus calls. If set too high, then slow
40 // devices may trigger a D-Bus timeout.
41 // The value below is a good initial estimate.
42 const size_t kFileInfoToFetchChunkSize = 25;
44 // On the first call to GetFileInfo, the offset to use is 0.
45 const size_t kInitialOffset = 0;
47 // The MediaTransferProtocolManager implementation.
48 class MediaTransferProtocolManagerImpl : public MediaTransferProtocolManager {
49 public:
50 explicit MediaTransferProtocolManagerImpl(
51 scoped_refptr<base::SequencedTaskRunner> task_runner)
52 : weak_ptr_factory_(this) {
53 #if defined(OS_CHROMEOS)
54 DCHECK(!task_runner.get());
55 #else
56 DCHECK(task_runner.get());
57 dbus::Bus::Options options;
58 options.bus_type = dbus::Bus::SYSTEM;
59 options.connection_type = dbus::Bus::PRIVATE;
60 options.dbus_task_runner = task_runner;
61 session_bus_ = new dbus::Bus(options);
62 #endif
64 if (GetBus()) {
65 // Listen for future mtpd service owner changes, in case it is not
66 // available right now. There is no guarantee on Linux or ChromeOS that
67 // mtpd is running already.
68 mtpd_owner_changed_callback_ = base::Bind(
69 &MediaTransferProtocolManagerImpl::FinishSetupOnOriginThread,
70 weak_ptr_factory_.GetWeakPtr());
71 GetBus()->ListenForServiceOwnerChange(mtpd::kMtpdServiceName,
72 mtpd_owner_changed_callback_);
73 GetBus()->GetServiceOwner(mtpd::kMtpdServiceName,
74 mtpd_owner_changed_callback_);
78 ~MediaTransferProtocolManagerImpl() override {
79 DCHECK(g_media_transfer_protocol_manager);
80 g_media_transfer_protocol_manager = NULL;
81 if (GetBus()) {
82 GetBus()->UnlistenForServiceOwnerChange(mtpd::kMtpdServiceName,
83 mtpd_owner_changed_callback_);
86 #if !defined(OS_CHROMEOS)
87 session_bus_->GetDBusTaskRunner()->PostTask(
88 FROM_HERE, base::Bind(&dbus::Bus::ShutdownAndBlock, session_bus_));
89 #endif
91 VLOG(1) << "MediaTransferProtocolManager Shutdown completed";
94 // MediaTransferProtocolManager override.
95 void AddObserver(Observer* observer) override {
96 DCHECK(thread_checker_.CalledOnValidThread());
97 observers_.AddObserver(observer);
100 // MediaTransferProtocolManager override.
101 void RemoveObserver(Observer* observer) override {
102 DCHECK(thread_checker_.CalledOnValidThread());
103 observers_.RemoveObserver(observer);
106 // MediaTransferProtocolManager override.
107 const std::vector<std::string> GetStorages() const override {
108 DCHECK(thread_checker_.CalledOnValidThread());
109 std::vector<std::string> storages;
110 for (StorageInfoMap::const_iterator it = storage_info_map_.begin();
111 it != storage_info_map_.end();
112 ++it) {
113 storages.push_back(it->first);
115 return storages;
118 // MediaTransferProtocolManager override.
119 const MtpStorageInfo* GetStorageInfo(
120 const std::string& storage_name) const override {
121 DCHECK(thread_checker_.CalledOnValidThread());
122 StorageInfoMap::const_iterator it = storage_info_map_.find(storage_name);
123 return it != storage_info_map_.end() ? &it->second : NULL;
126 // MediaTransferProtocolManager override.
127 void GetStorageInfoFromDevice(
128 const std::string& storage_name,
129 const GetStorageInfoFromDeviceCallback& callback) override {
130 DCHECK(thread_checker_.CalledOnValidThread());
131 if (!ContainsKey(storage_info_map_, storage_name) || !mtp_client_) {
132 MtpStorageInfo info;
133 callback.Run(info, true /* error */);
134 return;
136 get_storage_info_from_device_callbacks_.push(callback);
137 mtp_client_->GetStorageInfoFromDevice(
138 storage_name,
139 base::Bind(
140 &MediaTransferProtocolManagerImpl::OnGetStorageInfoFromDevice,
141 weak_ptr_factory_.GetWeakPtr()),
142 base::Bind(
143 &MediaTransferProtocolManagerImpl::OnGetStorageInfoFromDeviceError,
144 weak_ptr_factory_.GetWeakPtr()));
147 // MediaTransferProtocolManager override.
148 void OpenStorage(const std::string& storage_name,
149 const std::string& mode,
150 const OpenStorageCallback& callback) override {
151 DCHECK(thread_checker_.CalledOnValidThread());
152 if (!ContainsKey(storage_info_map_, storage_name) || !mtp_client_) {
153 callback.Run(std::string(), true);
154 return;
156 open_storage_callbacks_.push(callback);
157 mtp_client_->OpenStorage(
158 storage_name,
159 mode,
160 base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorage,
161 weak_ptr_factory_.GetWeakPtr()),
162 base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorageError,
163 weak_ptr_factory_.GetWeakPtr()));
166 // MediaTransferProtocolManager override.
167 void CloseStorage(const std::string& storage_handle,
168 const CloseStorageCallback& callback) override {
169 DCHECK(thread_checker_.CalledOnValidThread());
170 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
171 callback.Run(true);
172 return;
174 close_storage_callbacks_.push(std::make_pair(callback, storage_handle));
175 mtp_client_->CloseStorage(
176 storage_handle,
177 base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorage,
178 weak_ptr_factory_.GetWeakPtr()),
179 base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorageError,
180 weak_ptr_factory_.GetWeakPtr()));
183 void CreateDirectory(const std::string& storage_handle,
184 const uint32 parent_id,
185 const std::string& directory_name,
186 const CreateDirectoryCallback& callback) override {
187 DCHECK(thread_checker_.CalledOnValidThread());
188 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
189 callback.Run(true /* error */);
190 return;
192 create_directory_callbacks_.push(callback);
193 mtp_client_->CreateDirectory(
194 storage_handle, parent_id, directory_name,
195 base::Bind(&MediaTransferProtocolManagerImpl::OnCreateDirectory,
196 weak_ptr_factory_.GetWeakPtr()),
197 base::Bind(&MediaTransferProtocolManagerImpl::OnCreateDirectoryError,
198 weak_ptr_factory_.GetWeakPtr()));
201 // MediaTransferProtocolManager override.
202 void ReadDirectory(const std::string& storage_handle,
203 const uint32 file_id,
204 const size_t max_size,
205 const ReadDirectoryCallback& callback) override {
206 DCHECK(thread_checker_.CalledOnValidThread());
207 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
208 callback.Run(std::vector<MtpFileEntry>(),
209 false /* no more entries */,
210 true /* error */);
211 return;
213 read_directory_callbacks_.push(callback);
214 mtp_client_->ReadDirectoryEntryIds(
215 storage_handle, file_id,
216 base::Bind(&MediaTransferProtocolManagerImpl::
217 OnReadDirectoryEntryIdsToReadDirectory,
218 weak_ptr_factory_.GetWeakPtr(), storage_handle, max_size),
219 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
220 weak_ptr_factory_.GetWeakPtr()));
223 // MediaTransferProtocolManager override.
224 void ReadFileChunk(const std::string& storage_handle,
225 uint32 file_id,
226 uint32 offset,
227 uint32 count,
228 const ReadFileCallback& callback) override {
229 DCHECK(thread_checker_.CalledOnValidThread());
230 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
231 callback.Run(std::string(), true);
232 return;
234 read_file_callbacks_.push(callback);
235 mtp_client_->ReadFileChunk(
236 storage_handle, file_id, offset, count,
237 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile,
238 weak_ptr_factory_.GetWeakPtr()),
239 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError,
240 weak_ptr_factory_.GetWeakPtr()));
243 void GetFileInfo(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 std::vector<uint32> file_ids;
252 file_ids.push_back(file_id);
253 get_file_info_callbacks_.push(callback);
254 mtp_client_->GetFileInfo(
255 storage_handle,
256 file_ids,
257 kInitialOffset,
258 file_ids.size(),
259 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo,
260 weak_ptr_factory_.GetWeakPtr()),
261 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError,
262 weak_ptr_factory_.GetWeakPtr()));
265 void RenameObject(const std::string& storage_handle,
266 const uint32 object_id,
267 const std::string& new_name,
268 const RenameObjectCallback& callback) override {
269 DCHECK(thread_checker_.CalledOnValidThread());
270 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
271 callback.Run(true /* error */);
272 return;
274 rename_object_callbacks_.push(callback);
275 mtp_client_->RenameObject(
276 storage_handle, object_id, new_name,
277 base::Bind(&MediaTransferProtocolManagerImpl::OnRenameObject,
278 weak_ptr_factory_.GetWeakPtr()),
279 base::Bind(&MediaTransferProtocolManagerImpl::OnRenameObjectError,
280 weak_ptr_factory_.GetWeakPtr()));
283 void CopyFileFromLocal(const std::string& storage_handle,
284 const int source_file_descriptor,
285 const uint32 parent_id,
286 const std::string& file_name,
287 const CopyFileFromLocalCallback& callback) override {
288 DCHECK(thread_checker_.CalledOnValidThread());
289 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
290 callback.Run(true /* error */);
291 return;
293 copy_file_from_local_callbacks_.push(callback);
294 mtp_client_->CopyFileFromLocal(
295 storage_handle, source_file_descriptor, parent_id, file_name,
296 base::Bind(&MediaTransferProtocolManagerImpl::OnCopyFileFromLocal,
297 weak_ptr_factory_.GetWeakPtr()),
298 base::Bind(&MediaTransferProtocolManagerImpl::OnCopyFileFromLocalError,
299 weak_ptr_factory_.GetWeakPtr()));
302 void DeleteObject(const std::string& storage_handle,
303 const uint32 object_id,
304 const DeleteObjectCallback& callback) override {
305 DCHECK(thread_checker_.CalledOnValidThread());
306 if (!ContainsKey(handles_, storage_handle) || !mtp_client_) {
307 callback.Run(true /* error */);
308 return;
310 delete_object_callbacks_.push(callback);
311 mtp_client_->DeleteObject(
312 storage_handle, object_id,
313 base::Bind(&MediaTransferProtocolManagerImpl::OnDeleteObject,
314 weak_ptr_factory_.GetWeakPtr()),
315 base::Bind(&MediaTransferProtocolManagerImpl::OnDeleteObjectError,
316 weak_ptr_factory_.GetWeakPtr()));
319 private:
320 // Map of storage names to storage info.
321 typedef std::map<std::string, MtpStorageInfo> StorageInfoMap;
322 typedef std::queue<GetStorageInfoFromDeviceCallback>
323 GetStorageInfoFromDeviceCallbackQueue;
324 // Callback queues - DBus communication is in-order, thus callbacks are
325 // received in the same order as the requests.
326 typedef std::queue<OpenStorageCallback> OpenStorageCallbackQueue;
327 // (callback, handle)
328 typedef std::queue<std::pair<CloseStorageCallback, std::string>
329 > CloseStorageCallbackQueue;
330 typedef std::queue<CreateDirectoryCallback> CreateDirectoryCallbackQueue;
331 typedef std::queue<ReadDirectoryCallback> ReadDirectoryCallbackQueue;
332 typedef std::queue<ReadFileCallback> ReadFileCallbackQueue;
333 typedef std::queue<GetFileInfoCallback> GetFileInfoCallbackQueue;
334 typedef std::queue<RenameObjectCallback> RenameObjectCallbackQueue;
335 typedef std::queue<CopyFileFromLocalCallback> CopyFileFromLocalCallbackQueue;
336 typedef std::queue<DeleteObjectCallback> DeleteObjectCallbackQueue;
338 void OnStorageAttached(const std::string& storage_name) {
339 DCHECK(thread_checker_.CalledOnValidThread());
340 mtp_client_->GetStorageInfo(
341 storage_name,
342 base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo,
343 weak_ptr_factory_.GetWeakPtr()),
344 base::Bind(&base::DoNothing));
347 void OnStorageDetached(const std::string& storage_name) {
348 DCHECK(thread_checker_.CalledOnValidThread());
349 if (storage_info_map_.erase(storage_name) == 0) {
350 // This can happen for a storage where
351 // MediaTransferProtocolDaemonClient::GetStorageInfo() failed.
352 // Return to avoid giving observers phantom detach events.
353 return;
355 FOR_EACH_OBSERVER(Observer,
356 observers_,
357 StorageChanged(false /* detach */, storage_name));
360 void OnStorageChanged(bool is_attach, const std::string& storage_name) {
361 DCHECK(thread_checker_.CalledOnValidThread());
362 DCHECK(mtp_client_);
363 if (is_attach)
364 OnStorageAttached(storage_name);
365 else
366 OnStorageDetached(storage_name);
369 void OnEnumerateStorages(const std::vector<std::string>& storage_names) {
370 DCHECK(thread_checker_.CalledOnValidThread());
371 DCHECK(mtp_client_);
372 for (size_t i = 0; i < storage_names.size(); ++i) {
373 if (ContainsKey(storage_info_map_, storage_names[i])) {
374 // OnStorageChanged() might have gotten called first.
375 continue;
377 OnStorageAttached(storage_names[i]);
381 void OnGetStorageInfo(const MtpStorageInfo& storage_info) {
382 DCHECK(thread_checker_.CalledOnValidThread());
383 const std::string& storage_name = storage_info.storage_name();
384 if (ContainsKey(storage_info_map_, storage_name)) {
385 // This should not happen, since MediaTransferProtocolManagerImpl should
386 // only call EnumerateStorages() once, which populates |storage_info_map_|
387 // with the already-attached devices.
388 // After that, all incoming signals are either for new storage
389 // attachments, which should not be in |storage_info_map_|, or for
390 // storage detachments, which do not add to |storage_info_map_|.
391 // Return to avoid giving observers phantom detach events.
392 NOTREACHED();
393 return;
396 // New storage. Add it and let the observers know.
397 storage_info_map_.insert(std::make_pair(storage_name, storage_info));
398 FOR_EACH_OBSERVER(Observer,
399 observers_,
400 StorageChanged(true /* is attach */, storage_name));
403 void OnGetStorageInfoFromDevice(const MtpStorageInfo& storage_info) {
404 get_storage_info_from_device_callbacks_.front().Run(storage_info,
405 false /* no error */);
406 get_storage_info_from_device_callbacks_.pop();
409 void OnGetStorageInfoFromDeviceError() {
410 MtpStorageInfo info;
411 get_storage_info_from_device_callbacks_.front().Run(info, true /* error */);
412 get_storage_info_from_device_callbacks_.pop();
415 void OnOpenStorage(const std::string& handle) {
416 DCHECK(thread_checker_.CalledOnValidThread());
417 if (!ContainsKey(handles_, handle)) {
418 handles_.insert(handle);
419 open_storage_callbacks_.front().Run(handle, false);
420 } else {
421 NOTREACHED();
422 open_storage_callbacks_.front().Run(std::string(), true);
424 open_storage_callbacks_.pop();
427 void OnOpenStorageError() {
428 open_storage_callbacks_.front().Run(std::string(), true);
429 open_storage_callbacks_.pop();
432 void OnCloseStorage() {
433 DCHECK(thread_checker_.CalledOnValidThread());
434 const std::string& handle = close_storage_callbacks_.front().second;
435 if (ContainsKey(handles_, handle)) {
436 handles_.erase(handle);
437 close_storage_callbacks_.front().first.Run(false);
438 } else {
439 NOTREACHED();
440 close_storage_callbacks_.front().first.Run(true);
442 close_storage_callbacks_.pop();
445 void OnCloseStorageError() {
446 DCHECK(thread_checker_.CalledOnValidThread());
447 close_storage_callbacks_.front().first.Run(true);
448 close_storage_callbacks_.pop();
451 void OnCreateDirectory() {
452 DCHECK(thread_checker_.CalledOnValidThread());
453 create_directory_callbacks_.front().Run(false /* no error */);
454 create_directory_callbacks_.pop();
457 void OnCreateDirectoryError() {
458 DCHECK(thread_checker_.CalledOnValidThread());
459 create_directory_callbacks_.front().Run(true /* error */);
460 create_directory_callbacks_.pop();
463 void OnReadDirectoryEntryIdsToReadDirectory(
464 const std::string& storage_handle,
465 const size_t max_size,
466 const std::vector<uint32>& file_ids) {
467 DCHECK(thread_checker_.CalledOnValidThread());
469 if (file_ids.empty()) {
470 OnGotDirectoryEntries(storage_handle, file_ids, kInitialOffset, max_size,
471 file_ids, std::vector<MtpFileEntry>());
472 return;
475 std::vector<uint32> sorted_file_ids = file_ids;
476 std::sort(sorted_file_ids.begin(), sorted_file_ids.end());
478 const size_t chunk_size =
479 max_size == 0 ? kFileInfoToFetchChunkSize
480 : std::min(max_size, kFileInfoToFetchChunkSize);
482 mtp_client_->GetFileInfo(
483 storage_handle, file_ids, kInitialOffset, chunk_size,
484 base::Bind(&MediaTransferProtocolManagerImpl::OnGotDirectoryEntries,
485 weak_ptr_factory_.GetWeakPtr(), storage_handle, file_ids,
486 kInitialOffset, max_size, sorted_file_ids),
487 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
488 weak_ptr_factory_.GetWeakPtr()));
491 void OnGotDirectoryEntries(const std::string& storage_handle,
492 const std::vector<uint32>& file_ids,
493 const size_t offset,
494 const size_t max_size,
495 const std::vector<uint32>& sorted_file_ids,
496 const std::vector<MtpFileEntry>& file_entries) {
497 DCHECK(thread_checker_.CalledOnValidThread());
498 DCHECK_EQ(file_ids.size(), sorted_file_ids.size());
500 // Use |sorted_file_ids| to sanity check and make sure the results are a
501 // subset of the requested file ids.
502 for (size_t i = 0; i < file_entries.size(); ++i) {
503 std::vector<uint32>::const_iterator it =
504 std::lower_bound(sorted_file_ids.begin(),
505 sorted_file_ids.end(),
506 file_entries[i].item_id());
507 if (it == sorted_file_ids.end()) {
508 OnReadDirectoryError();
509 return;
513 const size_t directory_size =
514 max_size == 0 ? file_ids.size() : std::min(file_ids.size(), max_size);
515 size_t next_offset = directory_size;
516 if (offset < SIZE_MAX - kFileInfoToFetchChunkSize)
517 next_offset = std::min(next_offset, offset + kFileInfoToFetchChunkSize);
518 bool has_more = next_offset < directory_size;
519 read_directory_callbacks_.front().Run(file_entries,
520 has_more,
521 false /* no error */);
523 if (has_more) {
524 const size_t chunk_size =
525 std::min(directory_size - next_offset, kFileInfoToFetchChunkSize);
527 mtp_client_->GetFileInfo(
528 storage_handle, file_ids, next_offset, chunk_size,
529 base::Bind(&MediaTransferProtocolManagerImpl::OnGotDirectoryEntries,
530 weak_ptr_factory_.GetWeakPtr(), storage_handle, file_ids,
531 next_offset, max_size, sorted_file_ids),
532 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
533 weak_ptr_factory_.GetWeakPtr()));
534 return;
536 read_directory_callbacks_.pop();
539 void OnReadDirectoryError() {
540 DCHECK(thread_checker_.CalledOnValidThread());
541 read_directory_callbacks_.front().Run(std::vector<MtpFileEntry>(),
542 false /* no more entries */,
543 true /* error */);
544 read_directory_callbacks_.pop();
547 void OnReadFile(const std::string& data) {
548 DCHECK(thread_checker_.CalledOnValidThread());
549 read_file_callbacks_.front().Run(data, false);
550 read_file_callbacks_.pop();
553 void OnReadFileError() {
554 DCHECK(thread_checker_.CalledOnValidThread());
555 read_file_callbacks_.front().Run(std::string(), true);
556 read_file_callbacks_.pop();
559 void OnGetFileInfo(const std::vector<MtpFileEntry>& entries) {
560 DCHECK(thread_checker_.CalledOnValidThread());
561 if (entries.size() == 1) {
562 get_file_info_callbacks_.front().Run(entries[0], false /* no error */);
563 get_file_info_callbacks_.pop();
564 } else {
565 OnGetFileInfoError();
569 void OnGetFileInfoError() {
570 DCHECK(thread_checker_.CalledOnValidThread());
571 get_file_info_callbacks_.front().Run(MtpFileEntry(), true);
572 get_file_info_callbacks_.pop();
575 void OnRenameObject() {
576 DCHECK(thread_checker_.CalledOnValidThread());
577 rename_object_callbacks_.front().Run(false /* no error */);
578 rename_object_callbacks_.pop();
581 void OnRenameObjectError() {
582 DCHECK(thread_checker_.CalledOnValidThread());
583 rename_object_callbacks_.front().Run(true /* error */);
584 rename_object_callbacks_.pop();
587 void OnCopyFileFromLocal() {
588 DCHECK(thread_checker_.CalledOnValidThread());
589 copy_file_from_local_callbacks_.front().Run(false /* no error */);
590 copy_file_from_local_callbacks_.pop();
593 void OnCopyFileFromLocalError() {
594 DCHECK(thread_checker_.CalledOnValidThread());
595 copy_file_from_local_callbacks_.front().Run(true /* error */);
596 copy_file_from_local_callbacks_.pop();
599 void OnDeleteObject() {
600 DCHECK(thread_checker_.CalledOnValidThread());
601 delete_object_callbacks_.front().Run(false /* no error */);
602 delete_object_callbacks_.pop();
605 void OnDeleteObjectError() {
606 DCHECK(thread_checker_.CalledOnValidThread());
607 delete_object_callbacks_.front().Run(true /* error */);
608 delete_object_callbacks_.pop();
611 // Get the Bus object used to communicate with mtpd.
612 dbus::Bus* GetBus() {
613 DCHECK(thread_checker_.CalledOnValidThread());
614 #if defined(OS_CHROMEOS)
615 return chromeos::DBusThreadManager::Get()->GetSystemBus();
616 #else
617 return session_bus_.get();
618 #endif
621 // Callback to finish initialization after figuring out if the mtpd service
622 // has an owner, or if the service owner has changed.
623 // |mtpd_service_owner| contains the name of the current owner, if any.
624 void FinishSetupOnOriginThread(const std::string& mtpd_service_owner) {
625 DCHECK(thread_checker_.CalledOnValidThread());
627 if (mtpd_service_owner == current_mtpd_owner_)
628 return;
630 // In the case of a new service owner, clear |storage_info_map_|.
631 // Assume all storages have been disconnected. If there is a new service
632 // owner, reconnecting to it will reconnect all the storages as well.
634 // Save a copy of |storage_info_map_| keys as |storage_info_map_| can
635 // change in OnStorageDetached().
636 std::vector<std::string> storage_names;
637 for (StorageInfoMap::const_iterator it = storage_info_map_.begin();
638 it != storage_info_map_.end();
639 ++it) {
640 storage_names.push_back(it->first);
642 for (size_t i = 0; i != storage_names.size(); ++i)
643 OnStorageDetached(storage_names[i]);
645 if (mtpd_service_owner.empty()) {
646 current_mtpd_owner_.clear();
647 mtp_client_.reset();
648 return;
651 current_mtpd_owner_ = mtpd_service_owner;
653 mtp_client_.reset(MediaTransferProtocolDaemonClient::Create(GetBus()));
655 // Set up signals and start initializing |storage_info_map_|.
656 mtp_client_->ListenForChanges(
657 base::Bind(&MediaTransferProtocolManagerImpl::OnStorageChanged,
658 weak_ptr_factory_.GetWeakPtr()));
659 mtp_client_->EnumerateStorages(
660 base::Bind(&MediaTransferProtocolManagerImpl::OnEnumerateStorages,
661 weak_ptr_factory_.GetWeakPtr()),
662 base::Bind(&base::DoNothing));
665 // Mtpd DBus client.
666 scoped_ptr<MediaTransferProtocolDaemonClient> mtp_client_;
668 #if !defined(OS_CHROMEOS)
669 // And a D-Bus session for talking to mtpd.
670 scoped_refptr<dbus::Bus> session_bus_;
671 #endif
673 // Device attachment / detachment observers.
674 base::ObserverList<Observer> observers_;
676 // Map to keep track of attached storages by name.
677 StorageInfoMap storage_info_map_;
679 // Set of open storage handles.
680 std::set<std::string> handles_;
682 dbus::Bus::GetServiceOwnerCallback mtpd_owner_changed_callback_;
684 std::string current_mtpd_owner_;
686 // Queued callbacks.
687 GetStorageInfoFromDeviceCallbackQueue get_storage_info_from_device_callbacks_;
688 OpenStorageCallbackQueue open_storage_callbacks_;
689 CloseStorageCallbackQueue close_storage_callbacks_;
690 CreateDirectoryCallbackQueue create_directory_callbacks_;
691 ReadDirectoryCallbackQueue read_directory_callbacks_;
692 ReadFileCallbackQueue read_file_callbacks_;
693 GetFileInfoCallbackQueue get_file_info_callbacks_;
694 RenameObjectCallbackQueue rename_object_callbacks_;
695 CopyFileFromLocalCallbackQueue copy_file_from_local_callbacks_;
696 DeleteObjectCallbackQueue delete_object_callbacks_;
698 base::ThreadChecker thread_checker_;
700 base::WeakPtrFactory<MediaTransferProtocolManagerImpl> weak_ptr_factory_;
702 DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolManagerImpl);
705 } // namespace
707 // static
708 MediaTransferProtocolManager* MediaTransferProtocolManager::Initialize(
709 scoped_refptr<base::SequencedTaskRunner> task_runner) {
710 DCHECK(!g_media_transfer_protocol_manager);
712 g_media_transfer_protocol_manager =
713 new MediaTransferProtocolManagerImpl(task_runner);
714 VLOG(1) << "MediaTransferProtocolManager initialized";
716 return g_media_transfer_protocol_manager;
719 } // namespace device