summaryrefslogtreecommitdiffstats
path: root/device
diff options
context:
space:
mode:
Diffstat (limited to 'device')
-rw-r--r--device/device.gyp49
-rw-r--r--device/media_transfer_protocol/DEPS8
-rw-r--r--device/media_transfer_protocol/OWNERS2
-rw-r--r--device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc489
-rw-r--r--device/media_transfer_protocol/media_transfer_protocol_daemon_client.h180
-rw-r--r--device/media_transfer_protocol/media_transfer_protocol_manager.cc453
-rw-r--r--device/media_transfer_protocol/media_transfer_protocol_manager.h143
7 files changed, 1324 insertions, 0 deletions
diff --git a/device/device.gyp b/device/device.gyp
index 25db3cb..c8e6a50 100644
--- a/device/device.gyp
+++ b/device/device.gyp
@@ -151,4 +151,53 @@
],
},
],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'targets': [
+ {
+ # Protobuf compiler / generator for the MtpFileEntry and
+ # MtpFileEntries protocol buffers.
+ 'target_name': 'mtp_file_entry_proto',
+ 'type': 'static_library',
+ 'sources': [
+ '../third_party/cros_system_api/dbus/mtp_file_entry.proto',
+ ],
+ 'variables': {
+ 'proto_in_dir': '../third_party/cros_system_api/dbus',
+ 'proto_out_dir': 'device/media_transfer_protocol',
+ },
+ 'includes': ['../build/protoc.gypi'],
+ },
+ {
+ # Protobuf compiler / generator for the MtpStorageInfo protocol
+ # buffer.
+ 'target_name': 'mtp_storage_info_proto',
+ 'type': 'static_library',
+ 'sources': [
+ '../third_party/cros_system_api/dbus/mtp_storage_info.proto',
+ ],
+ 'variables': {
+ 'proto_in_dir': '../third_party/cros_system_api/dbus',
+ 'proto_out_dir': 'device/media_transfer_protocol',
+ },
+ 'includes': ['../build/protoc.gypi'],
+ },
+ {
+ 'target_name': 'device_media_transfer_protocol',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../build/linux/system.gyp:dbus',
+ 'mtp_file_entry_proto',
+ 'mtp_storage_info_proto',
+ ],
+ 'sources': [
+ 'media_transfer_protocol/media_transfer_protocol_daemon_client.cc',
+ 'media_transfer_protocol/media_transfer_protocol_daemon_client.h',
+ 'media_transfer_protocol/media_transfer_protocol_manager.cc',
+ 'media_transfer_protocol/media_transfer_protocol_manager.h',
+ ],
+ },
+ ],
+ }],
+ ],
}
diff --git a/device/media_transfer_protocol/DEPS b/device/media_transfer_protocol/DEPS
new file mode 100644
index 0000000..e461e37
--- /dev/null
+++ b/device/media_transfer_protocol/DEPS
@@ -0,0 +1,8 @@
+include_rules = [
+ # The media transfer protocol daemon uses D-Bus.
+ "+dbus",
+ "+chrome/common/chrome_switches.h",
+ "+chromeos/dbus",
+ "+content/public/browser/browser_thread.h",
+ "+third_party/cros_system_api/dbus",
+]
diff --git a/device/media_transfer_protocol/OWNERS b/device/media_transfer_protocol/OWNERS
new file mode 100644
index 0000000..8cada85
--- /dev/null
+++ b/device/media_transfer_protocol/OWNERS
@@ -0,0 +1,2 @@
+satorux@chromium.org
+thestig@chromium.org
diff --git a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
new file mode 100644
index 0000000..52e8e63
--- /dev/null
+++ b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.cc
@@ -0,0 +1,489 @@
+// 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
diff --git a/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
new file mode 100644
index 0000000..bba9794
--- /dev/null
+++ b/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
@@ -0,0 +1,180 @@
+// 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.
+
+// Client code to talk to the Media Transfer Protocol daemon. The MTP daemon is
+// responsible for communicating with PTP / MTP capable devices like cameras
+// and smartphones.
+
+#ifndef DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_DAEMON_CLIENT_H_
+#define DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_DAEMON_CLIENT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "build/build_config.h"
+
+#if !defined(OS_LINUX)
+#error "Only used on Linux and ChromeOS"
+#endif
+
+class MtpFileEntry;
+class MtpStorageInfo;
+
+namespace dbus {
+class Bus;
+}
+
+namespace device {
+
+// A class to make the actual DBus calls for mtpd service.
+// This class only makes calls, result/error handling should be done
+// by callbacks.
+class MediaTransferProtocolDaemonClient {
+ public:
+ // A callback to be called when DBus method call fails.
+ typedef base::Callback<void()> ErrorCallback;
+
+ // A callback to handle the result of EnumerateAutoMountableDevices.
+ // The argument is the enumerated storage names.
+ typedef base::Callback<void(const std::vector<std::string>& storage_names)
+ > EnumerateStoragesCallback;
+
+ // A callback to handle the result of GetStorageInfo.
+ // The argument is the information about the specified storage.
+ typedef base::Callback<void(const MtpStorageInfo& storage_info)
+ > GetStorageInfoCallback;
+
+ // A callback to handle the result of OpenStorage.
+ // The argument is the returned handle.
+ typedef base::Callback<void(const std::string& handle)> OpenStorageCallback;
+
+ // A callback to handle the result of CloseStorage.
+ typedef base::Callback<void()> CloseStorageCallback;
+
+ // A callback to handle the result of ReadDirectoryByPath/Id.
+ // The argument is a vector of file entries.
+ typedef base::Callback<void(const std::vector<MtpFileEntry>& file_entries)
+ > ReadDirectoryCallback;
+
+ // A callback to handle the result of ReadFileChunkByPath/Id.
+ // The argument is a string containing the file data.
+ typedef base::Callback<void(const std::string& data)> ReadFileCallback;
+
+ // A callback to handle the result of GetFileInfoByPath/Id.
+ // The argument is a file entry.
+ typedef base::Callback<void(const MtpFileEntry& file_entry)
+ > GetFileInfoCallback;
+
+ // A callback to handle storage attach/detach events.
+ // The first argument is true for attach, false for detach.
+ // The second argument is the storage name.
+ typedef base::Callback<void(bool is_attach,
+ const std::string& storage_name)
+ > MTPStorageEventHandler;
+
+ virtual ~MediaTransferProtocolDaemonClient();
+
+ // Calls EnumerateStorages method. |callback| is called after the
+ // method call succeeds, otherwise, |error_callback| is called.
+ virtual void EnumerateStorages(
+ const EnumerateStoragesCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls GetStorageInfo method. |callback| is called after the method call
+ // succeeds, otherwise, |error_callback| is called.
+ virtual void GetStorageInfo(const std::string& storage_name,
+ const GetStorageInfoCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls OpenStorage method. |callback| is called after the method call
+ // succeeds, otherwise, |error_callback| is called.
+ // OpenStorage returns a handle in |callback|.
+ virtual void OpenStorage(const std::string& storage_name,
+ const std::string& mode,
+ const OpenStorageCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls CloseStorage method. |callback| is called after the method call
+ // succeeds, otherwise, |error_callback| is called.
+ // |handle| comes from a OpenStorageCallback.
+ virtual void CloseStorage(const std::string& handle,
+ const CloseStorageCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls ReadDirectoryByPath method. |callback| is called after the method
+ // call succeeds, otherwise, |error_callback| is called.
+ virtual void ReadDirectoryByPath(const std::string& handle,
+ const std::string& path,
+ const ReadDirectoryCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls ReadDirectoryById method. |callback| is called after the method
+ // call succeeds, otherwise, |error_callback| is called.
+ // |file_id| is a MTP-device specific id for a file.
+ virtual void ReadDirectoryById(const std::string& handle,
+ uint32 file_id,
+ const ReadDirectoryCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls ReadFileChunkByPath method. |callback| is called after the method
+ // call succeeds, otherwise, |error_callback| is called.
+ // |bytes_to_read| cannot exceed 1 MiB.
+ virtual void ReadFileChunkByPath(const std::string& handle,
+ const std::string& path,
+ uint32 offset,
+ uint32 bytes_to_read,
+ const ReadFileCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // TODO(thestig) Remove this in the near future if we don't see anyone using
+ // it.
+ // Calls ReadFilePathById method. |callback| is called after the method call
+ // succeeds, otherwise, |error_callback| is called.
+ // |file_id| is a MTP-device specific id for a file.
+ // |bytes_to_read| cannot exceed 1 MiB.
+ virtual void ReadFileChunkById(const std::string& handle,
+ uint32 file_id,
+ uint32 offset,
+ uint32 bytes_to_read,
+ const ReadFileCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls GetFileInfoByPath method. |callback| is called after the method
+ // call succeeds, otherwise, |error_callback| is called.
+ virtual void GetFileInfoByPath(const std::string& handle,
+ const std::string& path,
+ const GetFileInfoCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Calls GetFileInfoById method. |callback| is called after the method
+ // call succeeds, otherwise, |error_callback| is called.
+ // |file_id| is a MTP-device specific id for a file.
+ virtual void GetFileInfoById(const std::string& handle,
+ uint32 file_id,
+ const GetFileInfoCallback& callback,
+ const ErrorCallback& error_callback) = 0;
+
+ // Registers given callback for events.
+ // |storage_event_handler| is called when a mtp storage attach or detach
+ // signal is received.
+ virtual void SetUpConnections(const MTPStorageEventHandler& handler) = 0;
+
+ // Factory function, creates a new instance and returns ownership.
+ // For normal usage, set |is_stub| to false.
+ static MediaTransferProtocolDaemonClient* Create(dbus::Bus* bus,
+ bool is_stub);
+
+ protected:
+ // Create() should be used instead.
+ MediaTransferProtocolDaemonClient();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDaemonClient);
+};
+
+} // namespace device
+
+#endif // DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_DAEMON_CLIENT_H_
diff --git a/device/media_transfer_protocol/media_transfer_protocol_manager.cc b/device/media_transfer_protocol/media_transfer_protocol_manager.cc
new file mode 100644
index 0000000..dba7d18
--- /dev/null
+++ b/device/media_transfer_protocol/media_transfer_protocol_manager.cc
@@ -0,0 +1,453 @@
+// 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_manager.h"
+
+#include <map>
+#include <queue>
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/stl_util.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/browser_thread.h"
+#include "device/media_transfer_protocol/media_transfer_protocol_daemon_client.h"
+#include "device/media_transfer_protocol/mtp_file_entry.pb.h"
+#include "device/media_transfer_protocol/mtp_storage_info.pb.h"
+
+#if defined(OS_CHROMEOS)
+#include "chromeos/dbus/dbus_thread_manager.h"
+#else
+#include "dbus/bus.h"
+#endif
+
+using content::BrowserThread;
+
+namespace device {
+
+namespace {
+
+MediaTransferProtocolManager* g_media_transfer_protocol_manager = NULL;
+
+// The MediaTransferProtocolManager implementation.
+class MediaTransferProtocolManagerImpl : public MediaTransferProtocolManager {
+ public:
+ MediaTransferProtocolManagerImpl() : weak_ptr_factory_(this) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType))
+ return;
+
+ dbus::Bus* bus = NULL;
+#if defined(OS_CHROMEOS)
+ chromeos::DBusThreadManager* dbus_thread_manager =
+ chromeos::DBusThreadManager::Get();
+ bus = dbus_thread_manager->GetSystemBus();
+ if (!bus)
+ return;
+#else
+ dbus::Bus::Options options;
+ options.bus_type = dbus::Bus::SYSTEM;
+ options.connection_type = dbus::Bus::PRIVATE;
+ options.dbus_thread_message_loop_proxy =
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE);
+ session_bus_ = new dbus::Bus(options);
+ bus = session_bus_.get();
+#endif
+
+ DCHECK(bus);
+ mtp_client_.reset(
+ MediaTransferProtocolDaemonClient::Create(bus, false /* not stub */));
+
+ // Set up signals and start initializing |storage_info_map_|.
+ mtp_client_->SetUpConnections(
+ base::Bind(&MediaTransferProtocolManagerImpl::OnStorageChanged,
+ weak_ptr_factory_.GetWeakPtr()));
+ mtp_client_->EnumerateStorages(
+ base::Bind(&MediaTransferProtocolManagerImpl::OnEnumerateStorages,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&base::DoNothing));
+ }
+
+ virtual ~MediaTransferProtocolManagerImpl() {
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void AddObserver(Observer* observer) OVERRIDE {
+ observers_.AddObserver(observer);
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void RemoveObserver(Observer* observer) OVERRIDE {
+ observers_.RemoveObserver(observer);
+ }
+
+ // MediaTransferProtocolManager override.
+ const std::vector<std::string> GetStorages() const OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ std::vector<std::string> storages;
+ for (StorageInfoMap::const_iterator it = storage_info_map_.begin();
+ it != storage_info_map_.end();
+ ++it) {
+ storages.push_back(it->first);
+ }
+ return storages;
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual const MtpStorageInfo* GetStorageInfo(
+ const std::string& storage_name) const OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ StorageInfoMap::const_iterator it = storage_info_map_.find(storage_name);
+ if (it == storage_info_map_.end())
+ return NULL;
+ return &it->second;
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void OpenStorage(const std::string& storage_name,
+ const std::string& mode,
+ const OpenStorageCallback& callback) OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!ContainsKey(storage_info_map_, storage_name)) {
+ callback.Run("", true);
+ return;
+ }
+ open_storage_callbacks_.push(callback);
+ mtp_client_->OpenStorage(
+ storage_name,
+ mode,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorage,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnOpenStorageError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void CloseStorage(const std::string& storage_handle,
+ const CloseStorageCallback& callback) OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(true);
+ return;
+ }
+ close_storage_callbacks_.push(std::make_pair(callback, storage_handle));
+ mtp_client_->CloseStorage(
+ storage_handle,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorage,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnCloseStorageError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void ReadDirectoryByPath(
+ const std::string& storage_handle,
+ const std::string& path,
+ const ReadDirectoryCallback& callback) OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(std::vector<MtpFileEntry>(), true);
+ return;
+ }
+ read_directory_callbacks_.push(callback);
+ mtp_client_->ReadDirectoryByPath(
+ storage_handle,
+ path,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void ReadDirectoryById(
+ const std::string& storage_handle,
+ uint32 file_id,
+ const ReadDirectoryCallback& callback) OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(std::vector<MtpFileEntry>(), true);
+ return;
+ }
+ read_directory_callbacks_.push(callback);
+ mtp_client_->ReadDirectoryById(
+ storage_handle,
+ file_id,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectory,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadDirectoryError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void ReadFileChunkByPath(const std::string& storage_handle,
+ const std::string& path,
+ uint32 offset,
+ uint32 count,
+ const ReadFileCallback& callback) OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(std::string(), true);
+ return;
+ }
+ read_file_callbacks_.push(callback);
+ mtp_client_->ReadFileChunkByPath(
+ storage_handle, path, offset, count,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ // MediaTransferProtocolManager override.
+ virtual void ReadFileChunkById(const std::string& storage_handle,
+ uint32 file_id,
+ uint32 offset,
+ uint32 count,
+ const ReadFileCallback& callback) OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(std::string(), true);
+ return;
+ }
+ read_file_callbacks_.push(callback);
+ mtp_client_->ReadFileChunkById(
+ storage_handle, file_id, offset, count,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadFile,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnReadFileError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ virtual void GetFileInfoByPath(const std::string& storage_handle,
+ const std::string& path,
+ const GetFileInfoCallback& callback) OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(MtpFileEntry(), true);
+ return;
+ }
+ get_file_info_callbacks_.push(callback);
+ mtp_client_->GetFileInfoByPath(
+ storage_handle,
+ path,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ virtual void GetFileInfoById(const std::string& storage_handle,
+ uint32 file_id,
+ const GetFileInfoCallback& callback) OVERRIDE {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (!ContainsKey(handles_, storage_handle)) {
+ callback.Run(MtpFileEntry(), true);
+ return;
+ }
+ get_file_info_callbacks_.push(callback);
+ mtp_client_->GetFileInfoById(
+ storage_handle,
+ file_id,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfo,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetFileInfoError,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ private:
+ // Map of storage names to storage info.
+ typedef std::map<std::string, MtpStorageInfo> StorageInfoMap;
+ // Callback queues - DBus communication is in-order, thus callbacks are
+ // received in the same order as the requests.
+ typedef std::queue<OpenStorageCallback> OpenStorageCallbackQueue;
+ // (callback, handle)
+ typedef std::queue<std::pair<CloseStorageCallback, std::string>
+ > CloseStorageCallbackQueue;
+ typedef std::queue<ReadDirectoryCallback> ReadDirectoryCallbackQueue;
+ typedef std::queue<ReadFileCallback> ReadFileCallbackQueue;
+ typedef std::queue<GetFileInfoCallback> GetFileInfoCallbackQueue;
+
+ void OnStorageChanged(bool is_attach, const std::string& storage_name) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (is_attach) {
+ mtp_client_->GetStorageInfo(
+ storage_name,
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&base::DoNothing));
+ return;
+ }
+
+ // Detach case.
+ StorageInfoMap::iterator it = storage_info_map_.find(storage_name);
+ if (it == storage_info_map_.end()) {
+ // This might happen during initialization when |storage_info_map_| has
+ // not been fully populated yet?
+ return;
+ }
+ storage_info_map_.erase(it);
+ FOR_EACH_OBSERVER(Observer,
+ observers_,
+ StorageChanged(false /* detach */, storage_name));
+ }
+
+ void OnEnumerateStorages(const std::vector<std::string>& storage_names) {
+ for (size_t i = 0; i < storage_names.size(); ++i) {
+ mtp_client_->GetStorageInfo(
+ storage_names[i],
+ base::Bind(&MediaTransferProtocolManagerImpl::OnGetStorageInfo,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&base::DoNothing));
+ }
+ }
+
+ void OnGetStorageInfo(const MtpStorageInfo& storage_info) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const std::string& storage_name = storage_info.storage_name();
+ if (ContainsKey(storage_info_map_, storage_name)) {
+ // This should not happen, since MediaTransferProtocolManagerImpl should
+ // only call EnumerateStorages() once, which populates |storage_info_map_|
+ // with the already-attached devices.
+ // After that, all incoming signals are either for new storage
+ // attachments, which should not be in |storage_info_map_|, or for
+ // storage detachements, which do not add to |storage_info_map_|.
+ NOTREACHED();
+ return;
+ }
+
+ // New storage. Add it and let the observers know.
+ storage_info_map_.insert(std::make_pair(storage_name, storage_info));
+ FOR_EACH_OBSERVER(Observer,
+ observers_,
+ StorageChanged(true /* is attach */, storage_name));
+ }
+
+ void OnOpenStorage(const std::string& handle) {
+ if (!ContainsKey(handles_, handle)) {
+ handles_.insert(handle);
+ open_storage_callbacks_.front().Run(handle, false);
+ } else {
+ NOTREACHED();
+ open_storage_callbacks_.front().Run("", true);
+ }
+ open_storage_callbacks_.pop();
+ }
+
+ void OnOpenStorageError() {
+ open_storage_callbacks_.front().Run("", true);
+ open_storage_callbacks_.pop();
+ }
+
+ void OnCloseStorage() {
+ const std::string& handle = close_storage_callbacks_.front().second;
+ if (ContainsKey(handles_, handle)) {
+ handles_.erase(handle);
+ close_storage_callbacks_.front().first.Run(false);
+ } else {
+ NOTREACHED();
+ close_storage_callbacks_.front().first.Run(true);
+ }
+ close_storage_callbacks_.pop();
+ }
+
+ void OnCloseStorageError() {
+ close_storage_callbacks_.front().first.Run(true);
+ close_storage_callbacks_.pop();
+ }
+
+ void OnReadDirectory(const std::vector<MtpFileEntry>& file_entries) {
+ read_directory_callbacks_.front().Run(file_entries, false);
+ read_directory_callbacks_.pop();
+ }
+
+ void OnReadDirectoryError() {
+ read_directory_callbacks_.front().Run(std::vector<MtpFileEntry>(), true);
+ read_directory_callbacks_.pop();
+ }
+
+ void OnReadFile(const std::string& data) {
+ read_file_callbacks_.front().Run(data, false);
+ read_file_callbacks_.pop();
+ }
+
+ void OnReadFileError() {
+ read_file_callbacks_.front().Run(std::string(), true);
+ read_file_callbacks_.pop();
+ }
+
+ void OnGetFileInfo(const MtpFileEntry& entry) {
+ get_file_info_callbacks_.front().Run(entry, false);
+ get_file_info_callbacks_.pop();
+ }
+
+ void OnGetFileInfoError() {
+ get_file_info_callbacks_.front().Run(MtpFileEntry(), true);
+ get_file_info_callbacks_.pop();
+ }
+
+ // Mtpd DBus client.
+ scoped_ptr<MediaTransferProtocolDaemonClient> mtp_client_;
+
+#if !defined(OS_CHROMEOS)
+ // And a D-Bus session for talking to mtpd.
+ scoped_refptr<dbus::Bus> session_bus_;
+#endif
+
+ // Device attachment / detachment observers.
+ ObserverList<Observer> observers_;
+
+ base::WeakPtrFactory<MediaTransferProtocolManagerImpl> weak_ptr_factory_;
+
+ // Everything below is only accessed on the UI thread.
+
+ // Map to keep track of attached storages by name.
+ StorageInfoMap storage_info_map_;
+
+ // Set of open storage handles.
+ std::set<std::string> handles_;
+
+ // Queued callbacks.
+ OpenStorageCallbackQueue open_storage_callbacks_;
+ CloseStorageCallbackQueue close_storage_callbacks_;
+ ReadDirectoryCallbackQueue read_directory_callbacks_;
+ ReadFileCallbackQueue read_file_callbacks_;
+ GetFileInfoCallbackQueue get_file_info_callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolManagerImpl);
+};
+
+} // namespace
+
+// static
+void MediaTransferProtocolManager::Initialize() {
+ if (g_media_transfer_protocol_manager) {
+ LOG(WARNING) << "MediaTransferProtocolManager was already initialized";
+ return;
+ }
+ g_media_transfer_protocol_manager = new MediaTransferProtocolManagerImpl();
+ VLOG(1) << "MediaTransferProtocolManager initialized";
+}
+
+// static
+void MediaTransferProtocolManager::Shutdown() {
+ if (!g_media_transfer_protocol_manager) {
+ LOG(WARNING) << "MediaTransferProtocolManager::Shutdown() called with "
+ << "NULL manager";
+ return;
+ }
+ delete g_media_transfer_protocol_manager;
+ g_media_transfer_protocol_manager = NULL;
+ VLOG(1) << "MediaTransferProtocolManager Shutdown completed";
+}
+
+// static
+MediaTransferProtocolManager* MediaTransferProtocolManager::GetInstance() {
+ return g_media_transfer_protocol_manager;
+}
+
+} // namespace device
diff --git a/device/media_transfer_protocol/media_transfer_protocol_manager.h b/device/media_transfer_protocol/media_transfer_protocol_manager.h
new file mode 100644
index 0000000..5c416b5
--- /dev/null
+++ b/device/media_transfer_protocol/media_transfer_protocol_manager.h
@@ -0,0 +1,143 @@
+// 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.
+
+#ifndef DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_MANAGER_H_
+#define DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_MANAGER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "build/build_config.h"
+
+#if !defined(OS_LINUX)
+#error "Only used on Linux and ChromeOS"
+#endif
+
+class MtpFileEntry;
+class MtpStorageInfo;
+
+namespace device {
+
+// This class handles the interaction with mtpd.
+// Other classes can add themselves as observers.
+class MediaTransferProtocolManager {
+ public:
+ // A callback to handle the result of OpenStorage.
+ // The first argument is the returned handle.
+ // The second argument is true if there was an error.
+ typedef base::Callback<void(const std::string& handle,
+ bool error)> OpenStorageCallback;
+
+ // A callback to handle the result of CloseStorage.
+ // The argument is true if there was an error.
+ typedef base::Callback<void(bool error)> CloseStorageCallback;
+
+ // A callback to handle the result of ReadDirectoryByPath/Id.
+ // The first argument is a vector of file entries.
+ // The second argument is true if there was an error.
+ typedef base::Callback<void(const std::vector<MtpFileEntry>& file_entries,
+ bool error)> ReadDirectoryCallback;
+
+ // A callback to handle the result of ReadFileChunkByPath/Id.
+ // The first argument is a string containing the file data.
+ // The second argument is true if there was an error.
+ typedef base::Callback<void(const std::string& data,
+ bool error)> ReadFileCallback;
+
+ // A callback to handle the result of GetFileInfoByPath/Id.
+ // The first argument is a file entry.
+ // The second argument is true if there was an error.
+ typedef base::Callback<void(const MtpFileEntry& file_entry,
+ bool error)> GetFileInfoCallback;
+
+ // Implement this interface to be notified about MTP storage
+ // attachment / detachment events.
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ // A function called after a MTP storage has been attached / detached.
+ virtual void StorageChanged(bool is_attached,
+ const std::string& storage_name) = 0;
+ };
+
+ virtual ~MediaTransferProtocolManager() {}
+
+ // Adds an observer.
+ virtual void AddObserver(Observer* observer) = 0;
+
+ // Removes an observer.
+ virtual void RemoveObserver(Observer* observer) = 0;
+
+ // Returns a vector of available MTP storages.
+ virtual const std::vector<std::string> GetStorages() const = 0;
+
+ // On success, returns the the metadata for |storage_name|.
+ // Otherwise returns NULL.
+ virtual const MtpStorageInfo* GetStorageInfo(
+ const std::string& storage_name) const = 0;
+
+ // Opens |storage_name| in |mode| and runs |callback|.
+ virtual void OpenStorage(const std::string& storage_name,
+ const std::string& mode,
+ const OpenStorageCallback& callback) = 0;
+
+ // Close |storage_handle| and runs |callback|.
+ virtual void CloseStorage(const std::string& storage_handle,
+ const CloseStorageCallback& callback) = 0;
+
+ // Reads directory entries from |path| on |storage_handle| and runs
+ // |callback|.
+ virtual void ReadDirectoryByPath(const std::string& storage_handle,
+ const std::string& path,
+ const ReadDirectoryCallback& callback) = 0;
+
+ // Reads directory entries from |file_id| on |storage_handle| and runs
+ // |callback|.
+ virtual void ReadDirectoryById(const std::string& storage_handle,
+ uint32 file_id,
+ const ReadDirectoryCallback& callback) = 0;
+
+ // Reads file data from |path| on |storage_handle| and runs |callback|.
+ // Reads |count| bytes of data starting at |offset|.
+ virtual void ReadFileChunkByPath(const std::string& storage_handle,
+ const std::string& path,
+ uint32 offset,
+ uint32 count,
+ const ReadFileCallback& callback) = 0;
+
+ // Reads file data from |file_id| on |storage_handle| and runs |callback|.
+ // Reads |count| bytes of data starting at |offset|.
+ virtual void ReadFileChunkById(const std::string& storage_handle,
+ uint32 file_id,
+ uint32 offset,
+ uint32 count,
+ const ReadFileCallback& callback) = 0;
+
+ // Gets the file metadata for |path| on |storage_handle| and runs |callback|.
+ virtual void GetFileInfoByPath(const std::string& storage_handle,
+ const std::string& path,
+ const GetFileInfoCallback& callback) = 0;
+
+ // Gets the file metadata for |file_id| on |storage_handle| and runs
+ // |callback|.
+ virtual void GetFileInfoById(const std::string& storage_handle,
+ uint32 file_id,
+ const GetFileInfoCallback& callback) = 0;
+
+ // Creates the global MediaTransferProtocolManager instance.
+ static void Initialize();
+
+ // Destroys the global MediaTransferProtocolManager instance if it exists.
+ static void Shutdown();
+
+ // Returns a pointer to the global MediaTransferProtocolManager instance.
+ // Initialize() should already have been called.
+ static MediaTransferProtocolManager* GetInstance();
+};
+
+} // namespace device
+
+#endif // DEVICE_MEDIA_TRANSFER_PROTOCOL_MEDIA_TRANSFER_PROTOCOL_MANAGER_H_