blob: 441b7feb662cce3391ccc475216c4d63740ab2ee [file] [log] [blame]
[email protected]2321d282012-01-31 23:06:591// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]4ae73292011-11-15 05:20:182// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]64e199252012-04-06 01:54:365#include "chromeos/dbus/cros_disks_client.h"
[email protected]4ae73292011-11-15 05:20:186
7#include "base/bind.h"
[email protected]b307bceb2011-11-17 07:49:558#include "base/stl_util.h"
[email protected]4ae73292011-11-15 05:20:189#include "dbus/bus.h"
10#include "dbus/message.h"
[email protected]216ed0b2012-02-14 21:29:0611#include "dbus/object_path.h"
[email protected]4ae73292011-11-15 05:20:1812#include "dbus/object_proxy.h"
13#include "third_party/cros_system_api/dbus/service_constants.h"
14
15namespace chromeos {
16
17namespace {
18
19const char* kDefaultMountOptions[] = {
20 "rw",
21 "nodev",
22 "noexec",
23 "nosuid",
[email protected]4ae73292011-11-15 05:20:1824};
25
26const char* kDefaultUnmountOptions[] = {
27 "force",
28};
29
[email protected]2321d282012-01-31 23:06:5930// Checks if retrieved media type is in boundaries of DeviceMediaType.
31bool IsValidMediaType(uint32 type) {
32 return type < static_cast<uint32>(cros_disks::DEVICE_MEDIA_NUM_VALUES);
33}
34
35
36// Translates enum used in cros-disks to enum used in Chrome.
37// Note that we could just do static_cast, but this is less sensitive to
38// changes in cros-disks.
39DeviceType DeviceMediaTypeToDeviceType(uint32 media_type_uint32) {
40 if (!IsValidMediaType(media_type_uint32))
41 return DEVICE_TYPE_UNKNOWN;
42
43 cros_disks::DeviceMediaType media_type =
44 cros_disks::DeviceMediaType(media_type_uint32);
45
46 switch (media_type) {
47 case(cros_disks::DEVICE_MEDIA_UNKNOWN):
48 return DEVICE_TYPE_UNKNOWN;
49 case(cros_disks::DEVICE_MEDIA_USB):
50 return DEVICE_TYPE_USB;
51 case(cros_disks::DEVICE_MEDIA_SD):
52 return DEVICE_TYPE_SD;
53 case(cros_disks::DEVICE_MEDIA_OPTICAL_DISC):
54 return DEVICE_TYPE_OPTICAL_DISC;
55 case(cros_disks::DEVICE_MEDIA_MOBILE):
56 return DEVICE_TYPE_MOBILE;
57 default:
58 return DEVICE_TYPE_UNKNOWN;
59 }
[email protected]4ae73292011-11-15 05:20:1860}
61
62// Pops a bool value when |reader| is not NULL.
63// Returns true when a value is popped, false otherwise.
64bool MaybePopBool(dbus::MessageReader* reader, bool* value) {
65 if (!reader)
66 return false;
67 return reader->PopBool(value);
68}
69
70// Pops a string value when |reader| is not NULL.
71// Returns true when a value is popped, false otherwise.
72bool MaybePopString(dbus::MessageReader* reader, std::string* value) {
73 if (!reader)
74 return false;
75 return reader->PopString(value);
76}
77
[email protected]2321d282012-01-31 23:06:5978// Pops a uint32 value when |reader| is not NULL.
79// Returns true when a value is popped, false otherwise.
80bool MaybePopUint32(dbus::MessageReader* reader, uint32* value) {
81 if (!reader)
82 return false;
83
84 return reader->PopUint32(value);
85}
86
[email protected]4ae73292011-11-15 05:20:1887// Pops a uint64 value when |reader| is not NULL.
88// Returns true when a value is popped, false otherwise.
89bool MaybePopUint64(dbus::MessageReader* reader, uint64* value) {
90 if (!reader)
91 return false;
92 return reader->PopUint64(value);
93}
94
95// Pops an array of strings when |reader| is not NULL.
96// Returns true when an array is popped, false otherwise.
97bool MaybePopArrayOfStrings(dbus::MessageReader* reader,
98 std::vector<std::string>* value) {
99 if (!reader)
100 return false;
101 return reader->PopArrayOfStrings(value);
102}
103
104// The CrosDisksClient implementation.
105class CrosDisksClientImpl : public CrosDisksClient {
106 public:
107 explicit CrosDisksClientImpl(dbus::Bus* bus)
[email protected]216ed0b2012-02-14 21:29:06108 : proxy_(bus->GetObjectProxy(
109 cros_disks::kCrosDisksServiceName,
110 dbus::ObjectPath(cros_disks::kCrosDisksServicePath))),
[email protected]4ae73292011-11-15 05:20:18111 weak_ptr_factory_(this) {
112 }
113
114 // CrosDisksClient override.
115 virtual void Mount(const std::string& source_path,
116 MountType type,
[email protected]4a404e52012-04-11 02:25:35117 const MountCallback& callback,
118 const ErrorCallback& error_callback) OVERRIDE {
[email protected]4ae73292011-11-15 05:20:18119 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
120 cros_disks::kMount);
121 dbus::MessageWriter writer(&method_call);
122 writer.AppendString(source_path);
123 writer.AppendString(""); // auto detect filesystem.
124 std::vector<std::string> mount_options(kDefaultMountOptions,
125 kDefaultMountOptions +
126 arraysize(kDefaultMountOptions));
127 writer.AppendArrayOfStrings(mount_options);
128 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
129 base::Bind(&CrosDisksClientImpl::OnMount,
130 weak_ptr_factory_.GetWeakPtr(),
131 callback,
132 error_callback));
133 }
134
135 // CrosDisksClient override.
136 virtual void Unmount(const std::string& device_path,
[email protected]4a404e52012-04-11 02:25:35137 const UnmountCallback& callback,
138 const ErrorCallback& error_callback) OVERRIDE {
[email protected]4ae73292011-11-15 05:20:18139 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
140 cros_disks::kUnmount);
141 dbus::MessageWriter writer(&method_call);
142 writer.AppendString(device_path);
143 std::vector<std::string> unmount_options(kDefaultUnmountOptions,
144 kDefaultUnmountOptions +
145 arraysize(kDefaultUnmountOptions));
146 writer.AppendArrayOfStrings(unmount_options);
147 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
148 base::Bind(&CrosDisksClientImpl::OnUnmount,
149 weak_ptr_factory_.GetWeakPtr(),
150 device_path,
151 callback,
152 error_callback));
153 }
154
155 // CrosDisksClient override.
156 virtual void EnumerateAutoMountableDevices(
[email protected]4a404e52012-04-11 02:25:35157 const EnumerateAutoMountableDevicesCallback& callback,
158 const ErrorCallback& error_callback) OVERRIDE {
[email protected]4ae73292011-11-15 05:20:18159 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
160 cros_disks::kEnumerateAutoMountableDevices);
161 proxy_->CallMethod(
162 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
163 base::Bind(&CrosDisksClientImpl::OnEnumerateAutoMountableDevices,
164 weak_ptr_factory_.GetWeakPtr(),
165 callback,
166 error_callback));
167 }
168
169 // CrosDisksClient override.
170 virtual void FormatDevice(const std::string& device_path,
171 const std::string& filesystem,
[email protected]4a404e52012-04-11 02:25:35172 const FormatDeviceCallback& callback,
173 const ErrorCallback& error_callback) OVERRIDE {
[email protected]4ae73292011-11-15 05:20:18174 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
175 cros_disks::kFormatDevice);
176 dbus::MessageWriter writer(&method_call);
177 writer.AppendString(device_path);
178 writer.AppendString(filesystem);
179 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
180 base::Bind(&CrosDisksClientImpl::OnFormatDevice,
181 weak_ptr_factory_.GetWeakPtr(),
182 device_path,
183 callback,
184 error_callback));
185 }
186
187 // CrosDisksClient override.
[email protected]4a404e52012-04-11 02:25:35188 virtual void GetDeviceProperties(
189 const std::string& device_path,
190 const GetDevicePropertiesCallback& callback,
191 const ErrorCallback& error_callback) OVERRIDE {
[email protected]4ae73292011-11-15 05:20:18192 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
193 cros_disks::kGetDeviceProperties);
194 dbus::MessageWriter writer(&method_call);
195 writer.AppendString(device_path);
196 proxy_->CallMethod(&method_call,
197 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
198 base::Bind(&CrosDisksClientImpl::OnGetDeviceProperties,
199 weak_ptr_factory_.GetWeakPtr(),
200 device_path,
201 callback,
202 error_callback));
203 }
204
205 // CrosDisksClient override.
206 virtual void SetUpConnections(
[email protected]4a404e52012-04-11 02:25:35207 const MountEventHandler& mount_event_handler,
208 const MountCompletedHandler& mount_completed_handler) OVERRIDE {
[email protected]4ae73292011-11-15 05:20:18209 static const SignalEventTuple kSignalEventTuples[] = {
[email protected]b3e3f492011-11-18 18:46:00210 { cros_disks::kDeviceAdded, DEVICE_ADDED },
211 { cros_disks::kDeviceScanned, DEVICE_SCANNED },
212 { cros_disks::kDeviceRemoved, DEVICE_REMOVED },
213 { cros_disks::kDiskAdded, DISK_ADDED },
214 { cros_disks::kDiskChanged, DISK_CHANGED },
215 { cros_disks::kDiskRemoved, DISK_REMOVED },
216 { cros_disks::kFormattingFinished, FORMATTING_FINISHED },
[email protected]4ae73292011-11-15 05:20:18217 };
218 const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples);
219
220 for (size_t i = 0; i < kNumSignalEventTuples; ++i) {
221 proxy_->ConnectToSignal(
222 cros_disks::kCrosDisksInterface,
223 kSignalEventTuples[i].signal_name,
224 base::Bind(&CrosDisksClientImpl::OnMountEvent,
225 weak_ptr_factory_.GetWeakPtr(),
226 kSignalEventTuples[i].event_type,
227 mount_event_handler),
228 base::Bind(&CrosDisksClientImpl::OnSignalConnected,
229 weak_ptr_factory_.GetWeakPtr()));
230 }
231 proxy_->ConnectToSignal(
232 cros_disks::kCrosDisksInterface,
[email protected]b3e3f492011-11-18 18:46:00233 cros_disks::kMountCompleted,
[email protected]4ae73292011-11-15 05:20:18234 base::Bind(&CrosDisksClientImpl::OnMountCompleted,
235 weak_ptr_factory_.GetWeakPtr(),
236 mount_completed_handler ),
237 base::Bind(&CrosDisksClientImpl::OnSignalConnected,
238 weak_ptr_factory_.GetWeakPtr()));
239 }
240
241 private:
242 // A struct to contain a pair of signal name and mount event type.
243 // Used by SetUpConnections.
244 struct SignalEventTuple {
245 const char *signal_name;
246 MountEventType event_type;
247 };
248
249 // Handles the result of Mount and calls |callback| or |error_callback|.
[email protected]4a404e52012-04-11 02:25:35250 void OnMount(const MountCallback& callback,
251 const ErrorCallback& error_callback,
[email protected]4ae73292011-11-15 05:20:18252 dbus::Response* response) {
253 if (!response) {
254 error_callback.Run();
255 return;
256 }
257 callback.Run();
258 }
259
260 // Handles the result of Unount and calls |callback| or |error_callback|.
261 void OnUnmount(const std::string& device_path,
[email protected]4a404e52012-04-11 02:25:35262 const UnmountCallback& callback,
263 const ErrorCallback& error_callback,
[email protected]4ae73292011-11-15 05:20:18264 dbus::Response* response) {
265 if (!response) {
266 error_callback.Run();
267 return;
268 }
269 callback.Run(device_path);
270 }
271
272 // Handles the result of EnumerateAutoMountableDevices and calls |callback| or
273 // |error_callback|.
274 void OnEnumerateAutoMountableDevices(
[email protected]4a404e52012-04-11 02:25:35275 const EnumerateAutoMountableDevicesCallback& callback,
276 const ErrorCallback& error_callback,
[email protected]4ae73292011-11-15 05:20:18277 dbus::Response* response) {
278 if (!response) {
279 error_callback.Run();
280 return;
281 }
282 dbus::MessageReader reader(response);
283 std::vector<std::string> device_paths;
284 if (!reader.PopArrayOfStrings(&device_paths)) {
285 LOG(ERROR) << "Invalid response: " << response->ToString();
286 error_callback.Run();
287 return;
288 }
289 callback.Run(device_paths);
290 }
291
292 // Handles the result of FormatDevice and calls |callback| or
293 // |error_callback|.
294 void OnFormatDevice(const std::string& device_path,
[email protected]4a404e52012-04-11 02:25:35295 const FormatDeviceCallback& callback,
296 const ErrorCallback& error_callback,
[email protected]4ae73292011-11-15 05:20:18297 dbus::Response* response) {
298 if (!response) {
299 error_callback.Run();
300 return;
301 }
302 dbus::MessageReader reader(response);
303 bool success = false;
304 if (!reader.PopBool(&success)) {
305 LOG(ERROR) << "Invalid response: " << response->ToString();
306 error_callback.Run();
307 return;
308 }
309 callback.Run(device_path, success);
310 }
311
312 // Handles the result of GetDeviceProperties and calls |callback| or
313 // |error_callback|.
314 void OnGetDeviceProperties(const std::string& device_path,
[email protected]4a404e52012-04-11 02:25:35315 const GetDevicePropertiesCallback& callback,
316 const ErrorCallback& error_callback,
[email protected]4ae73292011-11-15 05:20:18317 dbus::Response* response) {
318 if (!response) {
319 error_callback.Run();
320 return;
321 }
322 DiskInfo disk(device_path, response);
323 callback.Run(disk);
324 }
325
326 // Handles mount event signals and calls |handler|.
327 void OnMountEvent(MountEventType event_type,
328 MountEventHandler handler,
329 dbus::Signal* signal) {
330 dbus::MessageReader reader(signal);
331 std::string device;
332 if (!reader.PopString(&device)) {
333 LOG(ERROR) << "Invalid signal: " << signal->ToString();
334 return;
335 }
336 handler.Run(event_type, device);
337 }
338
339 // Handles MountCompleted signal and calls |handler|.
340 void OnMountCompleted(MountCompletedHandler handler, dbus::Signal* signal) {
341 dbus::MessageReader reader(signal);
342 unsigned int error_code = 0;
343 std::string source_path;
344 unsigned int mount_type = 0;
345 std::string mount_path;
346 if (!reader.PopUint32(&error_code) ||
347 !reader.PopString(&source_path) ||
348 !reader.PopUint32(&mount_type) ||
349 !reader.PopString(&mount_path)) {
350 LOG(ERROR) << "Invalid signal: " << signal->ToString();
351 return;
352 }
353 handler.Run(static_cast<MountError>(error_code), source_path,
354 static_cast<MountType>(mount_type), mount_path);
355 }
356
357 // Handles the result of signal connection setup.
358 void OnSignalConnected(const std::string& interface,
359 const std::string& signal,
360 bool successed) {
361 LOG_IF(ERROR, !successed) << "Connect to " << interface << " " <<
362 signal << " failed.";
363 }
364
365 dbus::ObjectProxy* proxy_;
366 base::WeakPtrFactory<CrosDisksClientImpl> weak_ptr_factory_;
367
368 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientImpl);
369};
370
371// A stub implementaion of CrosDisksClient.
372class CrosDisksClientStubImpl : public CrosDisksClient {
373 public:
374 CrosDisksClientStubImpl() {}
375 virtual ~CrosDisksClientStubImpl() {}
376
377 virtual void Mount(const std::string& source_path,
378 MountType type,
[email protected]4a404e52012-04-11 02:25:35379 const MountCallback& callback,
380 const ErrorCallback& error_callback) OVERRIDE {}
[email protected]4ae73292011-11-15 05:20:18381 virtual void Unmount(const std::string& device_path,
[email protected]4a404e52012-04-11 02:25:35382 const UnmountCallback& callback,
383 const ErrorCallback& error_callback) OVERRIDE {}
[email protected]4ae73292011-11-15 05:20:18384 virtual void EnumerateAutoMountableDevices(
[email protected]4a404e52012-04-11 02:25:35385 const EnumerateAutoMountableDevicesCallback& callback,
386 const ErrorCallback& error_callback) OVERRIDE {}
[email protected]4ae73292011-11-15 05:20:18387 virtual void FormatDevice(const std::string& device_path,
388 const std::string& filesystem,
[email protected]4a404e52012-04-11 02:25:35389 const FormatDeviceCallback& callback,
390 const ErrorCallback& error_callback) OVERRIDE {}
391 virtual void GetDeviceProperties(
392 const std::string& device_path,
393 const GetDevicePropertiesCallback& callback,
394 const ErrorCallback& error_callback) OVERRIDE {}
[email protected]4ae73292011-11-15 05:20:18395 virtual void SetUpConnections(
[email protected]4a404e52012-04-11 02:25:35396 const MountEventHandler& mount_event_handler,
397 const MountCompletedHandler& mount_completed_handler) OVERRIDE {}
[email protected]4ae73292011-11-15 05:20:18398
399 private:
400 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientStubImpl);
401};
402
403} // namespace
404
405////////////////////////////////////////////////////////////////////////////////
406// DiskInfo
407
408DiskInfo::DiskInfo(const std::string& device_path, dbus::Response* response)
409 : device_path_(device_path),
410 is_drive_(false),
411 has_media_(false),
412 on_boot_device_(false),
[email protected]2321d282012-01-31 23:06:59413 device_type_(DEVICE_TYPE_UNKNOWN),
[email protected]4ae73292011-11-15 05:20:18414 total_size_in_bytes_(0),
415 is_read_only_(false),
416 is_hidden_(true) {
417 InitializeFromResponse(response);
418}
419
420DiskInfo::~DiskInfo() {
421}
422
423// Initialize |this| from |response| given by the cros-disks service.
424// Below is an example of |response|'s raw message (long string is ellipsized).
425//
426//
427// message_type: MESSAGE_METHOD_RETURN
428// destination: :1.8
429// sender: :1.16
430// signature: a{sv}
431// serial: 96
432// reply_serial: 267
433//
434// array [
435// dict entry {
436// string "DeviceFile"
437// variant string "/dev/sdb"
438// }
439// dict entry {
440// string "DeviceIsDrive"
441// variant bool true
442// }
443// dict entry {
444// string "DeviceIsMediaAvailable"
445// variant bool true
446// }
447// dict entry {
448// string "DeviceIsMounted"
449// variant bool false
450// }
451// dict entry {
452// string "DeviceIsOnBootDevice"
453// variant bool false
454// }
455// dict entry {
456// string "DeviceIsOpticalDisc"
457// variant bool false
458// }
459// dict entry {
460// string "DeviceIsReadOnly"
461// variant bool false
462// }
463// dict entry {
464// string "DeviceIsVirtual"
465// variant bool false
466// }
467// dict entry {
468// string "DeviceMediaType"
469// variant uint32 1
470// }
471// dict entry {
472// string "DeviceMountPaths"
473// variant array [
474// ]
475// }
476// dict entry {
477// string "DevicePresentationHide"
478// variant bool true
479// }
480// dict entry {
481// string "DeviceSize"
482// variant uint64 7998537728
483// }
484// dict entry {
485// string "DriveIsRotational"
486// variant bool false
487// }
488// dict entry {
489// string "DriveModel"
490// variant string "TransMemory"
491// }
492// dict entry {
493// string "IdLabel"
494// variant string ""
495// }
496// dict entry {
497// string "IdUuid"
498// variant string ""
499// }
500// dict entry {
501// string "NativePath"
502// variant string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/...
503// }
504// ]
505void DiskInfo::InitializeFromResponse(dbus::Response* response) {
506 dbus::MessageReader response_reader(response);
507 dbus::MessageReader array_reader(response);
508 if (!response_reader.PopArray(&array_reader)) {
509 LOG(ERROR) << "Invalid response: " << response->ToString();
510 return;
511 }
512 // TODO(satorux): Rework this code using Protocol Buffers. crosbug.com/22626
[email protected]b307bceb2011-11-17 07:49:55513 typedef std::map<std::string, dbus::MessageReader*> PropertiesMap;
514 PropertiesMap properties;
515 STLValueDeleter<PropertiesMap> properties_value_deleter(&properties);
[email protected]4ae73292011-11-15 05:20:18516 while (array_reader.HasMoreData()) {
[email protected]4ae73292011-11-15 05:20:18517 dbus::MessageReader* value_reader = new dbus::MessageReader(response);
[email protected]4ae73292011-11-15 05:20:18518 dbus::MessageReader dict_entry_reader(response);
519 std::string key;
520 if (!array_reader.PopDictEntry(&dict_entry_reader) ||
521 !dict_entry_reader.PopString(&key) ||
522 !dict_entry_reader.PopVariant(value_reader)) {
523 LOG(ERROR) << "Invalid response: " << response->ToString();
524 return;
525 }
526 properties[key] = value_reader;
527 }
528 MaybePopBool(properties[cros_disks::kDeviceIsDrive], &is_drive_);
529 MaybePopBool(properties[cros_disks::kDeviceIsReadOnly], &is_read_only_);
530 MaybePopBool(properties[cros_disks::kDevicePresentationHide], &is_hidden_);
531 MaybePopBool(properties[cros_disks::kDeviceIsMediaAvailable], &has_media_);
532 MaybePopBool(properties[cros_disks::kDeviceIsOnBootDevice],
533 &on_boot_device_);
534 MaybePopString(properties[cros_disks::kNativePath], &system_path_);
535 MaybePopString(properties[cros_disks::kDeviceFile], &file_path_);
536 MaybePopString(properties[cros_disks::kDriveModel], &drive_model_);
537 MaybePopString(properties[cros_disks::kIdLabel], &label_);
538 MaybePopUint64(properties[cros_disks::kDeviceSize], &total_size_in_bytes_);
539
[email protected]2321d282012-01-31 23:06:59540 uint32 media_type_uint32 = 0;
541 if (MaybePopUint32(properties[cros_disks::kDeviceMediaType],
542 &media_type_uint32)) {
543 device_type_ = DeviceMediaTypeToDeviceType(media_type_uint32);
544 }
545
[email protected]4ae73292011-11-15 05:20:18546 std::vector<std::string> mount_paths;
547 if (MaybePopArrayOfStrings(properties[cros_disks::kDeviceMountPaths],
548 &mount_paths) && !mount_paths.empty())
549 mount_path_ = mount_paths[0];
[email protected]4ae73292011-11-15 05:20:18550}
551
552////////////////////////////////////////////////////////////////////////////////
553// CrosDisksClient
554
555CrosDisksClient::CrosDisksClient() {}
556
557CrosDisksClient::~CrosDisksClient() {}
558
559// static
[email protected]e8db03d62012-03-31 04:08:38560CrosDisksClient* CrosDisksClient::Create(DBusClientImplementationType type,
561 dbus::Bus* bus) {
562 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
[email protected]4ae73292011-11-15 05:20:18563 return new CrosDisksClientImpl(bus);
[email protected]e8db03d62012-03-31 04:08:38564 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
565 return new CrosDisksClientStubImpl();
[email protected]4ae73292011-11-15 05:20:18566}
567
568} // namespace chromeos