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

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 review 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/basictypes.h"
15 #include "base/bind.h" 16 #include "base/bind.h"
16 #include "base/file_path.h" 17 #include "base/file_path.h"
17 #include "base/memory/scoped_generic_obj.h" 18 #include "base/memory/scoped_generic_obj.h"
18 #include "base/metrics/histogram.h" 19 #include "base/metrics/histogram.h"
19 #include "base/stl_util.h" 20 #include "base/stl_util.h"
20 #include "base/string_number_conversions.h" 21 #include "base/string_number_conversions.h"
21 #include "base/string_util.h" 22 #include "base/string_util.h"
22 #include "base/system_monitor/system_monitor.h" 23 #include "base/system_monitor/system_monitor.h"
23 #include "base/utf_string_conversions.h" 24 #include "base/utf_string_conversions.h"
24 #include "chrome/browser/system_monitor/media_device_notifications_utils.h" 25 #include "chrome/browser/system_monitor/media_device_notifications_utils.h"
25 #include "chrome/browser/system_monitor/removable_device_constants.h" 26 #include "chrome/browser/system_monitor/removable_device_constants.h"
26 #include "chrome/browser/system_monitor/media_storage_util.h" 27 #include "chrome/browser/system_monitor/media_storage_util.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 partition size of the device specified by |device_path|.
151 // If the requested information is unavailable, returns 0.
152 uint64 GetDeviceStorageSize(const FilePath& device_path,
153 struct udev_device* device) {
154 // sysfs provides the device size in units of 512-byte blocks.
155 const std::string partition_size = udev_device_get_sysattr_value(
156 device, kSizeSysAttr);
157
158 // Keep track of device size, to see how often this information is
159 // unavailable.
160 UMA_HISTOGRAM_BOOLEAN(
161 "RemovableDeviceNotificationsLinux.device_partition_size_available",
162 !partition_size.empty());
163
164 uint64 total_size_in_bytes = 0;
165 if (!base::StringToUint64(partition_size, &total_size_in_bytes))
166 return 0;
167 return (total_size_in_bytes * 512 <= kuint64max) ?
Lei Zhang 2012/11/13 20:35:04 this is not the right way to detect integer overfl
kmadhusu 2012/11/13 21:57:27 Fixed. // Detection of unsigned multiplication i
168 total_size_in_bytes * 512 : kuint64max;
Lei Zhang 2012/11/13 20:35:04 If we cannot calculate the storage size properly,
kmadhusu 2012/11/13 21:57:27 Done.
169 }
170
171 // Constructs the device name from the device properties. If the device details
172 // are unavailable, returns an empty string.
173 string16 GetDeviceName(struct udev_device* device) {
174 std::string device_label = GetUdevDevicePropertyValue(device, kLabel);
175 if (!device_label.empty() && IsStringUTF8(device_label))
176 return UTF8ToUTF16(device_label);
177
178 device_label = GetUdevDevicePropertyValue(device, kFsUUID);
179 // Keep track of device uuid, to see how often we receive empty uuid values.
180 UMA_HISTOGRAM_BOOLEAN(
181 "RemovableDeviceNotificationsLinux.device_file_system_uuid_available",
182 !device_label.empty());
183
184 const string16 name = GetFullProductName(
185 GetUdevDevicePropertyValue(device, kVendor),
186 GetUdevDevicePropertyValue(device, kModel));
187 return (!name.empty() && IsStringUTF8(device_label)) ?
188 UTF8ToUTF16(device_label + " ") + name : string16();
Lei Zhang 2012/11/13 20:35:04 So if the device does not have a UUID, or has a UU
kmadhusu 2012/11/13 21:57:27 good catch. Fixed.
189 }
190
151 // Get the device information using udev library. 191 // Get the device information using udev library.
152 // On success, returns true and fill in |unique_id|, |name|, and |removable|. 192 // On success, returns true and fill in |unique_id|, |name|, |removable| and
153 void GetDeviceInfo(const FilePath& device_path, std::string* unique_id, 193 // |partition_size_in_bytes|.
154 string16* name, bool* removable) { 194 void GetDeviceInfo(const FilePath& device_path,
195 std::string* unique_id,
196 string16* name,
197 bool* removable,
198 uint64* partition_size_in_bytes) {
155 DCHECK(!device_path.empty()); 199 DCHECK(!device_path.empty());
156
157 ScopedUdevObject udev_obj(udev_new()); 200 ScopedUdevObject udev_obj(udev_new());
158 if (!udev_obj.get()) { 201 if (!udev_obj.get()) {
159 RecordGetDeviceInfoResult(false); 202 RecordGetDeviceInfoResult(false);
160 return; 203 return;
161 } 204 }
162 205
163 struct stat device_stat; 206 struct stat device_stat;
164 if (stat(device_path.value().c_str(), &device_stat) < 0) { 207 if (stat(device_path.value().c_str(), &device_stat) < 0) {
165 RecordGetDeviceInfoResult(false); 208 RecordGetDeviceInfoResult(false);
166 return; 209 return;
167 } 210 }
168 211
169 char device_type; 212 char device_type;
170 if (S_ISCHR(device_stat.st_mode)) { 213 if (S_ISCHR(device_stat.st_mode)) {
171 device_type = 'c'; 214 device_type = 'c';
172 } else if (S_ISBLK(device_stat.st_mode)) { 215 } else if (S_ISBLK(device_stat.st_mode)) {
173 device_type = 'b'; 216 device_type = 'b';
174 } else { 217 } else {
175 RecordGetDeviceInfoResult(false); 218 RecordGetDeviceInfoResult(false);
176 return; // Not a supported type. 219 return; // Not a supported type.
177 } 220 }
178 221
179 ScopedUdevDeviceObject device( 222 ScopedUdevDeviceObject device(
180 udev_device_new_from_devnum(udev_obj, device_type, device_stat.st_rdev)); 223 udev_device_new_from_devnum(udev_obj, device_type, device_stat.st_rdev));
181 if (!device.get()) { 224 if (!device.get()) {
182 RecordGetDeviceInfoResult(false); 225 RecordGetDeviceInfoResult(false);
183 return; 226 return;
184 } 227 }
185 228
186 // Construct a device name using label or manufacturer (vendor and model) 229 if (name)
187 // details. 230 *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 231
206 if (unique_id) { 232 if (unique_id)
207 *unique_id = MakeDeviceUniqueId(device); 233 *unique_id = MakeDeviceUniqueId(device);
208 }
209 234
210 if (removable) { 235 if (removable) {
211 const char* value = udev_device_get_sysattr_value(device, 236 const char* value = udev_device_get_sysattr_value(device,
212 kRemovableSysAttr); 237 kRemovableSysAttr);
213 if (!value) { 238 if (!value) {
214 // |parent_device| is owned by |device| and does not need to be cleaned 239 // |parent_device| is owned by |device| and does not need to be cleaned
215 // up. 240 // up.
216 struct udev_device* parent_device = 241 struct udev_device* parent_device =
217 udev_device_get_parent_with_subsystem_devtype(device, 242 udev_device_get_parent_with_subsystem_devtype(device,
218 kBlockSubsystemKey, 243 kBlockSubsystemKey,
219 kDiskDeviceTypeKey); 244 kDiskDeviceTypeKey);
220 value = udev_device_get_sysattr_value(parent_device, kRemovableSysAttr); 245 value = udev_device_get_sysattr_value(parent_device, kRemovableSysAttr);
221 } 246 }
222 *removable = (value && atoi(value) == 1); 247 *removable = (value && atoi(value) == 1);
223 } 248 }
249
250 if (partition_size_in_bytes)
251 *partition_size_in_bytes = GetDeviceStorageSize(device_path, device);
224 RecordGetDeviceInfoResult(true); 252 RecordGetDeviceInfoResult(true);
225 } 253 }
226 254
227 } // namespace 255 } // namespace
228 256
229 RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux( 257 RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux(
230 const FilePath& path) 258 const FilePath& path)
231 : initialized_(false), 259 : initialized_(false),
232 mtab_path_(path), 260 mtab_path_(path),
233 get_device_info_func_(&GetDeviceInfo) { 261 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) 293 for (size_t i = 0; i < arraysize(kKnownFileSystems); ++i)
266 known_file_systems_.insert(kKnownFileSystems[i]); 294 known_file_systems_.insert(kKnownFileSystems[i]);
267 295
268 BrowserThread::PostTask( 296 BrowserThread::PostTask(
269 BrowserThread::FILE, FROM_HERE, 297 BrowserThread::FILE, FROM_HERE,
270 base::Bind(&RemovableDeviceNotificationsLinux::InitOnFileThread, this)); 298 base::Bind(&RemovableDeviceNotificationsLinux::InitOnFileThread, this));
271 } 299 }
272 300
273 bool RemovableDeviceNotificationsLinux::GetDeviceInfoForPath( 301 bool RemovableDeviceNotificationsLinux::GetDeviceInfoForPath(
274 const FilePath& path, 302 const FilePath& path,
275 SystemMonitor::RemovableStorageInfo* device_info) const { 303 base::SystemMonitor::RemovableStorageInfo* device_info) const {
276 if (!path.IsAbsolute()) 304 if (!path.IsAbsolute())
277 return false; 305 return false;
278 306
279 FilePath current = path; 307 FilePath current = path;
280 while (!ContainsKey(mount_info_map_, current) && current != current.DirName()) 308 while (!ContainsKey(mount_info_map_, current) && current != current.DirName())
281 current = current.DirName(); 309 current = current.DirName();
282 310
283 MountMap::const_iterator mount_info = mount_info_map_.find(current); 311 MountMap::const_iterator mount_info = mount_info_map_.find(current);
284 if (mount_info == mount_info_map_.end()) 312 if (mount_info == mount_info_map_.end())
285 return false; 313 return false;
286 314
287 if (device_info) { 315 if (device_info) {
288 device_info->device_id = mount_info->second.device_id; 316 device_info->device_id = mount_info->second.device_id;
289 device_info->name = mount_info->second.device_name; 317 device_info->name = mount_info->second.device_name;
290 device_info->location = current.value(); 318 device_info->location = current.value();
291 } 319 }
292 return true; 320 return true;
293 } 321 }
294 322
323 uint64 RemovableDeviceNotificationsLinux::GetStorageSize(
324 const std::string& location) {
325 MountMap::const_iterator mount_info = mount_info_map_.find(
326 FilePath(location));
327 return (mount_info != mount_info_map_.end()) ?
328 mount_info->second.partition_size_in_bytes : 0;
329 }
330
295 void RemovableDeviceNotificationsLinux::OnFilePathChanged(const FilePath& path, 331 void RemovableDeviceNotificationsLinux::OnFilePathChanged(const FilePath& path,
296 bool error) { 332 bool error) {
297 if (path != mtab_path_) { 333 if (path != mtab_path_) {
298 // This cannot happen unless FilePathWatcher is buggy. Just ignore this 334 // This cannot happen unless FilePathWatcher is buggy. Just ignore this
299 // notification and do nothing. 335 // notification and do nothing.
300 NOTREACHED(); 336 NOTREACHED();
301 return; 337 return;
302 } 338 }
303 if (error) { 339 if (error) {
304 LOG(ERROR) << "Error watching " << mtab_path_.value(); 340 LOG(ERROR) << "Error watching " << mtab_path_.value();
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 // |mount_point|. 383 // |mount_point|.
348 if (new_iter == new_mtab.end() || (new_iter->second != mount_device)) { 384 if (new_iter == new_mtab.end() || (new_iter->second != mount_device)) {
349 MountPriorityMap::iterator priority = 385 MountPriorityMap::iterator priority =
350 mount_priority_map_.find(mount_device); 386 mount_priority_map_.find(mount_device);
351 DCHECK(priority != mount_priority_map_.end()); 387 DCHECK(priority != mount_priority_map_.end());
352 ReferencedMountPoint::const_iterator has_priority = 388 ReferencedMountPoint::const_iterator has_priority =
353 priority->second.find(mount_point); 389 priority->second.find(mount_point);
354 if (MediaStorageUtil::IsRemovableDevice(old_iter->second.device_id)) { 390 if (MediaStorageUtil::IsRemovableDevice(old_iter->second.device_id)) {
355 DCHECK(has_priority != priority->second.end()); 391 DCHECK(has_priority != priority->second.end());
356 if (has_priority->second) { 392 if (has_priority->second) {
357 SystemMonitor::Get()->ProcessRemovableStorageDetached( 393 base::SystemMonitor::Get()->ProcessRemovableStorageDetached(
358 old_iter->second.device_id); 394 old_iter->second.device_id);
359 } 395 }
360 if (priority->second.size() > 1) 396 if (priority->second.size() > 1)
361 multiple_mounted_devices_needing_reattachment.push_back(mount_device); 397 multiple_mounted_devices_needing_reattachment.push_back(mount_device);
362 } 398 }
363 priority->second.erase(mount_point); 399 priority->second.erase(mount_point);
364 if (priority->second.empty()) 400 if (priority->second.empty())
365 mount_priority_map_.erase(mount_device); 401 mount_priority_map_.erase(mount_device);
366 mount_points_to_erase.push_back(mount_point); 402 mount_points_to_erase.push_back(mount_point);
367 } 403 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 const FilePath& other_mount_point = priority->second.begin()->first; 454 const FilePath& other_mount_point = priority->second.begin()->first;
419 priority->second[mount_point] = false; 455 priority->second[mount_point] = false;
420 mount_info_map_[mount_point] = 456 mount_info_map_[mount_point] =
421 mount_info_map_.find(other_mount_point)->second; 457 mount_info_map_.find(other_mount_point)->second;
422 return; 458 return;
423 } 459 }
424 460
425 std::string unique_id; 461 std::string unique_id;
426 string16 name; 462 string16 name;
427 bool removable; 463 bool removable;
428 get_device_info_func_(mount_device, &unique_id, &name, &removable); 464 uint64 partition_size_in_bytes;
465 get_device_info_func_(mount_device, &unique_id, &name, &removable,
466 &partition_size_in_bytes);
429 467
430 // Keep track of device info details to see how often we get invalid values. 468 // Keep track of device info details to see how often we get invalid values.
431 MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, name); 469 MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, name);
432 if (unique_id.empty() || name.empty()) 470 if (unique_id.empty() || name.empty())
433 return; 471 return;
434 472
435 bool has_dcim = IsMediaDevice(mount_point.value()); 473 bool has_dcim = IsMediaDevice(mount_point.value());
436 MediaStorageUtil::Type type; 474 MediaStorageUtil::Type type;
437 if (removable) { 475 if (removable) {
438 if (has_dcim) { 476 if (has_dcim) {
439 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM; 477 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM;
440 } else { 478 } else {
441 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; 479 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM;
442 } 480 }
443 } else { 481 } else {
444 type = MediaStorageUtil::FIXED_MASS_STORAGE; 482 type = MediaStorageUtil::FIXED_MASS_STORAGE;
445 } 483 }
446 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); 484 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id);
447 485
448 MountPointInfo mount_point_info; 486 MountPointInfo mount_point_info;
449 mount_point_info.mount_device = mount_device; 487 mount_point_info.mount_device = mount_device;
450 mount_point_info.device_id = device_id; 488 mount_point_info.device_id = device_id;
451 mount_point_info.device_name = name; 489 mount_point_info.device_name = name;
490 mount_point_info.partition_size_in_bytes = partition_size_in_bytes;
452 491
453 mount_info_map_[mount_point] = mount_point_info; 492 mount_info_map_[mount_point] = mount_point_info;
454 mount_priority_map_[mount_device][mount_point] = removable; 493 mount_priority_map_[mount_device][mount_point] = removable;
455 494
456 if (removable) { 495 if (removable) {
457 SystemMonitor::Get()->ProcessRemovableStorageAttached(device_id, name, 496 base::SystemMonitor::Get()->ProcessRemovableStorageAttached(
458 mount_point.value()); 497 device_id, GetDisplayNameForDevice(partition_size_in_bytes, name),
498 mount_point.value());
459 } 499 }
460 } 500 }
461 501
462 } // namespace chrome 502 } // namespace chrome
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698