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

Unified Diff: chrome/browser/extensions/api/system_info_storage/storage_info_provider.cc

Issue 16707002: [SystemInfo API] Rewrite storage info provider using storage monitor impl. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove storage_info_provider_linux_unittest.cc in chrome_tests_unit.gypi Created 7 years, 6 months 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/extensions/api/system_info_storage/storage_info_provider.cc
diff --git a/chrome/browser/extensions/api/system_info_storage/storage_info_provider.cc b/chrome/browser/extensions/api/system_info_storage/storage_info_provider.cc
index b29afa09bb4b775392070e88523654f633290cc6..54f47654bb5e0f1c1ac7b4a6c18e5cd5c5d3e61a 100644
--- a/chrome/browser/extensions/api/system_info_storage/storage_info_provider.cc
+++ b/chrome/browser/extensions/api/system_info_storage/storage_info_provider.cc
@@ -6,6 +6,7 @@
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/storage_monitor/storage_monitor.h"
#include "content/public/browser/browser_thread.h"
@@ -13,7 +14,10 @@
namespace extensions {
using content::BrowserThread;
+using chrome::StorageMonitor;
using api::experimental_system_info_storage::StorageUnitInfo;
+using api::experimental_system_info_storage::STORAGE_UNIT_TYPE_FIXED;
+using api::experimental_system_info_storage::STORAGE_UNIT_TYPE_REMOVABLE;
namespace systeminfo {
@@ -21,127 +25,173 @@ const char kStorageTypeUnknown[] = "unknown";
const char kStorageTypeFixed[] = "fixed";
const char kStorageTypeRemovable[] = "removable";
+void BuildStorageUnitInfo(const chrome::StorageInfo& info,
+ StorageUnitInfo* unit) {
+ unit->id = info.device_id();
+#if defined(OS_POSIX)
+ unit->location = info.location();
+#elif defined(OS_WIN)
+ unit->location = WideToUTF8(info.location());
+#endif
+ // TODO(hmin): Might need to take MTP device into consideration.
+ unit->type = chrome::StorageInfo::IsRemovableDevice(unit->id) ?
+ STORAGE_UNIT_TYPE_REMOVABLE : STORAGE_UNIT_TYPE_FIXED;
+ unit->capacity = static_cast<double>(info.total_size_in_bytes());
+ unit->available_capacity = 0;
+}
+
} // namespace systeminfo
const int kDefaultPollingIntervalMs = 1000;
const char kWatchingTokenName[] = "_storage_info_watching_token_";
StorageInfoProvider::StorageInfoProvider()
- : observers_(new ObserverListThreadSafe<StorageInfoObserver>()),
+ : observers_(new ObserverListThreadSafe<StorageFreeSpaceObserver>()),
watching_interval_(kDefaultPollingIntervalMs) {
- DCHECK(chrome::StorageMonitor::GetInstance());
- chrome::StorageMonitor::GetInstance()->AddObserver(this);
}
StorageInfoProvider::~StorageInfoProvider() {
- // Note that StorageInfoProvider is defined as a LazyInstance which would be
- // destroyed at process exiting, so its lifetime should be longer than the
- // StorageMonitor instance that would be destroyed before
- // StorageInfoProvider.
- if (chrome::StorageMonitor::GetInstance())
- chrome::StorageMonitor::GetInstance()->RemoveObserver(this);
}
-void StorageInfoProvider::AddObserver(StorageInfoObserver* obs) {
- observers_->AddObserver(obs);
+void StorageInfoProvider::StartQueryInfoImpl() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // Register a callback to notify UI thread that StorageMonitor finishes the
+ // storage metadata retrieval on FILE thread. See the comments of
+ // StorageMonitor::Initialize about when the callback gets run.
+ StorageMonitor::GetInstance()->Initialize(
+ base::Bind(&StorageInfoProvider::QueryInfoImplOnUIThread, this));
}
-void StorageInfoProvider::RemoveObserver(StorageInfoObserver* obs) {
- observers_->RemoveObserver(obs);
+void StorageInfoProvider::QueryInfoImplOnUIThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // At this point, we can call StorageMonitor::GetAllAvailableStorages to
+ // get the correct results.
+ QueryInfo(&info_);
+ // The amount of available capacity should be queried on blocking pool.
+ PostQueryTaskToBlockingPool(FROM_HERE,
+ base::Bind(&StorageInfoProvider::QueryAvailableCapacityOnBlockingPool,
+ this));
}
-void StorageInfoProvider::OnRemovableStorageAttached(
- const chrome::StorageInfo& info) {
- // Since the storage API uses the location as identifier, e.g.
- // the drive letter on Windows while mount point on Posix. Here we has to
- // convert the |info.location| to UTF-8 encoding.
- //
- // TODO(hongbo): use |info.device_id| instead of using |info.location|
- // to keep the id persisting between device attachments, like
- // StorageMonitor does.
-#if defined(OS_POSIX)
- std::string id = info.location();
-#elif defined(OS_WIN)
- std::string id = UTF16ToUTF8(info.location());
-#endif
- // Post a task to blocking pool for querying the information.
- BrowserThread::PostBlockingPoolTask(FROM_HERE,
- base::Bind(&StorageInfoProvider::QueryAttachedStorageInfoOnBlockingPool,
- this, id));
+void StorageInfoProvider::QueryAvailableCapacityOnBlockingPool() {
+ DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+ for (StorageInfo::iterator it = info_.begin(); it != info_.end(); ++it) {
+ int64 amount = GetStorageFreeSpace(
+ base::FilePath::FromUTF8Unsafe((*it)->location));
+ if (amount > 0)
+ (*it)->available_capacity = static_cast<double>(amount);
+ }
+
+ // Notify UI thread that the querying operation is already completed.
+ BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&StorageInfoProvider::OnQueryCompleted, this, true));
}
-void StorageInfoProvider::QueryAttachedStorageInfoOnBlockingPool(
- const std::string& id) {
- DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
+std::vector<chrome::StorageInfo> StorageInfoProvider::GetAllStorages() const {
+ return StorageMonitor::GetInstance()->GetAllAvailableStorages();
+}
- StorageUnitInfo info;
- if (!QueryUnitInfo(id, &info))
- return;
- observers_->Notify(&StorageInfoObserver::OnStorageAttached,
- info.id,
- info.type,
- info.capacity,
- info.available_capacity);
+bool StorageInfoProvider::QueryInfo(StorageInfo* info) {
+ std::vector<chrome::StorageInfo> storage_list = GetAllStorages();
+ StorageInfo results;
+ std::vector<chrome::StorageInfo>::const_iterator it = storage_list.begin();
+ for (; it != storage_list.end(); ++it) {
+ linked_ptr<StorageUnitInfo> unit(new StorageUnitInfo());
+ systeminfo::BuildStorageUnitInfo(*it, unit.get());
+ results.push_back(unit);
+ }
+ info->swap(results);
+
+ return true;
}
-void StorageInfoProvider::OnRemovableStorageDetached(
- const chrome::StorageInfo& info) {
- // TODO(hongbo): Use |info.device_id| instead. Same as the above.
-#if defined(OS_POSIX)
- std::string id = info.location();
-#elif defined(OS_WIN)
- std::string id = UTF16ToUTF8(info.location());
-#endif
- observers_->Notify(&StorageInfoObserver::OnStorageDetached, id);
+void StorageInfoProvider::AddObserver(StorageFreeSpaceObserver* obs) {
+ observers_->AddObserver(obs);
+}
+
+void StorageInfoProvider::RemoveObserver(StorageFreeSpaceObserver* obs) {
+ observers_->RemoveObserver(obs);
+}
+
+int64 StorageInfoProvider::GetStorageFreeSpace(
+ const base::FilePath& mount_path) {
+ return base::SysInfo::AmountOfFreeDiskSpace(mount_path);
}
void StorageInfoProvider::StartWatching(const std::string& id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ base::FilePath mount_path;
+ if (!GetStoragePathFromId(id, &mount_path))
+ return;
+
BrowserThread::PostBlockingPoolSequencedTask(
kWatchingTokenName,
FROM_HERE,
base::Bind(&StorageInfoProvider::AddWatchedStorageOnBlockingPool,
- this, id));
+ this, mount_path));
}
void StorageInfoProvider::StopWatching(const std::string& id) {
+ base::FilePath mount_path;
+ if (!GetStoragePathFromId(id, &mount_path))
+ return;
BrowserThread::PostBlockingPoolSequencedTask(
kWatchingTokenName,
FROM_HERE,
base::Bind(&StorageInfoProvider::RemoveWatchedStorageOnBlockingPool,
- this, id));
+ this, mount_path));
+}
+
+bool StorageInfoProvider::GetStoragePathFromId(const std::string& id,
+ base::FilePath* mount_path) {
+
+ std::vector<chrome::StorageInfo> storage_list = GetAllStorages();
+
+ // Lookup the matched storage info by |id|.
+ for (std::vector<chrome::StorageInfo>::const_iterator it =
+ storage_list.begin();
+ it != storage_list.end(); ++it) {
+ if (id == it->device_id()) {
+ *mount_path = base::FilePath(it->location());
+ return true;
+ }
+ }
+
+ // No matched StorageInfo is found.
+ return false;
}
void StorageInfoProvider::AddWatchedStorageOnBlockingPool(
- const std::string& id) {
+ const base::FilePath path) {
DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
// If the storage |id| is already being watched.
- if (ContainsKey(storage_id_to_size_map_, id))
+ if (ContainsKey(storage_location_to_size_map_, path))
return;
- StorageUnitInfo info;
- if (!QueryUnitInfo(id, &info))
+ int64 available_bytes = GetStorageFreeSpace(path);
+ if (available_bytes < 0)
return;
- storage_id_to_size_map_[id] = info.available_capacity;
+ storage_location_to_size_map_[path] = available_bytes;
// If it is the first storage to be watched, we need to start the watching
// timer.
- if (storage_id_to_size_map_.size() == 1) {
+ if (storage_location_to_size_map_.size() == 1) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&StorageInfoProvider::StartWatchingTimerOnUIThread, this));
}
}
void StorageInfoProvider::RemoveWatchedStorageOnBlockingPool(
- const std::string& id) {
+ const base::FilePath path) {
DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
- if (!ContainsKey(storage_id_to_size_map_, id))
+ if (!ContainsKey(storage_location_to_size_map_, path))
return;
- storage_id_to_size_map_.erase(id);
+ storage_location_to_size_map_.erase(path);
// Stop watching timer if there is no storage to be watched.
- if (storage_id_to_size_map_.empty()) {
+ if (storage_location_to_size_map_.empty()) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&StorageInfoProvider::StopWatchingTimerOnUIThread, this));
}
@@ -149,38 +199,47 @@ void StorageInfoProvider::RemoveWatchedStorageOnBlockingPool(
void StorageInfoProvider::CheckWatchedStorages() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- BrowserThread::PostBlockingPoolSequencedTask(kWatchingTokenName, FROM_HERE,
- base::Bind(&StorageInfoProvider::CheckWatchedStoragesOnBlockingPool,
- this));
+ std::vector<chrome::StorageInfo> storage_list = GetAllStorages();
+
+ for (std::vector<chrome::StorageInfo>::iterator it = storage_list.begin();
+ it != storage_list.end(); ++it) {
+ BrowserThread::PostBlockingPoolSequencedTask(
+ kWatchingTokenName,
+ FROM_HERE,
+ base::Bind(&StorageInfoProvider::CheckWatchedStorageOnBlockingPool,
+ this, it->device_id(), base::FilePath(it->location())));
+ }
}
-void StorageInfoProvider::CheckWatchedStoragesOnBlockingPool() {
+void StorageInfoProvider::CheckWatchedStorageOnBlockingPool(
+ const std::string& id, const base::FilePath& mount_path) {
DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
- for (StorageIDToSizeMap::iterator it = storage_id_to_size_map_.begin();
- it != storage_id_to_size_map_.end(); ) {
- StorageUnitInfo info;
- if (!QueryUnitInfo(it->first, &info)) {
- storage_id_to_size_map_.erase(it++);
- continue;
- }
- if (it->second != info.available_capacity) {
- observers_->Notify(&StorageInfoObserver::OnStorageFreeSpaceChanged,
- it->first, /* storage id */
- it->second, /* old free space value */
- info.available_capacity /* new value */);
- it->second = info.available_capacity;
- }
- ++it;
+ if (!ContainsKey(storage_location_to_size_map_, mount_path)) {
+ return;
}
- if (storage_id_to_size_map_.size() == 0) {
+ double available_bytes = static_cast<double>(GetStorageFreeSpace(mount_path));
+ if (available_bytes < 0)
+ storage_location_to_size_map_.erase(mount_path);
+
+ if (storage_location_to_size_map_.size() == 0) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(&StorageInfoProvider::StopWatchingTimerOnUIThread,
- this));
- return;
+ base::Bind(&StorageInfoProvider::StopWatchingTimerOnUIThread, this));
}
- OnCheckWatchedStoragesFinishedForTesting();
+
+ double old_available_bytes = storage_location_to_size_map_[mount_path];
+
+ if (old_available_bytes != available_bytes) {
+ // Ignore free space change event if the old available capacity is 0.
+ if (old_available_bytes > 0) {
+ observers_->Notify(&StorageFreeSpaceObserver::OnFreeSpaceChanged,
+ id, /* storage id */
+ old_available_bytes, /* old value */
+ available_bytes /* new value */);
+ }
+ storage_location_to_size_map_[mount_path] = available_bytes;
+ }
}
void StorageInfoProvider::StartWatchingTimerOnUIThread() {
@@ -198,4 +257,9 @@ void StorageInfoProvider::StopWatchingTimerOnUIThread() {
watching_timer_.Stop();
}
+// static
+StorageInfoProvider* StorageInfoProvider::Get() {
+ return StorageInfoProvider::GetInstance<StorageInfoProvider>();
+}
+
} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698