зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1703578 - Part 3: Invoke WDBA to set UserChoice. r=bytesized
Depends on D113427 Differential Revision: https://phabricator.services.mozilla.com/D113428
This commit is contained in:
Родитель
f22ce8ffdd
Коммит
00133ca183
|
@ -263,6 +263,12 @@ pref("browser.shell.mostRecentDateSetAsDefault", "");
|
|||
pref("browser.shell.skipDefaultBrowserCheckOnFirstRun", true);
|
||||
pref("browser.shell.didSkipDefaultBrowserCheckOnFirstRun", false);
|
||||
pref("browser.shell.defaultBrowserCheckCount", 0);
|
||||
#if defined(XP_WIN)
|
||||
// Attempt to set the default browser on Windows 10 using the UserChoice registry keys,
|
||||
// before falling back to launching the modern Settings dialog.
|
||||
pref("browser.shell.setDefaultBrowserUserChoice", true);
|
||||
#endif
|
||||
|
||||
|
||||
// 0 = blank, 1 = home (browser.startup.homepage), 2 = last visited page, 3 = resume previous browser session
|
||||
// The behavior of option 3 is detailed at: http://wiki.mozilla.org/Session_Restore
|
||||
|
|
|
@ -19,6 +19,18 @@ ChromeUtils.defineModuleGetter(
|
|||
"resource://gre/modules/WindowsRegistry.jsm"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Subprocess: "resource://gre/modules/Subprocess.jsm",
|
||||
setTimeout: "resource://gre/modules/Timer.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
"XreDirProvider",
|
||||
"@mozilla.org/xre/directory-provider;1",
|
||||
"nsIXREDirProvider"
|
||||
);
|
||||
|
||||
/**
|
||||
* Internal functionality to save and restore the docShell.allow* properties.
|
||||
*/
|
||||
|
@ -112,6 +124,84 @@ let ShellServiceInternal = {
|
|||
return false;
|
||||
},
|
||||
|
||||
/*
|
||||
* Set the default browser through the UserChoice registry keys on Windows.
|
||||
*
|
||||
* NOTE: This does NOT open the System Settings app for manual selection
|
||||
* in case of failure. If that is desired, catch the exception and call
|
||||
* setDefaultBrowser().
|
||||
*
|
||||
* @return Promise, resolves when successful, rejects with Error on failure.
|
||||
*/
|
||||
async setAsDefaultUserChoice() {
|
||||
if (AppConstants.platform != "win") {
|
||||
throw new Error("Windows-only");
|
||||
}
|
||||
|
||||
// We launch the WDBA to handle the registry writes, see
|
||||
// SetDefaultBrowserUserChoice() in
|
||||
// toolkit/mozapps/defaultagent/SetDefaultBrowser.cpp.
|
||||
// This is external in case an overzealous antimalware product decides to
|
||||
// quarrantine any program that writes UserChoice, though this has not
|
||||
// occurred during extensive testing.
|
||||
|
||||
if (!ShellService.checkAllProgIDsExist()) {
|
||||
throw new Error("checkAllProgIDsExist() failed");
|
||||
}
|
||||
|
||||
if (!ShellService.checkBrowserUserChoiceHashes()) {
|
||||
throw new Error("checkBrowserUserChoiceHashes() failed");
|
||||
}
|
||||
|
||||
const wdba = Services.dirsvc.get("XREExeF", Ci.nsIFile);
|
||||
wdba.leafName = "default-browser-agent.exe";
|
||||
const aumi = XreDirProvider.getInstallHash();
|
||||
|
||||
const exeProcess = await Subprocess.call({
|
||||
command: wdba.path,
|
||||
arguments: ["set-default-browser-user-choice", aumi],
|
||||
});
|
||||
|
||||
// exit codes
|
||||
const S_OK = 0;
|
||||
const STILL_ACTIVE = 0x103;
|
||||
|
||||
const exeWaitTimeoutMs = 2000; // 2 seconds
|
||||
const exeWaitPromise = exeProcess.wait();
|
||||
const timeoutPromise = new Promise(function(resolve, reject) {
|
||||
setTimeout(() => resolve({ exitCode: STILL_ACTIVE }), exeWaitTimeoutMs);
|
||||
});
|
||||
const { exitCode } = await Promise.race([exeWaitPromise, timeoutPromise]);
|
||||
|
||||
if (exitCode != S_OK) {
|
||||
throw new Error(`WDBA nonzero exit code ${exitCode}`);
|
||||
}
|
||||
},
|
||||
|
||||
// override nsIShellService.setDefaultBrowser() on the ShellService proxy.
|
||||
setDefaultBrowser(claimAllTypes, forAllUsers) {
|
||||
// On Windows 10, our best chance is to set UserChoice, so try that first.
|
||||
if (
|
||||
AppConstants.isPlatformAndVersionAtLeast("win", "10") &&
|
||||
Services.prefs.getBoolPref(
|
||||
"browser.shell.setDefaultBrowserUserChoice",
|
||||
true
|
||||
)
|
||||
) {
|
||||
// nsWindowsShellService::SetDefaultBrowser() kicks off several
|
||||
// operations, but doesn't wait for their result. So we don't need to
|
||||
// await the result of setAsDefaultUserChoice() here, either, we just need
|
||||
// to fall back in case it fails.
|
||||
this.setAsDefaultUserChoice().catch(err => {
|
||||
Cu.reportError(err);
|
||||
this.shellService.setDefaultBrowser(claimAllTypes, forAllUsers);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.shellService.setDefaultBrowser(claimAllTypes, forAllUsers);
|
||||
},
|
||||
|
||||
setAsDefault() {
|
||||
let claimAllTypes = true;
|
||||
let setAsDefaultError = false;
|
||||
|
|
|
@ -51,11 +51,14 @@ elif CONFIG["OS_ARCH"] == "WINNT":
|
|||
SOURCES += [
|
||||
"nsWindowsShellService.cpp",
|
||||
"WindowsDefaultBrowser.cpp",
|
||||
"WindowsUserChoice.cpp",
|
||||
]
|
||||
LOCAL_INCLUDES += [
|
||||
"../../../other-licenses/nsis/Contrib/CityHash/cityhash",
|
||||
]
|
||||
OS_LIBS += [
|
||||
"bcrypt",
|
||||
"crypt32",
|
||||
"propsys",
|
||||
]
|
||||
|
||||
|
@ -70,7 +73,12 @@ EXTRA_JS_MODULES += [
|
|||
"ShellService.jsm",
|
||||
]
|
||||
|
||||
for var in ("MOZ_APP_DISPLAYNAME", "MOZ_APP_NAME", "MOZ_APP_VERSION"):
|
||||
for var in (
|
||||
"MOZ_APP_DISPLAYNAME",
|
||||
"MOZ_APP_NAME",
|
||||
"MOZ_APP_VERSION",
|
||||
"MOZ_DEFAULT_BROWSER_AGENT",
|
||||
):
|
||||
DEFINES[var] = '"%s"' % CONFIG[var]
|
||||
|
||||
CXXFLAGS += CONFIG["TK_CFLAGS"]
|
||||
|
|
|
@ -89,4 +89,23 @@ interface nsIWindowsShellService : nsISupports
|
|||
* for noncritical telemetry use.
|
||||
*/
|
||||
AString classifyShortcut(in AString aPath);
|
||||
|
||||
/*
|
||||
* Check if setDefaultBrowserUserChoice() is expected to succeed.
|
||||
*
|
||||
* This checks the ProgIDs for this installation, and the hash of the existing
|
||||
* UserChoice association.
|
||||
*
|
||||
* @return true if the check succeeds, false otherwise.
|
||||
*/
|
||||
bool canSetDefaultBrowserUserChoice();
|
||||
|
||||
/*
|
||||
* checkAllProgIDsExist() and checkBrowserUserChoiceHashes() are components
|
||||
* of canSetDefaultBrowserUserChoice(), broken out for telemetry purposes.
|
||||
*
|
||||
* @return true if the check succeeds, false otherwise.
|
||||
*/
|
||||
bool checkAllProgIDsExist();
|
||||
bool checkBrowserUserChoiceHashes();
|
||||
};
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "WindowsDefaultBrowser.h"
|
||||
#include "WindowsUserChoice.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
|
@ -231,6 +232,39 @@ nsresult nsWindowsShellService::LaunchControlPanelDefaultPrograms() {
|
|||
return ::LaunchControlPanelDefaultPrograms() ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::CheckAllProgIDsExist(bool* aResult) {
|
||||
*aResult = false;
|
||||
nsAutoString aumid;
|
||||
if (!mozilla::widget::WinTaskbar::GetAppUserModelID(aumid)) {
|
||||
return NS_OK;
|
||||
}
|
||||
*aResult =
|
||||
CheckProgIDExists(FormatProgID(L"FirefoxURL", aumid.get()).get()) &&
|
||||
CheckProgIDExists(FormatProgID(L"FirefoxHTML", aumid.get()).get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::CheckBrowserUserChoiceHashes(bool* aResult) {
|
||||
*aResult = ::CheckBrowserUserChoiceHashes();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsWindowsShellService::CanSetDefaultBrowserUserChoice(bool* aResult) {
|
||||
*aResult = false;
|
||||
// If the WDBA is not available, this could never succeed.
|
||||
#ifdef MOZ_DEFAULT_BROWSER_AGENT
|
||||
bool progIDsExist = false;
|
||||
bool hashOk = false;
|
||||
*aResult = NS_SUCCEEDED(CheckAllProgIDsExist(&progIDsExist)) &&
|
||||
progIDsExist &&
|
||||
NS_SUCCEEDED(CheckBrowserUserChoiceHashes(&hashOk)) && hashOk;
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsWindowsShellService::LaunchModernSettingsDialogDefaultApps() {
|
||||
return ::LaunchModernSettingsDialogDefaultApps() ? NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче