michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 1 | // Copyright 2016 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. |
| 4 | |
| 5 | #include "storage/browser/quota/quota_settings.h" |
| 6 | |
| 7 | #include <algorithm> |
Victor Costan | b410d1a | 2020-02-12 05:03:22 | [diff] [blame] | 8 | #include <limits> |
Jarryd | 451ab7b | 2019-02-12 06:39:06 | [diff] [blame] | 9 | #include <memory> |
Victor Costan | b410d1a | 2020-02-12 05:03:22 | [diff] [blame] | 10 | #include <utility> |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 11 | |
Sebastien Marchand | 6d0558fd | 2019-01-25 16:49:37 | [diff] [blame] | 12 | #include "base/bind.h" |
michaeln | fa4c8940 | 2017-04-11 02:36:20 | [diff] [blame] | 13 | #include "base/rand_util.h" |
Sebastien Marchand | 75a7cdf | 2018-11-13 23:47:03 | [diff] [blame] | 14 | #include "base/system/sys_info.h" |
Gabriel Charette | 44db142 | 2018-08-06 11:19:33 | [diff] [blame] | 15 | #include "base/task/post_task.h" |
Gabriel Charette | 77285f4 | 2020-02-26 17:01:23 | [diff] [blame] | 16 | #include "base/task/thread_pool.h" |
Etienne Pierre-Doray | 57cf470 | 2018-11-16 17:04:14 | [diff] [blame] | 17 | #include "base/threading/scoped_blocking_call.h" |
Kevin Marshall | f1bf4e5 | 2017-08-15 19:37:58 | [diff] [blame] | 18 | #include "build/build_config.h" |
Jarryd | 1f02b90 | 2019-11-07 03:29:57 | [diff] [blame] | 19 | #include "storage/browser/quota/quota_device_info_helper.h" |
Jarryd | 7a79f066 | 2019-01-24 07:26:44 | [diff] [blame] | 20 | #include "storage/browser/quota/quota_features.h" |
Oscar Johansson | 357dd5c | 2018-08-07 10:42:02 | [diff] [blame] | 21 | #include "storage/browser/quota/quota_macros.h" |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 22 | |
| 23 | namespace storage { |
| 24 | |
michaeln | fa4c8940 | 2017-04-11 02:36:20 | [diff] [blame] | 25 | namespace { |
| 26 | |
Ramin Halavati | 57e61893 | 2019-10-31 12:46:47 | [diff] [blame] | 27 | const int64_t kMBytes = 1024 * 1024; |
| 28 | const int kRandomizedPercentage = 10; |
Caitlin Fischer | 31f17812 | 2020-09-29 11:35:15 | [diff] [blame] | 29 | const double kDefaultPerHostRatio = 0.75; |
Ramin Halavati | f8e6df8 | 2020-10-05 21:39:46 | [diff] [blame] | 30 | const double kIncognitoQuotaRatioLowerBound = 0.15; |
| 31 | const double kIncognitoQuotaRatioUpperBound = 0.2; |
Ramin Halavati | 57e61893 | 2019-10-31 12:46:47 | [diff] [blame] | 32 | |
michaeln | fa4c8940 | 2017-04-11 02:36:20 | [diff] [blame] | 33 | // Skews |value| by +/- |percent|. |
| 34 | int64_t RandomizeByPercent(int64_t value, int percent) { |
| 35 | double random_percent = (base::RandDouble() - 0.5) * percent * 2; |
| 36 | return value + (value * (random_percent / 100.0)); |
| 37 | } |
| 38 | |
Victor Costan | b410d1a | 2020-02-12 05:03:22 | [diff] [blame] | 39 | QuotaSettings CalculateIncognitoDynamicSettings( |
Ramin Halavati | 57e61893 | 2019-10-31 12:46:47 | [diff] [blame] | 40 | int64_t physical_memory_amount) { |
Ramin Halavati | f8e6df8 | 2020-10-05 21:39:46 | [diff] [blame] | 41 | // The incognito pool size is a fraction of the amount of system memory. |
| 42 | double incognito_pool_size_ratio = |
| 43 | kIncognitoQuotaRatioLowerBound + |
| 44 | (base::RandDouble() * |
| 45 | (kIncognitoQuotaRatioUpperBound - kIncognitoQuotaRatioLowerBound)); |
Ramin Halavati | 57e61893 | 2019-10-31 12:46:47 | [diff] [blame] | 46 | |
Victor Costan | b410d1a | 2020-02-12 05:03:22 | [diff] [blame] | 47 | QuotaSettings settings; |
Ramin Halavati | f8e6df8 | 2020-10-05 21:39:46 | [diff] [blame] | 48 | settings.pool_size = |
| 49 | static_cast<int64_t>(physical_memory_amount * incognito_pool_size_ratio); |
Ramin Halavati | 57e61893 | 2019-10-31 12:46:47 | [diff] [blame] | 50 | settings.per_host_quota = settings.pool_size / 3; |
| 51 | settings.session_only_per_host_quota = settings.per_host_quota; |
| 52 | settings.refresh_interval = base::TimeDelta::Max(); |
| 53 | return settings; |
| 54 | } |
| 55 | |
Victor Costan | b410d1a | 2020-02-12 05:03:22 | [diff] [blame] | 56 | base::Optional<QuotaSettings> CalculateNominalDynamicSettings( |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 57 | const base::FilePath& partition_path, |
Jarryd | 451ab7b | 2019-02-12 06:39:06 | [diff] [blame] | 58 | bool is_incognito, |
Jarryd | 1f02b90 | 2019-11-07 03:29:57 | [diff] [blame] | 59 | QuotaDeviceInfoHelper* device_info_helper) { |
Etienne Bergeron | 436d4221 | 2019-02-26 17:15:12 | [diff] [blame] | 60 | base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, |
| 61 | base::BlockingType::MAY_BLOCK); |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 62 | |
| 63 | if (is_incognito) { |
Ramin Halavati | 57e61893 | 2019-10-31 12:46:47 | [diff] [blame] | 64 | return CalculateIncognitoDynamicSettings( |
Jarryd | 1f02b90 | 2019-11-07 03:29:57 | [diff] [blame] | 65 | device_info_helper->AmountOfPhysicalMemory()); |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 66 | } |
| 67 | |
Victor Costan | f39940a | 2019-12-02 19:37:29 | [diff] [blame] | 68 | // The fraction of the device's storage the browser is willing to use for |
| 69 | // temporary storage. |
Junbo Ke | 0f792b5 | 2021-01-26 22:58:13 | [diff] [blame^] | 70 | const double kTemporaryPoolSizeRatio = features::kPoolSizeRatio.Get(); |
| 71 | |
| 72 | // The fixed size in bytes the browser is willing to use for temporary |
| 73 | // storage. If both the ratio and the absolute size are set, the lower value |
| 74 | // will be honored. |
| 75 | const int64_t kTemporaryPoolSizeFixed = |
| 76 | static_cast<int64_t>(features::kPoolSizeBytes.Get()); |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 77 | |
Joshua Bell | 1e5b570 | 2018-02-28 06:36:29 | [diff] [blame] | 78 | // The amount of the device's storage the browser attempts to |
Joshua Bell | 9508bf4e | 2018-02-23 18:05:20 | [diff] [blame] | 79 | // keep free. If there is less than this amount of storage free |
| 80 | // on the device, Chrome will grant 0 quota to origins. |
Joshua Bell | 1e5b570 | 2018-02-28 06:36:29 | [diff] [blame] | 81 | // |
Joshua Bell | 73b18e3 | 2018-05-02 23:06:29 | [diff] [blame] | 82 | // Prior to M66, this was 10% of total storage instead of a fixed value on |
| 83 | // all devices. Now the minimum of a fixed value (2GB) and 10% is used to |
| 84 | // limit the reserve on devices with plenty of storage, but scale down for |
| 85 | // devices with extremely limited storage. |
| 86 | // * 1TB storage -- min(100GB,2GB) = 2GB |
| 87 | // * 500GB storage -- min(50GB,2GB) = 2GB |
| 88 | // * 64GB storage -- min(6GB,2GB) = 2GB |
| 89 | // * 16GB storage -- min(1.6GB,2GB) = 1.6GB |
| 90 | // * 8GB storage -- min(800MB,2GB) = 800MB |
Junbo Ke | 0f792b5 | 2021-01-26 22:58:13 | [diff] [blame^] | 91 | const int64_t kShouldRemainAvailableFixed = |
| 92 | static_cast<int64_t>(features::kShouldRemainAvailableBytes.Get()); |
| 93 | const double kShouldRemainAvailableRatio = |
| 94 | features::kShouldRemainAvailableRatio.Get(); |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 95 | |
Joshua Bell | 1e5b570 | 2018-02-28 06:36:29 | [diff] [blame] | 96 | // The amount of the device's storage the browser attempts to |
Joshua Bell | 9508bf4e | 2018-02-23 18:05:20 | [diff] [blame] | 97 | // keep free at all costs. Data will be aggressively evicted. |
Joshua Bell | 1e5b570 | 2018-02-28 06:36:29 | [diff] [blame] | 98 | // |
Joshua Bell | 73b18e3 | 2018-05-02 23:06:29 | [diff] [blame] | 99 | // Prior to M66, this was 1% of total storage instead of a fixed value on |
| 100 | // all devices. Now the minimum of a fixed value (1GB) and 1% is used to |
| 101 | // limit the reserve on devices with plenty of storage, but scale down for |
| 102 | // devices with extremely limited storage. |
| 103 | // * 1TB storage -- min(10GB,1GB) = 1GB |
| 104 | // * 500GB storage -- min(5GB,1GB) = 1GB |
| 105 | // * 64GB storage -- min(640MB,1GB) = 640MB |
| 106 | // * 16GB storage -- min(160MB,1GB) = 160MB |
| 107 | // * 8GB storage -- min(80MB,1GB) = 80MB |
Junbo Ke | 0f792b5 | 2021-01-26 22:58:13 | [diff] [blame^] | 108 | const int64_t kMustRemainAvailableFixed = |
| 109 | static_cast<int64_t>(features::kMustRemainAvailableBytes.Get()); |
| 110 | const double kMustRemainAvailableRatio = |
| 111 | features::kMustRemainAvailableRatio.Get(); |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 112 | |
Victor Costan | f39940a | 2019-12-02 19:37:29 | [diff] [blame] | 113 | // The fraction of the temporary pool that can be utilized by a single host. |
Jarryd | 48e8568 | 2020-10-01 01:51:19 | [diff] [blame] | 114 | const double kPerHostTemporaryRatio = kDefaultPerHostRatio; |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 115 | |
michaeln | fa4c8940 | 2017-04-11 02:36:20 | [diff] [blame] | 116 | // SessionOnly (or ephemeral) origins are allotted a fraction of what |
| 117 | // normal origins are provided, and the amount is capped to a hard limit. |
| 118 | const double kSessionOnlyHostQuotaRatio = 0.1; // 10% |
| 119 | const int64_t kMaxSessionOnlyHostQuota = 300 * kMBytes; |
| 120 | |
Victor Costan | b410d1a | 2020-02-12 05:03:22 | [diff] [blame] | 121 | QuotaSettings settings; |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 122 | |
Jarryd | 1f02b90 | 2019-11-07 03:29:57 | [diff] [blame] | 123 | int64_t total = device_info_helper->AmountOfTotalDiskSpace(partition_path); |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 124 | if (total == -1) { |
| 125 | LOG(ERROR) << "Unable to compute QuotaSettings."; |
| 126 | return base::nullopt; |
| 127 | } |
| 128 | |
Junbo Ke | 0f792b5 | 2021-01-26 22:58:13 | [diff] [blame^] | 129 | // Pool size calculated by ratio. |
| 130 | int64_t pool_size_by_ratio = total * kTemporaryPoolSizeRatio; |
| 131 | |
| 132 | int64_t pool_size = |
| 133 | kTemporaryPoolSizeFixed > 0 |
| 134 | ? std::min(kTemporaryPoolSizeFixed, pool_size_by_ratio) |
| 135 | : pool_size_by_ratio; |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 136 | |
| 137 | settings.pool_size = pool_size; |
Joshua Bell | 73b18e3 | 2018-05-02 23:06:29 | [diff] [blame] | 138 | settings.should_remain_available = |
| 139 | std::min(kShouldRemainAvailableFixed, |
| 140 | static_cast<int64_t>(total * kShouldRemainAvailableRatio)); |
| 141 | settings.must_remain_available = |
| 142 | std::min(kMustRemainAvailableFixed, |
| 143 | static_cast<int64_t>(total * kMustRemainAvailableRatio)); |
Jarryd | 7a79f066 | 2019-01-24 07:26:44 | [diff] [blame] | 144 | settings.per_host_quota = pool_size * kPerHostTemporaryRatio; |
michaeln | fa4c8940 | 2017-04-11 02:36:20 | [diff] [blame] | 145 | settings.session_only_per_host_quota = std::min( |
| 146 | RandomizeByPercent(kMaxSessionOnlyHostQuota, kRandomizedPercentage), |
| 147 | static_cast<int64_t>(settings.per_host_quota * |
| 148 | kSessionOnlyHostQuotaRatio)); |
michaeln | 10e5fc35 | 2017-02-07 02:07:58 | [diff] [blame] | 149 | settings.refresh_interval = base::TimeDelta::FromSeconds(60); |
| 150 | return settings; |
| 151 | } |
| 152 | |
| 153 | } // namespace |
tapted | e6d878e | 2017-06-24 01:53:45 | [diff] [blame] | 154 | |
| 155 | void GetNominalDynamicSettings(const base::FilePath& partition_path, |
| 156 | bool is_incognito, |
Jarryd | 1f02b90 | 2019-11-07 03:29:57 | [diff] [blame] | 157 | QuotaDeviceInfoHelper* device_info_helper, |
tapted | e6d878e | 2017-06-24 01:53:45 | [diff] [blame] | 158 | OptionalQuotaSettingsCallback callback) { |
Gabriel Charette | 77285f4 | 2020-02-26 17:01:23 | [diff] [blame] | 159 | base::ThreadPool::PostTaskAndReplyWithResult( |
tapted | e6d878e | 2017-06-24 01:53:45 | [diff] [blame] | 160 | FROM_HERE, |
Gabriel Charette | 77285f4 | 2020-02-26 17:01:23 | [diff] [blame] | 161 | {base::MayBlock(), base::TaskPriority::USER_VISIBLE, |
tapted | e6d878e | 2017-06-24 01:53:45 | [diff] [blame] | 162 | base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, |
| 163 | base::BindOnce(&CalculateNominalDynamicSettings, partition_path, |
Jarryd | 1f02b90 | 2019-11-07 03:29:57 | [diff] [blame] | 164 | is_incognito, base::Unretained(device_info_helper)), |
tapted | e6d878e | 2017-06-24 01:53:45 | [diff] [blame] | 165 | std::move(callback)); |
| 166 | } |
| 167 | |
Jarryd | 1f02b90 | 2019-11-07 03:29:57 | [diff] [blame] | 168 | QuotaDeviceInfoHelper* GetDefaultDeviceInfoHelper() { |
| 169 | static base::NoDestructor<QuotaDeviceInfoHelper> singleton; |
Jarryd | 451ab7b | 2019-02-12 06:39:06 | [diff] [blame] | 170 | return singleton.get(); |
| 171 | } |
| 172 | |
Ramin Halavati | f8e6df8 | 2020-10-05 21:39:46 | [diff] [blame] | 173 | double GetIncognitoQuotaRatioLowerBound_ForTesting() { |
| 174 | return kIncognitoQuotaRatioLowerBound; |
| 175 | } |
| 176 | double GetIncognitoQuotaRatioUpperBound_ForTesting() { |
| 177 | return kIncognitoQuotaRatioUpperBound; |
| 178 | } |
| 179 | |
tapted | e6d878e | 2017-06-24 01:53:45 | [diff] [blame] | 180 | } // namespace storage |