1 // Copyright 2020 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 "services/network/trust_tokens/trust_token_database_owner.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include "base/memory/ptr_util.h"
13 #include "base/memory/scoped_refptr.h"
14 #include "base/sequence_checker.h"
15 #include "base/sequenced_task_runner.h"
16 #include "components/sqlite_proto/key_value_data.h"
17 #include "components/sqlite_proto/key_value_table.h"
18 #include "components/sqlite_proto/proto_table_manager.h"
19 #include "services/network/trust_tokens/proto/storage.pb.h"
20
21 namespace network {
22
23 namespace {
24 const char kIssuerTableName[] = "trust_tokens_issuer_config";
25 const char kToplevelTableName[] = "trust_tokens_toplevel_config";
26 const char kIssuerToplevelPairTableName[] =
27 "trust_tokens_issuer_toplevel_pair_config";
28
29 } // namespace
30
Create(base::OnceCallback<bool (sql::Database *)> db_opener,scoped_refptr<base::SequencedTaskRunner> db_task_runner,base::TimeDelta flush_delay_for_writes,base::OnceCallback<void (std::unique_ptr<TrustTokenDatabaseOwner>)> on_done_initializing)31 void TrustTokenDatabaseOwner::Create(
32 base::OnceCallback<bool(sql::Database*)> db_opener,
33 scoped_refptr<base::SequencedTaskRunner> db_task_runner,
34 base::TimeDelta flush_delay_for_writes,
35 base::OnceCallback<void(std::unique_ptr<TrustTokenDatabaseOwner>)>
36 on_done_initializing) {
37 DCHECK(db_opener);
38 DCHECK(on_done_initializing);
39
40 // No leak: the constructed object wraps itself in a unique_ptr and passes
41 // that pointer to |on_done_initializing|.
42 new TrustTokenDatabaseOwner(std::move(db_opener), std::move(db_task_runner),
43 flush_delay_for_writes,
44 std::move(on_done_initializing));
45 }
46
~TrustTokenDatabaseOwner()47 TrustTokenDatabaseOwner::~TrustTokenDatabaseOwner() {
48 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
49
50 db_task_runner_->DeleteSoon(FROM_HERE, backing_database_.release());
51 }
52
53 sqlite_proto::KeyValueData<TrustTokenIssuerConfig>*
IssuerData()54 TrustTokenDatabaseOwner::IssuerData() {
55 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
56 return issuer_data_.get();
57 }
58
59 sqlite_proto::KeyValueData<TrustTokenToplevelConfig>*
ToplevelData()60 TrustTokenDatabaseOwner::ToplevelData() {
61 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
62 return toplevel_data_.get();
63 }
64
65 sqlite_proto::KeyValueData<TrustTokenIssuerToplevelPairConfig>*
IssuerToplevelPairData()66 TrustTokenDatabaseOwner::IssuerToplevelPairData() {
67 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
68 return issuer_toplevel_pair_data_.get();
69 }
70
71 // Marking NOINLINE saves a few hundred bytes of binary size.
TrustTokenDatabaseOwner(base::OnceCallback<bool (sql::Database *)> db_opener,scoped_refptr<base::SequencedTaskRunner> db_task_runner,base::TimeDelta flush_delay_for_writes,base::OnceCallback<void (std::unique_ptr<TrustTokenDatabaseOwner>)> on_done_initializing)72 NOINLINE TrustTokenDatabaseOwner::TrustTokenDatabaseOwner(
73 base::OnceCallback<bool(sql::Database*)> db_opener,
74 scoped_refptr<base::SequencedTaskRunner> db_task_runner,
75 base::TimeDelta flush_delay_for_writes,
76 base::OnceCallback<void(std::unique_ptr<TrustTokenDatabaseOwner>)>
77 on_done_initializing)
78 : on_done_initializing_(std::move(on_done_initializing)),
79 table_manager_(base::MakeRefCounted<sqlite_proto::ProtoTableManager>(
80 db_task_runner)),
81 db_task_runner_(db_task_runner),
82 backing_database_(std::make_unique<sql::Database>()),
83 issuer_table_(
84 std::make_unique<sqlite_proto::KeyValueTable<TrustTokenIssuerConfig>>(
85 kIssuerTableName)),
86 issuer_data_(
87 std::make_unique<sqlite_proto::KeyValueData<TrustTokenIssuerConfig>>(
88 table_manager_,
89 issuer_table_.get(),
90 /*max_num_entries=*/base::nullopt,
91 flush_delay_for_writes)),
92 toplevel_table_(std::make_unique<
93 sqlite_proto::KeyValueTable<TrustTokenToplevelConfig>>(
94 kToplevelTableName)),
95 toplevel_data_(std::make_unique<
96 sqlite_proto::KeyValueData<TrustTokenToplevelConfig>>(
97 table_manager_,
98 toplevel_table_.get(),
99 /*max_num_entries=*/base::nullopt,
100 flush_delay_for_writes)),
101 issuer_toplevel_pair_table_(
102 std::make_unique<
103 sqlite_proto::KeyValueTable<TrustTokenIssuerToplevelPairConfig>>(
104 kIssuerToplevelPairTableName)),
105 issuer_toplevel_pair_data_(
106 std::make_unique<
107 sqlite_proto::KeyValueData<TrustTokenIssuerToplevelPairConfig>>(
108 table_manager_,
109 issuer_toplevel_pair_table_.get(),
110 /*max_num_entries=*/base::nullopt,
111 flush_delay_for_writes)) {
112 // These two lines are boilerplate copied from predictor_database.cc.
113 backing_database_->set_histogram_tag("TrustTokens");
114 // We have to call this because the database doesn't have a "meta" table.
115 backing_database_->set_mmap_alt_status();
116
117 // Because TrustTokenDatabaseOwners are only constructed through an
118 // asynchronous factory method, they are impossible to delete prior to their
119 // initialization concluding.
120 db_task_runner->PostTaskAndReply(
121 FROM_HERE,
122 base::BindOnce(&TrustTokenDatabaseOwner::InitializeMembersOnDbSequence,
123 base::Unretained(this), std::move(db_opener)),
124 base::BindOnce(
125 &TrustTokenDatabaseOwner::FinishInitializationOnMainSequence,
126 base::Unretained(this)));
127 }
128
InitializeMembersOnDbSequence(base::OnceCallback<bool (sql::Database *)> db_opener)129 void TrustTokenDatabaseOwner::InitializeMembersOnDbSequence(
130 base::OnceCallback<bool(sql::Database*)> db_opener) {
131 DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
132
133 if (backing_database_ && !std::move(db_opener).Run(backing_database_.get())) {
134 // Giving a nullptr database to ProtoTableManager results in the
135 // operations it executes no-opping, so KeyValueData will fall back to
136 // reasonable behavior of caching operations' results in memory but not
137 // writing them to disk.
138 backing_database_.reset();
139 }
140
141 DCHECK(!backing_database_ || backing_database_->is_open());
142
143 if (backing_database_)
144 backing_database_->Preload();
145
146 table_manager_->InitializeOnDbSequence(
147 backing_database_.get(),
148 std::vector<std::string>{kIssuerTableName, kToplevelTableName,
149 kIssuerToplevelPairTableName});
150
151 issuer_data_->InitializeOnDBSequence();
152 toplevel_data_->InitializeOnDBSequence();
153 issuer_toplevel_pair_data_->InitializeOnDBSequence();
154 }
155
FinishInitializationOnMainSequence()156 void TrustTokenDatabaseOwner::FinishInitializationOnMainSequence() {
157 // Note: If the backing database fails to initialize,
158 // InitializeMembersOnDbSequence will provide the table manager a null DB
159 // pointer, which will make attempts to execute database operations no-op,
160 // so that the KeyValueData handles fall back to just storing this session's
161 // Trust Tokens data in memory.
162 //
163 // We still consider the TrustTokenDatabaseOwner as having initialized
164 // "successfully" in this case, since it is safe to execute operations in
165 // this single-session fallback state.
166 DCHECK(on_done_initializing_);
167 std::move(on_done_initializing_).Run(base::WrapUnique(this));
168 }
169
170 } // namespace network
171