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