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

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: Fix linux_clang compile error 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 <= kuint64max / 512) ?
168 total_size_in_bytes * 512 : 0;
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
188 const string16 device_label_utf16 =
189 (!device_label.empty() && IsStringUTF8(device_label)) ?
190 UTF8ToUTF16(device_label) : string16();
191 if (!name.empty() && !device_label_utf16.empty())
192 return device_label_utf16 + ASCIIToUTF16(" ") + name;
193 return name.empty() ? device_label_utf16 : name;
194 }
195
151 // Get the device information using udev library. 196 // Get the device information using udev library.
152 // On success, returns true and fill in |unique_id|, |name|, and |removable|. 197 // On success, returns true and fill in |unique_id|, |name|, |removable| and
153 void GetDeviceInfo(const FilePath& device_path, std::string* unique_id, 198 // |partition_size_in_bytes|.
154 string16* name, bool* removable) { 199 void GetDeviceInfo(const FilePath& device_path,
200 std::string* unique_id,
201 string16* name,
202 bool* removable,
203 uint64* partition_size_in_bytes) {
155 DCHECK(!device_path.empty()); 204 DCHECK(!device_path.empty());
156
157 ScopedUdevObject udev_obj(udev_new()); 205 ScopedUdevObject udev_obj(udev_new());
158 if (!udev_obj.get()) { 206 if (!udev_obj.get()) {
159 RecordGetDeviceInfoResult(false); 207 RecordGetDeviceInfoResult(false);
160 return; 208 return;
161 } 209 }
162 210
163 struct stat device_stat; 211 struct stat device_stat;
164 if (stat(device_path.value().c_str(), &device_stat) < 0) { 212 if (stat(device_path.value().c_str(), &device_stat) < 0) {
165 RecordGetDeviceInfoResult(false); 213 RecordGetDeviceInfoResult(false);
166 return; 214 return;
167 } 215 }
168 216
169 char device_type; 217 char device_type;
170 if (S_ISCHR(device_stat.st_mode)) { 218 if (S_ISCHR(device_stat.st_mode)) {
171 device_type = 'c'; 219 device_type = 'c';
172 } else if (S_ISBLK(device_stat.st_mode)) { 220 } else if (S_ISBLK(device_stat.st_mode)) {
173 device_type = 'b'; 221 device_type = 'b';
174 } else { 222 } else {
175 RecordGetDeviceInfoResult(false); 223 RecordGetDeviceInfoResult(false);
176 return; // Not a supported type. 224 return; // Not a supported type.
177 } 225 }
178 226
179 ScopedUdevDeviceObject device( 227 ScopedUdevDeviceObject device(
180 udev_device_new_from_devnum(udev_obj, device_type, device_stat.st_rdev)); 228 udev_device_new_from_devnum(udev_obj, device_type, device_stat.st_rdev));
181 if (!device.get()) { 229 if (!device.get()) {
182 RecordGetDeviceInfoResult(false); 230 RecordGetDeviceInfoResult(false);
183 return; 231 return;
184 } 232 }
185 233
186 // Construct a device name using label or manufacturer (vendor and model) 234 if (name)
187 // details. 235 *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 236
206 if (unique_id) { 237 if (unique_id)
207 *unique_id = MakeDeviceUniqueId(device); 238 *unique_id = MakeDeviceUniqueId(device);
208 }
209 239
210 if (removable) { 240 if (removable) {
211 const char* value = udev_device_get_sysattr_value(device, 241 const char* value = udev_device_get_sysattr_value(device,
212 kRemovableSysAttr); 242 kRemovableSysAttr);
213 if (!value) { 243 if (!value) {
214 // |parent_device| is owned by |device| and does not need to be cleaned 244 // |parent_device| is owned by |device| and does not need to be cleaned
215 // up. 245 // up.
216 struct udev_device* parent_device = 246 struct udev_device* parent_device =
217 udev_device_get_parent_with_subsystem_devtype(device, 247 udev_device_get_parent_with_subsystem_devtype(device,
218 kBlockSubsystemKey, 248 kBlockSubsystemKey,
219 kDiskDeviceTypeKey); 249 kDiskDeviceTypeKey);
220 value = udev_device_get_sysattr_value(parent_device, kRemovableSysAttr); 250 value = udev_device_get_sysattr_value(parent_device, kRemovableSysAttr);
221 } 251 }
222 *removable = (value && atoi(value) == 1); 252 *removable = (value && atoi(value) == 1);
223 } 253 }
254
255 if (partition_size_in_bytes)
256 *partition_size_in_bytes = GetDeviceStorageSize(device_path, device);
224 RecordGetDeviceInfoResult(true); 257 RecordGetDeviceInfoResult(true);
225 } 258 }
226 259
227 } // namespace 260 } // namespace
228 261
229 RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux( 262 RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux(
230 const FilePath& path) 263 const FilePath& path)
231 : initialized_(false), 264 : initialized_(false),
232 mtab_path_(path), 265 mtab_path_(path),
233 get_device_info_func_(&GetDeviceInfo) { 266 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) 298 for (size_t i = 0; i < arraysize(kKnownFileSystems); ++i)
266 known_file_systems_.insert(kKnownFileSystems[i]); 299 known_file_systems_.insert(kKnownFileSystems[i]);
267 300
268 BrowserThread::PostTask( 301 BrowserThread::PostTask(
269 BrowserThread::FILE, FROM_HERE, 302 BrowserThread::FILE, FROM_HERE,
270 base::Bind(&RemovableDeviceNotificationsLinux::InitOnFileThread, this)); 303 base::Bind(&RemovableDeviceNotificationsLinux::InitOnFileThread, this));
271 } 304 }
272 305
273 bool RemovableDeviceNotificationsLinux::GetDeviceInfoForPath( 306 bool RemovableDeviceNotificationsLinux::GetDeviceInfoForPath(
274 const FilePath& path, 307 const FilePath& path,
275 SystemMonitor::RemovableStorageInfo* device_info) const { 308 base::SystemMonitor::RemovableStorageInfo* device_info) const {
276 if (!path.IsAbsolute()) 309 if (!path.IsAbsolute())
277 return false; 310 return false;
278 311
279 FilePath current = path; 312 FilePath current = path;
280 while (!ContainsKey(mount_info_map_, current) && current != current.DirName()) 313 while (!ContainsKey(mount_info_map_, current) && current != current.DirName())
281 current = current.DirName(); 314 current = current.DirName();
282 315
283 MountMap::const_iterator mount_info = mount_info_map_.find(current); 316 MountMap::const_iterator mount_info = mount_info_map_.find(current);
284 if (mount_info == mount_info_map_.end()) 317 if (mount_info == mount_info_map_.end())
285 return false; 318 return false;
286 319
287 if (device_info) { 320 if (device_info) {
288 device_info->device_id = mount_info->second.device_id; 321 device_info->device_id = mount_info->second.device_id;
289 device_info->name = mount_info->second.device_name; 322 device_info->name = mount_info->second.device_name;
290 device_info->location = current.value(); 323 device_info->location = current.value();
291 } 324 }
292 return true; 325 return true;
293 } 326 }
294 327
328 uint64 RemovableDeviceNotificationsLinux::GetStorageSize(
329 const std::string& location) const {
330 MountMap::const_iterator mount_info = mount_info_map_.find(
331 FilePath(location));
332 return (mount_info != mount_info_map_.end()) ?
333 mount_info->second.partition_size_in_bytes : 0;
334 }
335
295 void RemovableDeviceNotificationsLinux::OnFilePathChanged(const FilePath& path, 336 void RemovableDeviceNotificationsLinux::OnFilePathChanged(const FilePath& path,
296 bool error) { 337 bool error) {
297 if (path != mtab_path_) { 338 if (path != mtab_path_) {
298 // This cannot happen unless FilePathWatcher is buggy. Just ignore this 339 // This cannot happen unless FilePathWatcher is buggy. Just ignore this
299 // notification and do nothing. 340 // notification and do nothing.
300 NOTREACHED(); 341 NOTREACHED();
301 return; 342 return;
302 } 343 }
303 if (error) { 344 if (error) {
304 LOG(ERROR) << "Error watching " << mtab_path_.value(); 345 LOG(ERROR) << "Error watching " << mtab_path_.value();
305 return; 346 return;
306 } 347 }
307 348
308 UpdateMtab(); 349 UpdateMtab();
309 } 350 }
310 351
352 RemovableDeviceNotificationsLinux::MountPointInfo::MountPointInfo()
353 : partition_size_in_bytes(0) {
354 }
355
311 void RemovableDeviceNotificationsLinux::InitOnFileThread() { 356 void RemovableDeviceNotificationsLinux::InitOnFileThread() {
312 DCHECK(!initialized_); 357 DCHECK(!initialized_);
313 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 358 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
314 initialized_ = true; 359 initialized_ = true;
315 360
316 // The callback passed to Watch() has to be unretained. Otherwise 361 // The callback passed to Watch() has to be unretained. Otherwise
317 // RemovableDeviceNotificationsLinux will live longer than expected, and 362 // RemovableDeviceNotificationsLinux will live longer than expected, and
318 // FilePathWatcher will get in trouble at shutdown time. 363 // FilePathWatcher will get in trouble at shutdown time.
319 bool ret = file_watcher_.Watch( 364 bool ret = file_watcher_.Watch(
320 mtab_path_, 365 mtab_path_,
(...skipping 26 matching lines...) Expand all
347 // |mount_point|. 392 // |mount_point|.
348 if (new_iter == new_mtab.end() || (new_iter->second != mount_device)) { 393 if (new_iter == new_mtab.end() || (new_iter->second != mount_device)) {
349 MountPriorityMap::iterator priority = 394 MountPriorityMap::iterator priority =
350 mount_priority_map_.find(mount_device); 395 mount_priority_map_.find(mount_device);
351 DCHECK(priority != mount_priority_map_.end()); 396 DCHECK(priority != mount_priority_map_.end());
352 ReferencedMountPoint::const_iterator has_priority = 397 ReferencedMountPoint::const_iterator has_priority =
353 priority->second.find(mount_point); 398 priority->second.find(mount_point);
354 if (MediaStorageUtil::IsRemovableDevice(old_iter->second.device_id)) { 399 if (MediaStorageUtil::IsRemovableDevice(old_iter->second.device_id)) {
355 DCHECK(has_priority != priority->second.end()); 400 DCHECK(has_priority != priority->second.end());
356 if (has_priority->second) { 401 if (has_priority->second) {
357 SystemMonitor::Get()->ProcessRemovableStorageDetached( 402 base::SystemMonitor::Get()->ProcessRemovableStorageDetached(
358 old_iter->second.device_id); 403 old_iter->second.device_id);
359 } 404 }
360 if (priority->second.size() > 1) 405 if (priority->second.size() > 1)
361 multiple_mounted_devices_needing_reattachment.push_back(mount_device); 406 multiple_mounted_devices_needing_reattachment.push_back(mount_device);
362 } 407 }
363 priority->second.erase(mount_point); 408 priority->second.erase(mount_point);
364 if (priority->second.empty()) 409 if (priority->second.empty())
365 mount_priority_map_.erase(mount_device); 410 mount_priority_map_.erase(mount_device);
366 mount_points_to_erase.push_back(mount_point); 411 mount_points_to_erase.push_back(mount_point);
367 } 412 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 const FilePath& other_mount_point = priority->second.begin()->first; 463 const FilePath& other_mount_point = priority->second.begin()->first;
419 priority->second[mount_point] = false; 464 priority->second[mount_point] = false;
420 mount_info_map_[mount_point] = 465 mount_info_map_[mount_point] =
421 mount_info_map_.find(other_mount_point)->second; 466 mount_info_map_.find(other_mount_point)->second;
422 return; 467 return;
423 } 468 }
424 469
425 std::string unique_id; 470 std::string unique_id;
426 string16 name; 471 string16 name;
427 bool removable; 472 bool removable;
428 get_device_info_func_(mount_device, &unique_id, &name, &removable); 473 uint64 partition_size_in_bytes;
474 get_device_info_func_(mount_device, &unique_id, &name, &removable,
475 &partition_size_in_bytes);
429 476
430 // Keep track of device info details to see how often we get invalid values. 477 // Keep track of device info details to see how often we get invalid values.
431 MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, name); 478 MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, name);
432 if (unique_id.empty() || name.empty()) 479 if (unique_id.empty() || name.empty())
433 return; 480 return;
434 481
435 bool has_dcim = IsMediaDevice(mount_point.value()); 482 bool has_dcim = IsMediaDevice(mount_point.value());
436 MediaStorageUtil::Type type; 483 MediaStorageUtil::Type type;
437 if (removable) { 484 if (removable) {
438 if (has_dcim) { 485 if (has_dcim) {
439 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM; 486 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_WITH_DCIM;
440 } else { 487 } else {
441 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; 488 type = MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM;
442 } 489 }
443 } else { 490 } else {
444 type = MediaStorageUtil::FIXED_MASS_STORAGE; 491 type = MediaStorageUtil::FIXED_MASS_STORAGE;
445 } 492 }
446 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); 493 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id);
447 494
448 MountPointInfo mount_point_info; 495 MountPointInfo mount_point_info;
449 mount_point_info.mount_device = mount_device; 496 mount_point_info.mount_device = mount_device;
450 mount_point_info.device_id = device_id; 497 mount_point_info.device_id = device_id;
451 mount_point_info.device_name = name; 498 mount_point_info.device_name = name;
499 mount_point_info.partition_size_in_bytes = partition_size_in_bytes;
452 500
453 mount_info_map_[mount_point] = mount_point_info; 501 mount_info_map_[mount_point] = mount_point_info;
454 mount_priority_map_[mount_device][mount_point] = removable; 502 mount_priority_map_[mount_device][mount_point] = removable;
455 503
456 if (removable) { 504 if (removable) {
457 SystemMonitor::Get()->ProcessRemovableStorageAttached(device_id, name, 505 base::SystemMonitor::Get()->ProcessRemovableStorageAttached(
458 mount_point.value()); 506 device_id, GetDisplayNameForDevice(partition_size_in_bytes, name),
507 mount_point.value());
459 } 508 }
460 } 509 }
461 510
462 } // namespace chrome 511 } // namespace chrome
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698