141 lines
4.9 KiB
JavaScript
141 lines
4.9 KiB
JavaScript
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/**
|
|
* The installer prefs component provides a way to get a specific set of prefs
|
|
* from a profile into a place where the installer can read them. The primary
|
|
* reason for wanting to do this is so we can run things like Shield studies
|
|
* on installer features; normally those are enabled by setting a pref, but
|
|
* the installer runs outside of any profile and so has no access to prefs.
|
|
* So we need to do something else to allow it to read these prefs.
|
|
*
|
|
* The mechanism we use here is to reflect the values of a list of relevant
|
|
* prefs into registry values. One registry value is created for each pref
|
|
* that is set. Each installation of the product gets its own registry key
|
|
* (based on the path hash). This is obviously a somewhat wider scope than a
|
|
* single profile, but it should be close enough in enough cases to suit our
|
|
* purposes here.
|
|
*
|
|
* Currently this module only supports bool prefs. Other types could likely
|
|
* be added if needed, but it doesn't seem necessary for the primary use case.
|
|
*/
|
|
|
|
// All prefs processed through this component must be in this branch.
|
|
const INSTALLER_PREFS_BRANCH = "installer.";
|
|
|
|
// This is the list of prefs that will be reflected to the registry. It should
|
|
// be kept up to date so that it reflects the list of prefs that are in
|
|
// current use (e.g., currently active experiments).
|
|
// Only add prefs to this list which are in INSTALLER_PREFS_BRANCH;
|
|
// any others will be ignored.
|
|
const INSTALLER_PREFS_LIST = ["installer.taskbarpin.win10.enabled"];
|
|
|
|
import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
|
|
|
|
// This constructor can take a list of prefs to override the default one,
|
|
// but this is really only intended for tests to use. Normal usage should be
|
|
// to leave the parameter omitted/undefined.
|
|
export function InstallerPrefs(prefsList) {
|
|
this.prefsList = prefsList || INSTALLER_PREFS_LIST;
|
|
|
|
// Each pref to be reflected will get a value created under this key, in HKCU.
|
|
// The path will look something like:
|
|
// "Software\Mozilla\Firefox\Installer\71AE18FE3142402B\".
|
|
ChromeUtils.defineLazyGetter(this, "_registryKeyPath", function () {
|
|
const app = AppConstants.MOZ_APP_NAME;
|
|
const vendor = Services.appinfo.vendor || "Mozilla";
|
|
const xreDirProvider = Cc[
|
|
"@mozilla.org/xre/directory-provider;1"
|
|
].getService(Ci.nsIXREDirProvider);
|
|
const installHash = xreDirProvider.getInstallHash();
|
|
return `Software\\${vendor}\\${app}\\Installer\\${installHash}`;
|
|
});
|
|
}
|
|
|
|
InstallerPrefs.prototype = {
|
|
classID: Components.ID("{cd8a6995-1f19-4cdd-9ed1-d6263302f594}"),
|
|
contractID: "@mozilla.org/installerprefs;1",
|
|
|
|
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
|
|
|
|
observe(subject, topic, data) {
|
|
switch (topic) {
|
|
case "profile-after-change": {
|
|
if (
|
|
AppConstants.platform != "win" ||
|
|
!this.prefsList ||
|
|
!this.prefsList.length
|
|
) {
|
|
// This module has no work to do.
|
|
break;
|
|
}
|
|
const regKey = this._openRegKey();
|
|
this._reflectPrefsToRegistry(regKey);
|
|
this._registerPrefListeners();
|
|
regKey.close();
|
|
break;
|
|
}
|
|
case "nsPref:changed": {
|
|
const regKey = this._openRegKey();
|
|
if (this.prefsList.includes(data)) {
|
|
this._reflectOnePrefToRegistry(regKey, data);
|
|
}
|
|
regKey.close();
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
_registerPrefListeners() {
|
|
Services.prefs.addObserver(INSTALLER_PREFS_BRANCH, this);
|
|
},
|
|
|
|
_cleanRegistryKey(regKey) {
|
|
for (let i = regKey.valueCount - 1; i >= 0; --i) {
|
|
const name = regKey.getValueName(i);
|
|
if (name.startsWith(INSTALLER_PREFS_BRANCH)) {
|
|
regKey.removeValue(name);
|
|
}
|
|
}
|
|
},
|
|
|
|
_reflectPrefsToRegistry(regKey) {
|
|
this._cleanRegistryKey(regKey);
|
|
this.prefsList.forEach(pref =>
|
|
this._reflectOnePrefToRegistry(regKey, pref)
|
|
);
|
|
},
|
|
|
|
_reflectOnePrefToRegistry(regKey, pref) {
|
|
if (!pref.startsWith(INSTALLER_PREFS_BRANCH)) {
|
|
return;
|
|
}
|
|
|
|
const value = Services.prefs.getBoolPref(pref, false);
|
|
if (value) {
|
|
regKey.writeIntValue(pref, 1);
|
|
} else {
|
|
try {
|
|
regKey.removeValue(pref);
|
|
} catch (ex) {
|
|
// This removeValue call is prone to failing because the value we
|
|
// tried to remove didn't exist. Obviously that isn't really an error
|
|
// that we need to handle.
|
|
}
|
|
}
|
|
},
|
|
|
|
_openRegKey() {
|
|
const key = Cc["@mozilla.org/windows-registry-key;1"].createInstance(
|
|
Ci.nsIWindowsRegKey
|
|
);
|
|
key.create(
|
|
key.ROOT_KEY_CURRENT_USER,
|
|
this._registryKeyPath,
|
|
key.ACCESS_READ | key.ACCESS_WRITE | key.WOW64_64
|
|
);
|
|
return key;
|
|
},
|
|
};
|