OLD | NEW |
---|---|
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/storage_monitor/removable_device_notifications_linux.h" | 7 #include "chrome/browser/storage_monitor/storage_monitor_linux.h" |
8 | 8 |
9 #include <mntent.h> | 9 #include <mntent.h> |
10 #include <stdio.h> | 10 #include <stdio.h> |
11 | 11 |
12 #include <list> | 12 #include <list> |
13 | 13 |
14 #include "base/basictypes.h" | 14 #include "base/basictypes.h" |
15 #include "base/bind.h" | 15 #include "base/bind.h" |
16 #include "base/files/file_path.h" | 16 #include "base/files/file_path.h" |
17 #include "base/metrics/histogram.h" | 17 #include "base/metrics/histogram.h" |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
116 // If the requested information is unavailable, returns 0. | 116 // If the requested information is unavailable, returns 0. |
117 uint64 GetDeviceStorageSize(const base::FilePath& device_path, | 117 uint64 GetDeviceStorageSize(const base::FilePath& device_path, |
118 struct udev_device* device) { | 118 struct udev_device* device) { |
119 // sysfs provides the device size in units of 512-byte blocks. | 119 // sysfs provides the device size in units of 512-byte blocks. |
120 const std::string partition_size = udev_device_get_sysattr_value( | 120 const std::string partition_size = udev_device_get_sysattr_value( |
121 device, kSizeSysAttr); | 121 device, kSizeSysAttr); |
122 | 122 |
123 // Keep track of device size, to see how often this information is | 123 // Keep track of device size, to see how often this information is |
124 // unavailable. | 124 // unavailable. |
125 UMA_HISTOGRAM_BOOLEAN( | 125 UMA_HISTOGRAM_BOOLEAN( |
126 "RemovableDeviceNotificationsLinux.device_partition_size_available", | 126 "RemovableDeviceNotificationsLinux.device_partition_size_available", |
tommycli
2013/03/01 18:26:29
This is still old name. I'll get it in a separate
vandebo (ex-Chrome)
2013/03/01 19:47:39
UMAs are special. A UMA is collecting data from us
| |
127 !partition_size.empty()); | 127 !partition_size.empty()); |
128 | 128 |
129 uint64 total_size_in_bytes = 0; | 129 uint64 total_size_in_bytes = 0; |
130 if (!base::StringToUint64(partition_size, &total_size_in_bytes)) | 130 if (!base::StringToUint64(partition_size, &total_size_in_bytes)) |
131 return 0; | 131 return 0; |
132 return (total_size_in_bytes <= kuint64max / 512) ? | 132 return (total_size_in_bytes <= kuint64max / 512) ? |
133 total_size_in_bytes * 512 : 0; | 133 total_size_in_bytes * 512 : 0; |
134 } | 134 } |
135 | 135 |
136 // Constructs the device name from the device properties. If the device details | 136 // Constructs the device name from the device properties. If the device details |
137 // are unavailable, returns an empty string. | 137 // are unavailable, returns an empty string. |
138 string16 GetDeviceName(struct udev_device* device) { | 138 string16 GetDeviceName(struct udev_device* device) { |
139 std::string device_label = GetUdevDevicePropertyValue(device, kLabel); | 139 std::string device_label = GetUdevDevicePropertyValue(device, kLabel); |
140 if (!device_label.empty() && IsStringUTF8(device_label)) | 140 if (!device_label.empty() && IsStringUTF8(device_label)) |
141 return UTF8ToUTF16(device_label); | 141 return UTF8ToUTF16(device_label); |
142 | 142 |
143 device_label = GetUdevDevicePropertyValue(device, kFsUUID); | 143 device_label = GetUdevDevicePropertyValue(device, kFsUUID); |
144 // Keep track of device uuid, to see how often we receive empty uuid values. | 144 // Keep track of device uuid, to see how often we receive empty uuid values. |
145 UMA_HISTOGRAM_BOOLEAN( | 145 UMA_HISTOGRAM_BOOLEAN( |
146 "RemovableDeviceNotificationsLinux.device_file_system_uuid_available", | 146 "RemovableDeviceNotificationsLinux.device_file_system_uuid_available", |
tommycli
2013/03/01 18:26:29
Samesies.
| |
147 !device_label.empty()); | 147 !device_label.empty()); |
148 | 148 |
149 const string16 name = GetFullProductName( | 149 const string16 name = GetFullProductName( |
150 GetUdevDevicePropertyValue(device, kVendor), | 150 GetUdevDevicePropertyValue(device, kVendor), |
151 GetUdevDevicePropertyValue(device, kModel)); | 151 GetUdevDevicePropertyValue(device, kModel)); |
152 | 152 |
153 const string16 device_label_utf16 = | 153 const string16 device_label_utf16 = |
154 (!device_label.empty() && IsStringUTF8(device_label)) ? | 154 (!device_label.empty() && IsStringUTF8(device_label)) ? |
155 UTF8ToUTF16(device_label) : string16(); | 155 UTF8ToUTF16(device_label) : string16(); |
156 if (!name.empty() && !device_label_utf16.empty()) | 156 if (!name.empty() && !device_label_utf16.empty()) |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
217 *removable = (value && atoi(value) == 1); | 217 *removable = (value && atoi(value) == 1); |
218 } | 218 } |
219 | 219 |
220 if (partition_size_in_bytes) | 220 if (partition_size_in_bytes) |
221 *partition_size_in_bytes = GetDeviceStorageSize(device_path, device); | 221 *partition_size_in_bytes = GetDeviceStorageSize(device_path, device); |
222 RecordGetDeviceInfoResult(true); | 222 RecordGetDeviceInfoResult(true); |
223 } | 223 } |
224 | 224 |
225 } // namespace | 225 } // namespace |
226 | 226 |
227 RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux( | 227 StorageMonitorLinux::StorageMonitorLinux( |
228 const base::FilePath& path) | 228 const base::FilePath& path) |
229 : initialized_(false), | 229 : initialized_(false), |
230 mtab_path_(path), | 230 mtab_path_(path), |
231 get_device_info_func_(&GetDeviceInfo) { | 231 get_device_info_func_(&GetDeviceInfo) { |
232 } | 232 } |
233 | 233 |
234 RemovableDeviceNotificationsLinux::RemovableDeviceNotificationsLinux( | 234 StorageMonitorLinux::StorageMonitorLinux( |
235 const base::FilePath& path, | 235 const base::FilePath& path, |
236 GetDeviceInfoFunc get_device_info_func) | 236 GetDeviceInfoFunc get_device_info_func) |
237 : initialized_(false), | 237 : initialized_(false), |
238 mtab_path_(path), | 238 mtab_path_(path), |
239 get_device_info_func_(get_device_info_func) { | 239 get_device_info_func_(get_device_info_func) { |
240 } | 240 } |
241 | 241 |
242 RemovableDeviceNotificationsLinux::~RemovableDeviceNotificationsLinux() { | 242 StorageMonitorLinux::~StorageMonitorLinux() { |
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
244 } | 244 } |
245 | 245 |
246 void RemovableDeviceNotificationsLinux::Init() { | 246 void StorageMonitorLinux::Init() { |
247 DCHECK(!mtab_path_.empty()); | 247 DCHECK(!mtab_path_.empty()); |
248 | 248 |
249 // Put |kKnownFileSystems| in std::set to get O(log N) access time. | 249 // Put |kKnownFileSystems| in std::set to get O(log N) access time. |
250 for (size_t i = 0; i < arraysize(kKnownFileSystems); ++i) | 250 for (size_t i = 0; i < arraysize(kKnownFileSystems); ++i) |
251 known_file_systems_.insert(kKnownFileSystems[i]); | 251 known_file_systems_.insert(kKnownFileSystems[i]); |
252 | 252 |
253 BrowserThread::PostTask( | 253 BrowserThread::PostTask( |
254 BrowserThread::FILE, FROM_HERE, | 254 BrowserThread::FILE, FROM_HERE, |
255 base::Bind(&RemovableDeviceNotificationsLinux::InitOnFileThread, this)); | 255 base::Bind(&StorageMonitorLinux::InitOnFileThread, this)); |
256 } | 256 } |
257 | 257 |
258 bool RemovableDeviceNotificationsLinux::GetStorageInfoForPath( | 258 bool StorageMonitorLinux::GetStorageInfoForPath( |
259 const base::FilePath& path, | 259 const base::FilePath& path, |
260 StorageInfo* device_info) const { | 260 StorageInfo* device_info) const { |
261 if (!path.IsAbsolute()) | 261 if (!path.IsAbsolute()) |
262 return false; | 262 return false; |
263 | 263 |
264 base::FilePath current = path; | 264 base::FilePath current = path; |
265 while (!ContainsKey(mount_info_map_, current) && current != current.DirName()) | 265 while (!ContainsKey(mount_info_map_, current) && current != current.DirName()) |
266 current = current.DirName(); | 266 current = current.DirName(); |
267 | 267 |
268 MountMap::const_iterator mount_info = mount_info_map_.find(current); | 268 MountMap::const_iterator mount_info = mount_info_map_.find(current); |
269 if (mount_info == mount_info_map_.end()) | 269 if (mount_info == mount_info_map_.end()) |
270 return false; | 270 return false; |
271 | 271 |
272 if (device_info) { | 272 if (device_info) { |
273 device_info->device_id = mount_info->second.device_id; | 273 device_info->device_id = mount_info->second.device_id; |
274 device_info->name = mount_info->second.device_name; | 274 device_info->name = mount_info->second.device_name; |
275 device_info->location = current.value(); | 275 device_info->location = current.value(); |
276 } | 276 } |
277 return true; | 277 return true; |
278 } | 278 } |
279 | 279 |
280 uint64 RemovableDeviceNotificationsLinux::GetStorageSize( | 280 uint64 StorageMonitorLinux::GetStorageSize( |
281 const std::string& location) const { | 281 const std::string& location) const { |
282 MountMap::const_iterator mount_info = mount_info_map_.find( | 282 MountMap::const_iterator mount_info = mount_info_map_.find( |
283 base::FilePath(location)); | 283 base::FilePath(location)); |
284 return (mount_info != mount_info_map_.end()) ? | 284 return (mount_info != mount_info_map_.end()) ? |
285 mount_info->second.partition_size_in_bytes : 0; | 285 mount_info->second.partition_size_in_bytes : 0; |
286 } | 286 } |
287 | 287 |
288 void RemovableDeviceNotificationsLinux::OnFilePathChanged( | 288 void StorageMonitorLinux::OnFilePathChanged( |
289 const base::FilePath& path, | 289 const base::FilePath& path, |
290 bool error) { | 290 bool error) { |
291 if (path != mtab_path_) { | 291 if (path != mtab_path_) { |
292 // This cannot happen unless FilePathWatcher is buggy. Just ignore this | 292 // This cannot happen unless FilePathWatcher is buggy. Just ignore this |
293 // notification and do nothing. | 293 // notification and do nothing. |
294 NOTREACHED(); | 294 NOTREACHED(); |
295 return; | 295 return; |
296 } | 296 } |
297 if (error) { | 297 if (error) { |
298 LOG(ERROR) << "Error watching " << mtab_path_.value(); | 298 LOG(ERROR) << "Error watching " << mtab_path_.value(); |
299 return; | 299 return; |
300 } | 300 } |
301 | 301 |
302 UpdateMtab(); | 302 UpdateMtab(); |
303 } | 303 } |
304 | 304 |
305 RemovableDeviceNotificationsLinux::MountPointInfo::MountPointInfo() | 305 StorageMonitorLinux::MountPointInfo::MountPointInfo() |
306 : partition_size_in_bytes(0) { | 306 : partition_size_in_bytes(0) { |
307 } | 307 } |
308 | 308 |
309 void RemovableDeviceNotificationsLinux::InitOnFileThread() { | 309 void StorageMonitorLinux::InitOnFileThread() { |
310 DCHECK(!initialized_); | 310 DCHECK(!initialized_); |
311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
312 initialized_ = true; | 312 initialized_ = true; |
313 | 313 |
314 // The callback passed to Watch() has to be unretained. Otherwise | 314 // The callback passed to Watch() has to be unretained. Otherwise |
315 // RemovableDeviceNotificationsLinux will live longer than expected, and | 315 // RemovableDeviceNotificationsLinux will live longer than expected, and |
316 // FilePathWatcher will get in trouble at shutdown time. | 316 // FilePathWatcher will get in trouble at shutdown time. |
317 bool ret = file_watcher_.Watch( | 317 bool ret = file_watcher_.Watch( |
318 mtab_path_, false, | 318 mtab_path_, false, |
319 base::Bind(&RemovableDeviceNotificationsLinux::OnFilePathChanged, | 319 base::Bind(&StorageMonitorLinux::OnFilePathChanged, |
320 base::Unretained(this))); | 320 base::Unretained(this))); |
321 if (!ret) { | 321 if (!ret) { |
322 LOG(ERROR) << "Adding watch for " << mtab_path_.value() << " failed"; | 322 LOG(ERROR) << "Adding watch for " << mtab_path_.value() << " failed"; |
323 return; | 323 return; |
324 } | 324 } |
325 | 325 |
326 UpdateMtab(); | 326 UpdateMtab(); |
327 } | 327 } |
328 | 328 |
329 void RemovableDeviceNotificationsLinux::UpdateMtab() { | 329 void StorageMonitorLinux::UpdateMtab() { |
330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 330 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
331 | 331 |
332 MountPointDeviceMap new_mtab; | 332 MountPointDeviceMap new_mtab; |
333 ReadMtab(mtab_path_, known_file_systems_, &new_mtab); | 333 ReadMtab(mtab_path_, known_file_systems_, &new_mtab); |
334 | 334 |
335 // Check existing mtab entries for unaccounted mount points. | 335 // Check existing mtab entries for unaccounted mount points. |
336 // These mount points must have been removed in the new mtab. | 336 // These mount points must have been removed in the new mtab. |
337 std::list<base::FilePath> mount_points_to_erase; | 337 std::list<base::FilePath> mount_points_to_erase; |
338 std::list<base::FilePath> multiple_mounted_devices_needing_reattachment; | 338 std::list<base::FilePath> multiple_mounted_devices_needing_reattachment; |
339 for (MountMap::const_iterator old_iter = mount_info_map_.begin(); | 339 for (MountMap::const_iterator old_iter = mount_info_map_.begin(); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
401 MountMap::iterator old_iter = mount_info_map_.find(mount_point); | 401 MountMap::iterator old_iter = mount_info_map_.find(mount_point); |
402 if (old_iter == mount_info_map_.end() || | 402 if (old_iter == mount_info_map_.end() || |
403 old_iter->second.mount_device != mount_device) { | 403 old_iter->second.mount_device != mount_device) { |
404 // New mount point found or an existing mount point found with a new | 404 // New mount point found or an existing mount point found with a new |
405 // device. | 405 // device. |
406 AddNewMount(mount_device, mount_point); | 406 AddNewMount(mount_device, mount_point); |
407 } | 407 } |
408 } | 408 } |
409 } | 409 } |
410 | 410 |
411 void RemovableDeviceNotificationsLinux::AddNewMount( | 411 void StorageMonitorLinux::AddNewMount( |
412 const base::FilePath& mount_device, const base::FilePath& mount_point) { | 412 const base::FilePath& mount_device, const base::FilePath& mount_point) { |
413 MountPriorityMap::iterator priority = | 413 MountPriorityMap::iterator priority = |
414 mount_priority_map_.find(mount_device); | 414 mount_priority_map_.find(mount_device); |
415 if (priority != mount_priority_map_.end()) { | 415 if (priority != mount_priority_map_.end()) { |
416 const base::FilePath& other_mount_point = priority->second.begin()->first; | 416 const base::FilePath& other_mount_point = priority->second.begin()->first; |
417 priority->second[mount_point] = false; | 417 priority->second[mount_point] = false; |
418 mount_info_map_[mount_point] = | 418 mount_info_map_[mount_point] = |
419 mount_info_map_.find(other_mount_point)->second; | 419 mount_info_map_.find(other_mount_point)->second; |
420 return; | 420 return; |
421 } | 421 } |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
455 mount_priority_map_[mount_device][mount_point] = removable; | 455 mount_priority_map_[mount_device][mount_point] = removable; |
456 | 456 |
457 if (removable) { | 457 if (removable) { |
458 receiver()->ProcessAttach(StorageInfo( | 458 receiver()->ProcessAttach(StorageInfo( |
459 device_id, GetDisplayNameForDevice(partition_size_in_bytes, name), | 459 device_id, GetDisplayNameForDevice(partition_size_in_bytes, name), |
460 mount_point.value())); | 460 mount_point.value())); |
461 } | 461 } |
462 } | 462 } |
463 | 463 |
464 } // namespace chrome | 464 } // namespace chrome |
OLD | NEW |