Chromium Code Reviews| Index: chromeos/dbus/mtpd_client.cc |
| =================================================================== |
| --- chromeos/dbus/mtpd_client.cc (revision 0) |
| +++ chromeos/dbus/mtpd_client.cc (revision 0) |
| @@ -0,0 +1,573 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "chromeos/dbus/mtpd_client.h" |
| + |
| +#include <map> |
| + |
| +#include "base/bind.h" |
| +#include "base/stl_util.h" |
| +#include "base/stringprintf.h" |
| +#include "dbus/bus.h" |
| +#include "dbus/message.h" |
| +#include "dbus/object_path.h" |
| +#include "dbus/object_proxy.h" |
| +#include "third_party/cros_system_api/dbus/service_constants.h" |
| + |
| +namespace chromeos { |
| + |
| +namespace { |
| + |
| +// Pops a string value when |reader| is not NULL. |
| +// Returns true when a value is popped, false otherwise. |
| +bool MaybePopString(dbus::MessageReader* reader, std::string* value) { |
| + if (!reader) |
| + return false; |
| + return reader->PopString(value); |
| +} |
| + |
| +// Pops a uint16 value when |reader| is not NULL. |
| +// Returns true when a value is popped, false otherwise. |
| +bool MaybePopUint16(dbus::MessageReader* reader, uint16* value) { |
| + if (!reader) |
| + return false; |
| + return reader->PopUint16(value); |
| +} |
| + |
| +// Pops a uint32 value when |reader| is not NULL. |
| +// Returns true when a value is popped, false otherwise. |
| +bool MaybePopUint32(dbus::MessageReader* reader, uint32* value) { |
| + if (!reader) |
| + return false; |
| + return reader->PopUint32(value); |
| +} |
| + |
| +// Pops a uint64 value when |reader| is not NULL. |
| +// Returns true when a value is popped, false otherwise. |
| +bool MaybePopUint64(dbus::MessageReader* reader, uint64* value) { |
| + if (!reader) |
| + return false; |
| + return reader->PopUint64(value); |
| +} |
| + |
| +// Pops a int64 value when |reader| is not NULL. |
| +// Returns true when a value is popped, false otherwise. |
| +bool MaybePopInt64(dbus::MessageReader* reader, int64* value) { |
| + if (!reader) |
| + return false; |
| + return reader->PopInt64(value); |
| +} |
| + |
| +// The MTPDClient implementation. |
| +class MTPDClientImpl : public MTPDClient { |
| + public: |
| + // TODO(thestig) Use mtpd::kMTPDServiceName and mtpd::kMTPDServicePath below. |
| + explicit MTPDClientImpl(dbus::Bus* bus) |
| + : proxy_(bus->GetObjectProxy( |
| + "org.chromium.MTPD", |
| + dbus::ObjectPath("/org/chromium/MTPD"))), |
| + weak_ptr_factory_(this) { |
| + } |
| + |
| + // MTPDClient override. |
| + virtual void EnumerateStorage(const EnumerateStorageCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE { |
| + // TODO(thestig) Use constants here. |
| + dbus::MethodCall method_call("org.chromium.MTPD", "EnumerateStorage"); |
| + proxy_->CallMethod( |
| + &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| + base::Bind(&MTPDClientImpl::OnEnumerateStorage, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback, |
| + error_callback)); |
| + } |
| + |
| + // MTPDClient override. |
| + virtual void GetStorageInfo(const std::string& storage_name, |
| + const GetStorageInfoCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE { |
| + // TODO(thestig) Use constants here. |
| + dbus::MethodCall method_call("org.chromium.MTPD", "GetStorageInfo"); |
| + dbus::MessageWriter writer(&method_call); |
| + writer.AppendString(storage_name); |
| + proxy_->CallMethod(&method_call, |
| + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| + base::Bind(&MTPDClientImpl::OnGetStorageInfo, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + storage_name, |
| + callback, |
| + error_callback)); |
| + } |
| + |
| + // MTPDClient override. |
| + virtual void OpenStorage(const std::string& storage_name, |
| + OpenStorageMode mode, |
| + const OpenStorageCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE { |
| + // TODO(thestig) Use constants here. |
| + dbus::MethodCall method_call("org.chromium.MTPD", "OpenStorage"); |
| + dbus::MessageWriter writer(&method_call); |
| + writer.AppendString(storage_name); |
| + DCHECK_EQ(OPEN_STORAGE_MODE_READ_ONLY, mode); |
| + // TODO(thestig) Use constants here. |
| + writer.AppendString("readonly"); |
| + proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| + base::Bind(&MTPDClientImpl::OnOpenStorage, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback, |
| + error_callback)); |
| + } |
| + |
| + // MTPDClient override. |
| + virtual void CloseStorage(const std::string& handle, |
| + const CloseStorageCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE { |
| + // TODO(thestig) Use constants here. |
| + dbus::MethodCall method_call("org.chromium.MTPD", "CloseStorage"); |
| + dbus::MessageWriter writer(&method_call); |
| + writer.AppendString(handle); |
| + proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| + base::Bind(&MTPDClientImpl::OnCloseStorage, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback, |
| + error_callback)); |
| + } |
| + |
| + // MTPDClient override. |
| + virtual void ReadDirectoryByPath( |
| + const std::string& handle, |
| + const std::string& path, |
| + const ReadDirectoryCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE { |
| + // TODO(thestig) Use constants here. |
| + dbus::MethodCall method_call("org.chromium.MTPD", "ReadDirectoryByPath"); |
| + dbus::MessageWriter writer(&method_call); |
| + writer.AppendString(handle); |
| + writer.AppendString(path); |
| + proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| + base::Bind(&MTPDClientImpl::OnReadDirectory, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback, |
| + error_callback)); |
| + } |
| + |
| + // MTPDClient override. |
| + virtual void ReadDirectoryById( |
| + const std::string& handle, |
| + uint32 file_id, |
| + const ReadDirectoryCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE { |
| + // TODO(thestig) Use constants here. |
| + dbus::MethodCall method_call("org.chromium.MTPD", "ReadDirectoryById"); |
| + dbus::MessageWriter writer(&method_call); |
| + writer.AppendString(handle); |
| + writer.AppendUint32(file_id); |
| + proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| + base::Bind(&MTPDClientImpl::OnReadDirectory, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback, |
| + error_callback)); |
| + } |
| + |
| + // MTPDClient override. |
| + virtual void ReadFileByPath(const std::string& handle, |
| + const std::string& path, |
| + const ReadFileCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE { |
| + // TODO(thestig) Use constants here. |
| + dbus::MethodCall method_call("org.chromium.MTPD", "ReadFileByPath"); |
| + dbus::MessageWriter writer(&method_call); |
| + writer.AppendString(handle); |
| + writer.AppendString(path); |
| + proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| + base::Bind(&MTPDClientImpl::OnReadFile, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback, |
| + error_callback)); |
| + } |
| + |
| + // MTPDClient override. |
| + virtual void ReadFileById(const std::string& handle, |
| + uint32 file_id, |
| + const ReadFileCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE { |
| + // TODO(thestig) Use constants here. |
| + dbus::MethodCall method_call("org.chromium.MTPD", "ReadFileById"); |
| + dbus::MessageWriter writer(&method_call); |
| + writer.AppendString(handle); |
| + writer.AppendUint32(file_id); |
| + proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| + base::Bind(&MTPDClientImpl::OnReadFile, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + callback, |
| + error_callback)); |
| + } |
| + |
| + // MTPDClient override. |
| + virtual void SetUpConnections( |
| + const MTPStorageEventHandler& handler) OVERRIDE { |
| + static const SignalEventTuple kSignalEventTuples[] = { |
| + // TODO(thestig) Use constants. |
| + { "MTPStorageAttached", true }, |
| + { "MTPStorageDetached", false }, |
| + }; |
| + const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples); |
| + |
| + for (size_t i = 0; i < kNumSignalEventTuples; ++i) { |
| + // TODO(thestig) Use mtpd::kMTPDInterface here. |
| + proxy_->ConnectToSignal( |
| + "org.chromium.MTPD", |
| + kSignalEventTuples[i].signal_name, |
| + base::Bind(&MTPDClientImpl::OnMTPStorageSignal, |
| + weak_ptr_factory_.GetWeakPtr(), |
| + handler, |
| + kSignalEventTuples[i].is_attach), |
| + base::Bind(&MTPDClientImpl::OnSignalConnected, |
| + weak_ptr_factory_.GetWeakPtr())); |
| + } |
| + } |
| + |
| + private: |
| + // A struct to contain a pair of signal name and attachment event type. |
| + // Used by SetUpConnections. |
| + struct SignalEventTuple { |
| + const char *signal_name; |
| + bool is_attach; |
| + }; |
| + |
| + // Handles the result of EnumerateStorage and calls |callback| or |
| + // |error_callback|. |
| + void OnEnumerateStorage(const EnumerateStorageCallback& callback, |
| + const ErrorCallback& error_callback, |
| + dbus::Response* response) { |
| + if (!response) { |
| + error_callback.Run(); |
| + return; |
| + } |
| + dbus::MessageReader reader(response); |
| + std::vector<std::string> storage_names; |
| + if (!reader.PopArrayOfStrings(&storage_names)) { |
| + LOG(ERROR) << "Invalid response: " << response->ToString(); |
| + error_callback.Run(); |
| + return; |
| + } |
| + callback.Run(storage_names); |
| + } |
| + |
| + // Handles the result of GetStorageInfo and calls |callback| or |
| + // |error_callback|. |
| + void OnGetStorageInfo(const std::string& storage_name, |
| + const GetStorageInfoCallback& callback, |
| + const ErrorCallback& error_callback, |
| + dbus::Response* response) { |
| + if (!response) { |
| + error_callback.Run(); |
| + return; |
| + } |
| + StorageInfo storage_info(storage_name, response); |
| + callback.Run(storage_info); |
| + } |
| + |
| + // Handles the result of OpenStorage and calls |callback| or |error_callback|. |
| + void OnOpenStorage(const OpenStorageCallback& callback, |
| + const ErrorCallback& error_callback, |
| + dbus::Response* response) { |
| + if (!response) { |
| + error_callback.Run(); |
| + return; |
| + } |
| + dbus::MessageReader reader(response); |
| + std::string handle; |
| + if (!reader.PopString(&handle)) { |
| + LOG(ERROR) << "Invalid response: " << response->ToString(); |
| + error_callback.Run(); |
| + return; |
| + } |
| + callback.Run(handle); |
| + } |
| + |
| + // Handles the result of CloseStorage and calls |callback| or |
| + // |error_callback|. |
| + void OnCloseStorage(const CloseStorageCallback& callback, |
| + const ErrorCallback& error_callback, |
| + dbus::Response* response) { |
| + if (!response) { |
| + error_callback.Run(); |
| + return; |
| + } |
| + callback.Run(); |
| + } |
| + |
| + // Handles the result of ReadDirectoryByPath/Id and calls |callback| or |
| + // |error_callback|. |
| + void OnReadDirectory(const ReadDirectoryCallback& callback, |
| + const ErrorCallback& error_callback, |
| + dbus::Response* response) { |
| + if (!response) { |
| + error_callback.Run(); |
| + return; |
| + } |
| + |
| + std::vector<FileEntry> file_entries; |
| + dbus::MessageReader response_reader(response); |
| + dbus::MessageReader array_reader(response); |
| + if (!response_reader.PopArray(&array_reader)) { |
| + LOG(ERROR) << "Invalid response: " << response->ToString(); |
| + error_callback.Run(); |
| + return; |
| + } |
| + while (array_reader.HasMoreData()) { |
| + FileEntry entry(response); |
| + file_entries.push_back(entry); |
| + } |
| + callback.Run(file_entries); |
| + } |
| + |
| + // Handles the result of ReadFileByPath/Id and calls |callback| or |
| + // |error_callback|. |
| + void OnReadFile(const ReadFileCallback& callback, |
| + const ErrorCallback& error_callback, |
| + dbus::Response* response) { |
| + if (!response) { |
| + error_callback.Run(); |
| + return; |
| + } |
| + |
| + uint8* data_bytes = NULL; |
| + size_t data_length = 0; |
| + dbus::MessageReader reader(response); |
| + if (!reader.PopArrayOfBytes(&data_bytes, &data_length)) { |
| + error_callback.Run(); |
| + return; |
| + } |
| + std::string data(reinterpret_cast<const char*>(data_bytes), data_length); |
| + callback.Run(data); |
| + } |
| + |
| + // Handles MTPStorageAttached/Dettached signals and calls |handler|. |
| + void OnMTPStorageSignal(MTPStorageEventHandler handler, |
| + bool is_attach, |
| + dbus::Signal* signal) { |
| + dbus::MessageReader reader(signal); |
| + std::string storage_name; |
| + if (!reader.PopString(&storage_name)) { |
| + LOG(ERROR) << "Invalid signal: " << signal->ToString(); |
| + return; |
| + } |
| + DCHECK(!storage_name.empty()); |
| + handler.Run(is_attach, storage_name); |
| + } |
| + |
| + |
| + // Handles the result of signal connection setup. |
| + void OnSignalConnected(const std::string& interface, |
| + const std::string& signal, |
| + bool successed) { |
| + LOG_IF(ERROR, !successed) << "Connect to " << interface << " " |
| + << signal << " failed."; |
| + } |
| + |
| + dbus::ObjectProxy* proxy_; |
| + base::WeakPtrFactory<MTPDClientImpl> weak_ptr_factory_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MTPDClientImpl); |
| +}; |
| + |
| +// A stub implementaion of MTPDClient. |
| +class MTPDClientStubImpl : public MTPDClient { |
| + public: |
| + MTPDClientStubImpl() {} |
| + virtual ~MTPDClientStubImpl() {} |
| + |
| + virtual void EnumerateStorage( |
| + const EnumerateStorageCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE {} |
| + virtual void GetStorageInfo( |
| + const std::string& storage_name, |
| + const GetStorageInfoCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE {} |
| + virtual void OpenStorage(const std::string& storage_name, |
| + OpenStorageMode mode, |
| + const OpenStorageCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE {} |
| + virtual void CloseStorage(const std::string& handle, |
| + const CloseStorageCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE {} |
| + virtual void ReadDirectoryByPath( |
| + const std::string& handle, |
| + const std::string& path, |
| + const ReadDirectoryCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE {} |
| + virtual void ReadDirectoryById( |
| + const std::string& handle, |
| + uint32 file_id, |
| + const ReadDirectoryCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE {} |
| + virtual void ReadFileByPath(const std::string& handle, |
| + const std::string& path, |
| + const ReadFileCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE {} |
| + virtual void ReadFileById(const std::string& handle, |
| + uint32 file_id, |
| + const ReadFileCallback& callback, |
| + const ErrorCallback& error_callback) OVERRIDE {} |
| + virtual void SetUpConnections( |
| + const MTPStorageEventHandler& handler) OVERRIDE {} |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(MTPDClientStubImpl); |
| +}; |
| + |
| +} // namespace |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// StorageInfo |
| + |
| +StorageInfo::StorageInfo(const std::string& storage_name, |
| + dbus::Response* response) |
| + : vendor_id_(0), |
| + product_id_(0), |
| + device_flags_(0), |
| + storage_name_(storage_name), |
| + storage_type_(0), |
| + filesystem_type_(0), |
| + access_capability_(0), |
| + max_capacity_(0), |
| + free_space_in_bytes_(0), |
| + free_space_in_objects_(0) { |
| + InitializeFromResponse(response); |
| +} |
| + |
| +StorageInfo::~StorageInfo() { |
| +} |
| + |
| +// Initializes |this| from |response| given by the mtpd service. |
| +void StorageInfo::InitializeFromResponse(dbus::Response* response) { |
| + dbus::MessageReader response_reader(response); |
| + dbus::MessageReader array_reader(response); |
| + if (!response_reader.PopArray(&array_reader)) { |
| + LOG(ERROR) << "Invalid response: " << response->ToString(); |
| + return; |
| + } |
| + // TODO(satorux): Rework this code using Protocol Buffers. crosbug.com/22626 |
| + typedef std::map<std::string, dbus::MessageReader*> PropertiesMap; |
| + PropertiesMap properties; |
| + STLValueDeleter<PropertiesMap> properties_value_deleter(&properties); |
| + while (array_reader.HasMoreData()) { |
| + dbus::MessageReader* value_reader = new dbus::MessageReader(response); |
| + dbus::MessageReader dict_entry_reader(response); |
| + std::string key; |
| + if (!array_reader.PopDictEntry(&dict_entry_reader) || |
| + !dict_entry_reader.PopString(&key) || |
| + !dict_entry_reader.PopVariant(value_reader)) { |
| + LOG(ERROR) << "Invalid response: " << response->ToString(); |
| + return; |
| + } |
| + properties[key] = value_reader; |
| + } |
| + // TODO(thestig) Add enums for fields below as appropriate. |
| + MaybePopString(properties["Vendor"], &vendor_); |
| + MaybePopString(properties["Product"], &product_); |
| + MaybePopString(properties["StorageDescription"], &storage_description_); |
| + MaybePopString(properties["VolumeIdentifier"], &volume_identifier_); |
| + MaybePopUint16(properties["VendorId"], &vendor_id_); |
| + MaybePopUint16(properties["ProductId"], &product_id_); |
| + MaybePopUint16(properties["StorageType"], &storage_type_); |
| + MaybePopUint16(properties["FilesystemType"], &filesystem_type_); |
| + MaybePopUint16(properties["AccessCapability"], &access_capability_); |
| + MaybePopUint32(properties["DeviceFlags"], &device_flags_); |
| + MaybePopUint64(properties["MaxCapacity"], &max_capacity_); |
| + MaybePopUint64(properties["FreeSpaceInBytes"], &free_space_in_bytes_); |
| + MaybePopUint64(properties["FreeSpaceInObjects"], &free_space_in_objects_); |
|
satorux1
2012/08/03 17:38:42
Here's an idea. As you've already learned, exchang
Lei Zhang
2012/08/03 18:44:15
Maybe in a later CL? I added a TODO.
|
| +} |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// FileEntry |
| + |
| +FileEntry::FileEntry(dbus::Response* response) |
| + : item_id_(0), |
| + parent_id_(0), |
| + file_size_(0), |
| + file_type_(FILE_TYPE_UNKNOWN) { |
| + InitializeFromResponse(response); |
| +} |
| + |
| +FileEntry::~FileEntry() { |
| +} |
| + |
| +// Initializes |this| from |response| given by the mtpd service. |
| +void FileEntry::InitializeFromResponse(dbus::Response* response) { |
| + dbus::MessageReader response_reader(response); |
| + dbus::MessageReader array_reader(response); |
| + if (!response_reader.PopArray(&array_reader)) { |
| + LOG(ERROR) << "Invalid response: " << response->ToString(); |
| + return; |
| + } |
| + // TODO(satorux): Rework this code using Protocol Buffers. crosbug.com/22626 |
| + typedef std::map<std::string, dbus::MessageReader*> PropertiesMap; |
| + PropertiesMap properties; |
| + STLValueDeleter<PropertiesMap> properties_value_deleter(&properties); |
| + while (array_reader.HasMoreData()) { |
| + dbus::MessageReader* value_reader = new dbus::MessageReader(response); |
| + dbus::MessageReader dict_entry_reader(response); |
| + std::string key; |
| + if (!array_reader.PopDictEntry(&dict_entry_reader) || |
| + !dict_entry_reader.PopString(&key) || |
| + !dict_entry_reader.PopVariant(value_reader)) { |
| + LOG(ERROR) << "Invalid response: " << response->ToString(); |
| + return; |
| + } |
| + properties[key] = value_reader; |
| + } |
| + |
| + // TODO(thestig) Use constants here. |
| + MaybePopString(properties["FileName"], &file_name_); |
| + MaybePopUint32(properties["ItemId"], &item_id_); |
| + MaybePopUint32(properties["ParentId"], &parent_id_); |
| + MaybePopUint64(properties["FileSize"], &file_size_); |
| + |
| + int64 modification_date = -1; |
| + if (MaybePopInt64(properties["ModificationDate"], &modification_date)) |
| + modification_date_ = base::Time::FromTimeT(modification_date); |
| + |
| + uint16 file_type = FILE_TYPE_OTHER; |
| + if (MaybePopUint16(properties["FileType"], &file_type)) { |
| + switch (file_type) { |
| + case FILE_TYPE_FOLDER: |
| + case FILE_TYPE_JPEG: |
| + case FILE_TYPE_JFIF: |
| + case FILE_TYPE_TIFF: |
| + case FILE_TYPE_BMP: |
| + case FILE_TYPE_GIF: |
| + case FILE_TYPE_PICT: |
| + case FILE_TYPE_PNG: |
| + case FILE_TYPE_WINDOWSIMAGEFORMAT: |
| + case FILE_TYPE_JP2: |
| + case FILE_TYPE_JPX: |
| + case FILE_TYPE_UNKNOWN: |
| + file_type_ = static_cast<FileType>(file_type); |
| + default: |
| + file_type_ = FILE_TYPE_OTHER; |
| + break; |
| + } |
| + } |
| +} |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// MTPDClient |
| + |
| +MTPDClient::MTPDClient() {} |
| + |
| +MTPDClient::~MTPDClient() {} |
| + |
| +// static |
| +MTPDClient* MTPDClient::Create(DBusClientImplementationType type, |
| + dbus::Bus* bus) { |
| + if (type == REAL_DBUS_CLIENT_IMPLEMENTATION) |
| + return new MTPDClientImpl(bus); |
| + DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type); |
| + return new MTPDClientStubImpl(); |
| +} |
| + |
| +} // namespace chromeos |
| Property changes on: chromeos/dbus/mtpd_client.cc |
| ___________________________________________________________________ |
| Added: svn:eol-style |
| + LF |