- add sources.
[platform/framework/web/crosswalk.git] / src / device / media_transfer_protocol / media_transfer_protocol_manager.cc
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.
4
5 #include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
6
7 #include <map>
8 #include <queue>
9 #include <set>
10 #include <utility>
11
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"
25
26 #if defined(OS_CHROMEOS)
27 #include "chromeos/dbus/dbus_thread_manager.h"
28 #endif
29
30 namespace device {
31
32 namespace {
33
34 MediaTransferProtocolManager* g_media_transfer_protocol_manager = NULL;
35
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
52
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_);
63   }
64
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_);
70
71 #if !defined(OS_CHROMEOS)
72     session_bus_->GetDBusTaskRunner()->PostTask(
73         FROM_HERE, base::Bind(&dbus::Bus::ShutdownAndBlock, session_bus_));
74 #endif
75
76     VLOG(1) << "MediaTransferProtocolManager Shutdown completed";
77   }
78
79   // MediaTransferProtocolManager override.
80   virtual void AddObserver(Observer* observer) OVERRIDE {
81     observers_.AddObserver(observer);
82   }
83
84   // MediaTransferProtocolManager override.
85   virtual void RemoveObserver(Observer* observer) OVERRIDE {
86     observers_.RemoveObserver(observer);
87   }
88
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);
97     }
98     return storages;
99   }
100
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;
107   }
108
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;
117     }
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()));
126   }
127
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;
135     }
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()));
143   }
144
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;
154     }
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()));
163   }
164
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;
174     }
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()));
183   }
184
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;
195     }
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()));
203   }
204
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;
215     }
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()));
223   }
224
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;
232     }
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()));
241   }
242
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;
250     }
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()));
259   }
260
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;
273
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;
284     }
285
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;
292     }
293     storage_info_map_.erase(it);
294     FOR_EACH_OBSERVER(Observer,
295                       observers_,
296                       StorageChanged(false /* detach */, storage_name));
297   }
298
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));
308     }
309   }
310
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;
323     }
324
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));
330   }
331
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);
340     }
341     open_storage_callbacks_.pop();
342   }
343
344   void OnOpenStorageError() {
345     open_storage_callbacks_.front().Run(std::string(), true);
346     open_storage_callbacks_.pop();
347   }
348
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);
358     }
359     close_storage_callbacks_.pop();
360   }
361
362   void OnCloseStorageError() {
363     DCHECK(thread_checker_.CalledOnValidThread());
364     close_storage_callbacks_.front().first.Run(true);
365     close_storage_callbacks_.pop();
366   }
367
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();
372   }
373
374   void OnReadDirectoryError() {
375     DCHECK(thread_checker_.CalledOnValidThread());
376     read_directory_callbacks_.front().Run(std::vector<MtpFileEntry>(), true);
377     read_directory_callbacks_.pop();
378   }
379
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();
384   }
385
386   void OnReadFileError() {
387     DCHECK(thread_checker_.CalledOnValidThread());
388     read_file_callbacks_.front().Run(std::string(), true);
389     read_file_callbacks_.pop();
390   }
391
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();
396   }
397
398   void OnGetFileInfoError() {
399     DCHECK(thread_checker_.CalledOnValidThread());
400     get_file_info_callbacks_.front().Run(MtpFileEntry(), true);
401     get_file_info_callbacks_.pop();
402   }
403
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
412   }
413
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());
419
420     if (mtpd_service_owner == current_mtpd_owner_)
421       return;
422
423     if (mtpd_service_owner.empty()) {
424       current_mtpd_owner_.clear();
425       mtp_client_.reset();
426       return;
427     }
428
429     current_mtpd_owner_ = mtpd_service_owner;
430
431     mtp_client_.reset(
432         MediaTransferProtocolDaemonClient::Create(GetBus(),
433                                                   false /* not stub */));
434
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));
443   }
444
445   // Mtpd DBus client.
446   scoped_ptr<MediaTransferProtocolDaemonClient> mtp_client_;
447
448 #if !defined(OS_CHROMEOS)
449   // And a D-Bus session for talking to mtpd.
450   scoped_refptr<dbus::Bus> session_bus_;
451 #endif
452
453   // Device attachment / detachment observers.
454   ObserverList<Observer> observers_;
455
456   base::WeakPtrFactory<MediaTransferProtocolManagerImpl> weak_ptr_factory_;
457
458   // Everything below is only accessed on the UI thread.
459
460   // Map to keep track of attached storages by name.
461   StorageInfoMap storage_info_map_;
462
463   // Set of open storage handles.
464   std::set<std::string> handles_;
465
466   dbus::Bus::GetServiceOwnerCallback mtpd_owner_changed_callback_;
467
468   std::string current_mtpd_owner_;
469
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_;
476
477   base::ThreadChecker thread_checker_;
478
479   DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolManagerImpl);
480 };
481
482 }  // namespace
483
484 // static
485 MediaTransferProtocolManager* MediaTransferProtocolManager::Initialize(
486     scoped_refptr<base::SequencedTaskRunner> task_runner) {
487   DCHECK(!g_media_transfer_protocol_manager);
488
489   g_media_transfer_protocol_manager =
490       new MediaTransferProtocolManagerImpl(task_runner);
491   VLOG(1) << "MediaTransferProtocolManager initialized";
492
493   return g_media_transfer_protocol_manager;
494 }
495
496 }  // namespace device