blob: 52e8e633d18379320b4ad333aee7793135cac431 [file] [log] [blame]
// 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 "device/media_transfer_protocol/media_transfer_protocol_daemon_client.h"
#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/object_proxy.h"
#include "device/media_transfer_protocol/mtp_file_entry.pb.h"
#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace device {
namespace {
const char kInvalidResponseMsg[] = "Invalid Response: ";
// The MediaTransferProtocolDaemonClient implementation.
class MediaTransferProtocolDaemonClientImpl
: public MediaTransferProtocolDaemonClient {
public:
explicit MediaTransferProtocolDaemonClientImpl(dbus::Bus* bus)
: proxy_(bus->GetObjectProxy(
mtpd::kMtpdServiceName,
dbus::ObjectPath(mtpd::kMtpdServicePath))),
weak_ptr_factory_(this) {
}
// MediaTransferProtocolDaemonClient override.
virtual void EnumerateStorages(const EnumerateStoragesCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
dbus::MethodCall method_call(mtpd::kMtpdInterface,
mtpd::kEnumerateStorages);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnEnumerateStorages,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
// MediaTransferProtocolDaemonClient override.
virtual void GetStorageInfo(const std::string& storage_name,
const GetStorageInfoCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kGetStorageInfo);
dbus::MessageWriter writer(&method_call);
writer.AppendString(storage_name);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetStorageInfo,
weak_ptr_factory_.GetWeakPtr(),
storage_name,
callback,
error_callback));
}
// MediaTransferProtocolDaemonClient override.
virtual void OpenStorage(const std::string& storage_name,
const std::string& mode,
const OpenStorageCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kOpenStorage);
dbus::MessageWriter writer(&method_call);
writer.AppendString(storage_name);
DCHECK_EQ(mtpd::kReadOnlyMode, mode);
writer.AppendString(mtpd::kReadOnlyMode);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnOpenStorage,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
// MediaTransferProtocolDaemonClient override.
virtual void CloseStorage(const std::string& handle,
const CloseStorageCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kCloseStorage);
dbus::MessageWriter writer(&method_call);
writer.AppendString(handle);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnCloseStorage,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
// MediaTransferProtocolDaemonClient override.
virtual void ReadDirectoryByPath(
const std::string& handle,
const std::string& path,
const ReadDirectoryCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
dbus::MethodCall method_call(mtpd::kMtpdInterface,
mtpd::kReadDirectoryByPath);
dbus::MessageWriter writer(&method_call);
writer.AppendString(handle);
writer.AppendString(path);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectory,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
// MediaTransferProtocolDaemonClient override.
virtual void ReadDirectoryById(
const std::string& handle,
uint32 file_id,
const ReadDirectoryCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
dbus::MethodCall method_call(mtpd::kMtpdInterface,
mtpd::kReadDirectoryById);
dbus::MessageWriter writer(&method_call);
writer.AppendString(handle);
writer.AppendUint32(file_id);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadDirectory,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
// MediaTransferProtocolDaemonClient override.
virtual void ReadFileChunkByPath(
const std::string& handle,
const std::string& path,
uint32 offset,
uint32 bytes_to_read,
const ReadFileCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
dbus::MethodCall method_call(mtpd::kMtpdInterface,
mtpd::kReadFileChunkByPath);
dbus::MessageWriter writer(&method_call);
writer.AppendString(handle);
writer.AppendString(path);
writer.AppendUint32(offset);
writer.AppendUint32(bytes_to_read);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
// MediaTransferProtocolDaemonClient override.
virtual void ReadFileChunkById(const std::string& handle,
uint32 file_id,
uint32 offset,
uint32 bytes_to_read,
const ReadFileCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
dbus::MethodCall method_call(mtpd::kMtpdInterface,
mtpd::kReadFileChunkById);
dbus::MessageWriter writer(&method_call);
writer.AppendString(handle);
writer.AppendUint32(file_id);
writer.AppendUint32(offset);
writer.AppendUint32(bytes_to_read);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnReadFile,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
// MediaTransferProtocolDaemonClient override.
virtual void GetFileInfoByPath(const std::string& handle,
const std::string& path,
const GetFileInfoCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
dbus::MethodCall method_call(mtpd::kMtpdInterface,
mtpd::kGetFileInfoByPath);
dbus::MessageWriter writer(&method_call);
writer.AppendString(handle);
writer.AppendString(path);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
// MediaTransferProtocolDaemonClient override.
virtual void GetFileInfoById(const std::string& handle,
uint32 file_id,
const GetFileInfoCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {
dbus::MethodCall method_call(mtpd::kMtpdInterface, mtpd::kGetFileInfoById);
dbus::MessageWriter writer(&method_call);
writer.AppendString(handle);
writer.AppendUint32(file_id);
proxy_->CallMethod(
&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnGetFileInfo,
weak_ptr_factory_.GetWeakPtr(),
callback,
error_callback));
}
// MediaTransferProtocolDaemonClient override.
virtual void SetUpConnections(
const MTPStorageEventHandler& handler) OVERRIDE {
static const SignalEventTuple kSignalEventTuples[] = {
{ mtpd::kMTPStorageAttached, true },
{ mtpd::kMTPStorageDetached, false },
};
const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples);
for (size_t i = 0; i < kNumSignalEventTuples; ++i) {
proxy_->ConnectToSignal(
mtpd::kMtpdInterface,
kSignalEventTuples[i].signal_name,
base::Bind(&MediaTransferProtocolDaemonClientImpl::OnMTPStorageSignal,
weak_ptr_factory_.GetWeakPtr(),
handler,
kSignalEventTuples[i].is_attach),
base::Bind(&MediaTransferProtocolDaemonClientImpl::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 EnumerateStorages and calls |callback| or
// |error_callback|.
void OnEnumerateStorages(const EnumerateStoragesCallback& 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) << kInvalidResponseMsg << 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;
}
dbus::MessageReader reader(response);
MtpStorageInfo protobuf;
if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
LOG(ERROR) << kInvalidResponseMsg << response->ToString();
error_callback.Run();
return;
}
callback.Run(protobuf);
}
// 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) << kInvalidResponseMsg << 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<MtpFileEntry> file_entries;
dbus::MessageReader reader(response);
MtpFileEntries entries_protobuf;
if (!reader.PopArrayOfBytesAsProto(&entries_protobuf)) {
LOG(ERROR) << kInvalidResponseMsg << response->ToString();
error_callback.Run();
return;
}
for (int i = 0; i < entries_protobuf.file_entries_size(); ++i)
file_entries.push_back(entries_protobuf.file_entries(i));
callback.Run(file_entries);
}
// Handles the result of ReadFileChunkByPath/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 the result of GetFileInfoByPath/Id and calls |callback| or
// |error_callback|.
void OnGetFileInfo(const GetFileInfoCallback& callback,
const ErrorCallback& error_callback,
dbus::Response* response) {
if (!response) {
error_callback.Run();
return;
}
dbus::MessageReader reader(response);
MtpFileEntry protobuf;
if (!reader.PopArrayOfBytesAsProto(&protobuf)) {
LOG(ERROR) << kInvalidResponseMsg << response->ToString();
error_callback.Run();
return;
}
callback.Run(protobuf);
}
// 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 succeeded) {
LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " "
<< signal << " failed.";
}
dbus::ObjectProxy* proxy_;
// Note: This should remain the last member so it'll be destroyed and
// invalidate its weak pointers before any other members are destroyed.
base::WeakPtrFactory<MediaTransferProtocolDaemonClientImpl> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClientImpl);
};
// A stub implementaion of MediaTransferProtocolDaemonClient.
class MediaTransferProtocolDaemonClientStubImpl
: public MediaTransferProtocolDaemonClient {
public:
MediaTransferProtocolDaemonClientStubImpl() {}
virtual ~MediaTransferProtocolDaemonClientStubImpl() {}
virtual void EnumerateStorages(
const EnumerateStoragesCallback& 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,
const std::string& 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 ReadFileChunkByPath(
const std::string& handle,
const std::string& path,
uint32 offset,
uint32 length,
const ReadFileCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {}
virtual void ReadFileChunkById(
const std::string& handle,
uint32 file_id,
uint32 offset,
uint32 length,
const ReadFileCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {}
virtual void GetFileInfoByPath(
const std::string& handle,
const std::string& path,
const GetFileInfoCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {}
virtual void GetFileInfoById(const std::string& handle,
uint32 file_id,
const GetFileInfoCallback& callback,
const ErrorCallback& error_callback) OVERRIDE {}
virtual void SetUpConnections(
const MTPStorageEventHandler& handler) OVERRIDE {}
private:
DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClientStubImpl);
};
} // namespace
////////////////////////////////////////////////////////////////////////////////
// MediaTransferProtocolDaemonClient
MediaTransferProtocolDaemonClient::MediaTransferProtocolDaemonClient() {}
MediaTransferProtocolDaemonClient::~MediaTransferProtocolDaemonClient() {}
// static
MediaTransferProtocolDaemonClient*
MediaTransferProtocolDaemonClient::Create(dbus::Bus* bus, bool is_stub) {
if (is_stub)
return new MediaTransferProtocolDaemonClientStubImpl();
return new MediaTransferProtocolDaemonClientImpl(bus);
}
} // namespace device