Add debugging screen for SeedFiles. Because we're moving the seed and other fields to the Seed Files, the content will not be available from chrome://local-state for debugging. This change adds the information stored in the Seed Files in the already existing chrome://metrics-internals/#variations page. To handle very large values, if the string is larger than 64 characters, it will be trimmed and a button for copying the value into the clipboard will be displayed. The change is visible in the attachment in the bug https://g-issues.chromium.org/issues/452071822 Bug: 452071822 Change-Id: I12887e615607323da58d16be4f2486b37e89118b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7100841 Reviewed-by: Alexei Svitkine <asvitkine@chromium.org> Commit-Queue: Alexei Svitkine <asvitkine@chromium.org> Cr-Commit-Position: refs/heads/main@{#1549170} NOKEYCHECK=True GitOrigin-RevId: 72f0a6bddb742f0cf2808b762f5dd503af1a2453
diff --git a/debug/app.html b/debug/app.html index 8b1c4f7..c618c23 100644 --- a/debug/app.html +++ b/debug/app.html
@@ -104,6 +104,16 @@ <table> <tbody id="variations-summary-body"></tbody> </table> + <h2>Stored Latest Seed Info</h2> + <button id="fetch-stored-latest-seed-info" disabled>Refresh</button> + <table> + <tbody id="stored-latest-seed-info-body"></tbody> + </table> + <h2>Stored Safe Seed Info</h2> + <button id="fetch-stored-safe-seed-info" disabled>Refresh</button> + <table> + <tbody id="stored-safe-seed-info-body"></tbody> + </table> </div> <div slot="tab">Field Trials</div> <div slot="panel"> @@ -140,3 +150,12 @@ <td><!-- Value --></td> </tr> </template> +<template id="seed-info-row-template"> + <tr> + <td><!-- Key --></td> + <td><!-- Value --></td> + <td><!-- Copy --> + <button>Copy</button> + </td> + </tr> +</template> \ No newline at end of file
diff --git a/debug/app.ts b/debug/app.ts index eaf8e65..5271d6b 100644 --- a/debug/app.ts +++ b/debug/app.ts
@@ -13,7 +13,7 @@ import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {getTemplate} from './app.html.js'; -import type {KeyValue, Log, LogData, MetricsInternalsBrowserProxy} from './browser_proxy.js'; +import type {KeyValue, Log, LogData, MetricsInternalsBrowserProxy, SeedType} from './browser_proxy.js'; import {MetricsInternalsBrowserProxyImpl} from './browser_proxy.js'; import {getEventsPeekString, logEventToString, sizeToString, timestampToString, umaLogTypeToString} from './log_utils.js'; @@ -29,6 +29,12 @@ events: [], }; +/** + * The maximum length of a value in the seed info table. Values longer than + * this will be truncated with an ellipsis. + */ +const VALUE_LENGTH_LIMIT = 64; + export class MetricsInternalsAppElement extends CustomElement { static get is(): string { return 'metrics-internals-app'; @@ -73,6 +79,22 @@ await this.updateVariationsSummary_(); setInterval(() => this.updateVariationsSummary_(), 3000); + // Fetch stored latest and safe seeds info and set up a listener for the + // buttons for refreshing the data. + await this.updateStoredSeedInfo_('Latest'); + const fetchStoredLatestSeedInfoButton = + this.getRequiredElement('#fetch-stored-latest-seed-info'); + assert(fetchStoredLatestSeedInfoButton); + fetchStoredLatestSeedInfoButton.addEventListener( + 'click', () => this.updateStoredSeedInfo_('Latest')); + + await this.updateStoredSeedInfo_('Safe'); + const fetchStoredSafeSeedInfoButton = + this.getRequiredElement('#fetch-stored-safe-seed-info'); + assert(fetchStoredSafeSeedInfoButton); + fetchStoredSafeSeedInfoButton.addEventListener( + 'click', () => this.updateStoredSeedInfo_('Safe')); + // Fetch UMA summary data and set up a recurring timer. await this.updateUmaSummary_(); setInterval(() => this.updateUmaSummary_(), 3000); @@ -185,6 +207,41 @@ } /** + * Fills the passed table element with the given seed info. + */ + private updateSeedInfoTable_(tableBody: HTMLElement, summary: KeyValue[]): + void { + // Clear the table first. + tableBody.replaceChildren(); + + const template = + this.getRequiredElement<HTMLTemplateElement>('#seed-info-row-template'); + for (const info of summary) { + const row = template.content.cloneNode(true) as HTMLElement; + const [key, value, copy] = row.querySelectorAll('td'); + + assert(key); + key.textContent = info.key; + + assert(value); + if (info.value.length > VALUE_LENGTH_LIMIT) { + value.textContent = info.value.substring(0, VALUE_LENGTH_LIMIT) + '...'; + } else { + value.textContent = info.value; + } + + assert(copy); + const copyButton = copy.querySelector('button'); + assert(copyButton); + copyButton.addEventListener('click', () => { + navigator.clipboard.writeText(info.value); + }); + + tableBody.appendChild(row); + } + } + + /** * Fetches variations summary data and updates the view. */ private async updateVariationsSummary_(): Promise<void> { @@ -204,6 +261,23 @@ } /** + * Fetches stored seed info and updates the view for the given seed type. + */ + private async updateStoredSeedInfo_(seedType: SeedType): Promise<void> { + const seedTypeKey = seedType.toLowerCase(); + const refreshButton = + this.getRequiredElement(`#fetch-stored-${seedTypeKey}-seed-info`); + assert(refreshButton); + refreshButton.setAttribute('disabled', ''); + const storedSeedInfo: KeyValue[] = + await this.browserProxy_.fetchStoredSeedInfo(seedType); + const storedSeedInfoTableBody = + this.getRequiredElement(`#stored-${seedTypeKey}-seed-info-body`); + this.updateSeedInfoTable_(storedSeedInfoTableBody, storedSeedInfo); + refreshButton.removeAttribute('disabled'); + } + + /** * Fetches UMA summary data and updates the view. */ private async updateUmaSummary_(): Promise<void> {
diff --git a/debug/browser_proxy.ts b/debug/browser_proxy.ts index bc28c0d..bd928d9 100644 --- a/debug/browser_proxy.ts +++ b/debug/browser_proxy.ts
@@ -109,6 +109,11 @@ fetchVariationsSummary(): Promise<KeyValue[]>; /** + * Fetches the stored seed info. + */ + fetchStoredSeedInfo(seedType: string): Promise<KeyValue[]>; + + /** * Fetches a summary of UMA info. */ fetchUmaSummary(): Promise<KeyValue[]>; @@ -149,6 +154,8 @@ restart(): Promise<void>; } +export type SeedType = 'Latest'|'Safe'; + export class MetricsInternalsBrowserProxyImpl implements MetricsInternalsBrowserProxy { getUmaLogData(includeLogProtoData: boolean): Promise<string> { @@ -159,6 +166,10 @@ return sendWithPromise('fetchVariationsSummary'); } + fetchStoredSeedInfo(seedType: SeedType): Promise<KeyValue[]> { + return sendWithPromise(`fetchStored${seedType}SeedInfo`); + } + fetchUmaSummary(): Promise<KeyValue[]> { return sendWithPromise('fetchUmaSummary'); }
diff --git a/debug/metrics_internals_utils.cc b/debug/metrics_internals_utils.cc index b63ffa6..62fe238 100644 --- a/debug/metrics_internals_utils.cc +++ b/debug/metrics_internals_utils.cc
@@ -7,6 +7,7 @@ #include <string> #include <string_view> +#include "base/base64.h" #include "base/strings/string_number_conversions.h" #include "build/branding_buildflags.h" #include "build/build_config.h" @@ -125,6 +126,31 @@ return dict; } +void StoredSeedInfoToKeyValueList( + base::OnceCallback<void(base::ValueView)> done_callback, + variations::StoredSeedInfo stored_seed_info) { + base::Value::List list; + // We need to encode the seed data so it's valid utf-8. + list.Append(CreateKeyValueDict("Seed Data", + base::Base64Encode(stored_seed_info.data()))); + list.Append( + CreateKeyValueDict("Seed Signature", stored_seed_info.signature())); + list.Append(CreateKeyValueDict( + "Seed Milestone", base::NumberToString(stored_seed_info.milestone()))); + list.Append(CreateKeyValueDict( + "Seed Date", base::NumberToString(stored_seed_info.seed_date()))); + list.Append(CreateKeyValueDict( + "Client Fetch Time", + base::NumberToString(stored_seed_info.client_fetch_time()))); + list.Append(CreateKeyValueDict("Session Country Code", + stored_seed_info.session_country_code())); + list.Append(CreateKeyValueDict("Permanent Country Code", + stored_seed_info.permanent_country_code())); + list.Append(CreateKeyValueDict("Permanent Version", + stored_seed_info.permanent_version())); + std::move(done_callback).Run(std::move(list)); +} + } // namespace base::Value::List GetUmaSummary(MetricsService* metrics_service) { @@ -175,4 +201,15 @@ return list; } +void GetStoredSeedInfo( + base::OnceCallback<void(base::ValueView)> done_callback, + metrics_services_manager::MetricsServicesManager* metrics_service_manager, + variations::VariationsSeedStore::SeedType seed_type) { + metrics_service_manager->GetVariationsService() + ->GetStoredSeedInfoForDebugging( + base::BindOnce(&StoredSeedInfoToKeyValueList, + std::move(done_callback)), + seed_type); +} + } // namespace metrics
diff --git a/debug/metrics_internals_utils.h b/debug/metrics_internals_utils.h index 2759f22..e9270a6 100644 --- a/debug/metrics_internals_utils.h +++ b/debug/metrics_internals_utils.h
@@ -8,6 +8,7 @@ #include "base/values.h" #include "components/metrics/metrics_service.h" #include "components/metrics_services_manager/metrics_services_manager.h" +#include "components/variations/variations_seed_store.h" namespace metrics { @@ -16,6 +17,11 @@ base::Value::List GetVariationsSummary( metrics_services_manager::MetricsServicesManager* metrics_service_manager); +void GetStoredSeedInfo( + base::OnceCallback<void(base::ValueView)> done_callback, + metrics_services_manager::MetricsServicesManager* metrics_service_manager, + variations::VariationsSeedStore::SeedType seed_type); + } // namespace metrics #endif // COMPONENTS_METRICS_DEBUG_METRICS_INTERNALS_UTILS_H_