Home | History | Annotate | Download | only in media_transfer_protocol
      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