diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index 97172158a09a..fbcc9e06c3c7 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -82,6 +82,7 @@ XPCOMUtils.defineLazyModuleGetters(this, { SearchSERPTelemetry: "resource:///modules/SearchSERPTelemetry.jsm", SessionStartup: "resource:///modules/sessionstore/SessionStartup.jsm", SessionStore: "resource:///modules/sessionstore/SessionStore.jsm", + ShellService: "resource:///modules/ShellService.jsm", ShortcutUtils: "resource://gre/modules/ShortcutUtils.jsm", TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm", TabUnloader: "resource:///modules/TabUnloader.jsm", @@ -2465,6 +2466,19 @@ BrowserGlue.prototype = { }, }, + // Report whether Firefox is the default handler for various files types, + // in particular, ".pdf". + { + condition: AppConstants.platform == "win", + task: () => { + Services.telemetry.keyedScalarSet( + "os.environment.is_default_handler", + ".pdf", + ShellService.isDefaultHandlerFor(".pdf") + ); + }, + }, + // Install built-in themes. We already installed the active built-in // theme, if any, before UI startup. { diff --git a/browser/components/shell/ShellService.jsm b/browser/components/shell/ShellService.jsm index af24c65f931f..2ad325e737b2 100644 --- a/browser/components/shell/ShellService.jsm +++ b/browser/components/shell/ShellService.jsm @@ -289,6 +289,21 @@ let ShellServiceInternal = { .add(setAsDefaultError); }, + /** + * Determine if we're the default handler for the given file extension (like + * ".pdf") or protocol (like "https"). Windows-only for now. + * + * @returns true if we are the default handler, false otherwise. + */ + isDefaultHandlerFor(aFileExtensionOrProtocol) { + if (AppConstants.platform == "win") { + return this.shellService + .QueryInterface(Ci.nsIWindowsShellService) + .isDefaultHandlerFor(aFileExtensionOrProtocol); + } + return false; + }, + /** * Checks if Firefox app can and isn't pinned to OS "taskbar." * diff --git a/browser/components/shell/nsIWindowsShellService.idl b/browser/components/shell/nsIWindowsShellService.idl index 9dee21a5d452..c08fb6854fcd 100644 --- a/browser/components/shell/nsIWindowsShellService.idl +++ b/browser/components/shell/nsIWindowsShellService.idl @@ -108,4 +108,11 @@ interface nsIWindowsShellService : nsISupports */ bool checkAllProgIDsExist(); bool checkBrowserUserChoiceHashes(); + + /* + * Determines whether or not Firefox is the "Default Handler", i.e., + * is registered to handle, the given file extension (like ".pdf") + * or protocol (like "https"). + */ + boolean isDefaultHandlerFor(in AString aFileExtensionOrProtocol); }; diff --git a/browser/components/shell/nsWindowsShellService.cpp b/browser/components/shell/nsWindowsShellService.cpp index 53e15984e0da..e279a75fa6f8 100644 --- a/browser/components/shell/nsWindowsShellService.cpp +++ b/browser/components/shell/nsWindowsShellService.cpp @@ -207,6 +207,32 @@ nsWindowsShellService::IsDefaultBrowser(bool aForAllTypes, return NS_OK; } +NS_IMETHODIMP +nsWindowsShellService::IsDefaultHandlerFor( + const nsAString& aFileExtensionOrProtocol, bool* aIsDefaultHandlerFor) { + *aIsDefaultHandlerFor = false; + + RefPtr pAAR; + HRESULT hr = CoCreateInstance( + CLSID_ApplicationAssociationRegistration, nullptr, CLSCTX_INPROC, + IID_IApplicationAssociationRegistration, getter_AddRefs(pAAR)); + if (FAILED(hr)) { + return NS_OK; + } + + wchar_t exePath[MAXPATHLEN] = L""; + nsresult rv = BinaryPath::GetLong(exePath); + + if (NS_FAILED(rv)) { + return NS_OK; + } + + const nsString& flatClass = PromiseFlatString(aFileExtensionOrProtocol); + + *aIsDefaultHandlerFor = IsPathDefaultForClass(pAAR, exePath, flatClass.get()); + return NS_OK; +} + nsresult nsWindowsShellService::LaunchControlPanelDefaultsSelectionUI() { IApplicationAssociationRegistrationUI* pAARUI; HRESULT hr = CoCreateInstance( diff --git a/browser/components/shell/test/browser_setDefaultPDFHandler.js b/browser/components/shell/test/browser_setDefaultPDFHandler.js index 244113b03aaa..9506e83f1ede 100644 --- a/browser/components/shell/test/browser_setDefaultPDFHandler.js +++ b/browser/components/shell/test/browser_setDefaultPDFHandler.js @@ -49,16 +49,12 @@ if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) { // Everything here is Windows 10+. add_task(async function remoteEnableWithPDF() { - await ExperimentFakes.remoteDefaultsHelper({ - feature: NimbusFeatures.shellService, - configuration: { - slug: "shellService_remoteEnableWithPDF", - variables: { - setDefaultBrowserUserChoice: true, - setDefaultPDFHandler: true, - enabled: true, - }, - targeting: "true", + let doCleanup = await ExperimentFakes.enrollWithRollout({ + featureId: NimbusFeatures.shellService.featureId, + value: { + setDefaultBrowserUserChoice: true, + setDefaultPDFHandler: true, + enabled: true, }, }); @@ -79,19 +75,17 @@ if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) { Assert.deepEqual(_callExternalDefaultBrowserAgentStub.firstCall.args, [ { arguments: ["set-default-browser-user-choice", aumi, ".pdf"] }, ]); + + await doCleanup(); }); add_task(async function remoteEnableWithoutPDF() { - await ExperimentFakes.remoteDefaultsHelper({ - feature: NimbusFeatures.shellService, - configuration: { - slug: "shellService_remoteEnableWithoutPDF", - variables: { - setDefaultBrowserUserChoice: true, - setDefaultPDFHandler: false, - enabled: true, - }, - targeting: "true", + let doCleanup = await ExperimentFakes.enrollWithRollout({ + featureId: NimbusFeatures.shellService.featureId, + value: { + setDefaultBrowserUserChoice: true, + setDefaultPDFHandler: false, + enabled: true, }, }); @@ -112,19 +106,17 @@ if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) { Assert.deepEqual(_callExternalDefaultBrowserAgentStub.firstCall.args, [ { arguments: ["set-default-browser-user-choice", aumi] }, ]); + + await doCleanup(); }); add_task(async function remoteDisable() { - await ExperimentFakes.remoteDefaultsHelper({ - feature: NimbusFeatures.shellService, - configuration: { - slug: "shellService_remoteDisable", - variables: { - setDefaultBrowserUserChoice: false, - setDefaultPDFHandler: true, - enabled: false, - }, - targeting: "true", + let doCleanup = await ExperimentFakes.enrollWithRollout({ + featureId: NimbusFeatures.shellService.featureId, + value: { + setDefaultBrowserUserChoice: false, + setDefaultPDFHandler: true, + enabled: false, }, }); @@ -142,5 +134,7 @@ if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) { Assert.ok(_callExternalDefaultBrowserAgentStub.notCalled); Assert.ok(setDefaultStub.called); + + await doCleanup(); }); } diff --git a/browser/components/tests/browser/browser_browserGlue_telemetry.js b/browser/components/tests/browser/browser_browserGlue_telemetry.js index 6ee9dbacbd40..4ff4c8c4561c 100644 --- a/browser/components/tests/browser/browser_browserGlue_telemetry.js +++ b/browser/components/tests/browser/browser_browserGlue_telemetry.js @@ -45,3 +45,42 @@ add_task(function check_startup_pinned_telemetry() { break; } }); + +// Check that telemetry reports whether Firefox is the default PDF handler. +// This is safe without any explicit coordination because idle tasks are +// guaranteed to have been invokedbefore the test harness invokes the test. See +// https://searchfox.org/mozilla-central/rev/1674b86019a96f076e0f98f1d0f5f3ab9d4e9020/browser/components/BrowserGlue.jsm#2320-2324 +// and +// https://searchfox.org/mozilla-central/rev/1674b86019a96f076e0f98f1d0f5f3ab9d4e9020/browser/base/content/browser.js#2364. +add_task(function check_is_default_handler_telemetry() { + const scalars = TelemetryTestUtils.getProcessScalars("parent", true); + + // Check the appropriate telemetry is set or not reported by platform. + switch (AppConstants.platform) { + case "win": + // We should always set whether we're the default PDF handler. + Assert.ok("os.environment.is_default_handler" in scalars); + Assert.deepEqual( + [".pdf"], + Object.keys(scalars["os.environment.is_default_handler"]) + ); + + if (Cu.isInAutomation) { + // But only in automation can we assume we're not the default handler. + TelemetryTestUtils.assertKeyedScalar( + scalars, + "os.environment.is_default_handler", + ".pdf", + false, + "Not default PDF handler on Windows" + ); + } + break; + default: + TelemetryTestUtils.assertScalarUnset( + scalars, + "os.environment.is_default_handler" + ); + break; + } +}); diff --git a/toolkit/components/telemetry/Scalars.yaml b/toolkit/components/telemetry/Scalars.yaml index 9b934850fd54..89f2035e75a7 100644 --- a/toolkit/components/telemetry/Scalars.yaml +++ b/toolkit/components/telemetry/Scalars.yaml @@ -1922,6 +1922,29 @@ os.environment: operating_systems: - windows + is_default_handler: + bug_numbers: + - 1743914 + description: > + Records whether Firefox was the default handler for particular file types + or protocols. The result is split into keys which represent the file + extension: currently, a subset of the file types Firefox registers to + handle, namely ".pdf". In the future, more file types may be recorded, + and/or a subset of the protocol schemes that Firefox registers to may be + recorded. + keyed: true + expires: "106" + kind: boolean + notification_emails: + - application-update-telemetry-alerts@mozilla.com + release_channel_collection: opt-out + products: + - firefox + record_in_processes: + - main + operating_systems: + - windows + is_kept_in_dock: bug_numbers: - 1715348