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
content / browser / media / media_license_storage_host.h [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_MEDIA_MEDIA_LICENSE_STORAGE_HOST_H_
#define CONTENT_BROWSER_MEDIA_MEDIA_LICENSE_STORAGE_HOST_H_
#include "base/containers/unique_ptr_adapters.h"
#include "base/files/file_path.h"
#include "base/functional/callback_forward.h"
#include "base/thread_annotations.h"
#include "base/threading/sequence_bound.h"
#include "base/types/pass_key.h"
#include "components/services/storage/public/cpp/buckets/bucket_locator.h"
#include "components/services/storage/public/mojom/quota_client.mojom.h"
#include "content/browser/media/cdm_storage_common.h"
#include "content/browser/media/media_license_manager.h"
#include "content/common/content_export.h"
#include "media/mojo/mojom/cdm_storage.mojom.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/unique_associated_receiver_set.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
namespace content {
class CdmFileImpl;
class MediaLicenseDatabase;
// Per-storage-key backend for media license (CDM) files. MediaLicenseManager
// owns an instance of this class for each storage key that is actively using
// CDM files. Each instance owns all CdmStorage receivers for the corresponding
// storage key.
class CONTENT_EXPORT MediaLicenseStorageHost : public media::mojom::CdmStorage {
public:
using ReadFileCallback =
base::OnceCallback<void(std::optional<std::vector<uint8_t>>)>;
using WriteFileCallback = base::OnceCallback<void(bool)>;
using DeleteFileCallback = base::OnceCallback<void(bool)>;
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class MediaLicenseStorageHostOpenError {
kOk = -1,
kInvalidBucket = 0, // The database's path could not be determined
// because the default storage bucket for the
// StorageKey could not be retrieved.
kNoFileSpecified = 1, // No file was specified.
kInvalidFileName = 2, // File name specified was invalid.
kDatabaseOpenError = 3, // Error occurred at the Database level.
kBucketNotFound = 4, // If the default Storage Bucket for the StorageKey
// is not found.
kDatabaseRazeError = 5, // The database was in an invalid state and failed
// to be razed.
kSQLExecutionError = 6, // Error executing the SQL statement.
kBucketLocatorError = 7, // Error with the bucket locator. This error was
// introduced after the previous errors so that
// we can drill down deeper on the source of the
// errors.
kMaxValue = kBucketLocatorError
};
static void ReportDatabaseOpenError(MediaLicenseStorageHostOpenError error,
bool in_memory);
MediaLicenseStorageHost(MediaLicenseManager* manager,
const storage::BucketLocator& bucket_locator);
~MediaLicenseStorageHost() override;
// media::mojom::CdmStorage implementation.
void Open(const std::string& file_name, OpenCallback callback) final;
void BindReceiver(const CdmStorageBindingContext& binding_context,
mojo::PendingReceiver<media::mojom::CdmStorage> receiver);
// CDM file operations.
void ReadFile(const media::CdmType& cdm_type,
const std::string& file_name,
ReadFileCallback callback);
void WriteFile(const media::CdmType& cdm_type,
const std::string& file_name,
const std::vector<uint8_t>& data,
WriteFileCallback callback);
void DeleteFile(const media::CdmType& cdm_type,
const std::string& file_name,
DeleteFileCallback callback);
void DeleteBucketData(base::OnceCallback<void(bool)> callback);
void OnFileReceiverDisconnect(const std::string& name,
const media::CdmType& cdm_type,
base::PassKey<CdmFileImpl> pass_key);
// True if there are no receivers connected to this host.
//
// The MediaLicenseManagerImpl that owns this host is expected to destroy the
// host when it isn't serving any receivers.
bool has_empty_receiver_set() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return receivers_.empty();
}
const blink::StorageKey& storage_key() { return bucket_locator_.storage_key; }
bool in_memory() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return manager_->in_memory();
}
private:
void OnReceiverDisconnect();
void DidOpenFile(const std::string& file_name,
CdmStorageBindingContext binding_context,
OpenCallback callback,
MediaLicenseStorageHostOpenError error);
void DidGetDatabaseSize(const uint64_t size);
void DidReadFile(const media::CdmType& cdm_type,
const std::string& file_name,
ReadFileCallback callback,
std::optional<std::vector<uint8_t>> data);
void DidWriteFile(WriteFileCallback callback, bool success);
SEQUENCE_CHECKER(sequence_checker_);
// Track MediaLicenseDatabaseSize
bool database_size_reported_ = false;
// MediaLicenseManager instance which owns this object.
const raw_ptr<MediaLicenseManager> manager_
GUARDED_BY_CONTEXT(sequence_checker_);
// Media licenses are only supported from the default bucket.
// `bucket_locator_` corresponds to the default bucket for the StorageKey this
// host represents.
const storage::BucketLocator bucket_locator_;
// This keeps track of the 'CdmFileIdTwo' values that have been migrated to
// the CdmStorageDatabase after the first read, so that when the Cdm goes to
// read during the migration, the second time and onwards, we read from the
// CdmStorageDatabase instead of the MediaLicenseDatabase. Note that this is
// not a permanent storage, so it has to be repopulated when user restarts
// Chrome.
std::vector<CdmFileIdTwo> files_migrated_
GUARDED_BY_CONTEXT(sequence_checker_);
// All file operations are run through this member.
base::SequenceBound<MediaLicenseDatabase> db_
GUARDED_BY_CONTEXT(sequence_checker_);
// All receivers for frames and workers whose storage key is `storage_key()`.
mojo::ReceiverSet<media::mojom::CdmStorage, CdmStorageBindingContext>
receivers_ GUARDED_BY_CONTEXT(sequence_checker_);
// Keep track of all media::mojom::CdmFile receivers, as each CdmFileImpl
// object keeps a reference to |this|. If |this| goes away unexpectedly,
// all remaining CdmFile receivers will be closed.
std::map<CdmFileId, std::unique_ptr<CdmFileImpl>> cdm_files_
GUARDED_BY_CONTEXT(sequence_checker_);
base::WeakPtrFactory<MediaLicenseStorageHost> weak_factory_
GUARDED_BY_CONTEXT(sequence_checker_){this};
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_MEDIA_LICENSE_STORAGE_HOST_H_