0

ukm: Add CDM_ID to list of SourceIds

To avoid a round trip to collect the sourceId, plus with the CDM
existing in its own process, define a new SourceIdType called CDM_ID.

Verified manually: https://photos.app.goo.gl/bYStWbBg4AHf6maH6

Also added to encrypted media browser tests.

Bug: 382073085
Change-Id: I0f614d6d4fd1f0030b5f91001c7e5f50c89cb2cd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6190953
Reviewed-by: Salvador Guerrero Ramos <salg@google.com>
Reviewed-by: Alexei Svitkine <asvitkine@chromium.org>
Reviewed-by: John Rummell <jrummell@chromium.org>
Reviewed-by: Nathan Hebert <nhebert@chromium.org>
Reviewed-by: Robert Kaplow <rkaplow@chromium.org>
Reviewed-by: Nasko Oskov <nasko@chromium.org>
Commit-Queue: Vikram Pasupathy <vpasupathy@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1416545}
This commit is contained in:
Vikram Pasupathy
2025-02-05 17:30:35 -08:00
committed by Chromium LUCI CQ
parent 455859c3e3
commit ccf870386b
19 changed files with 43 additions and 31 deletions

@@ -531,6 +531,9 @@ class ECKEncryptedMediaReportMetricsTest : public EncryptedMediaTestBase,
if (GetCdmInterfaceVersion() > 10) { if (GetCdmInterfaceVersion() > 10) {
EXPECT_EQ(report_metric_entries.size(), 1u); EXPECT_EQ(report_metric_entries.size(), 1u);
EXPECT_EQ(ukm::GetSourceIdType(report_metric_entries[0].source_id),
ukm::SourceIdType::CDM_ID);
// The ClearKey cdm does not report kCertificateSerialNumber or // The ClearKey cdm does not report kCertificateSerialNumber or
// kDecoderBypassBlockCount, so the entries should not even be set in the // kDecoderBypassBlockCount, so the entries should not even be set in the
// ukm data. // ukm data.

@@ -67,7 +67,6 @@ class MockFrameInterfaceFactory : public media::mojom::FrameInterfaceFactory {
MOCK_METHOD(void, CreateCdmStorage, (mojo::PendingReceiver<BrowserStorage>)); MOCK_METHOD(void, CreateCdmStorage, (mojo::PendingReceiver<BrowserStorage>));
MOCK_METHOD(bool, GetCdmOrigin, (url::Origin*)); MOCK_METHOD(bool, GetCdmOrigin, (url::Origin*));
MOCK_METHOD(void, GetCdmOrigin, (GetCdmOriginCallback)); MOCK_METHOD(void, GetCdmOrigin, (GetCdmOriginCallback));
MOCK_METHOD(void, GetPageUkmSourceId, (GetPageUkmSourceIdCallback callback));
MOCK_METHOD(void, BindEmbedderReceiver, (mojo::GenericPendingReceiver)); MOCK_METHOD(void, BindEmbedderReceiver, (mojo::GenericPendingReceiver));
}; };

@@ -422,6 +422,9 @@ void UkmDatabaseBackend::RestartTransaction() {
if (!current_transaction_->Begin()) { if (!current_transaction_->Begin()) {
current_transaction_.reset(); current_transaction_.reset();
} }
// Forces the wal file to be in sync with the main database.
std::ignore = db_.Execute("PRAGMA wal_checkpoint(TRUNCATE)");
} }
} // namespace segmentation_platform } // namespace segmentation_platform

@@ -52,6 +52,8 @@ BASE_FEATURE(kUkmSamplingRateFeature,
namespace { namespace {
// Allowlisted source ids are sent. Non-allowlisted source ids are sent if the
// url matches that of an allow-listed source.
bool IsAllowlistedSourceId(SourceId source_id) { bool IsAllowlistedSourceId(SourceId source_id) {
SourceIdType type = GetSourceIdType(source_id); SourceIdType type = GetSourceIdType(source_id);
switch (type) { switch (type) {
@@ -65,7 +67,8 @@ bool IsAllowlistedSourceId(SourceId source_id) {
case ukm::SourceIdObj::Type::WEB_IDENTITY_ID: case ukm::SourceIdObj::Type::WEB_IDENTITY_ID:
case ukm::SourceIdObj::Type::CHROMEOS_WEBSITE_ID: case ukm::SourceIdObj::Type::CHROMEOS_WEBSITE_ID:
case ukm::SourceIdObj::Type::NOTIFICATION_ID: case ukm::SourceIdObj::Type::NOTIFICATION_ID:
case ukm::SourceIdObj::Type::EXTENSION_ID: { case ukm::SourceIdObj::Type::EXTENSION_ID:
case ukm::SourceIdObj::Type::CDM_ID: {
return true; return true;
} }
case ukm::SourceIdObj::Type::DEFAULT: case ukm::SourceIdObj::Type::DEFAULT:
@@ -810,6 +813,7 @@ UkmConsentType UkmRecorderImpl::GetConsentType(SourceIdType type) {
case SourceIdType::CHROMEOS_WEBSITE_ID: case SourceIdType::CHROMEOS_WEBSITE_ID:
case SourceIdType::EXTENSION_ID: case SourceIdType::EXTENSION_ID:
case SourceIdType::NOTIFICATION_ID: case SourceIdType::NOTIFICATION_ID:
case SourceIdType::CDM_ID:
return UkmConsentType::MSBB; return UkmConsentType::MSBB;
} }
return UkmConsentType::MSBB; return UkmConsentType::MSBB;
@@ -862,7 +866,8 @@ void UkmRecorderImpl::MaybeMarkForDeletion(SourceId source_id) {
case ukm::SourceIdObj::Type::WEB_IDENTITY_ID: case ukm::SourceIdObj::Type::WEB_IDENTITY_ID:
case ukm::SourceIdObj::Type::CHROMEOS_WEBSITE_ID: case ukm::SourceIdObj::Type::CHROMEOS_WEBSITE_ID:
case ukm::SourceIdObj::Type::EXTENSION_ID: case ukm::SourceIdObj::Type::EXTENSION_ID:
case ukm::SourceIdObj::Type::NOTIFICATION_ID: { case ukm::SourceIdObj::Type::NOTIFICATION_ID:
case ukm::SourceIdObj::Type::CDM_ID: {
// Don't keep sources of these types after current report because their // Don't keep sources of these types after current report because their
// entries are logged only at source creation time. // entries are logged only at source creation time.
MarkSourceForDeletion(source_id); MarkSourceForDeletion(source_id);

@@ -206,10 +206,6 @@ class FrameInterfaceFactoryImpl : public media::mojom::FrameInterfaceFactory,
render_frame_host_->GetLastCommittedOrigin()); render_frame_host_->GetLastCommittedOrigin());
} }
void GetPageUkmSourceId(GetPageUkmSourceIdCallback callback) override {
return std::move(callback).Run(render_frame_host_->GetPageUkmSourceId());
}
void BindEmbedderReceiver(mojo::GenericPendingReceiver receiver) override { void BindEmbedderReceiver(mojo::GenericPendingReceiver receiver) override {
GetContentClient()->browser()->BindMediaServiceReceiver( GetContentClient()->browser()->BindMediaServiceReceiver(
render_frame_host_, std::move(receiver)); render_frame_host_, std::move(receiver));

@@ -245,8 +245,8 @@ CdmAdapter::CdmAdapter(
session_closed_cb_(session_closed_cb), session_closed_cb_(session_closed_cb),
session_keys_change_cb_(session_keys_change_cb), session_keys_change_cb_(session_keys_change_cb),
session_expiration_update_cb_(session_expiration_update_cb), session_expiration_update_cb_(session_expiration_update_cb),
cdm_origin_(helper_->GetCdmOrigin().Serialize()), scoped_crash_key_(&g_origin_crash_key,
scoped_crash_key_(&g_origin_crash_key, cdm_origin_), helper_->GetCdmOrigin().Serialize()),
task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()), task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()),
pool_(new AudioBufferMemoryPool()) { pool_(new AudioBufferMemoryPool()) {
DVLOG(1) << __func__; DVLOG(1) << __func__;
@@ -259,6 +259,8 @@ CdmAdapter::CdmAdapter(
DCHECK(session_keys_change_cb_); DCHECK(session_keys_change_cb_);
DCHECK(session_expiration_update_cb_); DCHECK(session_expiration_update_cb_);
cdm_metrics_data_.cdm_origin = helper_->GetCdmOrigin();
helper_->SetFileReadCB( helper_->SetFileReadCB(
base::BindRepeating(&CdmAdapter::OnFileRead, weak_factory_.GetWeakPtr())); base::BindRepeating(&CdmAdapter::OnFileRead, weak_factory_.GetWeakPtr()));
} }

@@ -230,8 +230,7 @@ class MEDIA_EXPORT CdmAdapter final : public ContentDecryptionModule,
SessionKeysChangeCB session_keys_change_cb_; SessionKeysChangeCB session_keys_change_cb_;
SessionExpirationUpdateCB session_expiration_update_cb_; SessionExpirationUpdateCB session_expiration_update_cb_;
// CDM origin and crash key to be used in crash reporting. // CDM crash key to be used in crash reporting.
const std::string cdm_origin_;
crash_reporter::ScopedCrashKeyString scoped_crash_key_; crash_reporter::ScopedCrashKeyString scoped_crash_key_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_; scoped_refptr<base::SingleThreadTaskRunner> task_runner_;

@@ -38,6 +38,8 @@ struct MEDIA_EXPORT CdmMetricsData {
std::optional<uint64_t> certificate_serial_number; std::optional<uint64_t> certificate_serial_number;
std::optional<uint64_t> decoder_bypass_block_count; std::optional<uint64_t> decoder_bypass_block_count;
url::Origin cdm_origin;
bool IsCdmValueSet() { bool IsCdmValueSet() {
return (license_sdk_version.has_value() || return (license_sdk_version.has_value() ||
certificate_serial_number.has_value() || certificate_serial_number.has_value() ||

@@ -46,10 +46,6 @@ interface FrameInterfaceFactory {
[Sync] [Sync]
GetCdmOrigin() => (url.mojom.Origin cdm_origin); GetCdmOrigin() => (url.mojom.Origin cdm_origin);
// Gets the UKMSourceId of the frame associated with the CDM.
[Sync]
GetPageUkmSourceId() => (int64 ukm_source_id);
// Binds a generic media frame-bound interface. This is to allow //content // Binds a generic media frame-bound interface. This is to allow //content
// embedders to provide additional interfaces. // embedders to provide additional interfaces.
BindEmbedderReceiver(mojo_base.mojom.GenericPendingReceiver receiver); BindEmbedderReceiver(mojo_base.mojom.GenericPendingReceiver receiver);

@@ -136,12 +136,12 @@ void MojoCdmHelper::ReportFileReadSize(int file_size_bytes) {
} }
void MojoCdmHelper::RecordUkm(const CdmMetricsData& cdm_metrics_data) { void MojoCdmHelper::RecordUkm(const CdmMetricsData& cdm_metrics_data) {
if (ukm_source_id_ == ukm::kInvalidSourceId) { ukm::SourceId source_id = ukm::ConvertToSourceId(ukm::AssignNewSourceId(),
DLOG(ERROR) << "Invalid UKM source ID"; ukm::SourceIdType::CDM_ID);
return; ukm_recorder_->UpdateSourceURL(source_id,
} cdm_metrics_data.cdm_origin.GetURL());
auto ukm_builder = ukm::builders::Media_EME_CdmMetrics(ukm_source_id_); auto ukm_builder = ukm::builders::Media_EME_CdmMetrics(source_id);
if (cdm_metrics_data.license_sdk_version.has_value()) { if (cdm_metrics_data.license_sdk_version.has_value()) {
ukm_builder.SetLicenseSdkVersion( ukm_builder.SetLicenseSdkVersion(
@@ -170,9 +170,6 @@ void MojoCdmHelper::RetrieveUkmRecordingObjects() {
ConnectToUkmRecorderFactory(); ConnectToUkmRecorderFactory();
ukm_recorder_ = ukm::MojoUkmRecorder::Create(*ukm_recorder_factory_); ukm_recorder_ = ukm::MojoUkmRecorder::Create(*ukm_recorder_factory_);
// TODO(crbug.com/382073085): Find a better way of updating the Ukm Source ID.
frame_interfaces_->GetPageUkmSourceId(&ukm_source_id_);
} }
void MojoCdmHelper::ConnectToOutputProtection() { void MojoCdmHelper::ConnectToOutputProtection() {

@@ -83,7 +83,6 @@ class MEDIA_MOJO_EXPORT MojoCdmHelper final : public CdmAuxiliaryHelper,
mojo::Remote<ukm::mojom::UkmRecorderFactory> ukm_recorder_factory_; mojo::Remote<ukm::mojom::UkmRecorderFactory> ukm_recorder_factory_;
std::unique_ptr<ukm::MojoUkmRecorder> ukm_recorder_; std::unique_ptr<ukm::MojoUkmRecorder> ukm_recorder_;
ukm::SourceId ukm_source_id_ = ukm::kInvalidSourceId;
std::unique_ptr<CdmAllocator> allocator_; std::unique_ptr<CdmAllocator> allocator_;

@@ -81,8 +81,6 @@ class TestFrameInterfaceFactory : public mojom::FrameInterfaceFactory {
mojo::PendingReceiver<mojom::DCOMPSurfaceRegistry> receiver) override {} mojo::PendingReceiver<mojom::DCOMPSurfaceRegistry> receiver) override {}
#endif // BUILDFLAG(IS_WIN) #endif // BUILDFLAG(IS_WIN)
void GetCdmOrigin(GetCdmOriginCallback callback) override {} void GetCdmOrigin(GetCdmOriginCallback callback) override {}
bool GetPageUkmSourceId(int64_t* ukm_source_id) override { return true; }
void GetPageUkmSourceId(GetPageUkmSourceIdCallback callback) override {}
void BindEmbedderReceiver(mojo::GenericPendingReceiver) override {} void BindEmbedderReceiver(mojo::GenericPendingReceiver) override {}
}; };

@@ -49,6 +49,8 @@ class METRICS_EXPORT MojoUkmRecorder
~MojoUkmRecorder() override; ~MojoUkmRecorder() override;
void UpdateSourceURL(SourceId source_id, const GURL& url) override;
base::WeakPtr<MojoUkmRecorder> GetWeakPtr(); base::WeakPtr<MojoUkmRecorder> GetWeakPtr();
protected: protected:
@@ -59,7 +61,6 @@ class METRICS_EXPORT MojoUkmRecorder
void ClientDisconnected(); void ClientDisconnected();
// UkmRecorder: // UkmRecorder:
void UpdateSourceURL(SourceId source_id, const GURL& url) override;
void UpdateAppURL(SourceId source_id, void UpdateAppURL(SourceId source_id,
const GURL& url, const GURL& url,
const AppType app_type) override; const AppType app_type) override;

@@ -68,6 +68,8 @@ SourceType ToProtobufSourceType(SourceIdType source_id_type) {
return SourceType::EXTENSION_ID; return SourceType::EXTENSION_ID;
case SourceIdType::NOTIFICATION_ID: case SourceIdType::NOTIFICATION_ID:
return SourceType::NOTIFICATION_ID; return SourceType::NOTIFICATION_ID;
case SourceIdType::CDM_ID:
return SourceType::CDM_ID;
} }
} }

@@ -115,6 +115,8 @@ std::string GetSourceIdTypeDebugString(SourceId source_id) {
return "EXTENSION_ID"; return "EXTENSION_ID";
case SourceIdObj::Type::NOTIFICATION_ID: case SourceIdObj::Type::NOTIFICATION_ID:
return "NOTIFICATION_ID"; return "NOTIFICATION_ID";
case SourceIdObj::Type::CDM_ID:
return "CDM_ID";
} }
} }

@@ -98,8 +98,15 @@ class METRICS_EXPORT SourceIdObj {
// report // report
// interval; it will not be kept in memory between different reports. // interval; it will not be kept in memory between different reports.
NOTIFICATION_ID = 13, NOTIFICATION_ID = 13,
// Source ID type for Content Decryption Module triggered events.
// The CDM persists a CDM origin which it receives from the renderer, and is
// used for crash reporting. To avoid making a round trip from the utility
// process where the CDM is hosted, and because the adapter exists for ~ 5
// more seconds after the renderer/tab is tore down, the events are logged
// with a CDM_ID SourceId type to specify exactly where it is coming from.
CDM_ID = 14,
kMaxValue = NOTIFICATION_ID, kMaxValue = CDM_ID,
}; };
// Default constructor has the invalid value. // Default constructor has the invalid value.

@@ -1,8 +1,8 @@
Name: Metrics Protos Name: Metrics Protos
Short Name: metrics_proto Short Name: metrics_proto
URL: This is the canonical public repository URL: This is the canonical public repository
Version: 720227175 Version: 722767857
Date: 2025-01-27 Date: 2025-02-03
License: BSD-3-Clause License: BSD-3-Clause
License File: LICENSE License File: LICENSE
Shipped: yes Shipped: yes

@@ -31,7 +31,7 @@ message CastLogsProto {
CAST_PRODUCT_TYPE_FUCHSIA_OS = 8; CAST_PRODUCT_TYPE_FUCHSIA_OS = 8;
CAST_PRODUCT_TYPE_LITE = 9; CAST_PRODUCT_TYPE_LITE = 9;
CAST_PRODUCT_TYPE_CORE = 10; CAST_PRODUCT_TYPE_CORE = 10;
CAST_PRODUCT_TYPE_11 = 11; CAST_PRODUCT_TYPE_ANDROID_TABLET = 11;
CAST_PRODUCT_TYPE_ANDROID_AUTOMOTIVE = 12; CAST_PRODUCT_TYPE_ANDROID_AUTOMOTIVE = 12;
CAST_PRODUCT_TYPE_ANDROID = 13; CAST_PRODUCT_TYPE_ANDROID = 13;
} }

@@ -28,6 +28,7 @@ enum SourceType {
CHROMEOS_WEBSITE_ID = 11; CHROMEOS_WEBSITE_ID = 11;
EXTENSION_ID = 12; EXTENSION_ID = 12;
NOTIFICATION_ID = 13; NOTIFICATION_ID = 13;
CDM_ID = 14;
} }
// Android Activity Type defined by // Android Activity Type defined by