1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/dbus/cros_disks_client.h"
10 #include "base/stl_util.h"
11 #include "base/stringprintf.h"
13 #include "dbus/message.h"
14 #include "dbus/object_path.h"
15 #include "dbus/object_proxy.h"
16 #include "third_party/cros_system_api/dbus/service_constants.h"
22 const char* kDefaultMountOptions
[] = {
29 const char* kDefaultUnmountOptions
[] = {
33 const char kLazyUnmountOption
[] = "lazy";
35 const char kMountLabelOption
[] = "mountlabel";
37 // Checks if retrieved media type is in boundaries of DeviceMediaType.
38 bool IsValidMediaType(uint32 type
) {
39 return type
< static_cast<uint32
>(cros_disks::DEVICE_MEDIA_NUM_VALUES
);
43 // Translates enum used in cros-disks to enum used in Chrome.
44 // Note that we could just do static_cast, but this is less sensitive to
45 // changes in cros-disks.
46 DeviceType
DeviceMediaTypeToDeviceType(uint32 media_type_uint32
) {
47 if (!IsValidMediaType(media_type_uint32
))
48 return DEVICE_TYPE_UNKNOWN
;
50 cros_disks::DeviceMediaType media_type
=
51 cros_disks::DeviceMediaType(media_type_uint32
);
54 case(cros_disks::DEVICE_MEDIA_UNKNOWN
):
55 return DEVICE_TYPE_UNKNOWN
;
56 case(cros_disks::DEVICE_MEDIA_USB
):
57 return DEVICE_TYPE_USB
;
58 case(cros_disks::DEVICE_MEDIA_SD
):
59 return DEVICE_TYPE_SD
;
60 case(cros_disks::DEVICE_MEDIA_OPTICAL_DISC
):
61 return DEVICE_TYPE_OPTICAL_DISC
;
62 case(cros_disks::DEVICE_MEDIA_MOBILE
):
63 return DEVICE_TYPE_MOBILE
;
64 case(cros_disks::DEVICE_MEDIA_DVD
):
65 return DEVICE_TYPE_DVD
;
67 return DEVICE_TYPE_UNKNOWN
;
71 // Pops a bool value when |reader| is not NULL.
72 // Returns true when a value is popped, false otherwise.
73 bool MaybePopBool(dbus::MessageReader
* reader
, bool* value
) {
76 return reader
->PopBool(value
);
79 // Pops a string value when |reader| is not NULL.
80 // Returns true when a value is popped, false otherwise.
81 bool MaybePopString(dbus::MessageReader
* reader
, std::string
* value
) {
84 return reader
->PopString(value
);
87 // Pops a uint32 value when |reader| is not NULL.
88 // Returns true when a value is popped, false otherwise.
89 bool MaybePopUint32(dbus::MessageReader
* reader
, uint32
* value
) {
93 return reader
->PopUint32(value
);
96 // Pops a uint64 value when |reader| is not NULL.
97 // Returns true when a value is popped, false otherwise.
98 bool MaybePopUint64(dbus::MessageReader
* reader
, uint64
* value
) {
101 return reader
->PopUint64(value
);
104 // Pops an array of strings when |reader| is not NULL.
105 // Returns true when an array is popped, false otherwise.
106 bool MaybePopArrayOfStrings(dbus::MessageReader
* reader
,
107 std::vector
<std::string
>* value
) {
110 return reader
->PopArrayOfStrings(value
);
113 // The CrosDisksClient implementation.
114 class CrosDisksClientImpl
: public CrosDisksClient
{
116 explicit CrosDisksClientImpl(dbus::Bus
* bus
)
117 : proxy_(bus
->GetObjectProxy(
118 cros_disks::kCrosDisksServiceName
,
119 dbus::ObjectPath(cros_disks::kCrosDisksServicePath
))),
120 weak_ptr_factory_(this) {
123 // CrosDisksClient override.
124 virtual void Mount(const std::string
& source_path
,
125 const std::string
& source_format
,
126 const std::string
& mount_label
,
128 const MountCallback
& callback
,
129 const ErrorCallback
& error_callback
) OVERRIDE
{
130 dbus::MethodCall
method_call(cros_disks::kCrosDisksInterface
,
132 dbus::MessageWriter
writer(&method_call
);
133 writer
.AppendString(source_path
);
134 writer
.AppendString(source_format
);
135 std::vector
<std::string
> mount_options(kDefaultMountOptions
,
136 kDefaultMountOptions
+
137 arraysize(kDefaultMountOptions
));
138 if (!mount_label
.empty()) {
139 std::string mount_label_option
= base::StringPrintf("%s=%s",
141 mount_label
.c_str());
142 mount_options
.push_back(mount_label_option
);
144 writer
.AppendArrayOfStrings(mount_options
);
145 proxy_
->CallMethod(&method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
146 base::Bind(&CrosDisksClientImpl::OnMount
,
147 weak_ptr_factory_
.GetWeakPtr(),
152 // CrosDisksClient override.
153 virtual void Unmount(const std::string
& device_path
,
154 UnmountOptions options
,
155 const UnmountCallback
& callback
,
156 const UnmountCallback
& error_callback
) OVERRIDE
{
157 dbus::MethodCall
method_call(cros_disks::kCrosDisksInterface
,
158 cros_disks::kUnmount
);
159 dbus::MessageWriter
writer(&method_call
);
160 writer
.AppendString(device_path
);
162 std::vector
<std::string
> unmount_options(
163 kDefaultUnmountOptions
,
164 kDefaultUnmountOptions
+ arraysize(kDefaultUnmountOptions
));
165 if (options
== UNMOUNT_OPTIONS_LAZY
)
166 unmount_options
.push_back(kLazyUnmountOption
);
168 writer
.AppendArrayOfStrings(unmount_options
);
169 proxy_
->CallMethod(&method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
170 base::Bind(&CrosDisksClientImpl::OnUnmount
,
171 weak_ptr_factory_
.GetWeakPtr(),
177 // CrosDisksClient override.
178 virtual void EnumerateAutoMountableDevices(
179 const EnumerateAutoMountableDevicesCallback
& callback
,
180 const ErrorCallback
& error_callback
) OVERRIDE
{
181 dbus::MethodCall
method_call(cros_disks::kCrosDisksInterface
,
182 cros_disks::kEnumerateAutoMountableDevices
);
184 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
185 base::Bind(&CrosDisksClientImpl::OnEnumerateAutoMountableDevices
,
186 weak_ptr_factory_
.GetWeakPtr(),
191 // CrosDisksClient override.
192 virtual void FormatDevice(const std::string
& device_path
,
193 const std::string
& filesystem
,
194 const FormatDeviceCallback
& callback
,
195 const ErrorCallback
& error_callback
) OVERRIDE
{
196 dbus::MethodCall
method_call(cros_disks::kCrosDisksInterface
,
197 cros_disks::kFormatDevice
);
198 dbus::MessageWriter
writer(&method_call
);
199 writer
.AppendString(device_path
);
200 writer
.AppendString(filesystem
);
201 proxy_
->CallMethod(&method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
202 base::Bind(&CrosDisksClientImpl::OnFormatDevice
,
203 weak_ptr_factory_
.GetWeakPtr(),
209 // CrosDisksClient override.
210 virtual void GetDeviceProperties(
211 const std::string
& device_path
,
212 const GetDevicePropertiesCallback
& callback
,
213 const ErrorCallback
& error_callback
) OVERRIDE
{
214 dbus::MethodCall
method_call(cros_disks::kCrosDisksInterface
,
215 cros_disks::kGetDeviceProperties
);
216 dbus::MessageWriter
writer(&method_call
);
217 writer
.AppendString(device_path
);
218 proxy_
->CallMethod(&method_call
,
219 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
220 base::Bind(&CrosDisksClientImpl::OnGetDeviceProperties
,
221 weak_ptr_factory_
.GetWeakPtr(),
227 // CrosDisksClient override.
228 virtual void SetUpConnections(
229 const MountEventHandler
& mount_event_handler
,
230 const MountCompletedHandler
& mount_completed_handler
) OVERRIDE
{
231 static const SignalEventTuple kSignalEventTuples
[] = {
232 { cros_disks::kDeviceAdded
, CROS_DISKS_DEVICE_ADDED
},
233 { cros_disks::kDeviceScanned
, CROS_DISKS_DEVICE_SCANNED
},
234 { cros_disks::kDeviceRemoved
, CROS_DISKS_DEVICE_REMOVED
},
235 { cros_disks::kDiskAdded
, CROS_DISKS_DISK_ADDED
},
236 { cros_disks::kDiskChanged
, CROS_DISKS_DISK_CHANGED
},
237 { cros_disks::kDiskRemoved
, CROS_DISKS_DISK_REMOVED
},
238 { cros_disks::kFormattingFinished
, CROS_DISKS_FORMATTING_FINISHED
},
240 const size_t kNumSignalEventTuples
= arraysize(kSignalEventTuples
);
242 for (size_t i
= 0; i
< kNumSignalEventTuples
; ++i
) {
243 proxy_
->ConnectToSignal(
244 cros_disks::kCrosDisksInterface
,
245 kSignalEventTuples
[i
].signal_name
,
246 base::Bind(&CrosDisksClientImpl::OnMountEvent
,
247 weak_ptr_factory_
.GetWeakPtr(),
248 kSignalEventTuples
[i
].event_type
,
249 mount_event_handler
),
250 base::Bind(&CrosDisksClientImpl::OnSignalConnected
,
251 weak_ptr_factory_
.GetWeakPtr()));
253 proxy_
->ConnectToSignal(
254 cros_disks::kCrosDisksInterface
,
255 cros_disks::kMountCompleted
,
256 base::Bind(&CrosDisksClientImpl::OnMountCompleted
,
257 weak_ptr_factory_
.GetWeakPtr(),
258 mount_completed_handler
),
259 base::Bind(&CrosDisksClientImpl::OnSignalConnected
,
260 weak_ptr_factory_
.GetWeakPtr()));
264 // A struct to contain a pair of signal name and mount event type.
265 // Used by SetUpConnections.
266 struct SignalEventTuple
{
267 const char *signal_name
;
268 MountEventType event_type
;
271 // Handles the result of Mount and calls |callback| or |error_callback|.
272 void OnMount(const MountCallback
& callback
,
273 const ErrorCallback
& error_callback
,
274 dbus::Response
* response
) {
276 error_callback
.Run();
282 // Handles the result of Unount and calls |callback| or |error_callback|.
283 void OnUnmount(const std::string
& device_path
,
284 const UnmountCallback
& callback
,
285 const UnmountCallback
& error_callback
,
286 dbus::Response
* response
) {
288 error_callback
.Run(device_path
);
291 callback
.Run(device_path
);
294 // Handles the result of EnumerateAutoMountableDevices and calls |callback| or
296 void OnEnumerateAutoMountableDevices(
297 const EnumerateAutoMountableDevicesCallback
& callback
,
298 const ErrorCallback
& error_callback
,
299 dbus::Response
* response
) {
301 error_callback
.Run();
304 dbus::MessageReader
reader(response
);
305 std::vector
<std::string
> device_paths
;
306 if (!reader
.PopArrayOfStrings(&device_paths
)) {
307 LOG(ERROR
) << "Invalid response: " << response
->ToString();
308 error_callback
.Run();
311 callback
.Run(device_paths
);
314 // Handles the result of FormatDevice and calls |callback| or
316 void OnFormatDevice(const std::string
& device_path
,
317 const FormatDeviceCallback
& callback
,
318 const ErrorCallback
& error_callback
,
319 dbus::Response
* response
) {
321 error_callback
.Run();
324 dbus::MessageReader
reader(response
);
325 bool success
= false;
326 if (!reader
.PopBool(&success
)) {
327 LOG(ERROR
) << "Invalid response: " << response
->ToString();
328 error_callback
.Run();
331 callback
.Run(device_path
, success
);
334 // Handles the result of GetDeviceProperties and calls |callback| or
336 void OnGetDeviceProperties(const std::string
& device_path
,
337 const GetDevicePropertiesCallback
& callback
,
338 const ErrorCallback
& error_callback
,
339 dbus::Response
* response
) {
341 error_callback
.Run();
344 DiskInfo
disk(device_path
, response
);
348 // Handles mount event signals and calls |handler|.
349 void OnMountEvent(MountEventType event_type
,
350 MountEventHandler handler
,
351 dbus::Signal
* signal
) {
352 dbus::MessageReader
reader(signal
);
354 if (!reader
.PopString(&device
)) {
355 LOG(ERROR
) << "Invalid signal: " << signal
->ToString();
358 handler
.Run(event_type
, device
);
361 // Handles MountCompleted signal and calls |handler|.
362 void OnMountCompleted(MountCompletedHandler handler
, dbus::Signal
* signal
) {
363 dbus::MessageReader
reader(signal
);
364 unsigned int error_code
= 0;
365 std::string source_path
;
366 unsigned int mount_type
= 0;
367 std::string mount_path
;
368 if (!reader
.PopUint32(&error_code
) ||
369 !reader
.PopString(&source_path
) ||
370 !reader
.PopUint32(&mount_type
) ||
371 !reader
.PopString(&mount_path
)) {
372 LOG(ERROR
) << "Invalid signal: " << signal
->ToString();
375 handler
.Run(static_cast<MountError
>(error_code
), source_path
,
376 static_cast<MountType
>(mount_type
), mount_path
);
379 // Handles the result of signal connection setup.
380 void OnSignalConnected(const std::string
& interface
,
381 const std::string
& signal
,
383 LOG_IF(ERROR
, !succeeded
) << "Connect to " << interface
<< " " <<
384 signal
<< " failed.";
387 dbus::ObjectProxy
* proxy_
;
389 // Note: This should remain the last member so it'll be destroyed and
390 // invalidate its weak pointers before any other members are destroyed.
391 base::WeakPtrFactory
<CrosDisksClientImpl
> weak_ptr_factory_
;
393 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientImpl
);
396 // A stub implementaion of CrosDisksClient.
397 class CrosDisksClientStubImpl
: public CrosDisksClient
{
399 CrosDisksClientStubImpl() {}
400 virtual ~CrosDisksClientStubImpl() {}
402 virtual void Mount(const std::string
& source_path
,
403 const std::string
& source_format
,
404 const std::string
& mount_label
,
406 const MountCallback
& callback
,
407 const ErrorCallback
& error_callback
) OVERRIDE
{}
408 virtual void Unmount(const std::string
& device_path
,
409 UnmountOptions options
,
410 const UnmountCallback
& callback
,
411 const UnmountCallback
& error_callback
) OVERRIDE
{}
412 virtual void EnumerateAutoMountableDevices(
413 const EnumerateAutoMountableDevicesCallback
& callback
,
414 const ErrorCallback
& error_callback
) OVERRIDE
{}
415 virtual void FormatDevice(const std::string
& device_path
,
416 const std::string
& filesystem
,
417 const FormatDeviceCallback
& callback
,
418 const ErrorCallback
& error_callback
) OVERRIDE
{}
419 virtual void GetDeviceProperties(
420 const std::string
& device_path
,
421 const GetDevicePropertiesCallback
& callback
,
422 const ErrorCallback
& error_callback
) OVERRIDE
{}
423 virtual void SetUpConnections(
424 const MountEventHandler
& mount_event_handler
,
425 const MountCompletedHandler
& mount_completed_handler
) OVERRIDE
{}
428 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientStubImpl
);
433 ////////////////////////////////////////////////////////////////////////////////
436 DiskInfo::DiskInfo(const std::string
& device_path
, dbus::Response
* response
)
437 : device_path_(device_path
),
440 on_boot_device_(false),
441 device_type_(DEVICE_TYPE_UNKNOWN
),
442 total_size_in_bytes_(0),
443 is_read_only_(false),
445 InitializeFromResponse(response
);
448 DiskInfo::~DiskInfo() {
451 // Initializes |this| from |response| given by the cros-disks service.
452 // Below is an example of |response|'s raw message (long string is ellipsized).
455 // message_type: MESSAGE_METHOD_RETURN
464 // string "DeviceFile"
465 // variant string "/dev/sdb"
468 // string "DeviceIsDrive"
472 // string "DeviceIsMediaAvailable"
476 // string "DeviceIsMounted"
477 // variant bool false
480 // string "DeviceIsOnBootDevice"
481 // variant bool false
484 // string "DeviceIsReadOnly"
485 // variant bool false
488 // string "DeviceIsVirtual"
489 // variant bool false
492 // string "DeviceMediaType"
496 // string "DeviceMountPaths"
501 // string "DevicePresentationHide"
505 // string "DeviceSize"
506 // variant uint64 7998537728
509 // string "DriveIsRotational"
510 // variant bool false
514 // variant string "18d1"
517 // string "VendorName"
518 // variant string "Google Inc."
521 // string "ProductId"
522 // variant string "4e11"
525 // string "ProductName"
526 // variant string "Nexus One"
529 // string "DriveModel"
530 // variant string "TransMemory"
541 // string "NativePath"
542 // variant string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/...
545 void DiskInfo::InitializeFromResponse(dbus::Response
* response
) {
546 dbus::MessageReader
response_reader(response
);
547 dbus::MessageReader
array_reader(response
);
548 if (!response_reader
.PopArray(&array_reader
)) {
549 LOG(ERROR
) << "Invalid response: " << response
->ToString();
552 // TODO(satorux): Rework this code using Protocol Buffers. crosbug.com/22626
553 typedef std::map
<std::string
, dbus::MessageReader
*> PropertiesMap
;
554 PropertiesMap properties
;
555 STLValueDeleter
<PropertiesMap
> properties_value_deleter(&properties
);
556 while (array_reader
.HasMoreData()) {
557 dbus::MessageReader
* value_reader
= new dbus::MessageReader(response
);
558 dbus::MessageReader
dict_entry_reader(response
);
560 if (!array_reader
.PopDictEntry(&dict_entry_reader
) ||
561 !dict_entry_reader
.PopString(&key
) ||
562 !dict_entry_reader
.PopVariant(value_reader
)) {
563 LOG(ERROR
) << "Invalid response: " << response
->ToString();
566 properties
[key
] = value_reader
;
568 MaybePopBool(properties
[cros_disks::kDeviceIsDrive
], &is_drive_
);
569 MaybePopBool(properties
[cros_disks::kDeviceIsReadOnly
], &is_read_only_
);
570 MaybePopBool(properties
[cros_disks::kDevicePresentationHide
], &is_hidden_
);
571 MaybePopBool(properties
[cros_disks::kDeviceIsMediaAvailable
], &has_media_
);
572 MaybePopBool(properties
[cros_disks::kDeviceIsOnBootDevice
],
574 MaybePopString(properties
[cros_disks::kNativePath
], &system_path_
);
575 MaybePopString(properties
[cros_disks::kDeviceFile
], &file_path_
);
576 MaybePopString(properties
[cros_disks::kVendorId
], &vendor_id_
);
577 MaybePopString(properties
[cros_disks::kVendorName
], &vendor_name_
);
578 MaybePopString(properties
[cros_disks::kProductId
], &product_id_
);
579 MaybePopString(properties
[cros_disks::kProductName
], &product_name_
);
580 MaybePopString(properties
[cros_disks::kDriveModel
], &drive_model_
);
581 MaybePopString(properties
[cros_disks::kIdLabel
], &label_
);
582 MaybePopString(properties
[cros_disks::kIdUuid
], &uuid_
);
583 MaybePopUint64(properties
[cros_disks::kDeviceSize
], &total_size_in_bytes_
);
585 uint32 media_type_uint32
= 0;
586 if (MaybePopUint32(properties
[cros_disks::kDeviceMediaType
],
587 &media_type_uint32
)) {
588 device_type_
= DeviceMediaTypeToDeviceType(media_type_uint32
);
591 std::vector
<std::string
> mount_paths
;
592 if (MaybePopArrayOfStrings(properties
[cros_disks::kDeviceMountPaths
],
593 &mount_paths
) && !mount_paths
.empty())
594 mount_path_
= mount_paths
[0];
597 ////////////////////////////////////////////////////////////////////////////////
600 CrosDisksClient::CrosDisksClient() {}
602 CrosDisksClient::~CrosDisksClient() {}
605 CrosDisksClient
* CrosDisksClient::Create(DBusClientImplementationType type
,
607 if (type
== REAL_DBUS_CLIENT_IMPLEMENTATION
)
608 return new CrosDisksClientImpl(bus
);
609 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION
, type
);
610 return new CrosDisksClientStubImpl();
613 } // namespace chromeos