blob: 217382cf17a8d2bad819c89d3470097abfd483c1 [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,
117 MountCallback callback,
118 ErrorCallback error_callback) OVERRIDE {
119 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,
137 UnmountCallback callback,
138 ErrorCallback error_callback) OVERRIDE {
139 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(
157 EnumerateAutoMountableDevicesCallback callback,
158 ErrorCallback error_callback) OVERRIDE {
159 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,
172 FormatDeviceCallback callback,
173 ErrorCallback error_callback) OVERRIDE {
174 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.
188 virtual void GetDeviceProperties(const std::string& device_path,
189 GetDevicePropertiesCallback callback,
190 ErrorCallback error_callback) OVERRIDE {
191 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
192 cros_disks::kGetDeviceProperties);
193 dbus::MessageWriter writer(&method_call);
194 writer.AppendString(device_path);
195 proxy_->CallMethod(&method_call,
196 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
197 base::Bind(&CrosDisksClientImpl::OnGetDeviceProperties,
198 weak_ptr_factory_.GetWeakPtr(),
199 device_path,
200 callback,
201 error_callback));
202 }
203
204 // CrosDisksClient override.
205 virtual void SetUpConnections(
206 MountEventHandler mount_event_handler,
207 MountCompletedHandler mount_completed_handler) OVERRIDE {
208 static const SignalEventTuple kSignalEventTuples[] = {
[email protected]b3e3f492011-11-18 18:46:00209 { cros_disks::kDeviceAdded, DEVICE_ADDED },
210 { cros_disks::kDeviceScanned, DEVICE_SCANNED },
211 { cros_disks::kDeviceRemoved, DEVICE_REMOVED },
212 { cros_disks::kDiskAdded, DISK_ADDED },
213 { cros_disks::kDiskChanged, DISK_CHANGED },
214 { cros_disks::kDiskRemoved, DISK_REMOVED },
215 { cros_disks::kFormattingFinished, FORMATTING_FINISHED },
[email protected]4ae73292011-11-15 05:20:18216 };
217 const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples);
218
219 for (size_t i = 0; i < kNumSignalEventTuples; ++i) {
220 proxy_->ConnectToSignal(
221 cros_disks::kCrosDisksInterface,
222 kSignalEventTuples[i].signal_name,
223 base::Bind(&CrosDisksClientImpl::OnMountEvent,
224 weak_ptr_factory_.GetWeakPtr(),
225 kSignalEventTuples[i].event_type,
226 mount_event_handler),
227 base::Bind(&CrosDisksClientImpl::OnSignalConnected,
228 weak_ptr_factory_.GetWeakPtr()));
229 }
230 proxy_->ConnectToSignal(
231 cros_disks::kCrosDisksInterface,
[email protected]b3e3f492011-11-18 18:46:00232 cros_disks::kMountCompleted,
[email protected]4ae73292011-11-15 05:20:18233 base::Bind(&CrosDisksClientImpl::OnMountCompleted,
234 weak_ptr_factory_.GetWeakPtr(),
235 mount_completed_handler ),
236 base::Bind(&CrosDisksClientImpl::OnSignalConnected,
237 weak_ptr_factory_.GetWeakPtr()));
238 }
239
240 private:
241 // A struct to contain a pair of signal name and mount event type.
242 // Used by SetUpConnections.
243 struct SignalEventTuple {
244 const char *signal_name;
245 MountEventType event_type;
246 };
247
248 // Handles the result of Mount and calls |callback| or |error_callback|.
249 void OnMount(MountCallback callback,
250 ErrorCallback error_callback,
251 dbus::Response* response) {
252 if (!response) {
253 error_callback.Run();
254 return;
255 }
256 callback.Run();
257 }
258
259 // Handles the result of Unount and calls |callback| or |error_callback|.
260 void OnUnmount(const std::string& device_path,
261 UnmountCallback callback,
262 ErrorCallback error_callback,
263 dbus::Response* response) {
264 if (!response) {
265 error_callback.Run();
266 return;
267 }
268 callback.Run(device_path);
269 }
270
271 // Handles the result of EnumerateAutoMountableDevices and calls |callback| or
272 // |error_callback|.
273 void OnEnumerateAutoMountableDevices(
274 EnumerateAutoMountableDevicesCallback callback,
275 ErrorCallback error_callback,
276 dbus::Response* response) {
277 if (!response) {
278 error_callback.Run();
279 return;
280 }
281 dbus::MessageReader reader(response);
282 std::vector<std::string> device_paths;
283 if (!reader.PopArrayOfStrings(&device_paths)) {
284 LOG(ERROR) << "Invalid response: " << response->ToString();
285 error_callback.Run();
286 return;
287 }
288 callback.Run(device_paths);
289 }
290
291 // Handles the result of FormatDevice and calls |callback| or
292 // |error_callback|.
293 void OnFormatDevice(const std::string& device_path,
294 FormatDeviceCallback callback,
295 ErrorCallback error_callback,
296 dbus::Response* response) {
297 if (!response) {
298 error_callback.Run();
299 return;
300 }
301 dbus::MessageReader reader(response);
302 bool success = false;
303 if (!reader.PopBool(&success)) {
304 LOG(ERROR) << "Invalid response: " << response->ToString();
305 error_callback.Run();
306 return;
307 }
308 callback.Run(device_path, success);
309 }
310
311 // Handles the result of GetDeviceProperties and calls |callback| or
312 // |error_callback|.
313 void OnGetDeviceProperties(const std::string& device_path,
314 GetDevicePropertiesCallback callback,
315 ErrorCallback error_callback,
316 dbus::Response* response) {
317 if (!response) {
318 error_callback.Run();
319 return;
320 }
321 DiskInfo disk(device_path, response);
322 callback.Run(disk);
323 }
324
325 // Handles mount event signals and calls |handler|.
326 void OnMountEvent(MountEventType event_type,
327 MountEventHandler handler,
328 dbus::Signal* signal) {
329 dbus::MessageReader reader(signal);
330 std::string device;
331 if (!reader.PopString(&device)) {
332 LOG(ERROR) << "Invalid signal: " << signal->ToString();
333 return;
334 }
335 handler.Run(event_type, device);
336 }
337
338 // Handles MountCompleted signal and calls |handler|.
339 void OnMountCompleted(MountCompletedHandler handler, dbus::Signal* signal) {
340 dbus::MessageReader reader(signal);
341 unsigned int error_code = 0;
342 std::string source_path;
343 unsigned int mount_type = 0;
344 std::string mount_path;
345 if (!reader.PopUint32(&error_code) ||
346 !reader.PopString(&source_path) ||
347 !reader.PopUint32(&mount_type) ||
348 !reader.PopString(&mount_path)) {
349 LOG(ERROR) << "Invalid signal: " << signal->ToString();
350 return;
351 }
352 handler.Run(static_cast<MountError>(error_code), source_path,
353 static_cast<MountType>(mount_type), mount_path);
354 }
355
356 // Handles the result of signal connection setup.
357 void OnSignalConnected(const std::string& interface,
358 const std::string& signal,
359 bool successed) {
360 LOG_IF(ERROR, !successed) << "Connect to " << interface << " " <<
361 signal << " failed.";
362 }
363
364 dbus::ObjectProxy* proxy_;
365 base::WeakPtrFactory<CrosDisksClientImpl> weak_ptr_factory_;
366
367 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientImpl);
368};
369
370// A stub implementaion of CrosDisksClient.
371class CrosDisksClientStubImpl : public CrosDisksClient {
372 public:
373 CrosDisksClientStubImpl() {}
374 virtual ~CrosDisksClientStubImpl() {}
375
376 virtual void Mount(const std::string& source_path,
377 MountType type,
378 MountCallback callback,
379 ErrorCallback error_callback) OVERRIDE {}
380 virtual void Unmount(const std::string& device_path,
381 UnmountCallback callback,
382 ErrorCallback error_callback) OVERRIDE {}
383 virtual void EnumerateAutoMountableDevices(
384 EnumerateAutoMountableDevicesCallback callback,
385 ErrorCallback error_callback) OVERRIDE {}
386 virtual void FormatDevice(const std::string& device_path,
387 const std::string& filesystem,
388 FormatDeviceCallback callback,
389 ErrorCallback error_callback) OVERRIDE {}
390 virtual void GetDeviceProperties(const std::string& device_path,
391 GetDevicePropertiesCallback callback,
392 ErrorCallback error_callback) OVERRIDE {}
393 virtual void SetUpConnections(
394 MountEventHandler mount_event_handler,
395 MountCompletedHandler mount_completed_handler) OVERRIDE {}
396
397 private:
398 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientStubImpl);
399};
400
401} // namespace
402
403////////////////////////////////////////////////////////////////////////////////
404// DiskInfo
405
406DiskInfo::DiskInfo(const std::string& device_path, dbus::Response* response)
407 : device_path_(device_path),
408 is_drive_(false),
409 has_media_(false),
410 on_boot_device_(false),
[email protected]2321d282012-01-31 23:06:59411 device_type_(DEVICE_TYPE_UNKNOWN),
[email protected]4ae73292011-11-15 05:20:18412 total_size_in_bytes_(0),
413 is_read_only_(false),
414 is_hidden_(true) {
415 InitializeFromResponse(response);
416}
417
418DiskInfo::~DiskInfo() {
419}
420
421// Initialize |this| from |response| given by the cros-disks service.
422// Below is an example of |response|'s raw message (long string is ellipsized).
423//
424//
425// message_type: MESSAGE_METHOD_RETURN
426// destination: :1.8
427// sender: :1.16
428// signature: a{sv}
429// serial: 96
430// reply_serial: 267
431//
432// array [
433// dict entry {
434// string "DeviceFile"
435// variant string "/dev/sdb"
436// }
437// dict entry {
438// string "DeviceIsDrive"
439// variant bool true
440// }
441// dict entry {
442// string "DeviceIsMediaAvailable"
443// variant bool true
444// }
445// dict entry {
446// string "DeviceIsMounted"
447// variant bool false
448// }
449// dict entry {
450// string "DeviceIsOnBootDevice"
451// variant bool false
452// }
453// dict entry {
454// string "DeviceIsOpticalDisc"
455// variant bool false
456// }
457// dict entry {
458// string "DeviceIsReadOnly"
459// variant bool false
460// }
461// dict entry {
462// string "DeviceIsVirtual"
463// variant bool false
464// }
465// dict entry {
466// string "DeviceMediaType"
467// variant uint32 1
468// }
469// dict entry {
470// string "DeviceMountPaths"
471// variant array [
472// ]
473// }
474// dict entry {
475// string "DevicePresentationHide"
476// variant bool true
477// }
478// dict entry {
479// string "DeviceSize"
480// variant uint64 7998537728
481// }
482// dict entry {
483// string "DriveIsRotational"
484// variant bool false
485// }
486// dict entry {
487// string "DriveModel"
488// variant string "TransMemory"
489// }
490// dict entry {
491// string "IdLabel"
492// variant string ""
493// }
494// dict entry {
495// string "IdUuid"
496// variant string ""
497// }
498// dict entry {
499// string "NativePath"
500// variant string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/...
501// }
502// ]
503void DiskInfo::InitializeFromResponse(dbus::Response* response) {
504 dbus::MessageReader response_reader(response);
505 dbus::MessageReader array_reader(response);
506 if (!response_reader.PopArray(&array_reader)) {
507 LOG(ERROR) << "Invalid response: " << response->ToString();
508 return;
509 }
510 // TODO(satorux): Rework this code using Protocol Buffers. crosbug.com/22626
[email protected]b307bceb2011-11-17 07:49:55511 typedef std::map<std::string, dbus::MessageReader*> PropertiesMap;
512 PropertiesMap properties;
513 STLValueDeleter<PropertiesMap> properties_value_deleter(&properties);
[email protected]4ae73292011-11-15 05:20:18514 while (array_reader.HasMoreData()) {
[email protected]4ae73292011-11-15 05:20:18515 dbus::MessageReader* value_reader = new dbus::MessageReader(response);
[email protected]4ae73292011-11-15 05:20:18516 dbus::MessageReader dict_entry_reader(response);
517 std::string key;
518 if (!array_reader.PopDictEntry(&dict_entry_reader) ||
519 !dict_entry_reader.PopString(&key) ||
520 !dict_entry_reader.PopVariant(value_reader)) {
521 LOG(ERROR) << "Invalid response: " << response->ToString();
522 return;
523 }
524 properties[key] = value_reader;
525 }
526 MaybePopBool(properties[cros_disks::kDeviceIsDrive], &is_drive_);
527 MaybePopBool(properties[cros_disks::kDeviceIsReadOnly], &is_read_only_);
528 MaybePopBool(properties[cros_disks::kDevicePresentationHide], &is_hidden_);
529 MaybePopBool(properties[cros_disks::kDeviceIsMediaAvailable], &has_media_);
530 MaybePopBool(properties[cros_disks::kDeviceIsOnBootDevice],
531 &on_boot_device_);
532 MaybePopString(properties[cros_disks::kNativePath], &system_path_);
533 MaybePopString(properties[cros_disks::kDeviceFile], &file_path_);
534 MaybePopString(properties[cros_disks::kDriveModel], &drive_model_);
535 MaybePopString(properties[cros_disks::kIdLabel], &label_);
536 MaybePopUint64(properties[cros_disks::kDeviceSize], &total_size_in_bytes_);
537
[email protected]2321d282012-01-31 23:06:59538 uint32 media_type_uint32 = 0;
539 if (MaybePopUint32(properties[cros_disks::kDeviceMediaType],
540 &media_type_uint32)) {
541 device_type_ = DeviceMediaTypeToDeviceType(media_type_uint32);
542 }
543
[email protected]4ae73292011-11-15 05:20:18544 std::vector<std::string> mount_paths;
545 if (MaybePopArrayOfStrings(properties[cros_disks::kDeviceMountPaths],
546 &mount_paths) && !mount_paths.empty())
547 mount_path_ = mount_paths[0];
[email protected]4ae73292011-11-15 05:20:18548}
549
550////////////////////////////////////////////////////////////////////////////////
551// CrosDisksClient
552
553CrosDisksClient::CrosDisksClient() {}
554
555CrosDisksClient::~CrosDisksClient() {}
556
557// static
[email protected]e8db03d62012-03-31 04:08:38558CrosDisksClient* CrosDisksClient::Create(DBusClientImplementationType type,
559 dbus::Bus* bus) {
560 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
[email protected]4ae73292011-11-15 05:20:18561 return new CrosDisksClientImpl(bus);
[email protected]e8db03d62012-03-31 04:08:38562 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
563 return new CrosDisksClientStubImpl();
[email protected]4ae73292011-11-15 05:20:18564}
565
566} // namespace chromeos