summaryrefslogtreecommitdiffstats
path: root/chromeos/dbus/cros_disks_client.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromeos/dbus/cros_disks_client.cc')
-rw-r--r--chromeos/dbus/cros_disks_client.cc566
1 files changed, 566 insertions, 0 deletions
diff --git a/chromeos/dbus/cros_disks_client.cc b/chromeos/dbus/cros_disks_client.cc
new file mode 100644
index 0000000..217382c
--- /dev/null
+++ b/chromeos/dbus/cros_disks_client.cc
@@ -0,0 +1,566 @@
+// 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/cros_disks_client.h"
+
+#include "base/bind.h"
+#include "base/stl_util.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 {
+
+const char* kDefaultMountOptions[] = {
+ "rw",
+ "nodev",
+ "noexec",
+ "nosuid",
+};
+
+const char* kDefaultUnmountOptions[] = {
+ "force",
+};
+
+// Checks if retrieved media type is in boundaries of DeviceMediaType.
+bool IsValidMediaType(uint32 type) {
+ return type < static_cast<uint32>(cros_disks::DEVICE_MEDIA_NUM_VALUES);
+}
+
+
+// Translates enum used in cros-disks to enum used in Chrome.
+// Note that we could just do static_cast, but this is less sensitive to
+// changes in cros-disks.
+DeviceType DeviceMediaTypeToDeviceType(uint32 media_type_uint32) {
+ if (!IsValidMediaType(media_type_uint32))
+ return DEVICE_TYPE_UNKNOWN;
+
+ cros_disks::DeviceMediaType media_type =
+ cros_disks::DeviceMediaType(media_type_uint32);
+
+ switch (media_type) {
+ case(cros_disks::DEVICE_MEDIA_UNKNOWN):
+ return DEVICE_TYPE_UNKNOWN;
+ case(cros_disks::DEVICE_MEDIA_USB):
+ return DEVICE_TYPE_USB;
+ case(cros_disks::DEVICE_MEDIA_SD):
+ return DEVICE_TYPE_SD;
+ case(cros_disks::DEVICE_MEDIA_OPTICAL_DISC):
+ return DEVICE_TYPE_OPTICAL_DISC;
+ case(cros_disks::DEVICE_MEDIA_MOBILE):
+ return DEVICE_TYPE_MOBILE;
+ default:
+ return DEVICE_TYPE_UNKNOWN;
+ }
+}
+
+// Pops a bool value when |reader| is not NULL.
+// Returns true when a value is popped, false otherwise.
+bool MaybePopBool(dbus::MessageReader* reader, bool* value) {
+ if (!reader)
+ return false;
+ return reader->PopBool(value);
+}
+
+// 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 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 an array of strings when |reader| is not NULL.
+// Returns true when an array is popped, false otherwise.
+bool MaybePopArrayOfStrings(dbus::MessageReader* reader,
+ std::vector<std::string>* value) {
+ if (!reader)
+ return false;
+ return reader->PopArrayOfStrings(value);
+}
+
+// The CrosDisksClient implementation.
+class CrosDisksClientImpl : public CrosDisksClient {
+ public:
+ explicit CrosDisksClientImpl(dbus::Bus* bus)
+ : proxy_(bus->GetObjectProxy(
+ cros_disks::kCrosDisksServiceName,
+ dbus::ObjectPath(cros_disks::kCrosDisksServicePath))),
+ weak_ptr_factory_(this) {
+ }
+
+ // CrosDisksClient override.
+ virtual void Mount(const std::string& source_path,
+ MountType type,
+ MountCallback callback,
+ ErrorCallback error_callback) OVERRIDE {
+ dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
+ cros_disks::kMount);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(source_path);
+ writer.AppendString(""); // auto detect filesystem.
+ std::vector<std::string> mount_options(kDefaultMountOptions,
+ kDefaultMountOptions +
+ arraysize(kDefaultMountOptions));
+ writer.AppendArrayOfStrings(mount_options);
+ proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&CrosDisksClientImpl::OnMount,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+
+ // CrosDisksClient override.
+ virtual void Unmount(const std::string& device_path,
+ UnmountCallback callback,
+ ErrorCallback error_callback) OVERRIDE {
+ dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
+ cros_disks::kUnmount);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(device_path);
+ std::vector<std::string> unmount_options(kDefaultUnmountOptions,
+ kDefaultUnmountOptions +
+ arraysize(kDefaultUnmountOptions));
+ writer.AppendArrayOfStrings(unmount_options);
+ proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&CrosDisksClientImpl::OnUnmount,
+ weak_ptr_factory_.GetWeakPtr(),
+ device_path,
+ callback,
+ error_callback));
+ }
+
+ // CrosDisksClient override.
+ virtual void EnumerateAutoMountableDevices(
+ EnumerateAutoMountableDevicesCallback callback,
+ ErrorCallback error_callback) OVERRIDE {
+ dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
+ cros_disks::kEnumerateAutoMountableDevices);
+ proxy_->CallMethod(
+ &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&CrosDisksClientImpl::OnEnumerateAutoMountableDevices,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ error_callback));
+ }
+
+ // CrosDisksClient override.
+ virtual void FormatDevice(const std::string& device_path,
+ const std::string& filesystem,
+ FormatDeviceCallback callback,
+ ErrorCallback error_callback) OVERRIDE {
+ dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
+ cros_disks::kFormatDevice);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(device_path);
+ writer.AppendString(filesystem);
+ proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&CrosDisksClientImpl::OnFormatDevice,
+ weak_ptr_factory_.GetWeakPtr(),
+ device_path,
+ callback,
+ error_callback));
+ }
+
+ // CrosDisksClient override.
+ virtual void GetDeviceProperties(const std::string& device_path,
+ GetDevicePropertiesCallback callback,
+ ErrorCallback error_callback) OVERRIDE {
+ dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
+ cros_disks::kGetDeviceProperties);
+ dbus::MessageWriter writer(&method_call);
+ writer.AppendString(device_path);
+ proxy_->CallMethod(&method_call,
+ dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+ base::Bind(&CrosDisksClientImpl::OnGetDeviceProperties,
+ weak_ptr_factory_.GetWeakPtr(),
+ device_path,
+ callback,
+ error_callback));
+ }
+
+ // CrosDisksClient override.
+ virtual void SetUpConnections(
+ MountEventHandler mount_event_handler,
+ MountCompletedHandler mount_completed_handler) OVERRIDE {
+ static const SignalEventTuple kSignalEventTuples[] = {
+ { cros_disks::kDeviceAdded, DEVICE_ADDED },
+ { cros_disks::kDeviceScanned, DEVICE_SCANNED },
+ { cros_disks::kDeviceRemoved, DEVICE_REMOVED },
+ { cros_disks::kDiskAdded, DISK_ADDED },
+ { cros_disks::kDiskChanged, DISK_CHANGED },
+ { cros_disks::kDiskRemoved, DISK_REMOVED },
+ { cros_disks::kFormattingFinished, FORMATTING_FINISHED },
+ };
+ const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples);
+
+ for (size_t i = 0; i < kNumSignalEventTuples; ++i) {
+ proxy_->ConnectToSignal(
+ cros_disks::kCrosDisksInterface,
+ kSignalEventTuples[i].signal_name,
+ base::Bind(&CrosDisksClientImpl::OnMountEvent,
+ weak_ptr_factory_.GetWeakPtr(),
+ kSignalEventTuples[i].event_type,
+ mount_event_handler),
+ base::Bind(&CrosDisksClientImpl::OnSignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+ proxy_->ConnectToSignal(
+ cros_disks::kCrosDisksInterface,
+ cros_disks::kMountCompleted,
+ base::Bind(&CrosDisksClientImpl::OnMountCompleted,
+ weak_ptr_factory_.GetWeakPtr(),
+ mount_completed_handler ),
+ base::Bind(&CrosDisksClientImpl::OnSignalConnected,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ private:
+ // A struct to contain a pair of signal name and mount event type.
+ // Used by SetUpConnections.
+ struct SignalEventTuple {
+ const char *signal_name;
+ MountEventType event_type;
+ };
+
+ // Handles the result of Mount and calls |callback| or |error_callback|.
+ void OnMount(MountCallback callback,
+ ErrorCallback error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+ callback.Run();
+ }
+
+ // Handles the result of Unount and calls |callback| or |error_callback|.
+ void OnUnmount(const std::string& device_path,
+ UnmountCallback callback,
+ ErrorCallback error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+ callback.Run(device_path);
+ }
+
+ // Handles the result of EnumerateAutoMountableDevices and calls |callback| or
+ // |error_callback|.
+ void OnEnumerateAutoMountableDevices(
+ EnumerateAutoMountableDevicesCallback callback,
+ ErrorCallback error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+ dbus::MessageReader reader(response);
+ std::vector<std::string> device_paths;
+ if (!reader.PopArrayOfStrings(&device_paths)) {
+ LOG(ERROR) << "Invalid response: " << response->ToString();
+ error_callback.Run();
+ return;
+ }
+ callback.Run(device_paths);
+ }
+
+ // Handles the result of FormatDevice and calls |callback| or
+ // |error_callback|.
+ void OnFormatDevice(const std::string& device_path,
+ FormatDeviceCallback callback,
+ ErrorCallback error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+ dbus::MessageReader reader(response);
+ bool success = false;
+ if (!reader.PopBool(&success)) {
+ LOG(ERROR) << "Invalid response: " << response->ToString();
+ error_callback.Run();
+ return;
+ }
+ callback.Run(device_path, success);
+ }
+
+ // Handles the result of GetDeviceProperties and calls |callback| or
+ // |error_callback|.
+ void OnGetDeviceProperties(const std::string& device_path,
+ GetDevicePropertiesCallback callback,
+ ErrorCallback error_callback,
+ dbus::Response* response) {
+ if (!response) {
+ error_callback.Run();
+ return;
+ }
+ DiskInfo disk(device_path, response);
+ callback.Run(disk);
+ }
+
+ // Handles mount event signals and calls |handler|.
+ void OnMountEvent(MountEventType event_type,
+ MountEventHandler handler,
+ dbus::Signal* signal) {
+ dbus::MessageReader reader(signal);
+ std::string device;
+ if (!reader.PopString(&device)) {
+ LOG(ERROR) << "Invalid signal: " << signal->ToString();
+ return;
+ }
+ handler.Run(event_type, device);
+ }
+
+ // Handles MountCompleted signal and calls |handler|.
+ void OnMountCompleted(MountCompletedHandler handler, dbus::Signal* signal) {
+ dbus::MessageReader reader(signal);
+ unsigned int error_code = 0;
+ std::string source_path;
+ unsigned int mount_type = 0;
+ std::string mount_path;
+ if (!reader.PopUint32(&error_code) ||
+ !reader.PopString(&source_path) ||
+ !reader.PopUint32(&mount_type) ||
+ !reader.PopString(&mount_path)) {
+ LOG(ERROR) << "Invalid signal: " << signal->ToString();
+ return;
+ }
+ handler.Run(static_cast<MountError>(error_code), source_path,
+ static_cast<MountType>(mount_type), mount_path);
+ }
+
+ // 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<CrosDisksClientImpl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrosDisksClientImpl);
+};
+
+// A stub implementaion of CrosDisksClient.
+class CrosDisksClientStubImpl : public CrosDisksClient {
+ public:
+ CrosDisksClientStubImpl() {}
+ virtual ~CrosDisksClientStubImpl() {}
+
+ virtual void Mount(const std::string& source_path,
+ MountType type,
+ MountCallback callback,
+ ErrorCallback error_callback) OVERRIDE {}
+ virtual void Unmount(const std::string& device_path,
+ UnmountCallback callback,
+ ErrorCallback error_callback) OVERRIDE {}
+ virtual void EnumerateAutoMountableDevices(
+ EnumerateAutoMountableDevicesCallback callback,
+ ErrorCallback error_callback) OVERRIDE {}
+ virtual void FormatDevice(const std::string& device_path,
+ const std::string& filesystem,
+ FormatDeviceCallback callback,
+ ErrorCallback error_callback) OVERRIDE {}
+ virtual void GetDeviceProperties(const std::string& device_path,
+ GetDevicePropertiesCallback callback,
+ ErrorCallback error_callback) OVERRIDE {}
+ virtual void SetUpConnections(
+ MountEventHandler mount_event_handler,
+ MountCompletedHandler mount_completed_handler) OVERRIDE {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CrosDisksClientStubImpl);
+};
+
+} // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// DiskInfo
+
+DiskInfo::DiskInfo(const std::string& device_path, dbus::Response* response)
+ : device_path_(device_path),
+ is_drive_(false),
+ has_media_(false),
+ on_boot_device_(false),
+ device_type_(DEVICE_TYPE_UNKNOWN),
+ total_size_in_bytes_(0),
+ is_read_only_(false),
+ is_hidden_(true) {
+ InitializeFromResponse(response);
+}
+
+DiskInfo::~DiskInfo() {
+}
+
+// Initialize |this| from |response| given by the cros-disks service.
+// Below is an example of |response|'s raw message (long string is ellipsized).
+//
+//
+// message_type: MESSAGE_METHOD_RETURN
+// destination: :1.8
+// sender: :1.16
+// signature: a{sv}
+// serial: 96
+// reply_serial: 267
+//
+// array [
+// dict entry {
+// string "DeviceFile"
+// variant string "/dev/sdb"
+// }
+// dict entry {
+// string "DeviceIsDrive"
+// variant bool true
+// }
+// dict entry {
+// string "DeviceIsMediaAvailable"
+// variant bool true
+// }
+// dict entry {
+// string "DeviceIsMounted"
+// variant bool false
+// }
+// dict entry {
+// string "DeviceIsOnBootDevice"
+// variant bool false
+// }
+// dict entry {
+// string "DeviceIsOpticalDisc"
+// variant bool false
+// }
+// dict entry {
+// string "DeviceIsReadOnly"
+// variant bool false
+// }
+// dict entry {
+// string "DeviceIsVirtual"
+// variant bool false
+// }
+// dict entry {
+// string "DeviceMediaType"
+// variant uint32 1
+// }
+// dict entry {
+// string "DeviceMountPaths"
+// variant array [
+// ]
+// }
+// dict entry {
+// string "DevicePresentationHide"
+// variant bool true
+// }
+// dict entry {
+// string "DeviceSize"
+// variant uint64 7998537728
+// }
+// dict entry {
+// string "DriveIsRotational"
+// variant bool false
+// }
+// dict entry {
+// string "DriveModel"
+// variant string "TransMemory"
+// }
+// dict entry {
+// string "IdLabel"
+// variant string ""
+// }
+// dict entry {
+// string "IdUuid"
+// variant string ""
+// }
+// dict entry {
+// string "NativePath"
+// variant string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/...
+// }
+// ]
+void DiskInfo::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;
+ }
+ MaybePopBool(properties[cros_disks::kDeviceIsDrive], &is_drive_);
+ MaybePopBool(properties[cros_disks::kDeviceIsReadOnly], &is_read_only_);
+ MaybePopBool(properties[cros_disks::kDevicePresentationHide], &is_hidden_);
+ MaybePopBool(properties[cros_disks::kDeviceIsMediaAvailable], &has_media_);
+ MaybePopBool(properties[cros_disks::kDeviceIsOnBootDevice],
+ &on_boot_device_);
+ MaybePopString(properties[cros_disks::kNativePath], &system_path_);
+ MaybePopString(properties[cros_disks::kDeviceFile], &file_path_);
+ MaybePopString(properties[cros_disks::kDriveModel], &drive_model_);
+ MaybePopString(properties[cros_disks::kIdLabel], &label_);
+ MaybePopUint64(properties[cros_disks::kDeviceSize], &total_size_in_bytes_);
+
+ uint32 media_type_uint32 = 0;
+ if (MaybePopUint32(properties[cros_disks::kDeviceMediaType],
+ &media_type_uint32)) {
+ device_type_ = DeviceMediaTypeToDeviceType(media_type_uint32);
+ }
+
+ std::vector<std::string> mount_paths;
+ if (MaybePopArrayOfStrings(properties[cros_disks::kDeviceMountPaths],
+ &mount_paths) && !mount_paths.empty())
+ mount_path_ = mount_paths[0];
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CrosDisksClient
+
+CrosDisksClient::CrosDisksClient() {}
+
+CrosDisksClient::~CrosDisksClient() {}
+
+// static
+CrosDisksClient* CrosDisksClient::Create(DBusClientImplementationType type,
+ dbus::Bus* bus) {
+ if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
+ return new CrosDisksClientImpl(bus);
+ DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
+ return new CrosDisksClientStubImpl();
+}
+
+} // namespace chromeos