OLD | NEW |
(Empty) | |
| 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 "chrome/browser/chromeos/mtp/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/memory/weak_ptr.h" |
| 14 #include "base/observer_list.h" |
| 15 #include "base/stl_util.h" |
| 16 #include "chromeos/dbus/dbus_thread_manager.h" |
| 17 #include "content/public/browser/browser_thread.h" |
| 18 |
| 19 using content::BrowserThread; |
| 20 |
| 21 namespace chromeos { |
| 22 namespace mtp { |
| 23 |
| 24 namespace { |
| 25 |
| 26 MediaTransferProtocolManager* g_media_transfer_protocol_manager = NULL; |
| 27 |
| 28 // The MediaTransferProtocolManager implementation. |
| 29 class MediaTransferProtocolManagerImpl : public MediaTransferProtocolManager { |
| 30 public: |
| 31 MediaTransferProtocolManagerImpl() : weak_ptr_factory_(this) { |
| 32 DBusThreadManager* dbus_thread_manager = DBusThreadManager::Get(); |
| 33 mtp_client_ = dbus_thread_manager->GetMediaTransferProtocolDaemonClient(); |
| 34 |
| 35 // Set up signals and start initializing |storage_info_map_|. |
| 36 mtp_client_->SetUpConnections( |
| 37 base::Bind(&MediaTransferProtocolManagerImpl::OnStorageChanged, |
| 38 weak_ptr_factory_.GetWeakPtr())); |
| 39 mtp_client_->EnumerateStorage( |
| 40 base::Bind(&MediaTransferProtocolManagerImpl::OnEnumerateStorage, |
| 41 weak_ptr_factory_.GetWeakPtr()), |
| 42 base::Bind(&base::DoNothing)); |
| 43 } |
| 44 |
| 45 virtual ~MediaTransferProtocolManagerImpl() { |
| 46 } |
| 47 |
| 48 // MediaTransferProtocolManager override. |
| 49 virtual void AddObserver(Observer* observer) OVERRIDE { |
| 50 observers_.AddObserver(observer); |
| 51 } |
| 52 |
| 53 // MediaTransferProtocolManager override. |
| 54 virtual void RemoveObserver(Observer* observer) OVERRIDE { |
| 55 observers_.RemoveObserver(observer); |
| 56 } |
| 57 |
| 58 // MediaTransferProtocolManager override. |
| 59 const std::vector<std::string> GetStorages() const OVERRIDE { |
| 60 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 61 std::vector<std::string> storages; |
| 62 for (StorageInfoMap::const_iterator it = storage_info_map_.begin(); |
| 63 it != storage_info_map_.end(); |
| 64 ++it) { |
| 65 storages.push_back(it->first); |
| 66 } |
| 67 return storages; |
| 68 } |
| 69 |
| 70 // MediaTransferProtocolManager override. |
| 71 virtual const StorageInfo* GetStorageInfo( |
| 72 const std::string& storage_name) const OVERRIDE { |
| 73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 74 StorageInfoMap::const_iterator it = storage_info_map_.find(storage_name); |
| 75 if (it == storage_info_map_.end()) |
| 76 return NULL; |
| 77 return &it->second; |
| 78 } |
| 79 |
| 80 // MediaTransferProtocolManager override. |
| 81 virtual void OpenStorage(const std::string& storage_name, |
| 82 OpenStorageMode mode, |
| 83 const OpenStorageCallback& callback) OVERRIDE { |
| 84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 85 if (!ContainsKey(storage_info_map_, storage_name)) { |
| 86 callback.Run("", true); |
| 87 return; |
| 88 } |
| 89 open_storage_callbacks_.push(callback); |
| 90 mtp_client_->OpenStorage( |
| 91 storage_name, |
| 92 mode, |
| 93 base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorage, |
| 94 weak_ptr_factory_.GetWeakPtr()), |
| 95 base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorageError, |
| 96 weak_ptr_factory_.GetWeakPtr())); |
| 97 } |
| 98 |
| 99 // MediaTransferProtocolManager override. |
| 100 virtual void CloseStorage(const std::string& storage_handle, |
| 101 const CloseStorageCallback& callback) OVERRIDE { |
| 102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 103 if (!ContainsKey(handles_, storage_handle)) { |
| 104 callback.Run(true); |
| 105 return; |
| 106 } |
| 107 close_storage_callbacks_.push(std::make_pair(callback, storage_handle)); |
| 108 mtp_client_->CloseStorage( |
| 109 storage_handle, |
| 110 base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorage, |
| 111 weak_ptr_factory_.GetWeakPtr()), |
| 112 base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorageError, |
| 113 weak_ptr_factory_.GetWeakPtr())); |
| 114 } |
| 115 |
| 116 // MediaTransferProtocolManager override. |
| 117 virtual void ReadDirectoryByPath( |
| 118 const std::string& storage_handle, |
| 119 const std::string& path, |
| 120 const ReadDirectoryCallback& callback) OVERRIDE { |
| 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 122 if (!ContainsKey(handles_, storage_handle)) { |
| 123 callback.Run(std::vector<FileEntry>(), true); |
| 124 return; |
| 125 } |
| 126 read_directory_callbacks_.push(callback); |
| 127 mtp_client_->ReadDirectoryByPath( |
| 128 storage_handle, |
| 129 path, |
| 130 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory, |
| 131 weak_ptr_factory_.GetWeakPtr()), |
| 132 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError, |
| 133 weak_ptr_factory_.GetWeakPtr())); |
| 134 } |
| 135 |
| 136 // MediaTransferProtocolManager override. |
| 137 virtual void ReadDirectoryById( |
| 138 const std::string& storage_handle, |
| 139 uint32 file_id, |
| 140 const ReadDirectoryCallback& callback) OVERRIDE { |
| 141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 142 if (!ContainsKey(handles_, storage_handle)) { |
| 143 callback.Run(std::vector<FileEntry>(), true); |
| 144 return; |
| 145 } |
| 146 read_directory_callbacks_.push(callback); |
| 147 mtp_client_->ReadDirectoryById( |
| 148 storage_handle, |
| 149 file_id, |
| 150 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory, |
| 151 weak_ptr_factory_.GetWeakPtr()), |
| 152 base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError, |
| 153 weak_ptr_factory_.GetWeakPtr())); |
| 154 } |
| 155 |
| 156 // MediaTransferProtocolManager override. |
| 157 virtual void ReadFileByPath(const std::string& storage_handle, |
| 158 const std::string& path, |
| 159 const ReadFileCallback& callback) OVERRIDE { |
| 160 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 161 if (!ContainsKey(handles_, storage_handle)) { |
| 162 callback.Run(std::string(), true); |
| 163 return; |
| 164 } |
| 165 read_file_callbacks_.push(callback); |
| 166 mtp_client_->ReadFileByPath( |
| 167 storage_handle, |
| 168 path, |
| 169 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile, |
| 170 weak_ptr_factory_.GetWeakPtr()), |
| 171 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError, |
| 172 weak_ptr_factory_.GetWeakPtr())); |
| 173 } |
| 174 |
| 175 // MediaTransferProtocolManager override. |
| 176 virtual void ReadFileById(const std::string& storage_handle, |
| 177 uint32 file_id, |
| 178 const ReadFileCallback& callback) OVERRIDE { |
| 179 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 180 if (!ContainsKey(handles_, storage_handle)) { |
| 181 callback.Run(std::string(), true); |
| 182 return; |
| 183 } |
| 184 read_file_callbacks_.push(callback); |
| 185 mtp_client_->ReadFileById( |
| 186 storage_handle, |
| 187 file_id, |
| 188 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile, |
| 189 weak_ptr_factory_.GetWeakPtr()), |
| 190 base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError, |
| 191 weak_ptr_factory_.GetWeakPtr())); |
| 192 } |
| 193 |
| 194 virtual void GetFileInfoByPath(const std::string& storage_handle, |
| 195 const std::string& path, |
| 196 const GetFileInfoCallback& callback) OVERRIDE { |
| 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 198 if (!ContainsKey(handles_, storage_handle)) { |
| 199 callback.Run(FileEntry(), true); |
| 200 return; |
| 201 } |
| 202 get_file_info_callbacks_.push(callback); |
| 203 mtp_client_->GetFileInfoByPath( |
| 204 storage_handle, |
| 205 path, |
| 206 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo, |
| 207 weak_ptr_factory_.GetWeakPtr()), |
| 208 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError, |
| 209 weak_ptr_factory_.GetWeakPtr())); |
| 210 } |
| 211 |
| 212 virtual void GetFileInfoById(const std::string& storage_handle, |
| 213 uint32 file_id, |
| 214 const GetFileInfoCallback& callback) OVERRIDE { |
| 215 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 216 if (!ContainsKey(handles_, storage_handle)) { |
| 217 callback.Run(FileEntry(), true); |
| 218 return; |
| 219 } |
| 220 get_file_info_callbacks_.push(callback); |
| 221 mtp_client_->GetFileInfoById( |
| 222 storage_handle, |
| 223 file_id, |
| 224 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo, |
| 225 weak_ptr_factory_.GetWeakPtr()), |
| 226 base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError, |
| 227 weak_ptr_factory_.GetWeakPtr())); |
| 228 } |
| 229 |
| 230 private: |
| 231 // Map of storage names to storage info. |
| 232 typedef std::map<std::string, StorageInfo> StorageInfoMap; |
| 233 // Callback queues - DBus communication is in-order, thus callbacks are |
| 234 // received in the same order as the requests. |
| 235 typedef std::queue<OpenStorageCallback> OpenStorageCallbackQueue; |
| 236 // (callback, handle) |
| 237 typedef std::queue<std::pair<CloseStorageCallback, std::string> |
| 238 > CloseStorageCallbackQueue; |
| 239 typedef std::queue<ReadDirectoryCallback> ReadDirectoryCallbackQueue; |
| 240 typedef std::queue<ReadFileCallback> ReadFileCallbackQueue; |
| 241 typedef std::queue<GetFileInfoCallback> GetFileInfoCallbackQueue; |
| 242 |
| 243 void OnStorageChanged(bool is_attach, const std::string& storage_name) { |
| 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 245 if (is_attach) { |
| 246 mtp_client_->GetStorageInfo( |
| 247 storage_name, |
| 248 base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo, |
| 249 weak_ptr_factory_.GetWeakPtr()), |
| 250 base::Bind(&base::DoNothing)); |
| 251 return; |
| 252 } |
| 253 |
| 254 // Detach case. |
| 255 StorageInfoMap::iterator it = storage_info_map_.find(storage_name); |
| 256 if (it == storage_info_map_.end()) { |
| 257 // This might happen during initialization when |storage_info_map_| has |
| 258 // not been fully populated yet? |
| 259 return; |
| 260 } |
| 261 storage_info_map_.erase(it); |
| 262 FOR_EACH_OBSERVER(Observer, |
| 263 observers_, |
| 264 StorageChanged(false /* detach */, storage_name)); |
| 265 } |
| 266 |
| 267 void OnEnumerateStorage(const std::vector<std::string>& storage_names) { |
| 268 for (size_t i = 0; i < storage_names.size(); ++i) { |
| 269 mtp_client_->GetStorageInfo( |
| 270 storage_names[i], |
| 271 base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo, |
| 272 weak_ptr_factory_.GetWeakPtr()), |
| 273 base::Bind(&base::DoNothing)); |
| 274 } |
| 275 } |
| 276 |
| 277 void OnGetStorageInfo(const StorageInfo& storage_info) { |
| 278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 279 const std::string& storage_name = storage_info.storage_name(); |
| 280 if (ContainsKey(storage_info_map_, storage_name)) { |
| 281 // This should not happen, since MediaTransferProtocolManagerImpl should |
| 282 // only call EnumerateStorage() once, which populates |storage_info_map_| |
| 283 // with the already-attached devices. |
| 284 // After that, all incoming signals are either for new storage |
| 285 // attachments, which should not be in |storage_info_map_|, or for |
| 286 // storage detachements, which do not add to |storage_info_map_|. |
| 287 NOTREACHED(); |
| 288 return; |
| 289 } |
| 290 |
| 291 // New storage. Add it and let the observers know. |
| 292 storage_info_map_.insert(std::make_pair(storage_name, storage_info)); |
| 293 FOR_EACH_OBSERVER(Observer, |
| 294 observers_, |
| 295 StorageChanged(true /* is attach */, storage_name)); |
| 296 } |
| 297 |
| 298 void OnOpenStorage(const std::string& handle) { |
| 299 if (!ContainsKey(handles_, handle)) { |
| 300 handles_.insert(handle); |
| 301 open_storage_callbacks_.front().Run(handle, false); |
| 302 } else { |
| 303 NOTREACHED(); |
| 304 open_storage_callbacks_.front().Run("", true); |
| 305 } |
| 306 open_storage_callbacks_.pop(); |
| 307 } |
| 308 |
| 309 void OnOpenStorageError() { |
| 310 open_storage_callbacks_.front().Run("", true); |
| 311 open_storage_callbacks_.pop(); |
| 312 } |
| 313 |
| 314 void OnCloseStorage() { |
| 315 const std::string& handle = close_storage_callbacks_.front().second; |
| 316 if (ContainsKey(handles_, handle)) { |
| 317 handles_.erase(handle); |
| 318 close_storage_callbacks_.front().first.Run(false); |
| 319 } else { |
| 320 NOTREACHED(); |
| 321 close_storage_callbacks_.front().first.Run(true); |
| 322 } |
| 323 close_storage_callbacks_.pop(); |
| 324 } |
| 325 |
| 326 void OnCloseStorageError() { |
| 327 close_storage_callbacks_.front().first.Run(true); |
| 328 close_storage_callbacks_.pop(); |
| 329 } |
| 330 |
| 331 void OnReadDirectory(const std::vector<FileEntry>& file_entries) { |
| 332 read_directory_callbacks_.front().Run(file_entries, false); |
| 333 read_directory_callbacks_.pop(); |
| 334 } |
| 335 |
| 336 void OnReadDirectoryError() { |
| 337 read_directory_callbacks_.front().Run(std::vector<FileEntry>(), true); |
| 338 read_directory_callbacks_.pop(); |
| 339 } |
| 340 |
| 341 void OnReadFile(const std::string& data) { |
| 342 read_file_callbacks_.front().Run(data, false); |
| 343 read_file_callbacks_.pop(); |
| 344 } |
| 345 |
| 346 void OnReadFileError() { |
| 347 read_file_callbacks_.front().Run(std::string(), true); |
| 348 read_file_callbacks_.pop(); |
| 349 } |
| 350 |
| 351 void OnGetFileInfo(const FileEntry& entry) { |
| 352 get_file_info_callbacks_.front().Run(entry, false); |
| 353 get_file_info_callbacks_.pop(); |
| 354 } |
| 355 |
| 356 void OnGetFileInfoError() { |
| 357 get_file_info_callbacks_.front().Run(FileEntry(), true); |
| 358 get_file_info_callbacks_.pop(); |
| 359 } |
| 360 |
| 361 // Mtpd DBus client. |
| 362 MediaTransferProtocolDaemonClient* mtp_client_; |
| 363 |
| 364 // Device attachment / detachment observers. |
| 365 ObserverList<Observer> observers_; |
| 366 |
| 367 base::WeakPtrFactory<MediaTransferProtocolManagerImpl> weak_ptr_factory_; |
| 368 |
| 369 // Everything below is only accessed on the UI thread. |
| 370 |
| 371 // Map to keep track of attached storages by name. |
| 372 StorageInfoMap storage_info_map_; |
| 373 |
| 374 // Set of open storage handles. |
| 375 std::set<std::string> handles_; |
| 376 |
| 377 // Queued callbacks. |
| 378 OpenStorageCallbackQueue open_storage_callbacks_; |
| 379 CloseStorageCallbackQueue close_storage_callbacks_; |
| 380 ReadDirectoryCallbackQueue read_directory_callbacks_; |
| 381 ReadFileCallbackQueue read_file_callbacks_; |
| 382 GetFileInfoCallbackQueue get_file_info_callbacks_; |
| 383 |
| 384 DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolManagerImpl); |
| 385 }; |
| 386 |
| 387 } // namespace |
| 388 |
| 389 // static |
| 390 void MediaTransferProtocolManager::Initialize() { |
| 391 if (g_media_transfer_protocol_manager) { |
| 392 LOG(WARNING) << "MediaTransferProtocolManager was already initialized"; |
| 393 return; |
| 394 } |
| 395 g_media_transfer_protocol_manager = new MediaTransferProtocolManagerImpl(); |
| 396 VLOG(1) << "MediaTransferProtocolManager initialized"; |
| 397 } |
| 398 |
| 399 // static |
| 400 void MediaTransferProtocolManager::Shutdown() { |
| 401 if (!g_media_transfer_protocol_manager) { |
| 402 LOG(WARNING) << "MediaTransferProtocolManager::Shutdown() called with " |
| 403 << "NULL manager"; |
| 404 return; |
| 405 } |
| 406 delete g_media_transfer_protocol_manager; |
| 407 g_media_transfer_protocol_manager = NULL; |
| 408 VLOG(1) << "MediaTransferProtocolManager Shutdown completed"; |
| 409 } |
| 410 |
| 411 // static |
| 412 MediaTransferProtocolManager* MediaTransferProtocolManager::GetInstance() { |
| 413 return g_media_transfer_protocol_manager; |
| 414 } |
| 415 |
| 416 } // namespace mtp |
| 417 } // namespace chromeos |
OLD | NEW |