[M120 Migration][VD] Enable direct rendering for TVPlus
[platform/framework/web/chromium-efl.git] / components / media_device_salt / media_device_salt_database.cc
1 // Copyright 2023 The Chromium Authors
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 "components/media_device_salt/media_device_salt_database.h"
6
7 #include "base/containers/cxx20_erase_vector.h"
8 #include "base/feature_list.h"
9 #include "base/functional/bind.h"
10 #include "base/strings/strcat.h"
11 #include "base/strings/string_util.h"
12 #include "base/time/time.h"
13 #include "sql/meta_table.h"
14 #include "sql/recovery.h"
15 #include "sql/statement.h"
16 #include "sql/transaction.h"
17 #include "third_party/blink/public/common/storage_key/storage_key.h"
18
19 namespace media_device_salt {
20
21 BASE_FEATURE(kMediaDeviceSaltDatabaseUseBuiltInRecoveryIfSupported,
22              "MediaDeviceSaltDatabaseUseBuiltInRecoveryIfSupported",
23              base::FEATURE_ENABLED_BY_DEFAULT);
24
25 namespace {
26 // The current version of the database schema.
27 constexpr int kCurrentVersion = 1;
28
29 // The lowest version of the database schema such that old versions of the code
30 // can still read/write the current database.
31 constexpr int kCompatibleVersion = 1;
32 }  // namespace
33
34 std::string CreateRandomSalt() {
35   return base::UnguessableToken::Create().ToString();
36 }
37
38 MediaDeviceSaltDatabase::MediaDeviceSaltDatabase(const base::FilePath& db_path)
39     : db_path_(db_path),
40       db_(sql::DatabaseOptions{.exclusive_locking = true,
41                                .page_size = 4096,
42                                .cache_size = 16}) {}
43
44 absl::optional<std::string> MediaDeviceSaltDatabase::GetOrInsertSalt(
45     const blink::StorageKey& storage_key,
46     absl::optional<std::string> candidate_salt) {
47   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
48   if (storage_key.origin().opaque() || !EnsureOpen()) {
49     return absl::nullopt;
50   }
51   sql::Transaction transaction(&db_);
52   if (!transaction.Begin()) {
53     return absl::nullopt;
54   }
55   static constexpr char kGetSaltSql[] =
56       "SELECT salt FROM media_device_salts WHERE storage_key=?";
57   DCHECK(db_.IsSQLValid(kGetSaltSql));
58   sql::Statement select_statement(
59       db_.GetCachedStatement(SQL_FROM_HERE, kGetSaltSql));
60   select_statement.BindString(0, storage_key.Serialize());
61   if (select_statement.Step()) {
62     return select_statement.ColumnString(0);
63   }
64   if (!select_statement.Succeeded()) {
65     return absl::nullopt;
66   }
67
68   static constexpr char kInsertSaltSql[] =
69       "INSERT INTO media_device_salts(storage_key,creation_time,salt) "
70       "VALUES(?,?,?)";
71   DCHECK(db_.IsSQLValid(kInsertSaltSql));
72   sql::Statement insert_statement(
73       db_.GetCachedStatement(SQL_FROM_HERE, kInsertSaltSql));
74   insert_statement.BindString(0, storage_key.Serialize());
75   insert_statement.BindTime(1, base::Time::Now());
76   std::string new_salt = candidate_salt.value_or(CreateRandomSalt());
77   insert_statement.BindString(2, new_salt);
78   return insert_statement.Run() && transaction.Commit()
79              ? absl::make_optional(new_salt)
80              : absl::nullopt;
81 }
82
83 void MediaDeviceSaltDatabase::DeleteEntries(
84     base::Time delete_begin,
85     base::Time delete_end,
86     content::StoragePartition::StorageKeyMatcherFunction matcher) {
87   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
88   if (!EnsureOpen()) {
89     return;
90   }
91
92   if (matcher.is_null()) {
93     static constexpr char kDeleteSaltsSql[] =
94         "DELETE FROM media_device_salts "
95         "WHERE creation_time>=? AND creation_time<=?";
96     DCHECK(db_.IsSQLValid(kDeleteSaltsSql));
97     sql::Statement statement(db_.GetUniqueStatement(kDeleteSaltsSql));
98     statement.BindTime(0, delete_begin);
99     statement.BindTime(1, delete_end);
100     statement.Run();
101     return;
102   }
103
104   sql::Transaction transaction(&db_);
105   if (!transaction.Begin()) {
106     return;
107   }
108   static constexpr char kGetStorageKeysSql[] =
109       "SELECT storage_key "
110       "FROM media_device_salts "
111       "WHERE creation_time>=? AND creation_time<=?";
112   DCHECK(db_.IsSQLValid(kGetStorageKeysSql));
113   sql::Statement select_statement(db_.GetUniqueStatement(kGetStorageKeysSql));
114   select_statement.BindTime(0, delete_begin);
115   select_statement.BindTime(1, delete_end);
116
117   std::vector<std::string> serialized_storage_keys;
118   while (select_statement.Step()) {
119     serialized_storage_keys.push_back(select_statement.ColumnString(0));
120   }
121
122   base::EraseIf(serialized_storage_keys,
123                 [&matcher](const std::string& serialized_storage_key) {
124                   absl::optional<blink::StorageKey> storage_key =
125                       blink::StorageKey::Deserialize(serialized_storage_key);
126                   if (!storage_key.has_value()) {
127                     // This shouldn't happen, but include non-Deserializable
128                     // keys for deletion if they're found.
129                     return false;
130                   }
131                   return !matcher.Run(*storage_key);
132                 });
133
134   if (serialized_storage_keys.empty()) {
135     return;
136   }
137
138   const std::string delete_storage_keys_sql =
139       base::StrCat({"DELETE FROM media_device_salts "
140                     "WHERE storage_key IN ('",
141                     base::JoinString(serialized_storage_keys, "','"), "')"});
142   DCHECK(db_.IsSQLValid(delete_storage_keys_sql.c_str()));
143   sql::Statement delete_statement(
144       db_.GetUniqueStatement(delete_storage_keys_sql.c_str()));
145   delete_statement.Run() && transaction.Commit();
146 }
147
148 void MediaDeviceSaltDatabase::DeleteEntry(
149     const blink::StorageKey& storage_key) {
150   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
151   if (storage_key.origin().opaque() || !EnsureOpen()) {
152     return;
153   }
154   static constexpr char kDeleteStorageKeySql[] =
155       "DELETE FROM media_device_salts "
156       "WHERE storage_key=?";
157   DCHECK(db_.IsSQLValid(kDeleteStorageKeySql));
158   sql::Statement statement(db_.GetUniqueStatement(kDeleteStorageKeySql));
159   statement.BindString(0, storage_key.Serialize());
160   statement.Run();
161 }
162
163 std::vector<blink::StorageKey> MediaDeviceSaltDatabase::GetAllStorageKeys() {
164   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
165   if (!EnsureOpen()) {
166     return {};
167   }
168   std::vector<blink::StorageKey> storage_keys;
169   static constexpr char kGetStorageKeysSql[] =
170       "SELECT storage_key FROM media_device_salts";
171   DCHECK(db_.IsSQLValid(kGetStorageKeysSql));
172   sql::Statement statement(db_.GetUniqueStatement(kGetStorageKeysSql));
173   while (statement.Step()) {
174     absl::optional<blink::StorageKey> key =
175         blink::StorageKey::Deserialize(statement.ColumnString(0));
176     if (key.has_value()) {
177       storage_keys.push_back(*key);
178     }
179   }
180   return storage_keys;
181 }
182
183 bool MediaDeviceSaltDatabase::EnsureOpen(bool is_retry) {
184   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
185   if (db_.is_open()) {
186     return true;
187   }
188   if (force_error_) {
189     return false;
190   }
191
192   db_.set_histogram_tag("Media Device Salts");
193   // base::Unretained() is safe here because `this` owns `db`.
194   db_.set_error_callback(base::BindRepeating(
195       &MediaDeviceSaltDatabase::OnDatabaseError, base::Unretained(this)));
196   if (db_path_.empty()) {
197     if (!db_.OpenInMemory()) {
198       return false;
199     }
200   } else if (!db_.Open(db_path_)) {
201     return false;
202   }
203
204   sql::Transaction transaction(&db_);
205   if (transaction.Begin()) {
206     sql::MetaTable metatable;
207     if (metatable.Init(&db_, kCurrentVersion, kCompatibleVersion) &&
208         metatable.GetCompatibleVersionNumber() <= kCurrentVersion &&
209         db_.Execute("CREATE TABLE IF NOT EXISTS media_device_salts("
210                     "  storage_key TEXT PRIMARY KEY NOT NULL,"
211                     "  creation_time INTEGER NOT NULL,"
212                     "  salt TEXT NOT NULL)") &&
213         db_.Execute("CREATE INDEX IF NOT EXISTS creation_time ON "
214                     "media_device_salts(creation_time)") &&
215         transaction.Commit()) {
216       return true;
217     }
218     transaction.Rollback();
219   }
220
221   db_.Raze();
222   return is_retry ? false : EnsureOpen(/*is_retry=*/true);
223 }
224
225 void MediaDeviceSaltDatabase::OnDatabaseError(int error,
226                                               sql::Statement* statement) {
227   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
228   sql::UmaHistogramSqliteResult("Media.MediaDevices.SaltDatabaseErrors", error);
229   std::ignore = sql::BuiltInRecovery::RecoverIfPossible(
230       &db_, error,
231       sql::BuiltInRecovery::Strategy::kRecoverWithMetaVersionOrRaze,
232       &kMediaDeviceSaltDatabaseUseBuiltInRecoveryIfSupported);
233 }
234
235 }  // namespace media_device_salt