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"
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"
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"
34 MediaTransferProtocolManager
* g_media_transfer_protocol_manager
= NULL
;
36 // The MediaTransferProtocolManager implementation.
37 class MediaTransferProtocolManagerImpl
: public MediaTransferProtocolManager
{
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());
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
);
54 // Listen for future mtpd service owner changes, in case it is not
55 // available right now. There is no guarantee on Linux or ChromeOS that
56 // mtpd is running already.
57 mtpd_owner_changed_callback_
= base::Bind(
58 &MediaTransferProtocolManagerImpl::FinishSetupOnOriginThread
,
59 weak_ptr_factory_
.GetWeakPtr());
60 GetBus()->ListenForServiceOwnerChange(mtpd::kMtpdServiceName
,
61 mtpd_owner_changed_callback_
);
62 GetBus()->GetServiceOwner(mtpd::kMtpdServiceName
,
63 mtpd_owner_changed_callback_
);
67 virtual ~MediaTransferProtocolManagerImpl() {
68 DCHECK(g_media_transfer_protocol_manager
);
69 g_media_transfer_protocol_manager
= NULL
;
71 GetBus()->UnlistenForServiceOwnerChange(mtpd::kMtpdServiceName
,
72 mtpd_owner_changed_callback_
);
75 #if !defined(OS_CHROMEOS)
76 session_bus_
->GetDBusTaskRunner()->PostTask(
77 FROM_HERE
, base::Bind(&dbus::Bus::ShutdownAndBlock
, session_bus_
));
80 VLOG(1) << "MediaTransferProtocolManager Shutdown completed";
83 // MediaTransferProtocolManager override.
84 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
85 DCHECK(thread_checker_
.CalledOnValidThread());
86 observers_
.AddObserver(observer
);
89 // MediaTransferProtocolManager override.
90 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
91 DCHECK(thread_checker_
.CalledOnValidThread());
92 observers_
.RemoveObserver(observer
);
95 // MediaTransferProtocolManager override.
96 virtual const std::vector
<std::string
> GetStorages() const OVERRIDE
{
97 DCHECK(thread_checker_
.CalledOnValidThread());
98 std::vector
<std::string
> storages
;
99 for (StorageInfoMap::const_iterator it
= storage_info_map_
.begin();
100 it
!= storage_info_map_
.end();
102 storages
.push_back(it
->first
);
107 // MediaTransferProtocolManager override.
108 virtual const MtpStorageInfo
* GetStorageInfo(
109 const std::string
& storage_name
) const OVERRIDE
{
110 DCHECK(thread_checker_
.CalledOnValidThread());
111 StorageInfoMap::const_iterator it
= storage_info_map_
.find(storage_name
);
112 return it
!= storage_info_map_
.end() ? &it
->second
: NULL
;
115 // MediaTransferProtocolManager override.
116 virtual void OpenStorage(const std::string
& storage_name
,
117 const std::string
& mode
,
118 const OpenStorageCallback
& callback
) OVERRIDE
{
119 DCHECK(thread_checker_
.CalledOnValidThread());
120 if (!ContainsKey(storage_info_map_
, storage_name
) || !mtp_client_
) {
121 callback
.Run(std::string(), true);
124 open_storage_callbacks_
.push(callback
);
125 mtp_client_
->OpenStorage(
128 base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorage
,
129 weak_ptr_factory_
.GetWeakPtr()),
130 base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorageError
,
131 weak_ptr_factory_
.GetWeakPtr()));
134 // MediaTransferProtocolManager override.
135 virtual void CloseStorage(const std::string
& storage_handle
,
136 const CloseStorageCallback
& callback
) OVERRIDE
{
137 DCHECK(thread_checker_
.CalledOnValidThread());
138 if (!ContainsKey(handles_
, storage_handle
) || !mtp_client_
) {
142 close_storage_callbacks_
.push(std::make_pair(callback
, storage_handle
));
143 mtp_client_
->CloseStorage(
145 base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorage
,
146 weak_ptr_factory_
.GetWeakPtr()),
147 base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorageError
,
148 weak_ptr_factory_
.GetWeakPtr()));
151 // MediaTransferProtocolManager override.
152 virtual void ReadDirectoryByPath(
153 const std::string
& storage_handle
,
154 const std::string
& path
,
155 const ReadDirectoryCallback
& callback
) OVERRIDE
{
156 DCHECK(thread_checker_
.CalledOnValidThread());
157 if (!ContainsKey(handles_
, storage_handle
) || !mtp_client_
) {
158 callback
.Run(std::vector
<MtpFileEntry
>(), true);
161 read_directory_callbacks_
.push(callback
);
162 mtp_client_
->ReadDirectoryByPath(
165 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory
,
166 weak_ptr_factory_
.GetWeakPtr()),
167 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError
,
168 weak_ptr_factory_
.GetWeakPtr()));
171 // MediaTransferProtocolManager override.
172 virtual void ReadDirectoryById(
173 const std::string
& storage_handle
,
175 const ReadDirectoryCallback
& callback
) OVERRIDE
{
176 DCHECK(thread_checker_
.CalledOnValidThread());
177 if (!ContainsKey(handles_
, storage_handle
) || !mtp_client_
) {
178 callback
.Run(std::vector
<MtpFileEntry
>(), true);
181 read_directory_callbacks_
.push(callback
);
182 mtp_client_
->ReadDirectoryById(
185 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory
,
186 weak_ptr_factory_
.GetWeakPtr()),
187 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError
,
188 weak_ptr_factory_
.GetWeakPtr()));
191 // MediaTransferProtocolManager override.
192 virtual void ReadFileChunkByPath(const std::string
& storage_handle
,
193 const std::string
& path
,
196 const ReadFileCallback
& callback
) OVERRIDE
{
197 DCHECK(thread_checker_
.CalledOnValidThread());
198 if (!ContainsKey(handles_
, storage_handle
) || !mtp_client_
) {
199 callback
.Run(std::string(), true);
202 read_file_callbacks_
.push(callback
);
203 mtp_client_
->ReadFileChunkByPath(
204 storage_handle
, path
, offset
, count
,
205 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile
,
206 weak_ptr_factory_
.GetWeakPtr()),
207 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError
,
208 weak_ptr_factory_
.GetWeakPtr()));
211 // MediaTransferProtocolManager override.
212 virtual void ReadFileChunkById(const std::string
& storage_handle
,
216 const ReadFileCallback
& callback
) OVERRIDE
{
217 DCHECK(thread_checker_
.CalledOnValidThread());
218 if (!ContainsKey(handles_
, storage_handle
) || !mtp_client_
) {
219 callback
.Run(std::string(), true);
222 read_file_callbacks_
.push(callback
);
223 mtp_client_
->ReadFileChunkById(
224 storage_handle
, file_id
, offset
, count
,
225 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile
,
226 weak_ptr_factory_
.GetWeakPtr()),
227 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError
,
228 weak_ptr_factory_
.GetWeakPtr()));
231 virtual void GetFileInfoByPath(const std::string
& storage_handle
,
232 const std::string
& path
,
233 const GetFileInfoCallback
& callback
) OVERRIDE
{
234 DCHECK(thread_checker_
.CalledOnValidThread());
235 if (!ContainsKey(handles_
, storage_handle
) || !mtp_client_
) {
236 callback
.Run(MtpFileEntry(), true);
239 get_file_info_callbacks_
.push(callback
);
240 mtp_client_
->GetFileInfoByPath(
243 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo
,
244 weak_ptr_factory_
.GetWeakPtr()),
245 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError
,
246 weak_ptr_factory_
.GetWeakPtr()));
249 virtual void GetFileInfoById(const std::string
& storage_handle
,
251 const GetFileInfoCallback
& callback
) OVERRIDE
{
252 DCHECK(thread_checker_
.CalledOnValidThread());
253 if (!ContainsKey(handles_
, storage_handle
) || !mtp_client_
) {
254 callback
.Run(MtpFileEntry(), true);
257 get_file_info_callbacks_
.push(callback
);
258 mtp_client_
->GetFileInfoById(
261 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo
,
262 weak_ptr_factory_
.GetWeakPtr()),
263 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError
,
264 weak_ptr_factory_
.GetWeakPtr()));
268 // Map of storage names to storage info.
269 typedef std::map
<std::string
, MtpStorageInfo
> StorageInfoMap
;
270 // Callback queues - DBus communication is in-order, thus callbacks are
271 // received in the same order as the requests.
272 typedef std::queue
<OpenStorageCallback
> OpenStorageCallbackQueue
;
273 // (callback, handle)
274 typedef std::queue
<std::pair
<CloseStorageCallback
, std::string
>
275 > CloseStorageCallbackQueue
;
276 typedef std::queue
<ReadDirectoryCallback
> ReadDirectoryCallbackQueue
;
277 typedef std::queue
<ReadFileCallback
> ReadFileCallbackQueue
;
278 typedef std::queue
<GetFileInfoCallback
> GetFileInfoCallbackQueue
;
280 void OnStorageAttached(const std::string
& storage_name
) {
281 DCHECK(thread_checker_
.CalledOnValidThread());
282 mtp_client_
->GetStorageInfo(
284 base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo
,
285 weak_ptr_factory_
.GetWeakPtr()),
286 base::Bind(&base::DoNothing
));
289 void OnStorageDetached(const std::string
& storage_name
) {
290 DCHECK(thread_checker_
.CalledOnValidThread());
291 if (storage_info_map_
.erase(storage_name
) == 0) {
292 // This can happen for a storage where
293 // MediaTransferProtocolDaemonClient::GetStorageInfo() failed.
294 // Return to avoid giving observers phantom detach events.
297 FOR_EACH_OBSERVER(Observer
,
299 StorageChanged(false /* detach */, storage_name
));
302 void OnStorageChanged(bool is_attach
, const std::string
& storage_name
) {
303 DCHECK(thread_checker_
.CalledOnValidThread());
306 OnStorageAttached(storage_name
);
308 OnStorageDetached(storage_name
);
311 void OnEnumerateStorages(const std::vector
<std::string
>& storage_names
) {
312 DCHECK(thread_checker_
.CalledOnValidThread());
314 for (size_t i
= 0; i
< storage_names
.size(); ++i
) {
315 if (ContainsKey(storage_info_map_
, storage_names
[i
])) {
316 // OnStorageChanged() might have gotten called first.
319 OnStorageAttached(storage_names
[i
]);
323 void OnGetStorageInfo(const MtpStorageInfo
& storage_info
) {
324 DCHECK(thread_checker_
.CalledOnValidThread());
325 const std::string
& storage_name
= storage_info
.storage_name();
326 if (ContainsKey(storage_info_map_
, storage_name
)) {
327 // This should not happen, since MediaTransferProtocolManagerImpl should
328 // only call EnumerateStorages() once, which populates |storage_info_map_|
329 // with the already-attached devices.
330 // After that, all incoming signals are either for new storage
331 // attachments, which should not be in |storage_info_map_|, or for
332 // storage detachments, which do not add to |storage_info_map_|.
333 // Return to avoid giving observers phantom detach events.
338 // New storage. Add it and let the observers know.
339 storage_info_map_
.insert(std::make_pair(storage_name
, storage_info
));
340 FOR_EACH_OBSERVER(Observer
,
342 StorageChanged(true /* is attach */, storage_name
));
345 void OnOpenStorage(const std::string
& handle
) {
346 DCHECK(thread_checker_
.CalledOnValidThread());
347 if (!ContainsKey(handles_
, handle
)) {
348 handles_
.insert(handle
);
349 open_storage_callbacks_
.front().Run(handle
, false);
352 open_storage_callbacks_
.front().Run(std::string(), true);
354 open_storage_callbacks_
.pop();
357 void OnOpenStorageError() {
358 open_storage_callbacks_
.front().Run(std::string(), true);
359 open_storage_callbacks_
.pop();
362 void OnCloseStorage() {
363 DCHECK(thread_checker_
.CalledOnValidThread());
364 const std::string
& handle
= close_storage_callbacks_
.front().second
;
365 if (ContainsKey(handles_
, handle
)) {
366 handles_
.erase(handle
);
367 close_storage_callbacks_
.front().first
.Run(false);
370 close_storage_callbacks_
.front().first
.Run(true);
372 close_storage_callbacks_
.pop();
375 void OnCloseStorageError() {
376 DCHECK(thread_checker_
.CalledOnValidThread());
377 close_storage_callbacks_
.front().first
.Run(true);
378 close_storage_callbacks_
.pop();
381 void OnReadDirectory(const std::vector
<MtpFileEntry
>& file_entries
) {
382 DCHECK(thread_checker_
.CalledOnValidThread());
383 read_directory_callbacks_
.front().Run(file_entries
, false);
384 read_directory_callbacks_
.pop();
387 void OnReadDirectoryError() {
388 DCHECK(thread_checker_
.CalledOnValidThread());
389 read_directory_callbacks_
.front().Run(std::vector
<MtpFileEntry
>(), true);
390 read_directory_callbacks_
.pop();
393 void OnReadFile(const std::string
& data
) {
394 DCHECK(thread_checker_
.CalledOnValidThread());
395 read_file_callbacks_
.front().Run(data
, false);
396 read_file_callbacks_
.pop();
399 void OnReadFileError() {
400 DCHECK(thread_checker_
.CalledOnValidThread());
401 read_file_callbacks_
.front().Run(std::string(), true);
402 read_file_callbacks_
.pop();
405 void OnGetFileInfo(const MtpFileEntry
& entry
) {
406 DCHECK(thread_checker_
.CalledOnValidThread());
407 get_file_info_callbacks_
.front().Run(entry
, false);
408 get_file_info_callbacks_
.pop();
411 void OnGetFileInfoError() {
412 DCHECK(thread_checker_
.CalledOnValidThread());
413 get_file_info_callbacks_
.front().Run(MtpFileEntry(), true);
414 get_file_info_callbacks_
.pop();
417 // Get the Bus object used to communicate with mtpd.
418 dbus::Bus
* GetBus() {
419 DCHECK(thread_checker_
.CalledOnValidThread());
420 #if defined(OS_CHROMEOS)
421 return chromeos::DBusThreadManager::Get()->GetSystemBus();
423 return session_bus_
.get();
427 // Callback to finish initialization after figuring out if the mtpd service
428 // has an owner, or if the service owner has changed.
429 // |mtpd_service_owner| contains the name of the current owner, if any.
430 void FinishSetupOnOriginThread(const std::string
& mtpd_service_owner
) {
431 DCHECK(thread_checker_
.CalledOnValidThread());
433 if (mtpd_service_owner
== current_mtpd_owner_
)
436 // In the case of a new service owner, clear |storage_info_map_|.
437 // Assume all storages have been disconnected. If there is a new service
438 // owner, reconnecting to it will reconnect all the storages as well.
440 // Save a copy of |storage_info_map_| keys as |storage_info_map_| can
441 // change in OnStorageDetached().
442 std::vector
<std::string
> storage_names
;
443 for (StorageInfoMap::const_iterator it
= storage_info_map_
.begin();
444 it
!= storage_info_map_
.end();
446 storage_names
.push_back(it
->first
);
448 for (size_t i
= 0; i
!= storage_names
.size(); ++i
)
449 OnStorageDetached(storage_names
[i
]);
451 if (mtpd_service_owner
.empty()) {
452 current_mtpd_owner_
.clear();
457 current_mtpd_owner_
= mtpd_service_owner
;
459 mtp_client_
.reset(MediaTransferProtocolDaemonClient::Create(GetBus()));
461 // Set up signals and start initializing |storage_info_map_|.
462 mtp_client_
->ListenForChanges(
463 base::Bind(&MediaTransferProtocolManagerImpl::OnStorageChanged
,
464 weak_ptr_factory_
.GetWeakPtr()));
465 mtp_client_
->EnumerateStorages(
466 base::Bind(&MediaTransferProtocolManagerImpl::OnEnumerateStorages
,
467 weak_ptr_factory_
.GetWeakPtr()),
468 base::Bind(&base::DoNothing
));
472 scoped_ptr
<MediaTransferProtocolDaemonClient
> mtp_client_
;
474 #if !defined(OS_CHROMEOS)
475 // And a D-Bus session for talking to mtpd.
476 scoped_refptr
<dbus::Bus
> session_bus_
;
479 // Device attachment / detachment observers.
480 ObserverList
<Observer
> observers_
;
482 // Map to keep track of attached storages by name.
483 StorageInfoMap storage_info_map_
;
485 // Set of open storage handles.
486 std::set
<std::string
> handles_
;
488 dbus::Bus::GetServiceOwnerCallback mtpd_owner_changed_callback_
;
490 std::string current_mtpd_owner_
;
493 OpenStorageCallbackQueue open_storage_callbacks_
;
494 CloseStorageCallbackQueue close_storage_callbacks_
;
495 ReadDirectoryCallbackQueue read_directory_callbacks_
;
496 ReadFileCallbackQueue read_file_callbacks_
;
497 GetFileInfoCallbackQueue get_file_info_callbacks_
;
499 base::ThreadChecker thread_checker_
;
501 base::WeakPtrFactory
<MediaTransferProtocolManagerImpl
> weak_ptr_factory_
;
503 DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolManagerImpl
);
509 MediaTransferProtocolManager
* MediaTransferProtocolManager::Initialize(
510 scoped_refptr
<base::SequencedTaskRunner
> task_runner
) {
511 DCHECK(!g_media_transfer_protocol_manager
);
513 g_media_transfer_protocol_manager
=
514 new MediaTransferProtocolManagerImpl(task_runner
);
515 VLOG(1) << "MediaTransferProtocolManager initialized";
517 return g_media_transfer_protocol_manager
;
520 } // namespace device