Commit 475ceeac authored by Wez's avatar Wez Committed by Commit Bot

[fuchsia] Support soft quota on each web.Context's /data directory.

Implement the |CreateContextParams.data_quota_bytes| option, to allow
a soft-quota to be applied to persisted browsing data.

If specified the quota is treated as the "total disk space" of the /data
volume, and used to report total & free disk space amounts in SysInfo.

Since the platform does not provide native quota, nor free-bytes metrics
from filesystems, this is implemented by calling ComputeDirectorySize()
to approximate the "used disk space".

Bug: 851734, 1071393, 1148334
Bug: b/154204041
Change-Id: Iab982202490080ed9942a7a1b16c62aee5c24cfd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2537698
Commit-Queue: Wez <wez@chromium.org>
Reviewed-by: default avatarDavid Dorwin <ddorwin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827620}
parent da898145
...@@ -66,6 +66,12 @@ class BASE_EXPORT SysInfo { ...@@ -66,6 +66,12 @@ class BASE_EXPORT SysInfo {
// on failure. // on failure.
static int64_t AmountOfTotalDiskSpace(const FilePath& path); static int64_t AmountOfTotalDiskSpace(const FilePath& path);
#if defined(OS_FUCHSIA)
// Sets the total amount of disk space to report under the specified |path|.
// If |bytes| is -ve then any existing entry for |path| is removed.
static void SetAmountOfTotalDiskSpace(const FilePath& path, int64_t bytes);
#endif
// Returns system uptime. // Returns system uptime.
static TimeDelta Uptime(); static TimeDelta Uptime();
......
...@@ -6,13 +6,57 @@ ...@@ -6,13 +6,57 @@
#include <zircon/syscalls.h> #include <zircon/syscalls.h>
#include "base/containers/flat_map.h"
#include "base/files/file_util.h"
#include "base/fuchsia/fuchsia_logging.h" #include "base/fuchsia/fuchsia_logging.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/no_destructor.h"
#include "base/synchronization/lock.h"
#include "base/threading/scoped_blocking_call.h" #include "base/threading/scoped_blocking_call.h"
#include "build/build_config.h" #include "build/build_config.h"
namespace base { namespace base {
namespace {
struct TotalDiskSpace {
Lock lock;
flat_map<FilePath, int64_t> space_map GUARDED_BY(lock);
};
TotalDiskSpace& GetTotalDiskSpace() {
static NoDestructor<TotalDiskSpace> total_disk_space;
return *total_disk_space;
}
// Returns the total-disk-space set for the volume containing |path|. If
// |volume_path| is non-null then it receives the path to the relevant volume.
// Returns -1, and does not modify |volume_path|, if no match is found.
int64_t GetAmountOfTotalDiskSpaceAndVolumePath(const FilePath& path,
base::FilePath* volume_path) {
CHECK(path.IsAbsolute());
TotalDiskSpace& total_disk_space = GetTotalDiskSpace();
AutoLock l(total_disk_space.lock);
int64_t result = -1;
base::FilePath matched_path;
for (const auto& path_and_size : total_disk_space.space_map) {
if (path_and_size.first == path || path_and_size.first.IsParent(path)) {
// If a deeper path was already matched then ignore this entry.
if (!matched_path.empty() && !matched_path.IsParent(path_and_size.first))
continue;
matched_path = path_and_size.first;
result = path_and_size.second;
}
}
if (volume_path)
*volume_path = matched_path;
return result;
}
} // namespace
// static // static
int64_t SysInfo::AmountOfPhysicalMemoryImpl() { int64_t SysInfo::AmountOfPhysicalMemoryImpl() {
return zx_system_get_physmem(); return zx_system_get_physmem();
...@@ -42,18 +86,37 @@ std::string SysInfo::OperatingSystemName() { ...@@ -42,18 +86,37 @@ std::string SysInfo::OperatingSystemName() {
// static // static
int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) { int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
base::BlockingType::MAY_BLOCK); base::FilePath volume_path;
NOTIMPLEMENTED_LOG_ONCE(); const int64_t total_space =
return -1; GetAmountOfTotalDiskSpaceAndVolumePath(path, &volume_path);
if (total_space < 0)
return -1;
// TODO(crbug.com/1148334): Replace this with an efficient implementation.
const int64_t used_space = ComputeDirectorySize(volume_path);
if (used_space < total_space)
return total_space - used_space;
return 0;
} }
// static // static
int64_t SysInfo::AmountOfTotalDiskSpace(const FilePath& path) { int64_t SysInfo::AmountOfTotalDiskSpace(const FilePath& path) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, if (path.empty())
base::BlockingType::MAY_BLOCK); return -1;
NOTIMPLEMENTED_LOG_ONCE(); return GetAmountOfTotalDiskSpaceAndVolumePath(path, nullptr);
return -1; }
// static
void SysInfo::SetAmountOfTotalDiskSpace(const FilePath& path, int64_t bytes) {
DCHECK(path.IsAbsolute());
TotalDiskSpace& total_disk_space = GetTotalDiskSpace();
AutoLock l(total_disk_space.lock);
if (bytes >= 0)
total_disk_space.space_map[path] = bytes;
else
total_disk_space.space_map.erase(path);
} }
// static // static
......
...@@ -89,34 +89,54 @@ TEST_F(SysInfoTest, MAYBE_AmountOfAvailablePhysicalMemory) { ...@@ -89,34 +89,54 @@ TEST_F(SysInfoTest, MAYBE_AmountOfAvailablePhysicalMemory) {
} }
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) #endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
#if defined(OS_FUCHSIA) TEST_F(SysInfoTest, AmountOfFreeDiskSpace) {
// TODO(crbug.com/851734): Implementation depends on statvfs, which is not
// implemented on Fuchsia
#define MAYBE_AmountOfFreeDiskSpace DISABLED_AmountOfFreeDiskSpace
#else
#define MAYBE_AmountOfFreeDiskSpace AmountOfFreeDiskSpace
#endif
TEST_F(SysInfoTest, MAYBE_AmountOfFreeDiskSpace) {
// We aren't actually testing that it's correct, just that it's sane. // We aren't actually testing that it's correct, just that it's sane.
FilePath tmp_path; FilePath tmp_path;
ASSERT_TRUE(GetTempDir(&tmp_path)); ASSERT_TRUE(GetTempDir(&tmp_path));
#if defined(OS_FUCHSIA)
// Fuchsia currently requires "total disk space" be set explicitly.
// See crbug.com/1148334.
SysInfo::SetAmountOfTotalDiskSpace(tmp_path, 1024);
#endif
EXPECT_GE(SysInfo::AmountOfFreeDiskSpace(tmp_path), 0) << tmp_path.value(); EXPECT_GE(SysInfo::AmountOfFreeDiskSpace(tmp_path), 0) << tmp_path.value();
} }
#if defined(OS_FUCHSIA) TEST_F(SysInfoTest, AmountOfTotalDiskSpace) {
// TODO(crbug.com/851734): Implementation depends on statvfs, which is not
// implemented on Fuchsia
#define MAYBE_AmountOfTotalDiskSpace DISABLED_AmountOfTotalDiskSpace
#else
#define MAYBE_AmountOfTotalDiskSpace AmountOfTotalDiskSpace
#endif
TEST_F(SysInfoTest, MAYBE_AmountOfTotalDiskSpace) {
// We aren't actually testing that it's correct, just that it's sane. // We aren't actually testing that it's correct, just that it's sane.
FilePath tmp_path; FilePath tmp_path;
ASSERT_TRUE(GetTempDir(&tmp_path)); ASSERT_TRUE(GetTempDir(&tmp_path));
#if defined(OS_FUCHSIA)
// Fuchsia currently requires "total disk space" be set explicitly.
// See crbug.com/1148334.
SysInfo::SetAmountOfTotalDiskSpace(tmp_path, 1024);
#endif
EXPECT_GT(SysInfo::AmountOfTotalDiskSpace(tmp_path), 0) << tmp_path.value(); EXPECT_GT(SysInfo::AmountOfTotalDiskSpace(tmp_path), 0) << tmp_path.value();
} }
#if defined(OS_FUCHSIA)
// Verify that specifying total disk space for nested directories matches
// the deepest-nested.
TEST_F(SysInfoTest, NestedVolumesAmountOfTotalDiskSpace) {
constexpr int64_t kOuterVolumeQuota = 1024;
constexpr int64_t kInnerVolumeQuota = kOuterVolumeQuota / 2;
FilePath tmp_path;
ASSERT_TRUE(GetTempDir(&tmp_path));
SysInfo::SetAmountOfTotalDiskSpace(tmp_path, kOuterVolumeQuota);
const FilePath subdirectory_path = tmp_path.Append("subdirectory");
SysInfo::SetAmountOfTotalDiskSpace(subdirectory_path, kInnerVolumeQuota);
EXPECT_EQ(SysInfo::AmountOfTotalDiskSpace(tmp_path), kOuterVolumeQuota);
EXPECT_EQ(SysInfo::AmountOfTotalDiskSpace(subdirectory_path),
kInnerVolumeQuota);
// Remove the inner directory quota setting and check again.
SysInfo::SetAmountOfTotalDiskSpace(subdirectory_path, -1);
EXPECT_EQ(SysInfo::AmountOfTotalDiskSpace(subdirectory_path),
kOuterVolumeQuota);
}
#endif // defined(OS_FUCHSIA)
#if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \ #if defined(OS_WIN) || defined(OS_APPLE) || defined(OS_LINUX) || \
defined(OS_CHROMEOS) || defined(OS_FUCHSIA) defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
TEST_F(SysInfoTest, OperatingSystemVersionNumbers) { TEST_F(SysInfoTest, OperatingSystemVersionNumbers) {
......
...@@ -12,25 +12,45 @@ ...@@ -12,25 +12,45 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/system/sys_info.h"
#include "components/keyed_service/core/simple_key_map.h" #include "components/keyed_service/core/simple_key_map.h"
#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/resource_context.h" #include "content/public/browser/resource_context.h"
#include "fuchsia/engine/browser/web_engine_net_log_observer.h" #include "fuchsia/engine/browser/web_engine_net_log_observer.h"
#include "fuchsia/engine/browser/web_engine_permission_delegate.h" #include "fuchsia/engine/browser/web_engine_permission_delegate.h"
#include "fuchsia/engine/switches.h"
#include "media/capabilities/in_memory_video_decode_stats_db_impl.h" #include "media/capabilities/in_memory_video_decode_stats_db_impl.h"
#include "media/mojo/services/video_decode_perf_history.h" #include "media/mojo/services/video_decode_perf_history.h"
#include "services/network/public/cpp/network_switches.h" #include "services/network/public/cpp/network_switches.h"
class WebEngineBrowserContext::ResourceContext namespace {
: public content::ResourceContext {
public:
ResourceContext() = default;
~ResourceContext() override = default;
private: // Determines whether a data directory is configured, and returns its path.
DISALLOW_COPY_AND_ASSIGN(ResourceContext); // Passes the quota, if specified, for SysInfo to report as total disk space.
}; base::FilePath InitializeDataDirectoryAndQuotaFromCommandLine() {
base::FilePath data_directory_path;
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
if (!base::PathService::Get(base::DIR_APP_DATA, &data_directory_path) ||
!base::PathExists(data_directory_path)) {
// Run in incognito mode if /data doesn't exist.
return base::FilePath();
}
if (command_line->HasSwitch(switches::kDataQuotaBytes)) {
// Configure SysInfo to use the specified quota as the total-disk-space
// for the |data_dir_path_|.
uint64_t quota_bytes = 0;
CHECK(base::StringToUint64(
command_line->GetSwitchValueASCII(switches::kDataQuotaBytes),
&quota_bytes));
base::SysInfo::SetAmountOfTotalDiskSpace(data_directory_path, quota_bytes);
}
return data_directory_path;
}
std::unique_ptr<WebEngineNetLogObserver> CreateNetLogObserver() { std::unique_ptr<WebEngineNetLogObserver> CreateNetLogObserver() {
std::unique_ptr<WebEngineNetLogObserver> result; std::unique_ptr<WebEngineNetLogObserver> result;
...@@ -46,16 +66,25 @@ std::unique_ptr<WebEngineNetLogObserver> CreateNetLogObserver() { ...@@ -46,16 +66,25 @@ std::unique_ptr<WebEngineNetLogObserver> CreateNetLogObserver() {
return result; return result;
} }
} // namespace
class WebEngineBrowserContext::ResourceContext
: public content::ResourceContext {
public:
ResourceContext() = default;
~ResourceContext() override = default;
private:
DISALLOW_COPY_AND_ASSIGN(ResourceContext);
};
WebEngineBrowserContext::WebEngineBrowserContext(bool force_incognito) WebEngineBrowserContext::WebEngineBrowserContext(bool force_incognito)
: net_log_observer_(CreateNetLogObserver()), : net_log_observer_(CreateNetLogObserver()),
resource_context_(new ResourceContext()) { resource_context_(new ResourceContext()) {
if (!force_incognito) { if (!force_incognito) {
base::PathService::Get(base::DIR_APP_DATA, &data_dir_path_); data_dir_path_ = InitializeDataDirectoryAndQuotaFromCommandLine();
if (!base::PathExists(data_dir_path_)) {
// Run in incognito mode if /data doesn't exist.
data_dir_path_.clear();
}
} }
simple_factory_key_ = simple_factory_key_ =
std::make_unique<SimpleFactoryKey>(GetPath(), IsOffTheRecord()); std::make_unique<SimpleFactoryKey>(GetPath(), IsOffTheRecord());
SimpleKeyMap::GetInstance()->Associate(this, simple_factory_key_.get()); SimpleKeyMap::GetInstance()->Associate(this, simple_factory_key_.get());
......
...@@ -19,5 +19,6 @@ const char kCorsExemptHeaders[] = "cors-exempt-headers"; ...@@ -19,5 +19,6 @@ const char kCorsExemptHeaders[] = "cors-exempt-headers";
const char kEnableCastStreamingReceiver[] = "enable-cast-streaming-receiver"; const char kEnableCastStreamingReceiver[] = "enable-cast-streaming-receiver";
const char kCdmDataDirectory[] = "cdm-data-directory"; const char kCdmDataDirectory[] = "cdm-data-directory";
const char kUseLegacyAndroidUserAgent[] = "use-legacy-android-user-agent"; const char kUseLegacyAndroidUserAgent[] = "use-legacy-android-user-agent";
const char kDataQuotaBytes[] = "data-quota-bytes";
} // namespace switches } // namespace switches
...@@ -56,6 +56,9 @@ extern const char kCdmDataDirectory[]; ...@@ -56,6 +56,9 @@ extern const char kCdmDataDirectory[];
// Enables reporting of an Android-like User Agent string. // Enables reporting of an Android-like User Agent string.
extern const char kUseLegacyAndroidUserAgent[]; extern const char kUseLegacyAndroidUserAgent[];
// Soft quota to apply to the Context's persistent data directory, in bytes.
extern const char kDataQuotaBytes[];
} // namespace switches } // namespace switches
#endif // FUCHSIA_ENGINE_SWITCHES_H_ #endif // FUCHSIA_ENGINE_SWITCHES_H_
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