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) {
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
// kDecoderBypassBlockCount, so the entries should not even be set in the
// ukm data.

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

@ -422,6 +422,9 @@ void UkmDatabaseBackend::RestartTransaction() {
if (!current_transaction_->Begin()) {
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

@ -52,6 +52,8 @@ BASE_FEATURE(kUkmSamplingRateFeature,
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) {
SourceIdType type = GetSourceIdType(source_id);
switch (type) {
@ -65,7 +67,8 @@ bool IsAllowlistedSourceId(SourceId source_id) {
case ukm::SourceIdObj::Type::WEB_IDENTITY_ID:
case ukm::SourceIdObj::Type::CHROMEOS_WEBSITE_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;
}
case ukm::SourceIdObj::Type::DEFAULT:
@ -810,6 +813,7 @@ UkmConsentType UkmRecorderImpl::GetConsentType(SourceIdType type) {
case SourceIdType::CHROMEOS_WEBSITE_ID:
case SourceIdType::EXTENSION_ID:
case SourceIdType::NOTIFICATION_ID:
case SourceIdType::CDM_ID:
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::CHROMEOS_WEBSITE_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
// entries are logged only at source creation time.
MarkSourceForDeletion(source_id);

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

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

@ -230,8 +230,7 @@ class MEDIA_EXPORT CdmAdapter final : public ContentDecryptionModule,
SessionKeysChangeCB session_keys_change_cb_;
SessionExpirationUpdateCB session_expiration_update_cb_;
// CDM origin and crash key to be used in crash reporting.
const std::string cdm_origin_;
// CDM crash key to be used in crash reporting.
crash_reporter::ScopedCrashKeyString scoped_crash_key_;
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> decoder_bypass_block_count;
url::Origin cdm_origin;
bool IsCdmValueSet() {
return (license_sdk_version.has_value() ||
certificate_serial_number.has_value() ||

@ -46,10 +46,6 @@ interface FrameInterfaceFactory {
[Sync]
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
// embedders to provide additional interfaces.
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) {
if (ukm_source_id_ == ukm::kInvalidSourceId) {
DLOG(ERROR) << "Invalid UKM source ID";
return;
}
ukm::SourceId source_id = ukm::ConvertToSourceId(ukm::AssignNewSourceId(),
ukm::SourceIdType::CDM_ID);
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()) {
ukm_builder.SetLicenseSdkVersion(
@ -170,9 +170,6 @@ void MojoCdmHelper::RetrieveUkmRecordingObjects() {
ConnectToUkmRecorderFactory();
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() {

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

@ -81,8 +81,6 @@ class TestFrameInterfaceFactory : public mojom::FrameInterfaceFactory {
mojo::PendingReceiver<mojom::DCOMPSurfaceRegistry> receiver) override {}
#endif // BUILDFLAG(IS_WIN)
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 {}
};

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

@ -68,6 +68,8 @@ SourceType ToProtobufSourceType(SourceIdType source_id_type) {
return SourceType::EXTENSION_ID;
case SourceIdType::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";
case SourceIdObj::Type::NOTIFICATION_ID:
return "NOTIFICATION_ID";
case SourceIdObj::Type::CDM_ID:
return "CDM_ID";
}
}

@ -98,8 +98,15 @@ class METRICS_EXPORT SourceIdObj {
// report
// interval; it will not be kept in memory between different reports.
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.

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

@ -31,7 +31,7 @@ message CastLogsProto {
CAST_PRODUCT_TYPE_FUCHSIA_OS = 8;
CAST_PRODUCT_TYPE_LITE = 9;
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 = 13;
}

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