1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/webdata/common/web_database_service.h"
#include <stddef.h>
#include <utility>
#include "base/check.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/task/sequenced_task_runner.h"
#include "components/os_crypt/async/browser/os_crypt_async.h"
#include "components/os_crypt/async/common/encryptor.h"
#include "components/webdata/common/web_data_request_manager.h"
#include "components/webdata/common/web_data_results.h"
#include "components/webdata/common/web_data_service_consumer.h"
#include "components/webdata/common/web_database_backend.h"
namespace features {
// If enabled, then an Encryptor will be requested that is not always backwards
// compatible with OSCrypt Sync. On some platforms, this might mean a key is
// used that is stored more securely, such as using App-Bound encryption on
// Windows.
// If this feature is enabled, any data stored by `WebDatabaseService` is not
// guaranteed to be retrievable if OSCrypt Async is not used.
BASE_FEATURE(kUseNewEncryptionKeyForWebData,
"UseNewEncryptionKeyForWebData",
base::FEATURE_ENABLED_BY_DEFAULT);
} // namespace features
// Receives messages from the backend on the DB sequence, posts them to
// WebDatabaseService on the UI sequence.
class WebDatabaseService::BackendDelegate
: public WebDatabaseBackend::Delegate {
public:
explicit BackendDelegate(
const base::WeakPtr<WebDatabaseService>& web_database_service)
: web_database_service_(web_database_service),
callback_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()) {}
void DBLoaded(sql::InitStatus status,
const std::string& diagnostics) override {
callback_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&WebDatabaseService::OnDatabaseLoadDone,
web_database_service_, status, diagnostics));
}
private:
const base::WeakPtr<WebDatabaseService> web_database_service_;
scoped_refptr<base::SequencedTaskRunner> callback_task_runner_;
};
WebDatabaseService::WebDatabaseService(
const base::FilePath& path,
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
scoped_refptr<base::SequencedTaskRunner> db_task_runner)
: base::RefCountedDeleteOnSequence<WebDatabaseService>(ui_task_runner),
path_(path),
db_task_runner_(std::move(db_task_runner)),
pending_task_queue_(
base::MakeRefCounted<base::DeferredSequencedTaskRunner>(
db_task_runner_)) {
DCHECK(ui_task_runner->RunsTasksInCurrentSequence());
DCHECK(db_task_runner_);
}
WebDatabaseService::~WebDatabaseService() = default;
void WebDatabaseService::AddTable(std::unique_ptr<WebDatabaseTable> table) {
CHECK(!pending_task_queue_->Started())
<< "Cannot call AddTable after LoadDatabase.";
if (!web_db_backend_) {
web_db_backend_ = base::MakeRefCounted<WebDatabaseBackend>(
path_,
std::make_unique<BackendDelegate>(weak_ptr_factory_.GetWeakPtr()),
db_task_runner_);
}
web_db_backend_->AddTable(std::move(table));
}
void WebDatabaseService::CompleteLoadDatabase(
os_crypt_async::Encryptor encryptor) {
DCHECK(web_db_backend_);
// All AddTable calls must have happened by the time LoadDatabase is called.
web_db_backend_->MaybeInitEncryptorOnUiSequence(std::move(encryptor));
// This ensures that the InitDatabase task gets executed on the DB task runner
// before any database tasks.
db_task_runner_->PostTask(
FROM_HERE, BindOnce(&WebDatabaseBackend::InitDatabase, web_db_backend_));
pending_task_queue_->Start();
}
void WebDatabaseService::LoadDatabase(os_crypt_async::OSCryptAsync* os_crypt) {
const auto option =
base::FeatureList::IsEnabled(features::kUseNewEncryptionKeyForWebData)
? os_crypt_async::Encryptor::Option::kNone
: os_crypt_async::Encryptor::Option::kEncryptSyncCompat;
// TODO(crbug.com/40267945): Place kEncryptSyncCompat behind base::Feature and
// then remove it.
os_crypt->GetInstance(
base::BindOnce(&WebDatabaseService::CompleteLoadDatabase, this), option);
}
void WebDatabaseService::ShutdownDatabase() {
error_callbacks_.clear();
weak_ptr_factory_.InvalidateWeakPtrs();
if (!web_db_backend_) {
return;
}
db_task_runner_->PostTask(
FROM_HERE,
BindOnce(&WebDatabaseBackend::ShutdownDatabase, web_db_backend_));
}
WebDatabase* WebDatabaseService::GetDatabaseOnDB() const {
DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
return web_db_backend_ ? web_db_backend_->database() : nullptr;
}
scoped_refptr<WebDatabaseBackend> WebDatabaseService::GetBackend() const {
return web_db_backend_;
}
scoped_refptr<base::SequencedTaskRunner> WebDatabaseService::GetDbSequence() {
return pending_task_queue_;
}
void WebDatabaseService::ScheduleDBTask(const base::Location& from_here,
WriteTask task) {
DCHECK(web_db_backend_);
std::unique_ptr<WebDataRequest> request =
web_db_backend_->request_manager()->NewRequest({});
pending_task_queue_->PostTask(
from_here,
BindOnce(&WebDatabaseBackend::DBWriteTaskWrapper, web_db_backend_,
std::move(task), std::move(request)));
}
WebDataServiceBase::Handle WebDatabaseService::ScheduleDBTaskWithResult(
const base::Location& from_here,
ReadTask task,
WebDataServiceConsumer* consumer) {
return ScheduleDBTaskWithResult(
from_here, std::move(task),
base::BindOnce(&WebDataServiceConsumer::OnWebDataServiceRequestDone,
consumer->GetWebDataServiceConsumerWeakPtr()));
}
WebDataServiceBase::Handle WebDatabaseService::ScheduleDBTaskWithResult(
const base::Location& from_here,
ReadTask task,
WebDataServiceRequestCallback consumer) {
DCHECK(consumer);
DCHECK(web_db_backend_);
std::unique_ptr<WebDataRequest> request =
web_db_backend_->request_manager()->NewRequest(std::move(consumer));
WebDataServiceBase::Handle handle = request->GetHandle();
pending_task_queue_->PostTask(
from_here,
BindOnce(&WebDatabaseBackend::DBReadTaskWrapper, web_db_backend_,
std::move(task), std::move(request)));
return handle;
}
void WebDatabaseService::CancelRequest(WebDataServiceBase::Handle h) {
if (web_db_backend_) {
web_db_backend_->request_manager()->CancelRequest(h);
}
}
void WebDatabaseService::RegisterDBErrorCallback(DBLoadErrorCallback callback) {
error_callbacks_.push_back(std::move(callback));
}
bool WebDatabaseService::UsesInMemoryDatabaseForTesting() const {
// This mimics what WebDatabase::Init() does internally, as it would require
// significant test-only boilerplate to actually fetch the authoritative
// boolean from the very underlying `sql::Database::in_memory_`.
return path_.value() == WebDatabase::kInMemoryPath;
}
void WebDatabaseService::OnDatabaseLoadDone(sql::InitStatus status,
const std::string& diagnostics) {
// The INIT_OK_WITH_DATA_LOSS status is an initialization success but with
// suspected data loss, so we also run the error callbacks.
if (status == sql::INIT_OK) {
return;
}
// Notify that the database load failed.
while (!error_callbacks_.empty()) {
// The profile error callback is a message box that runs in a nested run
// loop. While it's being displayed, other OnDatabaseLoadDone() will run
// (posted from WebDatabaseBackend::Delegate::DBLoaded()). We need to make
// sure that after the callback running the message box returns, it checks
// |error_callbacks_| before it accesses it.
DBLoadErrorCallback error_callback = std::move(error_callbacks_.back());
error_callbacks_.pop_back();
if (!error_callback.is_null()) {
std::move(error_callback).Run(status, diagnostics);
}
}
}
|