File: web_database_service.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (209 lines) | stat: -rw-r--r-- 8,035 bytes parent folder | download | duplicates (3)
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);
    }
  }
}