Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(112)

Side by Side Diff: chrome/browser/system_monitor/removable_device_notifications_linux.cc

Issue 11363153: [Media Gallery][Linux] Improve device media gallery names. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removed UDISKS related code Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // RemovableDeviceNotificationsLinux implementation. 5 // RemovableDeviceNotificationsLinux implementation.
6 6
7 #include "chrome/browser/system_monitor/removable_device_notifications_linux.h" 7 #include "chrome/browser/system_monitor/removable_device_notifications_linux.h"
8 8
9 #include <libudev.h> 9 #include <libudev.h>
10 #include <mntent.h> 10 #include <mntent.h>
11 #include <stdio.h> 11 #include <stdio.h>
12 12
13 #include <list> 13 #include <list>
14 14
15 #include "base/bind.h" 15 #include "base/bind.h"
16 #include "base/file_path.h" 16 #include "base/file_path.h"
17 #include "base/memory/scoped_generic_obj.h" 17 #include "base/memory/scoped_generic_obj.h"
18 #include "base/metrics/histogram.h" 18 #include "base/metrics/histogram.h"
19 #include "base/stl_util.h" 19 #include "base/stl_util.h"
20 #include "base/string_number_conversions.h" 20 #include "base/string_number_conversions.h"
21 #include "base/string_util.h" 21 #include "base/string_util.h"
22 #include "base/system_monitor/system_monitor.h" 22 #include "base/system_monitor/system_monitor.h"
23 #include "base/utf_string_conversions.h" 23 #include "base/utf_string_conversions.h"
24 #include "chrome/browser/system_monitor/media_device_notifications_utils.h" 24 #include "chrome/browser/system_monitor/media_device_notifications_utils.h"
25 #include "chrome/browser/system_monitor/removable_device_constants.h" 25 #include "chrome/browser/system_monitor/removable_device_constants.h"
26 #include "chrome/browser/system_monitor/media_storage_util.h" 26 #include "chrome/browser/system_monitor/media_storage_util.h"
27 #include "ui/base/text/bytes_formatting.h"
27 28
28 namespace chrome { 29 namespace chrome {
29 30
30 using base::SystemMonitor;
31 using content::BrowserThread; 31 using content::BrowserThread;
32 32
33 namespace { 33 namespace {
34 34
35 static RemovableDeviceNotificationsLinux* 35 static RemovableDeviceNotificationsLinux*
36 g_removable_device_notifications_linux = NULL; 36 g_removable_device_notifications_linux = NULL;
37 37
38 // List of file systems we care about. 38 // List of file systems we care about.
39 const char* const kKnownFileSystems[] = { 39 const char* const kKnownFileSystems[] = {
40 "ext2", 40 "ext2",
41 "ext3", 41 "ext3",
42 "ext4", 42 "ext4",
43 "fat", 43 "fat",
44 "hfsplus", 44 "hfsplus",
45 "iso9660", 45 "iso9660",
46 "msdos", 46 "msdos",
47 "ntfs", 47 "ntfs",
48 "udf", 48 "udf",
49 "vfat", 49 "vfat",
50 }; 50 };
51 51
52 // udev device property constants. 52 // udev device property constants.
53 const char kBlockSubsystemKey[] = "block"; 53 const char kBlockSubsystemKey[] = "block";
54 const char kDevName[] = "DEVNAME";
55 const char kDiskDeviceTypeKey[] = "disk"; 54 const char kDiskDeviceTypeKey[] = "disk";
56 const char kFsUUID[] = "ID_FS_UUID"; 55 const char kFsUUID[] = "ID_FS_UUID";
57 const char kLabel[] = "ID_FS_LABEL"; 56 const char kLabel[] = "ID_FS_LABEL";
58 const char kModel[] = "ID_MODEL"; 57 const char kModel[] = "ID_MODEL";
59 const char kModelID[] = "ID_MODEL_ID"; 58 const char kModelID[] = "ID_MODEL_ID";
60 const char kRemovableSysAttr[] = "removable"; 59 const char kRemovableSysAttr[] = "removable";
61 const char kSerial[] = "ID_SERIAL";
62 const char kSerialShort[] = "ID_SERIAL_SHORT"; 60 const char kSerialShort[] = "ID_SERIAL_SHORT";
61 const char kSizeSysAttr[] = "size";
63 const char kVendor[] = "ID_VENDOR"; 62 const char kVendor[] = "ID_VENDOR";
64 const char kVendorID[] = "ID_VENDOR_ID"; 63 const char kVendorID[] = "ID_VENDOR_ID";
65 64
66 // (mount point, mount device) 65 // (mount point, mount device)
67 // A mapping from mount point to mount device, as extracted from the mtab 66 // A mapping from mount point to mount device, as extracted from the mtab
68 // file. 67 // file.
69 typedef std::map<FilePath, FilePath> MountPointDeviceMap; 68 typedef std::map<FilePath, FilePath> MountPointDeviceMap;
70 69
71 // Reads mtab file entries into |mtab|. 70 // Reads mtab file entries into |mtab|.
72 void ReadMtab(const FilePath& mtab_path, 71 void ReadMtab(const FilePath& mtab_path,
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 return std::string(); 140 return std::string();
142 141
143 return kVendorModelSerialPrefix + vendor + ":" + model + ":" + serial_short; 142 return kVendorModelSerialPrefix + vendor + ":" + model + ":" + serial_short;
144 } 143 }
145 144
146 // Records GetDeviceInfo result, to see how often we fail to get device details. 145 // Records GetDeviceInfo result, to see how often we fail to get device details.
147 void RecordGetDeviceInfoResult(bool result) { 146 void RecordGetDeviceInfoResult(bool result) {
148 UMA_HISTOGRAM_BOOLEAN("MediaDeviceNotification.UdevRequestSuccess", result); 147 UMA_HISTOGRAM_BOOLEAN("MediaDeviceNotification.UdevRequestSuccess", result);
149 } 148 }
150 149
150 // Returns the storage size information of the device specified by
151 // |device_path|. If the requested information is unavailable, returns an
152 // empty string.
153 string16 GetSizeInfo(const FilePath& device_path, struct udev_device* device) {
154 // sysfs provides the device size value, which is the actual size in bytes
155 // divided by 512.
156 const std::string partition_size = udev_device_get_sysattr_value(
157 device, kSizeSysAttr);
158 uint64 total_size_in_bytes = 0;
159 if (partition_size.empty() ||
160 !base::StringToUint64(partition_size, &total_size_in_bytes))
161 return string16();
162 return ui::FormatBytes(total_size_in_bytes * 512);
163 }
164
165 // Constructs the device name from the device properties. If the device details
166 // are unavailable, returns an empty string.
167 string16 GetDeviceName(struct udev_device* device) {
168 std::string device_label = GetUdevDevicePropertyValue(device, kLabel);
169 if (!device_label.empty() && IsStringUTF8(device_label))
170 return UTF8ToUTF16(device_label);
171
172 device_label = GetUdevDevicePropertyValue(device, kFsUUID);
Lei Zhang 2012/11/12 08:01:39 What are the chances that a partition will not hav
Lei Zhang 2012/11/12 08:01:39 Also, why do we put the UUID in the display name o
kmadhusu 2012/11/12 19:56:19 On Linux, When the user opens a device in a file d
kmadhusu 2012/11/12 19:56:19 Chances are very less. Added a UMA to track this.
173 std::string manufacturer_name = GetDeviceManufacturerName(
174 GetUdevDevicePropertyValue(device, kVendor),
175 GetUdevDevicePropertyValue(device, kModel));
176 if (!manufacturer_name.empty())
177 device_label += " " + manufacturer_name;
178 return IsStringUTF8(device_label) ? UTF8ToUTF16(device_label) : string16();
179 }
180
151 // Get the device information using udev library. 181 // Get the device information using udev library.
152 // On success, returns true and fill in |unique_id|, |name|, and |removable|. 182 // On success, returns true and fill in |unique_id|, |name|, |removable| and
183 // |storage_size|.
153 void GetDeviceInfo(const FilePath& device_path, std::string* unique_id, 184 void GetDeviceInfo(const FilePath& device_path, std::string* unique_id,
154 string16* name, bool* removable) { 185 string16* name, bool* removable, string16* storage_size) {
155 DCHECK(!device_path.empty()); 186 DCHECK(!device_path.empty());
156 187 DCHECK(storage_size);
Lei Zhang 2012/11/12 08:01:39 It's weird to make |storage_size| required, but th
kmadhusu 2012/11/12 19:56:19 Made |storage_size| as a optional param just to be
157 ScopedUdevObject udev_obj(udev_new()); 188 ScopedUdevObject udev_obj(udev_new());
158 if (!udev_obj.get()) { 189 if (!udev_obj.get()) {
159 RecordGetDeviceInfoResult(false); 190 RecordGetDeviceInfoResult(false);
160 return; 191 return;
161 } 192 }
162 193
163 struct stat device_stat; 194 struct stat device_stat;
164 if (stat(device_path.value().c_str(), &device_stat) < 0) { 195 if (stat(device_path.value().c_str(), &device_stat) < 0) {
165 RecordGetDeviceInfoResult(false); 196 RecordGetDeviceInfoResult(false);
166 return; 197 return;
167 } 198 }
168 199
169 char device_type; 200 char device_type;
170 if (S_ISCHR(device_stat.st_mode)) { 201 if (S_ISCHR(device_stat.st_mode)) {
171 device_type = 'c'; 202 device_type = 'c';
172 } else if (S_ISBLK(device_stat.st_mode)) { 203 } else if (S_ISBLK(device_stat.st_mode)) {
173 device_type = 'b'; 204 device_type = 'b';
174 } else { 205 } else {
175 RecordGetDeviceInfoResult(false); 206 RecordGetDeviceInfoResult(false);
176 return; // Not a supported type. 207 return; // Not a supported type.
177 } 208 }
178 209
179 ScopedUdevDeviceObject device( 210 ScopedUdevDeviceObject device(
180 udev_device_new_from_devnum(udev_obj, device_type, device_stat.st_rdev)); 211 udev_device_new_from_devnum(udev_obj, device_type, device_stat.st_rdev));
181 if (!device.get()) { 212 if (!device.get()) {
182 RecordGetDeviceInfoResult(false); 213 RecordGetDeviceInfoResult(false);
183 return; 214 return;
184 } 215 }
185 216
186 // Construct a device name using label or manufacturer (vendor and model) 217 if (name)
187 // details. 218 *name = GetDeviceName(device);
188 if (name) {
189 std::string device_label = GetUdevDevicePropertyValue(device, kLabel);
190 if (device_label.empty())
191 device_label = GetUdevDevicePropertyValue(device, kSerial);
192 if (device_label.empty()) {
193 // Format: VendorInfo ModelInfo
194 // E.g.: KnCompany Model2010
195 device_label = GetUdevDevicePropertyValue(device, kVendor);
196 std::string model_name = GetUdevDevicePropertyValue(device, kModel);
197 if (device_label.empty())
198 device_label = model_name;
199 else if (!model_name.empty())
200 device_label += " " + model_name;
201 }
202 if (IsStringUTF8(device_label))
203 *name = UTF8ToUTF16(device_label);
204 }
205 219
206 if (unique_id) { 220 if (unique_id)
207 *unique_id = MakeDeviceUniqueId(device); 221 *unique_id = MakeDeviceUniqueId(device);
208 }
209 222
210 if (removable) { 223 if (removable) {
211 const char* value = udev_device_get_sysattr_value(device, 224 const char* value = udev_device_get_sysattr_value(device,
212 kRemovableSysAttr); 225 kRemovableSysAttr);
213 if (!value) { 226 if (!value) {
214 // |parent_device| is owned by |device| and does not need to be cleaned 227 // |parent_device| is owned by |device| and does not need to be cleaned
215 // up. 228 // up.
216 struct udev_device* parent_device = 229 struct udev_device* parent_device =
217 udev_device_get_parent_with_subsystem_devtype(device, 230 udev_device_get_parent_with_subsystem_devtype(device,
218 kBlockSubsystemKey, 231 kBlockSubsystemKey,
219 kDiskDeviceTypeKey); 232 kDiskDeviceTypeKey);
220 value = udev_device_get_sysattr_value(parent_device, kRemovableSysAttr); 233 value = udev_device_get_sysattr_value(parent_device, kRemovableSysAttr);
221 } 234 }
222 *removable = (value && atoi(value) == 1); 235 *removable = (value && atoi(value) == 1);
223 } 236 }
237 *storage_size = GetSizeInfo(device_path, device);
224 RecordGetDeviceInfoResult(true); 238 RecordGetDeviceInfoResult(true);
225 } 239 }
226 240
227 } // namespace 241 } // namespace
228 242
229 RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux( 243 RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux(
230 const FilePath& path) 244 const FilePath& path)
231 : initialized_(false), 245 : initialized_(false),
232 mtab_path_(path), 246 mtab_path_(path),
233 get_device_info_func_(&GetDeviceInfo) { 247 get_device_info_func_(&GetDeviceInfo) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 for (size_t i = 0; i < arraysize(kKnownFileSystems); ++i) 279 for (size_t i = 0; i < arraysize(kKnownFileSystems); ++i)
266 known_file_systems_.insert(kKnownFileSystems[i]); 280 known_file_systems_.insert(kKnownFileSystems[i]);
267 281
268 BrowserThread::PostTask( 282 BrowserThread::PostTask(
269 BrowserThread::FILE, FROM_HERE, 283 BrowserThread::FILE, FROM_HERE,
270 base::Bind(&RemovableDeviceNotificationsLinux::InitOnFileThread, this)); 284 base::Bind(&RemovableDeviceNotificationsLinux::InitOnFileThread, this));
271 } 285 }
272 286
273 bool RemovableDeviceNotificationsLinux::GetDeviceInfoForPath( 287 bool RemovableDeviceNotificationsLinux::GetDeviceInfoForPath(
274 const FilePath& path, 288 const FilePath& path,
275 SystemMonitor::RemovableStorageInfo* device_info) const { 289 base::SystemMonitor::RemovableStorageInfo* device_info) const {
276 if (!path.IsAbsolute()) 290 if (!path.IsAbsolute())
277 return false; 291 return false;
278 292
279 FilePath current = path; 293 FilePath current = path;
280 while (!ContainsKey(mount_info_map_, current) && current != current.DirName()) 294 while (!ContainsKey(mount_info_map_, current) && current != current.DirName())
281 current = current.DirName(); 295 current = current.DirName();
282 296
283 MountMap::const_iterator mount_info = mount_info_map_.find(current); 297 MountMap::const_iterator mount_info = mount_info_map_.find(current);
284 if (mount_info == mount_info_map_.end()) 298 if (mount_info == mount_info_map_.end())
285 return false; 299 return false;
286 300
287 if (device_info) { 301 if (device_info) {
288 device_info->device_id = mount_info->second.device_id; 302 device_info->device_id = mount_info->second.device_id;
289 device_info->name = mount_info->second.device_name; 303 device_info->name = mount_info->second.device_name;
290 device_info->location = current.value(); 304 device_info->location = current.value();
291 } 305 }
292 return true; 306 return true;
293 } 307 }
294 308
309 string16 RemovableDeviceNotificationsLinux::GetStorageSize(
310 const std::string& location) {
311 MountMap::const_iterator mount_info = mount_info_map_.find(
312 FilePath(location));
313 return (mount_info != mount_info_map_.end()) ?
314 mount_info->second.device_partition_size : string16();
315 }
316
295 void RemovableDeviceNotificationsLinux::OnFilePathChanged(const FilePath& path, 317 void RemovableDeviceNotificationsLinux::OnFilePathChanged(const FilePath& path,
296 bool error) { 318 bool error) {
297 if (path != mtab_path_) { 319 if (path != mtab_path_) {
298 // This cannot happen unless FilePathWatcher is buggy. Just ignore this 320 // This cannot happen unless FilePathWatcher is buggy. Just ignore this
299 // notification and do nothing. 321 // notification and do nothing.
300 NOTREACHED(); 322 NOTREACHED();
301 return; 323 return;
302 } 324 }
303 if (error) { 325 if (error) {
304 LOG(ERROR) << "Error watching " << mtab_path_.value(); 326 LOG(ERROR) << "Error watching " << mtab_path_.value();
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 // |mount_point|. 369 // |mount_point|.
348 if (new_iter == new_mtab.end() || (new_iter->second != mount_device)) { 370 if (new_iter == new_mtab.end() || (new_iter->second != mount_device)) {
349 MountPriorityMap::iterator priority = 371 MountPriorityMap::iterator priority =
350 mount_priority_map_.find(mount_device); 372 mount_priority_map_.find(mount_device);
351 DCHECK(priority != mount_priority_map_.end()); 373 DCHECK(priority != mount_priority_map_.end());
352 ReferencedMountPoint::const_iterator has_priority = 374 ReferencedMountPoint::const_iterator has_priority =
353 priority->second.find(mount_point); 375 priority->second.find(mount_point);
354 if (MediaStorageUtil::IsRemovableDevice(old_iter->second.device_id)) { 376 if (MediaStorageUtil::IsRemovableDevice(old_iter->second.device_id)) {
355 DCHECK(has_priority != priority->second.end()); 377 DCHECK(has_priority != priority->second.end());
356 if (has_priority->second) { 378 if (has_priority->second) {
357 SystemMonitor::Get()->ProcessRemovableStorageDetached( 379 base::SystemMonitor::Get()->ProcessRemovableStorageDetached(
358 old_iter->second.device_id); 380 old_iter->second.device_id);
359 } 381 }
360 if (priority->second.size() > 1) 382 if (priority->second.size() > 1)
361 multiple_mounted_devices_needing_reattachment.push_back(mount_device); 383 multiple_mounted_devices_needing_reattachment.push_back(mount_device);
362 } 384 }
363 priority->second.erase(mount_point); 385 priority->second.erase(mount_point);
364 if (priority->second.empty()) 386 if (priority->second.empty())
365 mount_priority_map_.erase(mount_device); 387 mount_priority_map_.erase(mount_device);
366 mount_points_to_erase.push_back(mount_point); 388 mount_points_to_erase.push_back(mount_point);
367 } 389 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 const FilePath& other_mount_point = priority->second.begin()->first; 440 const FilePath& other_mount_point = priority->second.begin()->first;
419 priority->second[mount_point] = false; 441 priority->second[mount_point] = false;
420 mount_info_map_[mount_point] = 442 mount_info_map_[mount_point] =
421 mount_info_map_.find(other_mount_point)->second; 443 mount_info_map_.find(other_mount_point)->second;
422 return; 444 return;
423 } 445 }
424 446
425 std::string unique_id; 447 std::string unique_id;
426 string16 name; 448 string16 name;
427 bool removable; 449 bool removable;
428 get_device_info_func_(mount_device, &unique_id, &name, &removable); 450 string16 device_partition_size;
451 get_device_info_func_(mount_device, &unique_id, &name, &removable,
452 &device_partition_size);
429 453
430 // Keep track of device info details to see how often we get invalid values. 454 // Keep track of device info details to see how often we get invalid values.
431 MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, name); 455 MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, name);
432 if (unique_id.empty() || name.empty()) 456 if (unique_id.empty() || name.empty())
433 return; 457 return;
434 458
435 bool has_dcim = IsMediaDevice(mount_point.value()); 459 bool has_dcim = IsMediaDevice(mount_point.value());
436 MediaStorageUtil::Type type; 460 MediaStorageUtil::Type type;
437 if (removable) { 461 if (removable) {
438 if (has_dcim) { 462 if (has_dcim) {
439 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM; 463 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM;
440 } else { 464 } else {
441 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; 465 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM;
442 } 466 }
443 } else { 467 } else {
444 type = MediaStorageUtil::FIXED_MASS_STORAGE; 468 type = MediaStorageUtil::FIXED_MASS_STORAGE;
445 } 469 }
446 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); 470 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id);
447 471
448 MountPointInfo mount_point_info; 472 MountPointInfo mount_point_info;
449 mount_point_info.mount_device = mount_device; 473 mount_point_info.mount_device = mount_device;
450 mount_point_info.device_id = device_id; 474 mount_point_info.device_id = device_id;
451 mount_point_info.device_name = name; 475 mount_point_info.device_name = name;
476 mount_point_info.device_partition_size = device_partition_size;
452 477
453 mount_info_map_[mount_point] = mount_point_info; 478 mount_info_map_[mount_point] = mount_point_info;
454 mount_priority_map_[mount_device][mount_point] = removable; 479 mount_priority_map_[mount_device][mount_point] = removable;
455 480
456 if (removable) { 481 if (removable) {
457 SystemMonitor::Get()->ProcessRemovableStorageAttached(device_id, name, 482 base::SystemMonitor::Get()->ProcessRemovableStorageAttached(
458 mount_point.value()); 483 device_id, GetDisplayNameForDevice(device_partition_size, name),
484 mount_point.value());
459 } 485 }
460 } 486 }
461 487
462 } // namespace chrome 488 } // namespace chrome
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698