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

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: Addressed comments. 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 27
28 namespace chrome { 28 namespace chrome {
29 29
30 using base::SystemMonitor;
31 using content::BrowserThread; 30 using content::BrowserThread;
32 31
33 namespace { 32 namespace {
34 33
35 static RemovableDeviceNotificationsLinux* 34 static RemovableDeviceNotificationsLinux*
36 g_removable_device_notifications_linux = NULL; 35 g_removable_device_notifications_linux = NULL;
37 36
38 // List of file systems we care about. 37 // List of file systems we care about.
39 const char* const kKnownFileSystems[] = { 38 const char* const kKnownFileSystems[] = {
40 "ext2", 39 "ext2",
41 "ext3", 40 "ext3",
42 "ext4", 41 "ext4",
43 "fat", 42 "fat",
44 "hfsplus", 43 "hfsplus",
45 "iso9660", 44 "iso9660",
46 "msdos", 45 "msdos",
47 "ntfs", 46 "ntfs",
48 "udf", 47 "udf",
49 "vfat", 48 "vfat",
50 }; 49 };
51 50
52 // udev device property constants. 51 // udev device property constants.
53 const char kBlockSubsystemKey[] = "block"; 52 const char kBlockSubsystemKey[] = "block";
54 const char kDevName[] = "DEVNAME";
55 const char kDiskDeviceTypeKey[] = "disk"; 53 const char kDiskDeviceTypeKey[] = "disk";
56 const char kFsUUID[] = "ID_FS_UUID"; 54 const char kFsUUID[] = "ID_FS_UUID";
57 const char kLabel[] = "ID_FS_LABEL"; 55 const char kLabel[] = "ID_FS_LABEL";
58 const char kModel[] = "ID_MODEL"; 56 const char kModel[] = "ID_MODEL";
59 const char kModelID[] = "ID_MODEL_ID"; 57 const char kModelID[] = "ID_MODEL_ID";
60 const char kRemovableSysAttr[] = "removable"; 58 const char kRemovableSysAttr[] = "removable";
61 const char kSerial[] = "ID_SERIAL";
62 const char kSerialShort[] = "ID_SERIAL_SHORT"; 59 const char kSerialShort[] = "ID_SERIAL_SHORT";
60 const char kSizeSysAttr[] = "size";
63 const char kVendor[] = "ID_VENDOR"; 61 const char kVendor[] = "ID_VENDOR";
64 const char kVendorID[] = "ID_VENDOR_ID"; 62 const char kVendorID[] = "ID_VENDOR_ID";
65 63
66 // (mount point, mount device) 64 // (mount point, mount device)
67 // A mapping from mount point to mount device, as extracted from the mtab 65 // A mapping from mount point to mount device, as extracted from the mtab
68 // file. 66 // file.
69 typedef std::map<FilePath, FilePath> MountPointDeviceMap; 67 typedef std::map<FilePath, FilePath> MountPointDeviceMap;
70 68
71 // Reads mtab file entries into |mtab|. 69 // Reads mtab file entries into |mtab|.
72 void ReadMtab(const FilePath& mtab_path, 70 void ReadMtab(const FilePath& mtab_path,
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 return std::string(); 139 return std::string();
142 140
143 return kVendorModelSerialPrefix + vendor + ":" + model + ":" + serial_short; 141 return kVendorModelSerialPrefix + vendor + ":" + model + ":" + serial_short;
144 } 142 }
145 143
146 // Records GetDeviceInfo result, to see how often we fail to get device details. 144 // Records GetDeviceInfo result, to see how often we fail to get device details.
147 void RecordGetDeviceInfoResult(bool result) { 145 void RecordGetDeviceInfoResult(bool result) {
148 UMA_HISTOGRAM_BOOLEAN("MediaDeviceNotification.UdevRequestSuccess", result); 146 UMA_HISTOGRAM_BOOLEAN("MediaDeviceNotification.UdevRequestSuccess", result);
149 } 147 }
150 148
149 // Returns the storage partition size of the device specified by |device_path|.
150 // If the requested information is unavailable, returns 0.
151 uint64 GetDeviceStorageSize(const FilePath& device_path,
152 struct udev_device* device) {
153 // sysfs provides the device size in units of 512-byte blocks.
154 const std::string partition_size = udev_device_get_sysattr_value(
155 device, kSizeSysAttr);
156
157 // Keep track of device size, to see how often this information is
158 // unavailable.
159 UMA_HISTOGRAM_BOOLEAN(
160 "RemovableDeviceNotificationsLinux.device_partition_size_available",
161 !partition_size.empty());
162
163 uint64 total_size_in_bytes = 0;
164 return base::StringToUint64(partition_size, &total_size_in_bytes) ?
165 total_size_in_bytes * 512 : 0;
Lei Zhang 2012/11/13 03:35:07 Oh, it's probably good to make sure this does not
kmadhusu 2012/11/13 17:47:44 Added to check to make sure "total_size_in_bytes *
166 }
167
168 // Constructs the device name from the device properties. If the device details
169 // are unavailable, returns an empty string.
170 string16 GetDeviceName(struct udev_device* device) {
171 std::string device_label = GetUdevDevicePropertyValue(device, kLabel);
172 if (!device_label.empty() && IsStringUTF8(device_label))
173 return UTF8ToUTF16(device_label);
174
175 device_label = GetUdevDevicePropertyValue(device, kFsUUID);
176 // Keep track of device uuid, to see how often we receive empty uuid values.
177 UMA_HISTOGRAM_BOOLEAN(
178 "RemovableDeviceNotificationsLinux.device_file_system_uuid_available",
179 !device_label.empty());
180
181 const string16 name = GetFullProductName(
182 GetUdevDevicePropertyValue(device, kVendor),
183 GetUdevDevicePropertyValue(device, kModel));
184 return (!name.empty() && IsStringUTF8(device_label)) ?
185 UTF8ToUTF16(device_label + " ") + name : string16();
186 }
187
151 // Get the device information using udev library. 188 // Get the device information using udev library.
152 // On success, returns true and fill in |unique_id|, |name|, and |removable|. 189 // On success, returns true and fill in |unique_id|, |name|, |removable| and
153 void GetDeviceInfo(const FilePath& device_path, std::string* unique_id, 190 // |partition_size_in_bytes|.
154 string16* name, bool* removable) { 191 void GetDeviceInfo(const FilePath& device_path,
192 std::string* unique_id,
193 string16* name,
194 bool* removable,
195 uint64* partition_size_in_bytes) {
155 DCHECK(!device_path.empty()); 196 DCHECK(!device_path.empty());
156
157 ScopedUdevObject udev_obj(udev_new()); 197 ScopedUdevObject udev_obj(udev_new());
158 if (!udev_obj.get()) { 198 if (!udev_obj.get()) {
159 RecordGetDeviceInfoResult(false); 199 RecordGetDeviceInfoResult(false);
160 return; 200 return;
161 } 201 }
162 202
163 struct stat device_stat; 203 struct stat device_stat;
164 if (stat(device_path.value().c_str(), &device_stat) < 0) { 204 if (stat(device_path.value().c_str(), &device_stat) < 0) {
165 RecordGetDeviceInfoResult(false); 205 RecordGetDeviceInfoResult(false);
166 return; 206 return;
167 } 207 }
168 208
169 char device_type; 209 char device_type;
170 if (S_ISCHR(device_stat.st_mode)) { 210 if (S_ISCHR(device_stat.st_mode)) {
171 device_type = 'c'; 211 device_type = 'c';
172 } else if (S_ISBLK(device_stat.st_mode)) { 212 } else if (S_ISBLK(device_stat.st_mode)) {
173 device_type = 'b'; 213 device_type = 'b';
174 } else { 214 } else {
175 RecordGetDeviceInfoResult(false); 215 RecordGetDeviceInfoResult(false);
176 return; // Not a supported type. 216 return; // Not a supported type.
177 } 217 }
178 218
179 ScopedUdevDeviceObject device( 219 ScopedUdevDeviceObject device(
180 udev_device_new_from_devnum(udev_obj, device_type, device_stat.st_rdev)); 220 udev_device_new_from_devnum(udev_obj, device_type, device_stat.st_rdev));
181 if (!device.get()) { 221 if (!device.get()) {
182 RecordGetDeviceInfoResult(false); 222 RecordGetDeviceInfoResult(false);
183 return; 223 return;
184 } 224 }
185 225
186 // Construct a device name using label or manufacturer (vendor and model) 226 if (name)
187 // details. 227 *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 228
206 if (unique_id) { 229 if (unique_id)
207 *unique_id = MakeDeviceUniqueId(device); 230 *unique_id = MakeDeviceUniqueId(device);
208 }
209 231
210 if (removable) { 232 if (removable) {
211 const char* value = udev_device_get_sysattr_value(device, 233 const char* value = udev_device_get_sysattr_value(device,
212 kRemovableSysAttr); 234 kRemovableSysAttr);
213 if (!value) { 235 if (!value) {
214 // |parent_device| is owned by |device| and does not need to be cleaned 236 // |parent_device| is owned by |device| and does not need to be cleaned
215 // up. 237 // up.
216 struct udev_device* parent_device = 238 struct udev_device* parent_device =
217 udev_device_get_parent_with_subsystem_devtype(device, 239 udev_device_get_parent_with_subsystem_devtype(device,
218 kBlockSubsystemKey, 240 kBlockSubsystemKey,
219 kDiskDeviceTypeKey); 241 kDiskDeviceTypeKey);
220 value = udev_device_get_sysattr_value(parent_device, kRemovableSysAttr); 242 value = udev_device_get_sysattr_value(parent_device, kRemovableSysAttr);
221 } 243 }
222 *removable = (value && atoi(value) == 1); 244 *removable = (value && atoi(value) == 1);
223 } 245 }
246
247 if (partition_size_in_bytes)
248 *partition_size_in_bytes = GetDeviceStorageSize(device_path, device);
224 RecordGetDeviceInfoResult(true); 249 RecordGetDeviceInfoResult(true);
225 } 250 }
226 251
227 } // namespace 252 } // namespace
228 253
229 RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux( 254 RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux(
230 const FilePath& path) 255 const FilePath& path)
231 : initialized_(false), 256 : initialized_(false),
232 mtab_path_(path), 257 mtab_path_(path),
233 get_device_info_func_(&GetDeviceInfo) { 258 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) 290 for (size_t i = 0; i < arraysize(kKnownFileSystems); ++i)
266 known_file_systems_.insert(kKnownFileSystems[i]); 291 known_file_systems_.insert(kKnownFileSystems[i]);
267 292
268 BrowserThread::PostTask( 293 BrowserThread::PostTask(
269 BrowserThread::FILE, FROM_HERE, 294 BrowserThread::FILE, FROM_HERE,
270 base::Bind(&RemovableDeviceNotificationsLinux::InitOnFileThread, this)); 295 base::Bind(&RemovableDeviceNotificationsLinux::InitOnFileThread, this));
271 } 296 }
272 297
273 bool RemovableDeviceNotificationsLinux::GetDeviceInfoForPath( 298 bool RemovableDeviceNotificationsLinux::GetDeviceInfoForPath(
274 const FilePath& path, 299 const FilePath& path,
275 SystemMonitor::RemovableStorageInfo* device_info) const { 300 base::SystemMonitor::RemovableStorageInfo* device_info) const {
276 if (!path.IsAbsolute()) 301 if (!path.IsAbsolute())
277 return false; 302 return false;
278 303
279 FilePath current = path; 304 FilePath current = path;
280 while (!ContainsKey(mount_info_map_, current) && current != current.DirName()) 305 while (!ContainsKey(mount_info_map_, current) && current != current.DirName())
281 current = current.DirName(); 306 current = current.DirName();
282 307
283 MountMap::const_iterator mount_info = mount_info_map_.find(current); 308 MountMap::const_iterator mount_info = mount_info_map_.find(current);
284 if (mount_info == mount_info_map_.end()) 309 if (mount_info == mount_info_map_.end())
285 return false; 310 return false;
286 311
287 if (device_info) { 312 if (device_info) {
288 device_info->device_id = mount_info->second.device_id; 313 device_info->device_id = mount_info->second.device_id;
289 device_info->name = mount_info->second.device_name; 314 device_info->name = mount_info->second.device_name;
290 device_info->location = current.value(); 315 device_info->location = current.value();
291 } 316 }
292 return true; 317 return true;
293 } 318 }
294 319
320 uint64 RemovableDeviceNotificationsLinux::GetStorageSize(
321 const std::string& location) {
322 MountMap::const_iterator mount_info = mount_info_map_.find(
323 FilePath(location));
324 return (mount_info != mount_info_map_.end()) ?
325 mount_info->second.partition_size_in_bytes : 0;
326 }
327
295 void RemovableDeviceNotificationsLinux::OnFilePathChanged(const FilePath& path, 328 void RemovableDeviceNotificationsLinux::OnFilePathChanged(const FilePath& path,
296 bool error) { 329 bool error) {
297 if (path != mtab_path_) { 330 if (path != mtab_path_) {
298 // This cannot happen unless FilePathWatcher is buggy. Just ignore this 331 // This cannot happen unless FilePathWatcher is buggy. Just ignore this
299 // notification and do nothing. 332 // notification and do nothing.
300 NOTREACHED(); 333 NOTREACHED();
301 return; 334 return;
302 } 335 }
303 if (error) { 336 if (error) {
304 LOG(ERROR) << "Error watching " << mtab_path_.value(); 337 LOG(ERROR) << "Error watching " << mtab_path_.value();
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 // |mount_point|. 380 // |mount_point|.
348 if (new_iter == new_mtab.end() || (new_iter->second != mount_device)) { 381 if (new_iter == new_mtab.end() || (new_iter->second != mount_device)) {
349 MountPriorityMap::iterator priority = 382 MountPriorityMap::iterator priority =
350 mount_priority_map_.find(mount_device); 383 mount_priority_map_.find(mount_device);
351 DCHECK(priority != mount_priority_map_.end()); 384 DCHECK(priority != mount_priority_map_.end());
352 ReferencedMountPoint::const_iterator has_priority = 385 ReferencedMountPoint::const_iterator has_priority =
353 priority->second.find(mount_point); 386 priority->second.find(mount_point);
354 if (MediaStorageUtil::IsRemovableDevice(old_iter->second.device_id)) { 387 if (MediaStorageUtil::IsRemovableDevice(old_iter->second.device_id)) {
355 DCHECK(has_priority != priority->second.end()); 388 DCHECK(has_priority != priority->second.end());
356 if (has_priority->second) { 389 if (has_priority->second) {
357 SystemMonitor::Get()->ProcessRemovableStorageDetached( 390 base::SystemMonitor::Get()->ProcessRemovableStorageDetached(
358 old_iter->second.device_id); 391 old_iter->second.device_id);
359 } 392 }
360 if (priority->second.size() > 1) 393 if (priority->second.size() > 1)
361 multiple_mounted_devices_needing_reattachment.push_back(mount_device); 394 multiple_mounted_devices_needing_reattachment.push_back(mount_device);
362 } 395 }
363 priority->second.erase(mount_point); 396 priority->second.erase(mount_point);
364 if (priority->second.empty()) 397 if (priority->second.empty())
365 mount_priority_map_.erase(mount_device); 398 mount_priority_map_.erase(mount_device);
366 mount_points_to_erase.push_back(mount_point); 399 mount_points_to_erase.push_back(mount_point);
367 } 400 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 const FilePath& other_mount_point = priority->second.begin()->first; 451 const FilePath& other_mount_point = priority->second.begin()->first;
419 priority->second[mount_point] = false; 452 priority->second[mount_point] = false;
420 mount_info_map_[mount_point] = 453 mount_info_map_[mount_point] =
421 mount_info_map_.find(other_mount_point)->second; 454 mount_info_map_.find(other_mount_point)->second;
422 return; 455 return;
423 } 456 }
424 457
425 std::string unique_id; 458 std::string unique_id;
426 string16 name; 459 string16 name;
427 bool removable; 460 bool removable;
428 get_device_info_func_(mount_device, &unique_id, &name, &removable); 461 uint64 partition_size_in_bytes;
462 get_device_info_func_(mount_device, &unique_id, &name, &removable,
463 &partition_size_in_bytes);
429 464
430 // Keep track of device info details to see how often we get invalid values. 465 // Keep track of device info details to see how often we get invalid values.
431 MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, name); 466 MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, name);
432 if (unique_id.empty() || name.empty()) 467 if (unique_id.empty() || name.empty())
433 return; 468 return;
434 469
435 bool has_dcim = IsMediaDevice(mount_point.value()); 470 bool has_dcim = IsMediaDevice(mount_point.value());
436 MediaStorageUtil::Type type; 471 MediaStorageUtil::Type type;
437 if (removable) { 472 if (removable) {
438 if (has_dcim) { 473 if (has_dcim) {
439 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM; 474 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM;
440 } else { 475 } else {
441 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; 476 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM;
442 } 477 }
443 } else { 478 } else {
444 type = MediaStorageUtil::FIXED_MASS_STORAGE; 479 type = MediaStorageUtil::FIXED_MASS_STORAGE;
445 } 480 }
446 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); 481 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id);
447 482
448 MountPointInfo mount_point_info; 483 MountPointInfo mount_point_info;
449 mount_point_info.mount_device = mount_device; 484 mount_point_info.mount_device = mount_device;
450 mount_point_info.device_id = device_id; 485 mount_point_info.device_id = device_id;
451 mount_point_info.device_name = name; 486 mount_point_info.device_name = name;
487 mount_point_info.partition_size_in_bytes = partition_size_in_bytes;
452 488
453 mount_info_map_[mount_point] = mount_point_info; 489 mount_info_map_[mount_point] = mount_point_info;
454 mount_priority_map_[mount_device][mount_point] = removable; 490 mount_priority_map_[mount_device][mount_point] = removable;
455 491
456 if (removable) { 492 if (removable) {
457 SystemMonitor::Get()->ProcessRemovableStorageAttached(device_id, name, 493 base::SystemMonitor::Get()->ProcessRemovableStorageAttached(
458 mount_point.value()); 494 device_id, GetDisplayNameForDevice(partition_size_in_bytes, name),
495 mount_point.value());
459 } 496 }
460 } 497 }
461 498
462 } // namespace chrome 499 } // namespace chrome
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698