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_daemon_client.h" 6 7 #include "base/bind.h" 8 #include "base/memory/weak_ptr.h" 9 #include "dbus/bus.h" 10 #include "dbus/message.h" 11 #include "dbus/object_path.h" 12 #include "dbus/object_proxy.h" 13 #include "device/media_transfer_protocol/mtp_file_entry.pb.h" 14 #include "device/media_transfer_protocol/mtp_storage_info.pb.h" 15 #include "third_party/cros_system_api/dbus/service_constants.h" 16 17 namespace device { 18 19 namespace { 20 21 const char kInvalidResponseMsg[] = "Invalid Response: "; 22 23 // The MediaTransferProtocolDaemonClient implementation. 24 class MediaTransferProtocolDaemonClientImpl 25 : public MediaTransferProtocolDaemonClient { 26 public: 27 explicit MediaTransferProtocolDaemonClientImpl(dbus::Bus* bus) 28 : proxy_(bus->GetObjectProxy( 29 mtpd::kMtpdServiceName, 30 dbus::ObjectPath(mtpd::kMtpdServicePath))), 31 weak_ptr_factory_(this) { 32 } 33 34 // MediaTransferProtocolDaemonClient override. 35 virtual void EnumerateStorages(const EnumerateStoragesCallback& callback, 36 const ErrorCallback& error_callback) OVERRIDE { 37 dbus::MethodCall method_call(mtpd::kMtpdInterface, 38 mtpd::kEnumerateStorages); 39 proxy_->CallMethod( 40 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 41 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnEnumerateStorages, 42 weak_ptr_factory_.GetWeakPtr(), 43 callback, 44 error_callback)); 45 } 46 47 // MediaTransferProtocolDaemonClient override. 48 virtual void GetStorageInfo(const std::string& storage_name, 49 const GetStorageInfoCallback& callback, 50 const ErrorCallback& error_callback) OVERRIDE { 51 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kGetStorageInfo); 52 dbus::MessageWriter writer(&method_call); 53 writer.AppendString(storage_name); 54 proxy_->CallMethod( 55 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 56 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetStorageInfo, 57 weak_ptr_factory_.GetWeakPtr(), 58 storage_name, 59 callback, 60 error_callback)); 61 } 62 63 // MediaTransferProtocolDaemonClient override. 64 virtual void OpenStorage(const std::string& storage_name, 65 const std::string& mode, 66 const OpenStorageCallback& callback, 67 const ErrorCallback& error_callback) OVERRIDE { 68 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kOpenStorage); 69 dbus::MessageWriter writer(&method_call); 70 writer.AppendString(storage_name); 71 DCHECK_EQ(mtpd::kReadOnlyMode, mode); 72 writer.AppendString(mtpd::kReadOnlyMode); 73 proxy_->CallMethod( 74 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 75 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnOpenStorage, 76 weak_ptr_factory_.GetWeakPtr(), 77 callback, 78 error_callback)); 79 } 80 81 // MediaTransferProtocolDaemonClient override. 82 virtual void CloseStorage(const std::string& handle, 83 const CloseStorageCallback& callback, 84 const ErrorCallback& error_callback) OVERRIDE { 85 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kCloseStorage); 86 dbus::MessageWriter writer(&method_call); 87 writer.AppendString(handle); 88 proxy_->CallMethod( 89 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 90 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCloseStorage, 91 weak_ptr_factory_.GetWeakPtr(), 92 callback, 93 error_callback)); 94 } 95 96 // MediaTransferProtocolDaemonClient override. 97 virtual void ReadDirectoryByPath( 98 const std::string& handle, 99 const std::string& path, 100 const ReadDirectoryCallback& callback, 101 const ErrorCallback& error_callback) OVERRIDE { 102 dbus::MethodCall method_call(mtpd::kMtpdInterface, 103 mtpd::kReadDirectoryByPath); 104 dbus::MessageWriter writer(&method_call); 105 writer.AppendString(handle); 106 writer.AppendString(path); 107 proxy_->CallMethod( 108 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 109 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectory, 110 weak_ptr_factory_.GetWeakPtr(), 111 callback, 112 error_callback)); 113 } 114 115 // MediaTransferProtocolDaemonClient override. 116 virtual void ReadDirectoryById( 117 const std::string& handle, 118 uint32 file_id, 119 const ReadDirectoryCallback& callback, 120 const ErrorCallback& error_callback) OVERRIDE { 121 dbus::MethodCall method_call(mtpd::kMtpdInterface, 122 mtpd::kReadDirectoryById); 123 dbus::MessageWriter writer(&method_call); 124 writer.AppendString(handle); 125 writer.AppendUint32(file_id); 126 proxy_->CallMethod( 127 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 128 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectory, 129 weak_ptr_factory_.GetWeakPtr(), 130 callback, 131 error_callback)); 132 } 133 134 // MediaTransferProtocolDaemonClient override. 135 virtual void ReadFileChunkByPath( 136 const std::string& handle, 137 const std::string& path, 138 uint32 offset, 139 uint32 bytes_to_read, 140 const ReadFileCallback& callback, 141 const ErrorCallback& error_callback) OVERRIDE { 142 dbus::MethodCall method_call(mtpd::kMtpdInterface, 143 mtpd::kReadFileChunkByPath); 144 dbus::MessageWriter writer(&method_call); 145 writer.AppendString(handle); 146 writer.AppendString(path); 147 writer.AppendUint32(offset); 148 writer.AppendUint32(bytes_to_read); 149 proxy_->CallMethod( 150 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 151 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile, 152 weak_ptr_factory_.GetWeakPtr(), 153 callback, 154 error_callback)); 155 } 156 157 // MediaTransferProtocolDaemonClient override. 158 virtual void ReadFileChunkById(const std::string& handle, 159 uint32 file_id, 160 uint32 offset, 161 uint32 bytes_to_read, 162 const ReadFileCallback& callback, 163 const ErrorCallback& error_callback) OVERRIDE { 164 dbus::MethodCall method_call(mtpd::kMtpdInterface, 165 mtpd::kReadFileChunkById); 166 dbus::MessageWriter writer(&method_call); 167 writer.AppendString(handle); 168 writer.AppendUint32(file_id); 169 writer.AppendUint32(offset); 170 writer.AppendUint32(bytes_to_read); 171 proxy_->CallMethod( 172 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 173 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile, 174 weak_ptr_factory_.GetWeakPtr(), 175 callback, 176 error_callback)); 177 } 178 179 // MediaTransferProtocolDaemonClient override. 180 virtual void GetFileInfoByPath(const std::string& handle, 181 const std::string& path, 182 const GetFileInfoCallback& callback, 183 const ErrorCallback& error_callback) OVERRIDE { 184 dbus::MethodCall method_call(mtpd::kMtpdInterface, 185 mtpd::kGetFileInfoByPath); 186 dbus::MessageWriter writer(&method_call); 187 writer.AppendString(handle); 188 writer.AppendString(path); 189 proxy_->CallMethod( 190 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 191 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo, 192 weak_ptr_factory_.GetWeakPtr(), 193 callback, 194 error_callback)); 195 } 196 197 // MediaTransferProtocolDaemonClient override. 198 virtual void GetFileInfoById(const std::string& handle, 199 uint32 file_id, 200 const GetFileInfoCallback& callback, 201 const ErrorCallback& error_callback) OVERRIDE { 202 dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kGetFileInfoById); 203 dbus::MessageWriter writer(&method_call); 204 writer.AppendString(handle); 205 writer.AppendUint32(file_id); 206 proxy_->CallMethod( 207 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, 208 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo, 209 weak_ptr_factory_.GetWeakPtr(), 210 callback, 211 error_callback)); 212 } 213 214 // MediaTransferProtocolDaemonClient override. 215 virtual void SetUpConnections( 216 const MTPStorageEventHandler& handler) OVERRIDE { 217 static const SignalEventTuple kSignalEventTuples[] = { 218 { mtpd::kMTPStorageAttached, true }, 219 { mtpd::kMTPStorageDetached, false }, 220 }; 221 const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples); 222 223 for (size_t i = 0; i < kNumSignalEventTuples; ++i) { 224 proxy_->ConnectToSignal( 225 mtpd::kMtpdInterface, 226 kSignalEventTuples[i].signal_name, 227 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnMTPStorageSignal, 228 weak_ptr_factory_.GetWeakPtr(), 229 handler, 230 kSignalEventTuples[i].is_attach), 231 base::Bind(&MediaTransferProtocolDaemonClientImpl::OnSignalConnected, 232 weak_ptr_factory_.GetWeakPtr())); 233 } 234 } 235 236 private: 237 // A struct to contain a pair of signal name and attachment event type. 238 // Used by SetUpConnections. 239 struct SignalEventTuple { 240 const char *signal_name; 241 bool is_attach; 242 }; 243 244 // Handles the result of EnumerateStorages and calls |callback| or 245 // |error_callback|. 246 void OnEnumerateStorages(const EnumerateStoragesCallback& callback, 247 const ErrorCallback& error_callback, 248 dbus::Response* response) { 249 if (!response) { 250 error_callback.Run(); 251 return; 252 } 253 dbus::MessageReader reader(response); 254 std::vector<std::string> storage_names; 255 if (!reader.PopArrayOfStrings(&storage_names)) { 256 LOG(ERROR) << kInvalidResponseMsg << response->ToString(); 257 error_callback.Run(); 258 return; 259 } 260 callback.Run(storage_names); 261 } 262 263 // Handles the result of GetStorageInfo and calls |callback| or 264 // |error_callback|. 265 void OnGetStorageInfo(const std::string& storage_name, 266 const GetStorageInfoCallback& callback, 267 const ErrorCallback& error_callback, 268 dbus::Response* response) { 269 if (!response) { 270 error_callback.Run(); 271 return; 272 } 273 274 dbus::MessageReader reader(response); 275 MtpStorageInfo protobuf; 276 if (!reader.PopArrayOfBytesAsProto(&protobuf)) { 277 LOG(ERROR) << kInvalidResponseMsg << response->ToString(); 278 error_callback.Run(); 279 return; 280 } 281 callback.Run(protobuf); 282 } 283 284 // Handles the result of OpenStorage and calls |callback| or |error_callback|. 285 void OnOpenStorage(const OpenStorageCallback& callback, 286 const ErrorCallback& error_callback, 287 dbus::Response* response) { 288 if (!response) { 289 error_callback.Run(); 290 return; 291 } 292 dbus::MessageReader reader(response); 293 std::string handle; 294 if (!reader.PopString(&handle)) { 295 LOG(ERROR) << kInvalidResponseMsg << response->ToString(); 296 error_callback.Run(); 297 return; 298 } 299 callback.Run(handle); 300 } 301 302 // Handles the result of CloseStorage and calls |callback| or 303 // |error_callback|. 304 void OnCloseStorage(const CloseStorageCallback& callback, 305 const ErrorCallback& error_callback, 306 dbus::Response* response) { 307 if (!response) { 308 error_callback.Run(); 309 return; 310 } 311 callback.Run(); 312 } 313 314 // Handles the result of ReadDirectoryByPath/Id and calls |callback| or 315 // |error_callback|. 316 void OnReadDirectory(const ReadDirectoryCallback& callback, 317 const ErrorCallback& error_callback, 318 dbus::Response* response) { 319 if (!response) { 320 error_callback.Run(); 321 return; 322 } 323 324 std::vector<MtpFileEntry> file_entries; 325 dbus::MessageReader reader(response); 326 MtpFileEntries entries_protobuf; 327 if (!reader.PopArrayOfBytesAsProto(&entries_protobuf)) { 328 LOG(ERROR) << kInvalidResponseMsg << response->ToString(); 329 error_callback.Run(); 330 return; 331 } 332 333 for (int i = 0; i < entries_protobuf.file_entries_size(); ++i) 334 file_entries.push_back(entries_protobuf.file_entries(i)); 335 callback.Run(file_entries); 336 } 337 338 // Handles the result of ReadFileChunkByPath/Id and calls |callback| or 339 // |error_callback|. 340 void OnReadFile(const ReadFileCallback& callback, 341 const ErrorCallback& error_callback, 342 dbus::Response* response) { 343 if (!response) { 344 error_callback.Run(); 345 return; 346 } 347 348 uint8* data_bytes = NULL; 349 size_t data_length = 0; 350 dbus::MessageReader reader(response); 351 if (!reader.PopArrayOfBytes(&data_bytes, &data_length)) { 352 error_callback.Run(); 353 return; 354 } 355 std::string data(reinterpret_cast<const char*>(data_bytes), data_length); 356 callback.Run(data); 357 } 358 359 // Handles the result of GetFileInfoByPath/Id and calls |callback| or 360 // |error_callback|. 361 void OnGetFileInfo(const GetFileInfoCallback& callback, 362 const ErrorCallback& error_callback, 363 dbus::Response* response) { 364 if (!response) { 365 error_callback.Run(); 366 return; 367 } 368 369 dbus::MessageReader reader(response); 370 MtpFileEntry protobuf; 371 if (!reader.PopArrayOfBytesAsProto(&protobuf)) { 372 LOG(ERROR) << kInvalidResponseMsg << response->ToString(); 373 error_callback.Run(); 374 return; 375 } 376 callback.Run(protobuf); 377 } 378 379 // Handles MTPStorageAttached/Dettached signals and calls |handler|. 380 void OnMTPStorageSignal(MTPStorageEventHandler handler, 381 bool is_attach, 382 dbus::Signal* signal) { 383 dbus::MessageReader reader(signal); 384 std::string storage_name; 385 if (!reader.PopString(&storage_name)) { 386 LOG(ERROR) << "Invalid signal: " << signal->ToString(); 387 return; 388 } 389 DCHECK(!storage_name.empty()); 390 handler.Run(is_attach, storage_name); 391 } 392 393 394 // Handles the result of signal connection setup. 395 void OnSignalConnected(const std::string& interface, 396 const std::string& signal, 397 bool succeeded) { 398 LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " " 399 << signal << " failed."; 400 } 401 402 dbus::ObjectProxy* proxy_; 403 404 // Note: This should remain the last member so it'll be destroyed and 405 // invalidate its weak pointers before any other members are destroyed. 406 base::WeakPtrFactory<MediaTransferProtocolDaemonClientImpl> weak_ptr_factory_; 407 408 DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClientImpl); 409 }; 410 411 // A stub implementaion of MediaTransferProtocolDaemonClient. 412 class MediaTransferProtocolDaemonClientStubImpl 413 : public MediaTransferProtocolDaemonClient { 414 public: 415 MediaTransferProtocolDaemonClientStubImpl() {} 416 virtual ~MediaTransferProtocolDaemonClientStubImpl() {} 417 418 virtual void EnumerateStorages( 419 const EnumerateStoragesCallback& callback, 420 const ErrorCallback& error_callback) OVERRIDE {} 421 virtual void GetStorageInfo( 422 const std::string& storage_name, 423 const GetStorageInfoCallback& callback, 424 const ErrorCallback& error_callback) OVERRIDE {} 425 virtual void OpenStorage(const std::string& storage_name, 426 const std::string& mode, 427 const OpenStorageCallback& callback, 428 const ErrorCallback& error_callback) OVERRIDE {} 429 virtual void CloseStorage(const std::string& handle, 430 const CloseStorageCallback& callback, 431 const ErrorCallback& error_callback) OVERRIDE {} 432 virtual void ReadDirectoryByPath( 433 const std::string& handle, 434 const std::string& path, 435 const ReadDirectoryCallback& callback, 436 const ErrorCallback& error_callback) OVERRIDE {} 437 virtual void ReadDirectoryById( 438 const std::string& handle, 439 uint32 file_id, 440 const ReadDirectoryCallback& callback, 441 const ErrorCallback& error_callback) OVERRIDE {} 442 virtual void ReadFileChunkByPath( 443 const std::string& handle, 444 const std::string& path, 445 uint32 offset, 446 uint32 length, 447 const ReadFileCallback& callback, 448 const ErrorCallback& error_callback) OVERRIDE {} 449 virtual void ReadFileChunkById( 450 const std::string& handle, 451 uint32 file_id, 452 uint32 offset, 453 uint32 length, 454 const ReadFileCallback& callback, 455 const ErrorCallback& error_callback) OVERRIDE {} 456 virtual void GetFileInfoByPath( 457 const std::string& handle, 458 const std::string& path, 459 const GetFileInfoCallback& callback, 460 const ErrorCallback& error_callback) OVERRIDE {} 461 virtual void GetFileInfoById(const std::string& handle, 462 uint32 file_id, 463 const GetFileInfoCallback& callback, 464 const ErrorCallback& error_callback) OVERRIDE {} 465 virtual void SetUpConnections( 466 const MTPStorageEventHandler& handler) OVERRIDE {} 467 468 private: 469 DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClientStubImpl); 470 }; 471 472 } // namespace 473 474 //////////////////////////////////////////////////////////////////////////////// 475 // MediaTransferProtocolDaemonClient 476 477 MediaTransferProtocolDaemonClient::MediaTransferProtocolDaemonClient() {} 478 479 MediaTransferProtocolDaemonClient::~MediaTransferProtocolDaemonClient() {} 480 481 // static 482 MediaTransferProtocolDaemonClient* 483 MediaTransferProtocolDaemonClient::Create(dbus::Bus* bus, bool is_stub) { 484 if (is_stub) 485 return new MediaTransferProtocolDaemonClientStubImpl(); 486 return new MediaTransferProtocolDaemonClientImpl(bus); 487 } 488 489 } // namespace device 490