| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2011 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. |
| 4 |
| 5 #include "chrome/browser/chromeos/dbus/cros_disks_client.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/memory/scoped_vector.h" |
| 9 #include "chrome/browser/chromeos/system/runtime_environment.h" |
| 10 #include "dbus/bus.h" |
| 11 #include "dbus/message.h" |
| 12 #include "dbus/object_proxy.h" |
| 13 #include "third_party/cros_system_api/dbus/service_constants.h" |
| 14 |
| 15 namespace chromeos { |
| 16 |
| 17 namespace { |
| 18 |
| 19 const char* kDefaultMountOptions[] = { |
| 20 "rw", |
| 21 "nodev", |
| 22 "noexec", |
| 23 "nosuid", |
| 24 "sync", |
| 25 }; |
| 26 |
| 27 const char* kDefaultUnmountOptions[] = { |
| 28 "force", |
| 29 }; |
| 30 |
| 31 // Returns the device type from the given arguments. |
| 32 DeviceType GetDeviceType(bool is_optical, bool is_rotational) { |
| 33 if (is_optical) |
| 34 return OPTICAL; |
| 35 if (is_rotational) |
| 36 return HDD; |
| 37 return FLASH; |
| 38 } |
| 39 |
| 40 // Pops a bool value when |reader| is not NULL. |
| 41 // Returns true when a value is popped, false otherwise. |
| 42 bool MaybePopBool(dbus::MessageReader* reader, bool* value) { |
| 43 if (!reader) |
| 44 return false; |
| 45 return reader->PopBool(value); |
| 46 } |
| 47 |
| 48 // Pops a string value when |reader| is not NULL. |
| 49 // Returns true when a value is popped, false otherwise. |
| 50 bool MaybePopString(dbus::MessageReader* reader, std::string* value) { |
| 51 if (!reader) |
| 52 return false; |
| 53 return reader->PopString(value); |
| 54 } |
| 55 |
| 56 // Pops a uint64 value when |reader| is not NULL. |
| 57 // Returns true when a value is popped, false otherwise. |
| 58 bool MaybePopUint64(dbus::MessageReader* reader, uint64* value) { |
| 59 if (!reader) |
| 60 return false; |
| 61 return reader->PopUint64(value); |
| 62 } |
| 63 |
| 64 // Pops an array of strings when |reader| is not NULL. |
| 65 // Returns true when an array is popped, false otherwise. |
| 66 bool MaybePopArrayOfStrings(dbus::MessageReader* reader, |
| 67 std::vector<std::string>* value) { |
| 68 if (!reader) |
| 69 return false; |
| 70 return reader->PopArrayOfStrings(value); |
| 71 } |
| 72 |
| 73 // The CrosDisksClient implementation. |
| 74 class CrosDisksClientImpl : public CrosDisksClient { |
| 75 public: |
| 76 explicit CrosDisksClientImpl(dbus::Bus* bus) |
| 77 : proxy_(bus->GetObjectProxy(cros_disks::kCrosDisksServiceName, |
| 78 cros_disks::kCrosDisksServicePath)), |
| 79 weak_ptr_factory_(this) { |
| 80 } |
| 81 |
| 82 // CrosDisksClient override. |
| 83 virtual void Mount(const std::string& source_path, |
| 84 MountType type, |
| 85 MountCallback callback, |
| 86 ErrorCallback error_callback) OVERRIDE { |
| 87 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface, |
| 88 cros_disks::kMount); |
| 89 dbus::MessageWriter writer(&method_call); |
| 90 writer.AppendString(source_path); |
| 91 writer.AppendString(""); // auto detect filesystem. |
| 92 std::vector<std::string> mount_options(kDefaultMountOptions, |
| 93 kDefaultMountOptions + |
| 94 arraysize(kDefaultMountOptions)); |
| 95 writer.AppendArrayOfStrings(mount_options); |
| 96 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| 97 base::Bind(&CrosDisksClientImpl::OnMount, |
| 98 weak_ptr_factory_.GetWeakPtr(), |
| 99 callback, |
| 100 error_callback)); |
| 101 } |
| 102 |
| 103 // CrosDisksClient override. |
| 104 virtual void Unmount(const std::string& device_path, |
| 105 UnmountCallback callback, |
| 106 ErrorCallback error_callback) OVERRIDE { |
| 107 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface, |
| 108 cros_disks::kUnmount); |
| 109 dbus::MessageWriter writer(&method_call); |
| 110 writer.AppendString(device_path); |
| 111 std::vector<std::string> unmount_options(kDefaultUnmountOptions, |
| 112 kDefaultUnmountOptions + |
| 113 arraysize(kDefaultUnmountOptions)); |
| 114 writer.AppendArrayOfStrings(unmount_options); |
| 115 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| 116 base::Bind(&CrosDisksClientImpl::OnUnmount, |
| 117 weak_ptr_factory_.GetWeakPtr(), |
| 118 device_path, |
| 119 callback, |
| 120 error_callback)); |
| 121 } |
| 122 |
| 123 // CrosDisksClient override. |
| 124 virtual void EnumerateAutoMountableDevices( |
| 125 EnumerateAutoMountableDevicesCallback callback, |
| 126 ErrorCallback error_callback) OVERRIDE { |
| 127 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface, |
| 128 cros_disks::kEnumerateAutoMountableDevices); |
| 129 proxy_->CallMethod( |
| 130 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| 131 base::Bind(&CrosDisksClientImpl::OnEnumerateAutoMountableDevices, |
| 132 weak_ptr_factory_.GetWeakPtr(), |
| 133 callback, |
| 134 error_callback)); |
| 135 } |
| 136 |
| 137 // CrosDisksClient override. |
| 138 virtual void FormatDevice(const std::string& device_path, |
| 139 const std::string& filesystem, |
| 140 FormatDeviceCallback callback, |
| 141 ErrorCallback error_callback) OVERRIDE { |
| 142 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface, |
| 143 cros_disks::kFormatDevice); |
| 144 dbus::MessageWriter writer(&method_call); |
| 145 writer.AppendString(device_path); |
| 146 writer.AppendString(filesystem); |
| 147 proxy_->CallMethod(&method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| 148 base::Bind(&CrosDisksClientImpl::OnFormatDevice, |
| 149 weak_ptr_factory_.GetWeakPtr(), |
| 150 device_path, |
| 151 callback, |
| 152 error_callback)); |
| 153 } |
| 154 |
| 155 // CrosDisksClient override. |
| 156 virtual void GetDeviceProperties(const std::string& device_path, |
| 157 GetDevicePropertiesCallback callback, |
| 158 ErrorCallback error_callback) OVERRIDE { |
| 159 dbus::MethodCall method_call(cros_disks::kCrosDisksInterface, |
| 160 cros_disks::kGetDeviceProperties); |
| 161 dbus::MessageWriter writer(&method_call); |
| 162 writer.AppendString(device_path); |
| 163 proxy_->CallMethod(&method_call, |
| 164 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT, |
| 165 base::Bind(&CrosDisksClientImpl::OnGetDeviceProperties, |
| 166 weak_ptr_factory_.GetWeakPtr(), |
| 167 device_path, |
| 168 callback, |
| 169 error_callback)); |
| 170 } |
| 171 |
| 172 // CrosDisksClient override. |
| 173 virtual void SetUpConnections( |
| 174 MountEventHandler mount_event_handler, |
| 175 MountCompletedHandler mount_completed_handler) OVERRIDE { |
| 176 static const SignalEventTuple kSignalEventTuples[] = { |
| 177 { "DeviceAdded", DEVICE_ADDED }, |
| 178 { "DeviceScanned", DEVICE_SCANNED }, |
| 179 { "DeviceRemoved", DEVICE_REMOVED }, |
| 180 { "DiskAdded", DISK_ADDED }, |
| 181 { "DiskChanged", DISK_CHANGED }, |
| 182 { "DiskRemoved", DISK_REMOVED }, |
| 183 { "FormattingFinished", FORMATTING_FINISHED }, |
| 184 }; |
| 185 const size_t kNumSignalEventTuples = arraysize(kSignalEventTuples); |
| 186 |
| 187 for (size_t i = 0; i < kNumSignalEventTuples; ++i) { |
| 188 proxy_->ConnectToSignal( |
| 189 cros_disks::kCrosDisksInterface, |
| 190 kSignalEventTuples[i].signal_name, |
| 191 base::Bind(&CrosDisksClientImpl::OnMountEvent, |
| 192 weak_ptr_factory_.GetWeakPtr(), |
| 193 kSignalEventTuples[i].event_type, |
| 194 mount_event_handler), |
| 195 base::Bind(&CrosDisksClientImpl::OnSignalConnected, |
| 196 weak_ptr_factory_.GetWeakPtr())); |
| 197 } |
| 198 proxy_->ConnectToSignal( |
| 199 cros_disks::kCrosDisksInterface, |
| 200 "MountCompleted", |
| 201 base::Bind(&CrosDisksClientImpl::OnMountCompleted, |
| 202 weak_ptr_factory_.GetWeakPtr(), |
| 203 mount_completed_handler ), |
| 204 base::Bind(&CrosDisksClientImpl::OnSignalConnected, |
| 205 weak_ptr_factory_.GetWeakPtr())); |
| 206 } |
| 207 |
| 208 private: |
| 209 // A struct to contain a pair of signal name and mount event type. |
| 210 // Used by SetUpConnections. |
| 211 struct SignalEventTuple { |
| 212 const char *signal_name; |
| 213 MountEventType event_type; |
| 214 }; |
| 215 |
| 216 // Handles the result of Mount and calls |callback| or |error_callback|. |
| 217 void OnMount(MountCallback callback, |
| 218 ErrorCallback error_callback, |
| 219 dbus::Response* response) { |
| 220 if (!response) { |
| 221 error_callback.Run(); |
| 222 return; |
| 223 } |
| 224 callback.Run(); |
| 225 } |
| 226 |
| 227 // Handles the result of Unount and calls |callback| or |error_callback|. |
| 228 void OnUnmount(const std::string& device_path, |
| 229 UnmountCallback callback, |
| 230 ErrorCallback error_callback, |
| 231 dbus::Response* response) { |
| 232 if (!response) { |
| 233 error_callback.Run(); |
| 234 return; |
| 235 } |
| 236 callback.Run(device_path); |
| 237 } |
| 238 |
| 239 // Handles the result of EnumerateAutoMountableDevices and calls |callback| or |
| 240 // |error_callback|. |
| 241 void OnEnumerateAutoMountableDevices( |
| 242 EnumerateAutoMountableDevicesCallback callback, |
| 243 ErrorCallback error_callback, |
| 244 dbus::Response* response) { |
| 245 if (!response) { |
| 246 error_callback.Run(); |
| 247 return; |
| 248 } |
| 249 dbus::MessageReader reader(response); |
| 250 std::vector<std::string> device_paths; |
| 251 if (!reader.PopArrayOfStrings(&device_paths)) { |
| 252 LOG(ERROR) << "Invalid response: " << response->ToString(); |
| 253 error_callback.Run(); |
| 254 return; |
| 255 } |
| 256 callback.Run(device_paths); |
| 257 } |
| 258 |
| 259 // Handles the result of FormatDevice and calls |callback| or |
| 260 // |error_callback|. |
| 261 void OnFormatDevice(const std::string& device_path, |
| 262 FormatDeviceCallback callback, |
| 263 ErrorCallback error_callback, |
| 264 dbus::Response* response) { |
| 265 if (!response) { |
| 266 error_callback.Run(); |
| 267 return; |
| 268 } |
| 269 dbus::MessageReader reader(response); |
| 270 bool success = false; |
| 271 if (!reader.PopBool(&success)) { |
| 272 LOG(ERROR) << "Invalid response: " << response->ToString(); |
| 273 error_callback.Run(); |
| 274 return; |
| 275 } |
| 276 callback.Run(device_path, success); |
| 277 } |
| 278 |
| 279 // Handles the result of GetDeviceProperties and calls |callback| or |
| 280 // |error_callback|. |
| 281 void OnGetDeviceProperties(const std::string& device_path, |
| 282 GetDevicePropertiesCallback callback, |
| 283 ErrorCallback error_callback, |
| 284 dbus::Response* response) { |
| 285 if (!response) { |
| 286 error_callback.Run(); |
| 287 return; |
| 288 } |
| 289 DiskInfo disk(device_path, response); |
| 290 callback.Run(disk); |
| 291 } |
| 292 |
| 293 // Handles mount event signals and calls |handler|. |
| 294 void OnMountEvent(MountEventType event_type, |
| 295 MountEventHandler handler, |
| 296 dbus::Signal* signal) { |
| 297 dbus::MessageReader reader(signal); |
| 298 std::string device; |
| 299 if (!reader.PopString(&device)) { |
| 300 LOG(ERROR) << "Invalid signal: " << signal->ToString(); |
| 301 return; |
| 302 } |
| 303 handler.Run(event_type, device); |
| 304 } |
| 305 |
| 306 // Handles MountCompleted signal and calls |handler|. |
| 307 void OnMountCompleted(MountCompletedHandler handler, dbus::Signal* signal) { |
| 308 dbus::MessageReader reader(signal); |
| 309 unsigned int error_code = 0; |
| 310 std::string source_path; |
| 311 unsigned int mount_type = 0; |
| 312 std::string mount_path; |
| 313 if (!reader.PopUint32(&error_code) || |
| 314 !reader.PopString(&source_path) || |
| 315 !reader.PopUint32(&mount_type) || |
| 316 !reader.PopString(&mount_path)) { |
| 317 LOG(ERROR) << "Invalid signal: " << signal->ToString(); |
| 318 return; |
| 319 } |
| 320 handler.Run(static_cast<MountError>(error_code), source_path, |
| 321 static_cast<MountType>(mount_type), mount_path); |
| 322 } |
| 323 |
| 324 // Handles the result of signal connection setup. |
| 325 void OnSignalConnected(const std::string& interface, |
| 326 const std::string& signal, |
| 327 bool successed) { |
| 328 LOG_IF(ERROR, !successed) << "Connect to " << interface << " " << |
| 329 signal << " failed."; |
| 330 } |
| 331 |
| 332 dbus::ObjectProxy* proxy_; |
| 333 base::WeakPtrFactory<CrosDisksClientImpl> weak_ptr_factory_; |
| 334 |
| 335 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientImpl); |
| 336 }; |
| 337 |
| 338 // A stub implementaion of CrosDisksClient. |
| 339 class CrosDisksClientStubImpl : public CrosDisksClient { |
| 340 public: |
| 341 CrosDisksClientStubImpl() {} |
| 342 virtual ~CrosDisksClientStubImpl() {} |
| 343 |
| 344 virtual void Mount(const std::string& source_path, |
| 345 MountType type, |
| 346 MountCallback callback, |
| 347 ErrorCallback error_callback) OVERRIDE {} |
| 348 virtual void Unmount(const std::string& device_path, |
| 349 UnmountCallback callback, |
| 350 ErrorCallback error_callback) OVERRIDE {} |
| 351 virtual void EnumerateAutoMountableDevices( |
| 352 EnumerateAutoMountableDevicesCallback callback, |
| 353 ErrorCallback error_callback) OVERRIDE {} |
| 354 virtual void FormatDevice(const std::string& device_path, |
| 355 const std::string& filesystem, |
| 356 FormatDeviceCallback callback, |
| 357 ErrorCallback error_callback) OVERRIDE {} |
| 358 virtual void GetDeviceProperties(const std::string& device_path, |
| 359 GetDevicePropertiesCallback callback, |
| 360 ErrorCallback error_callback) OVERRIDE {} |
| 361 virtual void SetUpConnections( |
| 362 MountEventHandler mount_event_handler, |
| 363 MountCompletedHandler mount_completed_handler) OVERRIDE {} |
| 364 |
| 365 private: |
| 366 DISALLOW_COPY_AND_ASSIGN(CrosDisksClientStubImpl); |
| 367 }; |
| 368 |
| 369 } // namespace |
| 370 |
| 371 //////////////////////////////////////////////////////////////////////////////// |
| 372 // DiskInfo |
| 373 |
| 374 DiskInfo::DiskInfo(const std::string& device_path, dbus::Response* response) |
| 375 : device_path_(device_path), |
| 376 is_drive_(false), |
| 377 has_media_(false), |
| 378 on_boot_device_(false), |
| 379 device_type_(UNDEFINED), |
| 380 total_size_in_bytes_(0), |
| 381 is_read_only_(false), |
| 382 is_hidden_(true) { |
| 383 InitializeFromResponse(response); |
| 384 } |
| 385 |
| 386 DiskInfo::~DiskInfo() { |
| 387 } |
| 388 |
| 389 // Initialize |this| from |response| given by the cros-disks service. |
| 390 // Below is an example of |response|'s raw message (long string is ellipsized). |
| 391 // |
| 392 // |
| 393 // message_type: MESSAGE_METHOD_RETURN |
| 394 // destination: :1.8 |
| 395 // sender: :1.16 |
| 396 // signature: a{sv} |
| 397 // serial: 96 |
| 398 // reply_serial: 267 |
| 399 // |
| 400 // array [ |
| 401 // dict entry { |
| 402 // string "DeviceFile" |
| 403 // variant string "/dev/sdb" |
| 404 // } |
| 405 // dict entry { |
| 406 // string "DeviceIsDrive" |
| 407 // variant bool true |
| 408 // } |
| 409 // dict entry { |
| 410 // string "DeviceIsMediaAvailable" |
| 411 // variant bool true |
| 412 // } |
| 413 // dict entry { |
| 414 // string "DeviceIsMounted" |
| 415 // variant bool false |
| 416 // } |
| 417 // dict entry { |
| 418 // string "DeviceIsOnBootDevice" |
| 419 // variant bool false |
| 420 // } |
| 421 // dict entry { |
| 422 // string "DeviceIsOpticalDisc" |
| 423 // variant bool false |
| 424 // } |
| 425 // dict entry { |
| 426 // string "DeviceIsReadOnly" |
| 427 // variant bool false |
| 428 // } |
| 429 // dict entry { |
| 430 // string "DeviceIsVirtual" |
| 431 // variant bool false |
| 432 // } |
| 433 // dict entry { |
| 434 // string "DeviceMediaType" |
| 435 // variant uint32 1 |
| 436 // } |
| 437 // dict entry { |
| 438 // string "DeviceMountPaths" |
| 439 // variant array [ |
| 440 // ] |
| 441 // } |
| 442 // dict entry { |
| 443 // string "DevicePresentationHide" |
| 444 // variant bool true |
| 445 // } |
| 446 // dict entry { |
| 447 // string "DeviceSize" |
| 448 // variant uint64 7998537728 |
| 449 // } |
| 450 // dict entry { |
| 451 // string "DriveIsRotational" |
| 452 // variant bool false |
| 453 // } |
| 454 // dict entry { |
| 455 // string "DriveModel" |
| 456 // variant string "TransMemory" |
| 457 // } |
| 458 // dict entry { |
| 459 // string "IdLabel" |
| 460 // variant string "" |
| 461 // } |
| 462 // dict entry { |
| 463 // string "IdUuid" |
| 464 // variant string "" |
| 465 // } |
| 466 // dict entry { |
| 467 // string "NativePath" |
| 468 // variant string "/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-4/... |
| 469 // } |
| 470 // ] |
| 471 void DiskInfo::InitializeFromResponse(dbus::Response* response) { |
| 472 dbus::MessageReader response_reader(response); |
| 473 dbus::MessageReader array_reader(response); |
| 474 if (!response_reader.PopArray(&array_reader)) { |
| 475 LOG(ERROR) << "Invalid response: " << response->ToString(); |
| 476 return; |
| 477 } |
| 478 // TODO(satorux): Rework this code using Protocol Buffers. crosbug.com/22626 |
| 479 ScopedVector<dbus::MessageReader> value_readers_owner; |
| 480 std::map<std::string, dbus::MessageReader*> properties; |
| 481 while (array_reader.HasMoreData()) { |
| 482 // |value_readers_owner| is responsible to delete |value_reader|. |
| 483 dbus::MessageReader* value_reader = new dbus::MessageReader(response); |
| 484 value_readers_owner.push_back(value_reader); |
| 485 dbus::MessageReader dict_entry_reader(response); |
| 486 std::string key; |
| 487 if (!array_reader.PopDictEntry(&dict_entry_reader) || |
| 488 !dict_entry_reader.PopString(&key) || |
| 489 !dict_entry_reader.PopVariant(value_reader)) { |
| 490 LOG(ERROR) << "Invalid response: " << response->ToString(); |
| 491 return; |
| 492 } |
| 493 properties[key] = value_reader; |
| 494 } |
| 495 MaybePopBool(properties[cros_disks::kDeviceIsDrive], &is_drive_); |
| 496 MaybePopBool(properties[cros_disks::kDeviceIsReadOnly], &is_read_only_); |
| 497 MaybePopBool(properties[cros_disks::kDevicePresentationHide], &is_hidden_); |
| 498 MaybePopBool(properties[cros_disks::kDeviceIsMediaAvailable], &has_media_); |
| 499 MaybePopBool(properties[cros_disks::kDeviceIsOnBootDevice], |
| 500 &on_boot_device_); |
| 501 MaybePopString(properties[cros_disks::kNativePath], &system_path_); |
| 502 MaybePopString(properties[cros_disks::kDeviceFile], &file_path_); |
| 503 MaybePopString(properties[cros_disks::kDriveModel], &drive_model_); |
| 504 MaybePopString(properties[cros_disks::kIdLabel], &label_); |
| 505 MaybePopUint64(properties[cros_disks::kDeviceSize], &total_size_in_bytes_); |
| 506 |
| 507 std::vector<std::string> mount_paths; |
| 508 if (MaybePopArrayOfStrings(properties[cros_disks::kDeviceMountPaths], |
| 509 &mount_paths) && !mount_paths.empty()) |
| 510 mount_path_ = mount_paths[0]; |
| 511 |
| 512 bool is_rotational = false; |
| 513 bool is_optical = false; |
| 514 if (MaybePopBool(properties[cros_disks::kDriveIsRotational], |
| 515 &is_rotational) && |
| 516 MaybePopBool(properties[cros_disks::kDeviceIsOpticalDisc], |
| 517 &is_optical)) |
| 518 device_type_ = GetDeviceType(is_optical, is_rotational); |
| 519 } |
| 520 |
| 521 //////////////////////////////////////////////////////////////////////////////// |
| 522 // CrosDisksClient |
| 523 |
| 524 CrosDisksClient::CrosDisksClient() {} |
| 525 |
| 526 CrosDisksClient::~CrosDisksClient() {} |
| 527 |
| 528 // static |
| 529 CrosDisksClient* CrosDisksClient::Create(dbus::Bus* bus) { |
| 530 if (system::runtime_environment::IsRunningOnChromeOS()) |
| 531 return new CrosDisksClientImpl(bus); |
| 532 else |
| 533 return new CrosDisksClientStubImpl(); |
| 534 } |
| 535 |
| 536 } // namespace chromeos |
| OLD | NEW |