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