Commit 72ad04ce authored by Jeremie Boulic's avatar Jeremie Boulic Committed by Commit Bot

Round total storage size to the next power of 2

On the storage management page, to have the numbers match up to the size
that was advertised when the user bought the device, we round the total
size to the next power of 2.

The total size that was displayed on the storage page was the size of
the stateful partition, by far the largest of the 12 partitions present
on a ChromeOS device. The vast majority of users doesn't want to worry
about these details. We want to numbers on the storage page to add up
to the disk size advertized by the manufacturer, a rounded power of 2.

unit_tests  --gtest_filter="*StorageHandlerTest*"

Test: 
Bug: 1056507, 1013452
Change-Id: Ie8185730183572f5f61fd8646bb9a1fe0f318d8d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2074821
Commit-Queue: Jeremie Boulic <jboulic@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#746567}
parent 6ab54981
......@@ -100,9 +100,9 @@ void SizeStatCalculator::PerformCalculation() {
base::Owned(available_size)));
}
void SizeStatCalculator::OnGetSizeStat(int64_t* total_size,
int64_t* available_size) {
NotifySizeCalculated(*total_size, *available_size);
void SizeStatCalculator::OnGetSizeStat(int64_t* total_bytes,
int64_t* available_bytes) {
NotifySizeCalculated(*total_bytes, *available_bytes);
}
MyFilesSizeCalculator::MyFilesSizeCalculator(
......
......@@ -86,7 +86,7 @@ class SizeStatCalculator : public SizeCalculator {
void PerformCalculation() override;
// Updates disk space information.
void OnGetSizeStat(int64_t* total_size, int64_t* available_size);
void OnGetSizeStat(int64_t* total_bytes, int64_t* available_bytes);
Profile* profile_;
base::WeakPtrFactory<SizeStatCalculator> weak_ptr_factory_{this};
......
......@@ -104,6 +104,28 @@ void StorageHandler::OnJavascriptDisallowed() {
StopObservingEvents();
}
int64_t StorageHandler::RoundByteSize(int64_t bytes) {
if (bytes < 0) {
NOTREACHED() << "Negative bytes value";
return -1;
}
// Subtract one to the original number of bytes.
bytes--;
// Set all the lower bits to 1.
bytes |= bytes >> 1;
bytes |= bytes >> 2;
bytes |= bytes >> 4;
bytes |= bytes >> 8;
bytes |= bytes >> 16;
bytes |= bytes >> 32;
// Add one. The one bit beyond the highest set bit is set to 1. All the lower
// bits are set to 0.
bytes++;
return bytes;
}
void StorageHandler::HandleUpdateAndroidEnabled(
const base::ListValue* unused_args) {
// OnJavascriptAllowed() calls ArcSessionManager::AddObserver() later.
......@@ -235,13 +257,14 @@ void StorageHandler::UpdateStorageItem(const std::string& event_name,
void StorageHandler::UpdateSizeStat(const std::string& event_name,
int64_t total_bytes,
int64_t available_bytes) {
int64_t in_use_total_bytes_ = total_bytes - available_bytes;
int64_t rounded_total_bytes = RoundByteSize(total_bytes);
int64_t in_use_total_bytes_ = rounded_total_bytes - available_bytes;
base::DictionaryValue size_stat;
size_stat.SetString("availableSize", ui::FormatBytes(available_bytes));
size_stat.SetString("usedSize", ui::FormatBytes(in_use_total_bytes_));
size_stat.SetDouble("usedRatio",
static_cast<double>(in_use_total_bytes_) / total_bytes);
size_stat.SetDouble("usedRatio", static_cast<double>(in_use_total_bytes_) /
rounded_total_bytes);
int storage_space_state =
static_cast<int>(StorageSpaceState::kStorageSpaceNormal);
if (available_bytes < kSpaceCriticallyLowBytes)
......
......@@ -69,6 +69,11 @@ class StorageHandler : public ::settings::SettingsPageUIHandler,
// Remove the handler from the list of observers of every observed instances.
void StopObservingEvents();
protected:
// Round a given number of bytes up to the next power of 2.
// Ex: 14 => 16, 150 => 256.
int64_t RoundByteSize(int64_t bytes);
private:
// Handlers of JS messages.
void HandleUpdateAndroidEnabled(const base::ListValue* unused_args);
......
......@@ -44,6 +44,7 @@ class TestStorageHandler : public StorageHandler {
: StorageHandler(profile, html_source) {}
// Pull WebUIMessageHandler::set_web_ui() into public so tests can call it.
using StorageHandler::RoundByteSize;
using StorageHandler::set_web_ui;
};
......@@ -206,14 +207,46 @@ class StorageHandlerTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(StorageHandlerTest);
};
TEST_F(StorageHandlerTest, RoundByteSize) {
static const struct {
int64_t bytes;
const char* expected;
} cases[] = {
{0, "0 B"},
{3, "4 B"},
{4, "4 B"},
{5, "8 B"},
{8 * 1024 - 1, "8.0 KB"},
{8 * 1024, "8.0 KB"},
{8 * 1024 + 1, "16.0 KB"},
{31 * 1024 * 1024, "32.0 MB"},
{32 * 1024 * 1024, "32.0 MB"},
{50 * 1024 * 1024, "64.0 MB"},
{65LL * 1024 * 1024 * 1024, "128 GB"},
{130LL * 1024 * 1024 * 1024, "256 GB"},
{130LL * 1024 * 1024 * 1024, "256 GB"},
{1LL * 1024 * 1024 * 1024 * 1024, "1.0 TB"},
{1LL * 1024 * 1024 * 1024 * 1024 + 1, "2.0 TB"},
{(1LL << 61) + 1, "4,096 PB"},
};
for (auto& c : cases) {
int64_t rounded_bytes = handler_->RoundByteSize(c.bytes);
EXPECT_EQ(base::ASCIIToUTF16(c.expected), ui::FormatBytes(rounded_bytes));
}
}
TEST_F(StorageHandlerTest, GlobalSizeStat) {
// Get local filesystem storage statistics.
const base::FilePath mount_path =
file_manager::util::GetMyFilesFolderForProfile(profile_);
int64_t total_size = base::SysInfo::AmountOfTotalDiskSpace(mount_path);
int64_t available_size = base::SysInfo::AmountOfFreeDiskSpace(mount_path);
int64_t used_size = total_size - available_size;
double used_ratio = static_cast<double>(used_size) / total_size;
// Round the total size.
int64_t rounded_total_size = handler_->RoundByteSize(total_size);
int64_t used_size = rounded_total_size - available_size;
double used_ratio = static_cast<double>(used_size) / rounded_total_size;
// Get statistics from storage handler's UpdateSizeStat.
size_stat_test_api_->StartCalculation();
......@@ -239,9 +272,9 @@ TEST_F(StorageHandlerTest, GlobalSizeStat) {
: storage_handler_used_ratio - used_ratio;
// Running the test while writing data on disk (~400MB/s), the difference
// between the values returned by the two AmountOfFreeDiskSpace calls is never
// more than 100KB. By expecting diff to be less than 100KB / total_size, the
// test is very unlikely to be flaky.
EXPECT_LE(diff, static_cast<double>(100 * 1024) / total_size);
// more than 100KB. By expecting diff to be less than 100KB /
// rounded_total_size, the test is very unlikely to be flaky.
EXPECT_LE(diff, static_cast<double>(100 * 1024) / rounded_total_size);
}
TEST_F(StorageHandlerTest, StorageSpaceState) {
......@@ -311,9 +344,9 @@ TEST_F(StorageHandlerTest, MyFilesSize) {
}
TEST_F(StorageHandlerTest, AppsExtensionsSize) {
// The data for apps and extensions installed from the webstore is stored in
// the Extensions folder. Add data at a random location in the Extensions
// folder and check UI callback message.
// The data for apps and extensions apps_size_test_api_installed from the
// webstore is stored in the Extensions folder. Add data at a random location
// in the Extensions folder and check UI callback message.
const base::FilePath extensions_data_path =
profile_->GetPath()
.AppendASCII("Extensions")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment