cros: Update enable-dev UI.
[chromium-blink-merge.git] / components / storage_monitor / storage_monitor_chromeos.cc
bloba584f6732188922e3c57fdefb62d5039b0137e82
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/storage_monitor/storage_monitor_chromeos.h"
7 #include "base/files/file_path.h"
8 #include "base/logging.h"
9 #include "base/stl_util.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "components/storage_monitor/media_storage_util.h"
15 #include "components/storage_monitor/media_transfer_protocol_device_observer_linux.h"
16 #include "components/storage_monitor/removable_device_constants.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
20 using chromeos::disks::DiskMountManager;
22 namespace storage_monitor {
24 namespace {
26 // Constructs a device id using uuid or manufacturer (vendor and product) id
27 // details.
28 std::string MakeDeviceUniqueId(const DiskMountManager::Disk& disk) {
29 std::string uuid = disk.fs_uuid();
30 if (!uuid.empty())
31 return kFSUniqueIdPrefix + uuid;
33 // If one of the vendor or product information is missing, its value in the
34 // string is empty.
35 // Format: VendorModelSerial:VendorInfo:ModelInfo:SerialInfo
36 // TODO(kmadhusu) Extract serial information for the disks and append it to
37 // the device unique id.
38 const std::string& vendor = disk.vendor_id();
39 const std::string& product = disk.product_id();
40 if (vendor.empty() && product.empty())
41 return std::string();
42 return kVendorModelSerialPrefix + vendor + ":" + product + ":";
45 // Returns true if the requested device is valid, else false. On success, fills
46 // in |info|.
47 bool GetDeviceInfo(const DiskMountManager::MountPointInfo& mount_info,
48 bool has_dcim,
49 StorageInfo* info) {
50 DCHECK(info);
51 std::string source_path = mount_info.source_path;
53 const DiskMountManager::Disk* disk =
54 DiskMountManager::GetInstance()->FindDiskBySourcePath(source_path);
55 if (!disk || disk->device_type() == chromeos::DEVICE_TYPE_UNKNOWN)
56 return false;
58 std::string unique_id = MakeDeviceUniqueId(*disk);
59 // Keep track of device uuid and label, to see how often we receive empty
60 // values.
61 base::string16 device_label = base::UTF8ToUTF16(disk->device_label());
62 MediaStorageUtil::RecordDeviceInfoHistogram(true, unique_id, device_label);
63 if (unique_id.empty())
64 return false;
66 StorageInfo::Type type = has_dcim ?
67 StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM :
68 StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM;
70 *info = StorageInfo(StorageInfo::MakeDeviceId(type, unique_id),
71 mount_info.mount_path,
72 device_label,
73 base::UTF8ToUTF16(disk->vendor_name()),
74 base::UTF8ToUTF16(disk->product_name()),
75 disk->total_size_in_bytes());
76 return true;
79 // Returns whether the mount point in |mount_info| is a media device or not.
80 bool CheckMountedPathOnFileThread(
81 const DiskMountManager::MountPointInfo& mount_info) {
82 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE));
83 return MediaStorageUtil::HasDcim(base::FilePath(mount_info.mount_path));
86 } // namespace
88 using content::BrowserThread;
90 StorageMonitorCros::StorageMonitorCros()
91 : weak_ptr_factory_(this) {
94 StorageMonitorCros::~StorageMonitorCros() {
95 DiskMountManager* manager = DiskMountManager::GetInstance();
96 if (manager) {
97 manager->RemoveObserver(this);
101 void StorageMonitorCros::Init() {
102 DCHECK(DiskMountManager::GetInstance());
103 DiskMountManager::GetInstance()->AddObserver(this);
104 CheckExistingMountPoints();
106 if (!media_transfer_protocol_manager_) {
107 scoped_refptr<base::MessageLoopProxy> loop_proxy;
108 media_transfer_protocol_manager_.reset(
109 device::MediaTransferProtocolManager::Initialize(loop_proxy));
112 media_transfer_protocol_device_observer_.reset(
113 new MediaTransferProtocolDeviceObserverLinux(
114 receiver(), media_transfer_protocol_manager_.get()));
117 void StorageMonitorCros::CheckExistingMountPoints() {
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
119 const DiskMountManager::MountPointMap& mount_point_map =
120 DiskMountManager::GetInstance()->mount_points();
121 for (DiskMountManager::MountPointMap::const_iterator it =
122 mount_point_map.begin(); it != mount_point_map.end(); ++it) {
123 BrowserThread::PostTaskAndReplyWithResult(
124 BrowserThread::FILE, FROM_HERE,
125 base::Bind(&CheckMountedPathOnFileThread, it->second),
126 base::Bind(&StorageMonitorCros::AddMountedPath,
127 weak_ptr_factory_.GetWeakPtr(), it->second));
130 // Note: relies on scheduled tasks on the file thread being sequential. This
131 // block needs to follow the for loop, so that the DoNothing call on the FILE
132 // thread happens after the scheduled metadata retrievals, meaning that the
133 // reply callback will then happen after all the AddNewMount calls.
134 BrowserThread::PostTaskAndReply(
135 BrowserThread::FILE, FROM_HERE,
136 base::Bind(&base::DoNothing),
137 base::Bind(&StorageMonitorCros::MarkInitialized,
138 weak_ptr_factory_.GetWeakPtr()));
141 void StorageMonitorCros::OnDiskEvent(DiskMountManager::DiskEvent event,
142 const DiskMountManager::Disk* disk) {}
144 void StorageMonitorCros::OnDeviceEvent(DiskMountManager::DeviceEvent event,
145 const std::string& device_path) {}
147 void StorageMonitorCros::OnMountEvent(
148 DiskMountManager::MountEvent event,
149 chromeos::MountError error_code,
150 const DiskMountManager::MountPointInfo& mount_info) {
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
153 // Ignore mount points that are not devices.
154 if (mount_info.mount_type != chromeos::MOUNT_TYPE_DEVICE)
155 return;
156 // Ignore errors.
157 if (error_code != chromeos::MOUNT_ERROR_NONE)
158 return;
159 if (mount_info.mount_condition != chromeos::disks::MOUNT_CONDITION_NONE)
160 return;
162 switch (event) {
163 case DiskMountManager::MOUNTING: {
164 if (ContainsKey(mount_map_, mount_info.mount_path)) {
165 NOTREACHED();
166 return;
169 BrowserThread::PostTaskAndReplyWithResult(
170 BrowserThread::FILE, FROM_HERE,
171 base::Bind(&CheckMountedPathOnFileThread, mount_info),
172 base::Bind(&StorageMonitorCros::AddMountedPath,
173 weak_ptr_factory_.GetWeakPtr(), mount_info));
174 break;
176 case DiskMountManager::UNMOUNTING: {
177 MountMap::iterator it = mount_map_.find(mount_info.mount_path);
178 if (it == mount_map_.end())
179 return;
180 receiver()->ProcessDetach(it->second.device_id());
181 mount_map_.erase(it);
182 break;
187 void StorageMonitorCros::OnFormatEvent(DiskMountManager::FormatEvent event,
188 chromeos::FormatError error_code,
189 const std::string& device_path) {}
191 void StorageMonitorCros::SetMediaTransferProtocolManagerForTest(
192 device::MediaTransferProtocolManager* test_manager) {
193 DCHECK(!media_transfer_protocol_manager_);
194 media_transfer_protocol_manager_.reset(test_manager);
198 bool StorageMonitorCros::GetStorageInfoForPath(
199 const base::FilePath& path,
200 StorageInfo* device_info) const {
201 DCHECK(device_info);
203 if (media_transfer_protocol_device_observer_->GetStorageInfoForPath(
204 path, device_info)) {
205 return true;
208 if (!path.IsAbsolute())
209 return false;
211 base::FilePath current = path;
212 while (!ContainsKey(mount_map_, current.value()) &&
213 current != current.DirName()) {
214 current = current.DirName();
217 MountMap::const_iterator info_it = mount_map_.find(current.value());
218 if (info_it == mount_map_.end())
219 return false;
221 *device_info = info_it->second;
222 return true;
225 // Callback executed when the unmount call is run by DiskMountManager.
226 // Forwards result to |EjectDevice| caller.
227 void NotifyUnmountResult(
228 base::Callback<void(StorageMonitor::EjectStatus)> callback,
229 chromeos::MountError error_code) {
230 if (error_code == chromeos::MOUNT_ERROR_NONE)
231 callback.Run(StorageMonitor::EJECT_OK);
232 else
233 callback.Run(StorageMonitor::EJECT_FAILURE);
236 void StorageMonitorCros::EjectDevice(
237 const std::string& device_id,
238 base::Callback<void(EjectStatus)> callback) {
239 StorageInfo::Type type;
240 if (!StorageInfo::CrackDeviceId(device_id, &type, NULL)) {
241 callback.Run(EJECT_FAILURE);
242 return;
245 if (type == StorageInfo::MTP_OR_PTP) {
246 media_transfer_protocol_device_observer_->EjectDevice(device_id, callback);
247 return;
250 std::string mount_path;
251 for (MountMap::const_iterator info_it = mount_map_.begin();
252 info_it != mount_map_.end(); ++info_it) {
253 if (info_it->second.device_id() == device_id)
254 mount_path = info_it->first;
257 if (mount_path.empty()) {
258 callback.Run(EJECT_NO_SUCH_DEVICE);
259 return;
262 DiskMountManager* manager = DiskMountManager::GetInstance();
263 if (!manager) {
264 callback.Run(EJECT_FAILURE);
265 return;
268 manager->UnmountPath(mount_path, chromeos::UNMOUNT_OPTIONS_NONE,
269 base::Bind(NotifyUnmountResult, callback));
272 device::MediaTransferProtocolManager*
273 StorageMonitorCros::media_transfer_protocol_manager() {
274 return media_transfer_protocol_manager_.get();
277 void StorageMonitorCros::AddMountedPath(
278 const DiskMountManager::MountPointInfo& mount_info,
279 bool has_dcim) {
280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
282 if (ContainsKey(mount_map_, mount_info.mount_path)) {
283 // CheckExistingMountPointsOnUIThread() added the mount point information
284 // in the map before the device attached handler is called. Therefore, an
285 // entry for the device already exists in the map.
286 return;
289 // Get the media device uuid and label if exists.
290 StorageInfo info;
291 if (!GetDeviceInfo(mount_info, has_dcim, &info))
292 return;
294 if (info.device_id().empty())
295 return;
297 mount_map_.insert(std::make_pair(mount_info.mount_path, info));
299 receiver()->ProcessAttach(info);
302 StorageMonitor* StorageMonitor::CreateInternal() {
303 return new StorageMonitorCros();
306 } // namespace storage_monitor