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