blob: d119afafeb40f0c538c8ebeb609198dab5ca7dbd [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/services/storage/storage_service_impl.h"
#include "base/bind.h"
#include "base/task/post_task.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
#include "components/services/storage/dom_storage/storage_area_impl.h"
#include "components/services/storage/filesystem_proxy_factory.h"
#include "components/services/storage/partition_impl.h"
#include "components/services/storage/public/cpp/filesystem/filesystem_proxy.h"
#include "components/services/storage/sandboxed_vfs_delegate.h"
#include "components/services/storage/test_api_stubs.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "sql/database.h"
#include "sql/sandboxed_vfs.h"
#include "third_party/leveldatabase/env_chromium.h"
namespace storage {
namespace {
// We don't use out-of-process Storage Service on Android, so we can avoid
// pulling all the related code (including Directory mojom) into the build.
#if !defined(OS_ANDROID)
// The name under which we register our own sandboxed VFS instance when running
// out-of-process.
constexpr char kVfsName[] = "storage_service";
using DirectoryBinder =
base::RepeatingCallback<void(mojo::PendingReceiver<mojom::Directory>)>;
std::unique_ptr<FilesystemProxy> CreateRestrictedFilesystemProxy(
const base::FilePath& directory_path,
scoped_refptr<base::SequencedTaskRunner> io_task_runner,
DirectoryBinder binder,
scoped_refptr<base::SequencedTaskRunner> binder_task_runner) {
mojo::PendingRemote<mojom::Directory> directory;
binder_task_runner->PostTask(
FROM_HERE,
base::BindOnce(binder, directory.InitWithNewPipeAndPassReceiver()));
return std::make_unique<FilesystemProxy>(FilesystemProxy::RESTRICTED,
directory_path, std::move(directory),
std::move(io_task_runner));
}
#endif
} // namespace
StorageServiceImpl::StorageServiceImpl(
mojo::PendingReceiver<mojom::StorageService> receiver,
scoped_refptr<base::SequencedTaskRunner> io_task_runner)
: receiver_(this, std::move(receiver)),
io_task_runner_(std::move(io_task_runner)) {}
StorageServiceImpl::~StorageServiceImpl() = default;
void StorageServiceImpl::EnableAggressiveDomStorageFlushing() {
StorageAreaImpl::EnableAggressiveCommitDelay();
}
#if !defined(OS_ANDROID)
void StorageServiceImpl::SetDataDirectory(
const base::FilePath& path,
mojo::PendingRemote<mojom::Directory> directory) {
remote_data_directory_path_ = path;
remote_data_directory_.Bind(std::move(directory));
// We can assume we must be sandboxed if we're getting a remote data
// directory handle. Override the default FilesystemProxy factory to produce
// instances restricted to operations within |path|, which can operate
// from within a sandbox.
SetFilesystemProxyFactory(base::BindRepeating(
&CreateRestrictedFilesystemProxy, remote_data_directory_path_,
io_task_runner_,
base::BindRepeating(&StorageServiceImpl::BindDataDirectoryReceiver,
weak_ptr_factory_.GetWeakPtr()),
base::SequencedTaskRunnerHandle::Get()));
// Prevent SQLite from trying to use mmap, as SandboxedVfs does not currently
// support this.
//
// TODO(crbug.com/1117049): Configure this per Database instance.
sql::Database::DisableMmapByDefault();
// SQLite needs our VFS implementation to work over a FilesystemProxy. This
// installs it as the default implementation for the service process.
sql::SandboxedVfs::Register(
kVfsName, std::make_unique<SandboxedVfsDelegate>(CreateFilesystemProxy()),
/*make_default=*/true);
}
#endif // !defined(OS_ANDROID)
void StorageServiceImpl::BindPartition(
const absl::optional<base::FilePath>& path,
mojo::PendingReceiver<mojom::Partition> receiver) {
if (path.has_value()) {
if (!path->IsAbsolute()) {
// Refuse to bind Partitions for relative paths.
return;
}
// If this is a persistent partition that already exists, bind to it and
// we're done.
auto iter = persistent_partition_map_.find(*path);
if (iter != persistent_partition_map_.end()) {
iter->second->BindReceiver(std::move(receiver));
return;
}
}
auto new_partition = std::make_unique<PartitionImpl>(this, path);
new_partition->BindReceiver(std::move(receiver));
if (path.has_value())
persistent_partition_map_[*path] = new_partition.get();
partitions_.insert(std::move(new_partition));
}
void StorageServiceImpl::BindTestApi(
mojo::ScopedMessagePipeHandle test_api_receiver) {
GetTestApiBinderForTesting().Run(std::move(test_api_receiver));
}
void StorageServiceImpl::RemovePartition(PartitionImpl* partition) {
if (partition->path().has_value())
persistent_partition_map_.erase(partition->path().value());
auto iter = partitions_.find(partition);
if (iter != partitions_.end())
partitions_.erase(iter);
}
#if !defined(OS_ANDROID)
void StorageServiceImpl::BindDataDirectoryReceiver(
mojo::PendingReceiver<mojom::Directory> receiver) {
DCHECK(remote_data_directory_.is_bound());
remote_data_directory_->Clone(std::move(receiver));
}
#endif
} // namespace storage