Revert of Roll src/third_party/WebKit e0eac24:489c548 (svn 193311:193320) (patchset...
[chromium-blink-merge.git] / chromeos / dbus / cros_disks_client.cc
blob71a71eaf84ff7353b7f17ba19620c7bd4d00cace
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"
7 #include <map>
9 #include "base/bind.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/location.h"
13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/stl_util.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/sys_info.h"
17 #include "base/task_runner_util.h"
18 #include "base/threading/worker_pool.h"
19 #include "base/values.h"
20 #include "chromeos/dbus/fake_cros_disks_client.h"
21 #include "dbus/bus.h"
22 #include "dbus/message.h"
23 #include "dbus/object_path.h"
24 #include "dbus/object_proxy.h"
25 #include "dbus/values_util.h"
26 #include "third_party/cros_system_api/dbus/service_constants.h"
28 namespace chromeos {
30 namespace {
32 const char* kDefaultMountOptions[] = {
33 "rw",
34 "nodev",
35 "noexec",
36 "nosuid",
39 const char* kDefaultUnmountOptions[] = {
40 "force",
43 const char kLazyUnmountOption[] = "lazy";
45 const char kMountLabelOption[] = "mountlabel";
47 // Checks if retrieved media type is in boundaries of DeviceMediaType.
48 bool IsValidMediaType(uint32 type) {
49 return type < static_cast<uint32>(cros_disks::DEVICE_MEDIA_NUM_VALUES);
52 // Translates enum used in cros-disks to enum used in Chrome.
53 // Note that we could just do static_cast, but this is less sensitive to
54 // changes in cros-disks.
55 DeviceType DeviceMediaTypeToDeviceType(uint32 media_type_uint32) {
56 if (!IsValidMediaType(media_type_uint32))
57 return DEVICE_TYPE_UNKNOWN;
59 cros_disks::DeviceMediaType media_type =
60 cros_disks::DeviceMediaType(media_type_uint32);
62 switch (media_type) {
63 case(cros_disks::DEVICE_MEDIA_UNKNOWN):
64 return DEVICE_TYPE_UNKNOWN;
65 case(cros_disks::DEVICE_MEDIA_USB):
66 return DEVICE_TYPE_USB;
67 case(cros_disks::DEVICE_MEDIA_SD):
68 return DEVICE_TYPE_SD;
69 case(cros_disks::DEVICE_MEDIA_OPTICAL_DISC):
70 return DEVICE_TYPE_OPTICAL_DISC;
71 case(cros_disks::DEVICE_MEDIA_MOBILE):
72 return DEVICE_TYPE_MOBILE;
73 case(cros_disks::DEVICE_MEDIA_DVD):
74 return DEVICE_TYPE_DVD;
75 default:
76 return DEVICE_TYPE_UNKNOWN;
80 bool ReadMountEntryFromDbus(dbus::MessageReader* reader, MountEntry* entry) {
81 uint32 error_code = 0;
82 std::string source_path;
83 uint32 mount_type = 0;
84 std::string mount_path;
85 if (!reader->PopUint32(&error_code) ||
86 !reader->PopString(&source_path) ||
87 !reader->PopUint32(&mount_type) ||
88 !reader->PopString(&mount_path)) {
89 return false;
91 *entry = MountEntry(static_cast<MountError>(error_code), source_path,
92 static_cast<MountType>(mount_type), mount_path);
93 return true;
96 // The CrosDisksClient implementation.
97 class CrosDisksClientImpl : public CrosDisksClient {
98 public:
99 CrosDisksClientImpl() : proxy_(NULL), weak_ptr_factory_(this) {}
101 // CrosDisksClient override.
102 void Mount(const std::string& source_path,
103 const std::string& source_format,
104 const std::string& mount_label,
105 const base::Closure& callback,
106 const base::Closure& error_callback) override {
107 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
108 cros_disks::kMount);
109 dbus::MessageWriter writer(&method_call);
110 writer.AppendString(source_path);
111 writer.AppendString(source_format);
112 std::vector<std::string> mount_options(kDefaultMountOptions,
113 kDefaultMountOptions +
114 arraysize(kDefaultMountOptions));
115 if (!mount_label.empty()) {
116 std::string mount_label_option = base::StringPrintf("%s=%s",
117 kMountLabelOption,
118 mount_label.c_str());
119 mount_options.push_back(mount_label_option);
121 writer.AppendArrayOfStrings(mount_options);
122 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
123 base::Bind(&CrosDisksClientImpl::OnMount,
124 weak_ptr_factory_.GetWeakPtr(),
125 callback,
126 error_callback));
129 // CrosDisksClient override.
130 void Unmount(const std::string& device_path,
131 UnmountOptions options,
132 const base::Closure& callback,
133 const base::Closure& error_callback) override {
134 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
135 cros_disks::kUnmount);
136 dbus::MessageWriter writer(&method_call);
137 writer.AppendString(device_path);
139 std::vector<std::string> unmount_options(
140 kDefaultUnmountOptions,
141 kDefaultUnmountOptions + arraysize(kDefaultUnmountOptions));
142 if (options == UNMOUNT_OPTIONS_LAZY)
143 unmount_options.push_back(kLazyUnmountOption);
145 writer.AppendArrayOfStrings(unmount_options);
146 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
147 base::Bind(&CrosDisksClientImpl::OnUnmount,
148 weak_ptr_factory_.GetWeakPtr(),
149 callback,
150 error_callback));
153 // CrosDisksClient override.
154 void EnumerateAutoMountableDevices(
155 const EnumerateAutoMountableDevicesCallback& callback,
156 const base::Closure& error_callback) override {
157 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
158 cros_disks::kEnumerateAutoMountableDevices);
159 proxy_->CallMethod(
160 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
161 base::Bind(&CrosDisksClientImpl::OnEnumerateAutoMountableDevices,
162 weak_ptr_factory_.GetWeakPtr(),
163 callback,
164 error_callback));
167 // CrosDisksClient override.
168 void EnumerateMountEntries(const EnumerateMountEntriesCallback& callback,
169 const base::Closure& error_callback) override {
170 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
171 cros_disks::kEnumerateMountEntries);
172 proxy_->CallMethod(
173 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
174 base::Bind(&CrosDisksClientImpl::OnEnumerateMountEntries,
175 weak_ptr_factory_.GetWeakPtr(),
176 callback,
177 error_callback));
180 // CrosDisksClient override.
181 void Format(const std::string& device_path,
182 const std::string& filesystem,
183 const base::Closure& callback,
184 const base::Closure& error_callback) override {
185 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
186 cros_disks::kFormat);
187 dbus::MessageWriter writer(&method_call);
188 writer.AppendString(device_path);
189 writer.AppendString(filesystem);
190 // No format option is currently specified, but we can later use this
191 // argument to specify options for the format operation.
192 std::vector<std::string> format_options;
193 writer.AppendArrayOfStrings(format_options);
194 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
195 base::Bind(&CrosDisksClientImpl::OnFormat,
196 weak_ptr_factory_.GetWeakPtr(),
197 callback,
198 error_callback));
201 // CrosDisksClient override.
202 void GetDeviceProperties(const std::string& device_path,
203 const GetDevicePropertiesCallback& callback,
204 const base::Closure& error_callback) override {
205 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface,
206 cros_disks::kGetDeviceProperties);
207 dbus::MessageWriter writer(&method_call);
208 writer.AppendString(device_path);
209 proxy_->CallMethod(&method_call,
210 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
211 base::Bind(&CrosDisksClientImpl::OnGetDeviceProperties,
212 weak_ptr_factory_.GetWeakPtr(),
213 device_path,
214 callback,
215 error_callback));
218 // CrosDisksClient override.
219 void SetMountEventHandler(
220 const MountEventHandler& mount_event_handler) override {
221 static const SignalEventTuple kSignalEventTuples[] = {
222 { cros_disks::kDeviceAdded, CROS_DISKS_DEVICE_ADDED },
223 { cros_disks::kDeviceScanned, CROS_DISKS_DEVICE_SCANNED },
224 { cros_disks::kDeviceRemoved, CROS_DISKS_DEVICE_REMOVED },
225 { cros_disks::kDiskAdded, CROS_DISKS_DISK_ADDED },
226 { cros_disks::kDiskChanged, CROS_DISKS_DISK_CHANGED },
227 { cros_disks::kDiskRemoved, CROS_DISKS_DISK_REMOVED },
229 const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples);
231 for (size_t i = 0; i < kNumSignalEventTuples; ++i) {
232 proxy_->ConnectToSignal(
233 cros_disks::kCrosDisksInterface,
234 kSignalEventTuples[i].signal_name,
235 base::Bind(&CrosDisksClientImpl::OnMountEvent,
236 weak_ptr_factory_.GetWeakPtr(),
237 kSignalEventTuples[i].event_type,
238 mount_event_handler),
239 base::Bind(&CrosDisksClientImpl::OnSignalConnected,
240 weak_ptr_factory_.GetWeakPtr()));
244 // CrosDisksClient override.
245 void SetMountCompletedHandler(
246 const MountCompletedHandler& mount_completed_handler) override {
247 proxy_->ConnectToSignal(
248 cros_disks::kCrosDisksInterface,
249 cros_disks::kMountCompleted,
250 base::Bind(&CrosDisksClientImpl::OnMountCompleted,
251 weak_ptr_factory_.GetWeakPtr(),
252 mount_completed_handler),
253 base::Bind(&CrosDisksClientImpl::OnSignalConnected,
254 weak_ptr_factory_.GetWeakPtr()));
257 // CrosDisksClient override.
258 void SetFormatCompletedHandler(
259 const FormatCompletedHandler& format_completed_handler) override {
260 proxy_->ConnectToSignal(
261 cros_disks::kCrosDisksInterface,
262 cros_disks::kFormatCompleted,
263 base::Bind(&CrosDisksClientImpl::OnFormatCompleted,
264 weak_ptr_factory_.GetWeakPtr(),
265 format_completed_handler),
266 base::Bind(&CrosDisksClientImpl::OnSignalConnected,
267 weak_ptr_factory_.GetWeakPtr()));
270 protected:
271 void Init(dbus::Bus* bus) override {
272 proxy_ = bus->GetObjectProxy(
273 cros_disks::kCrosDisksServiceName,
274 dbus::ObjectPath(cros_disks::kCrosDisksServicePath));
277 private:
278 // A struct to contain a pair of signal name and mount event type.
279 // Used by SetMountEventHandler.
280 struct SignalEventTuple {
281 const char *signal_name;
282 MountEventType event_type;
285 // Handles the result of Mount and calls |callback| or |error_callback|.
286 void OnMount(const base::Closure& callback,
287 const base::Closure& error_callback,
288 dbus::Response* response) {
289 if (!response) {
290 error_callback.Run();
291 return;
293 callback.Run();
296 // Handles the result of Unmount and calls |callback| or |error_callback|.
297 void OnUnmount(const base::Closure& callback,
298 const base::Closure& error_callback,
299 dbus::Response* response) {
300 if (!response) {
301 error_callback.Run();
302 return;
305 // Temporarly allow Unmount method to report failure both by setting dbus
306 // error (in which case response is not set) and by returning mount error
307 // different from MOUNT_ERROR_NONE. This is done so we can change Unmount
308 // method to return mount error (http://crbug.com/288974) without breaking
309 // Chrome.
310 // TODO(tbarzic): When Unmount implementation is changed on cros disks side,
311 // make this fail if reader is not able to read the error code value from
312 // the response.
313 dbus::MessageReader reader(response);
314 uint32 error_code = 0;
315 if (reader.PopUint32(&error_code) &&
316 static_cast<MountError>(error_code) != MOUNT_ERROR_NONE) {
317 error_callback.Run();
318 return;
321 callback.Run();
324 // Handles the result of EnumerateAutoMountableDevices and calls |callback| or
325 // |error_callback|.
326 void OnEnumerateAutoMountableDevices(
327 const EnumerateAutoMountableDevicesCallback& callback,
328 const base::Closure& error_callback,
329 dbus::Response* response) {
330 if (!response) {
331 error_callback.Run();
332 return;
334 dbus::MessageReader reader(response);
335 std::vector<std::string> device_paths;
336 if (!reader.PopArrayOfStrings(&device_paths)) {
337 LOG(ERROR) << "Invalid response: " << response->ToString();
338 error_callback.Run();
339 return;
341 callback.Run(device_paths);
344 // Handles the result of EnumerateMountEntries and calls |callback| or
345 // |error_callback|.
346 void OnEnumerateMountEntries(
347 const EnumerateMountEntriesCallback& callback,
348 const base::Closure& error_callback,
349 dbus::Response* response) {
350 if (!response) {
351 error_callback.Run();
352 return;
355 dbus::MessageReader reader(response);
356 dbus::MessageReader array_reader(NULL);
357 if (!reader.PopArray(&array_reader)) {
358 LOG(ERROR) << "Invalid response: " << response->ToString();
359 error_callback.Run();
360 return;
363 std::vector<MountEntry> entries;
364 while (array_reader.HasMoreData()) {
365 MountEntry entry;
366 dbus::MessageReader sub_reader(NULL);
367 if (!array_reader.PopStruct(&sub_reader) ||
368 !ReadMountEntryFromDbus(&sub_reader, &entry)) {
369 LOG(ERROR) << "Invalid response: " << response->ToString();
370 error_callback.Run();
371 return;
373 entries.push_back(entry);
375 callback.Run(entries);
378 // Handles the result of Format and calls |callback| or |error_callback|.
379 void OnFormat(const base::Closure& callback,
380 const base::Closure& error_callback,
381 dbus::Response* response) {
382 if (!response) {
383 error_callback.Run();
384 return;
386 callback.Run();
389 // Handles the result of GetDeviceProperties and calls |callback| or
390 // |error_callback|.
391 void OnGetDeviceProperties(const std::string& device_path,
392 const GetDevicePropertiesCallback& callback,
393 const base::Closure& error_callback,
394 dbus::Response* response) {
395 if (!response) {
396 error_callback.Run();
397 return;
399 DiskInfo disk(device_path, response);
400 callback.Run(disk);
403 // Handles mount event signals and calls |handler|.
404 void OnMountEvent(MountEventType event_type,
405 MountEventHandler handler,
406 dbus::Signal* signal) {
407 dbus::MessageReader reader(signal);
408 std::string device;
409 if (!reader.PopString(&device)) {
410 LOG(ERROR) << "Invalid signal: " << signal->ToString();
411 return;
413 handler.Run(event_type, device);
416 // Handles MountCompleted signal and calls |handler|.
417 void OnMountCompleted(MountCompletedHandler handler, dbus::Signal* signal) {
418 dbus::MessageReader reader(signal);
419 MountEntry entry;
420 if (!ReadMountEntryFromDbus(&reader, &entry)) {
421 LOG(ERROR) << "Invalid signal: " << signal->ToString();
422 return;
424 handler.Run(entry);
427 // Handles FormatCompleted signal and calls |handler|.
428 void OnFormatCompleted(FormatCompletedHandler handler, dbus::Signal* signal) {
429 dbus::MessageReader reader(signal);
430 uint32 error_code = 0;
431 std::string device_path;
432 if (!reader.PopUint32(&error_code) || !reader.PopString(&device_path)) {
433 LOG(ERROR) << "Invalid signal: " << signal->ToString();
434 return;
436 handler.Run(static_cast<FormatError>(error_code), device_path);
439 // Handles the result of signal connection setup.
440 void OnSignalConnected(const std::string& interface,
441 const std::string& signal,
442 bool succeeded) {
443 LOG_IF(ERROR, !succeeded) << "Connect to " << interface << " " <<
444 signal << " failed.";
447 dbus::ObjectProxy* proxy_;
449 // Note: This should remain the last member so it'll be destroyed and
450 // invalidate its weak pointers before any other members are destroyed.
451 base::WeakPtrFactory<CrosDisksClientImpl> weak_ptr_factory_;
453 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientImpl);
456 } // namespace
458 ////////////////////////////////////////////////////////////////////////////////
459 // DiskInfo
461 DiskInfo::DiskInfo(const std::string& device_path, dbus::Response* response)
462 : device_path_(device_path),
463 is_drive_(false),
464 has_media_(false),
465 on_boot_device_(false),
466 on_removable_device_(false),
467 device_type_(DEVICE_TYPE_UNKNOWN),
468 total_size_in_bytes_(0),
469 is_read_only_(false),
470 is_hidden_(true) {
471 InitializeFromResponse(response);
474 DiskInfo::~DiskInfo() {
477 // Initializes |this| from |response| given by the cros-disks service.
478 // Below is an example of |response|'s raw message (long string is ellipsized).
481 // message_type: MESSAGE_METHOD_RETURN
482 // destination: :1.8
483 // sender: :1.16
484 // signature: a{sv}
485 // serial: 96
486 // reply_serial: 267
488 // array [
489 // dict entry {
490 // string "DeviceFile"
491 // variant string "/dev/sdb"
492 // }
493 // dict entry {
494 // string "DeviceIsDrive"
495 // variant bool true
496 // }
497 // dict entry {
498 // string "DeviceIsMediaAvailable"
499 // variant bool true
500 // }
501 // dict entry {
502 // string "DeviceIsMounted"
503 // variant bool false
504 // }
505 // dict entry {
506 // string "DeviceIsOnBootDevice"
507 // variant bool false
508 // }
509 // dict entry {
510 // string "DeviceIsOnRemovableDevice"
511 // variant bool true
512 // }
513 // dict entry {
514 // string "DeviceIsReadOnly"
515 // variant bool false
516 // }
517 // dict entry {
518 // string "DeviceIsVirtual"
519 // variant bool false
520 // }
521 // dict entry {
522 // string "DeviceMediaType"
523 // variant uint32 1
524 // }
525 // dict entry {
526 // string "DeviceMountPaths"
527 // variant array [
528 // ]
529 // }
530 // dict entry {
531 // string "DevicePresentationHide"
532 // variant bool true
533 // }
534 // dict entry {
535 // string "DeviceSize"
536 // variant uint64 7998537728
537 // }
538 // dict entry {
539 // string "DriveIsRotational"
540 // variant bool false
541 // }
542 // dict entry {
543 // string "VendorId"
544 // variant string "18d1"
545 // }
546 // dict entry {
547 // string "VendorName"
548 // variant string "Google Inc."
549 // }
550 // dict entry {
551 // string "ProductId"
552 // variant string "4e11"
553 // }
554 // dict entry {
555 // string "ProductName"
556 // variant string "Nexus One"
557 // }
558 // dict entry {
559 // string "DriveModel"
560 // variant string "TransMemory"
561 // }
562 // dict entry {
563 // string "IdLabel"
564 // variant string ""
565 // }
566 // dict entry {
567 // string "IdUuid"
568 // variant string ""
569 // }
570 // dict entry {
571 // string "NativePath"
572 // variant string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/...
573 // }
574 // ]
575 void DiskInfo::InitializeFromResponse(dbus::Response* response) {
576 dbus::MessageReader reader(response);
577 scoped_ptr<base::Value> value(dbus::PopDataAsValue(&reader));
578 base::DictionaryValue* properties = NULL;
579 if (!value || !value->GetAsDictionary(&properties))
580 return;
582 properties->GetBooleanWithoutPathExpansion(
583 cros_disks::kDeviceIsDrive, &is_drive_);
584 properties->GetBooleanWithoutPathExpansion(
585 cros_disks::kDeviceIsReadOnly, &is_read_only_);
586 properties->GetBooleanWithoutPathExpansion(
587 cros_disks::kDevicePresentationHide, &is_hidden_);
588 properties->GetBooleanWithoutPathExpansion(
589 cros_disks::kDeviceIsMediaAvailable, &has_media_);
590 properties->GetBooleanWithoutPathExpansion(
591 cros_disks::kDeviceIsOnBootDevice, &on_boot_device_);
592 properties->GetBooleanWithoutPathExpansion(
593 cros_disks::kDeviceIsOnRemovableDevice, &on_removable_device_);
594 properties->GetStringWithoutPathExpansion(
595 cros_disks::kNativePath, &system_path_);
596 properties->GetStringWithoutPathExpansion(
597 cros_disks::kDeviceFile, &file_path_);
598 properties->GetStringWithoutPathExpansion(cros_disks::kVendorId, &vendor_id_);
599 properties->GetStringWithoutPathExpansion(
600 cros_disks::kVendorName, &vendor_name_);
601 properties->GetStringWithoutPathExpansion(
602 cros_disks::kProductId, &product_id_);
603 properties->GetStringWithoutPathExpansion(
604 cros_disks::kProductName, &product_name_);
605 properties->GetStringWithoutPathExpansion(
606 cros_disks::kDriveModel, &drive_model_);
607 properties->GetStringWithoutPathExpansion(cros_disks::kIdLabel, &label_);
608 properties->GetStringWithoutPathExpansion(cros_disks::kIdUuid, &uuid_);
610 // dbus::PopDataAsValue() pops uint64 as double.
611 // The top 11 bits of uint64 are dropped by the use of double. But, this works
612 // unless the size exceeds 8 PB.
613 double device_size_double = 0;
614 if (properties->GetDoubleWithoutPathExpansion(cros_disks::kDeviceSize,
615 &device_size_double))
616 total_size_in_bytes_ = device_size_double;
618 // dbus::PopDataAsValue() pops uint32 as double.
619 double media_type_double = 0;
620 if (properties->GetDoubleWithoutPathExpansion(cros_disks::kDeviceMediaType,
621 &media_type_double))
622 device_type_ = DeviceMediaTypeToDeviceType(media_type_double);
624 base::ListValue* mount_paths = NULL;
625 if (properties->GetListWithoutPathExpansion(cros_disks::kDeviceMountPaths,
626 &mount_paths))
627 mount_paths->GetString(0, &mount_path_);
630 ////////////////////////////////////////////////////////////////////////////////
631 // CrosDisksClient
633 CrosDisksClient::CrosDisksClient() {}
635 CrosDisksClient::~CrosDisksClient() {}
637 // static
638 CrosDisksClient* CrosDisksClient::Create(DBusClientImplementationType type) {
639 if (type == REAL_DBUS_CLIENT_IMPLEMENTATION)
640 return new CrosDisksClientImpl();
641 DCHECK_EQ(STUB_DBUS_CLIENT_IMPLEMENTATION, type);
642 return new FakeCrosDisksClient();
645 // static
646 base::FilePath CrosDisksClient::GetArchiveMountPoint() {
647 return base::FilePath(base::SysInfo::IsRunningOnChromeOS() ?
648 FILE_PATH_LITERAL("/media/archive") :
649 FILE_PATH_LITERAL("/tmp/chromeos/media/archive"));
652 // static
653 base::FilePath CrosDisksClient::GetRemovableDiskMountPoint() {
654 return base::FilePath(base::SysInfo::IsRunningOnChromeOS() ?
655 FILE_PATH_LITERAL("/media/removable") :
656 FILE_PATH_LITERAL("/tmp/chromeos/media/removable"));
659 } // namespace chromeos