Mypal/toolkit/modules/UpdateUtils.jsm

250 lines
8.0 KiB
JavaScript

/* 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/. */
#filter substitution
#if !MOZ_PKG_SPECIAL
#define MOZ_PKG_SPECIAL false
#endif
this.EXPORTED_SYMBOLS = ["UpdateUtils"];
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
#ifdef XP_WIN
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://gre/modules/WindowsRegistry.jsm");
const WINREG_HKLM = Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE;
const WINREG_WINNT = "Software\\Microsoft\\Windows NT\\CurrentVersion";
#endif
const FILE_UPDATE_LOCALE = "update.locale";
const PREF_APP_DISTRIBUTION = "distribution.id";
const PREF_APP_DISTRIBUTION_VERSION = "distribution.version";
const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
const PREF_APP_UPDATE_CUSTOM = "app.update.custom";
const PREF_APP_UPDATE_IMEI_HASH = "app.update.imei_hash";
this.UpdateUtils = {
get UpdateChannel() {
return Services.prefs.getDefaultBranch(null)
.getCharPref(PREF_APP_UPDATE_CHANNEL, "@MOZ_UPDATE_CHANNEL@");
},
/**
* Formats a URL by replacing %...% values with OS, build and locale specific
* values.
*
* @param aUpdateURL
* The URL to format.
* @param aAdditionalSubsts
* @return The formatted URL.
*/
formatUpdateURL: function(aUpdateURL, aAdditionalSubsts = null) {
// We want to be able to accept additional substs but also to have them be able to
// override the default ones below
if (aAdditionalSubsts) {
try {
aAdditionalSubsts.forEach(([_subst, _value]) => aUpdateURL = aUpdateURL.replace(_subst, _value));
} catch(ex) {
Cu.reportError(ex);
}
}
// appName SHOULD be lower case and not contain spaces even if it has in the past
let appName = Services.appinfo.name.replace(/\s+/g, '').toLowerCase()
// We want default pref values if they exist
let prefBranch = Services.prefs.getDefaultBranch(null)
let custom = prefBranch.getCharPref(PREF_APP_UPDATE_CUSTOM, "");
let distribution = prefBranch.getCharPref(PREF_APP_DISTRIBUTION, "default");
let distributionVersion = prefBranch.getCharPref(PREF_APP_DISTRIBUTION_VERSION, "default");
let substs = [
[/%ID%/g, Services.appinfo.ID],
[/%PRODUCT%/g, Services.appinfo.name],
[/%VERSION%/g, Services.appinfo.version],
[/%BUILD_ID%/g, Services.appinfo.appBuildID],
[/%BUILD_TARGET%/g, Services.appinfo.OS + "_" + this.ABI],
[/%BUILD_SPECIAL%/g, "@MOZ_PKG_SPECIAL@"],
[/%OS_VERSION%/g, this.OSVersion],
[/%WIDGET_TOOLKIT%/g, "@MOZ_WIDGET_TOOLKIT@"],
[/%CHANNEL%/g, this.UpdateChannel],
[/%CUSTOM%/g, custom],
[/%PLATFORM_VERSION%/g, Services.appinfo.platformVersion],
[/%DISTRIBUTION%/g, distribution],
[/%DISTRIBUTION_VERSION%/g, distributionVersion],
[/%LOCALE%/g, this.Locale]
];
substs.forEach(([_subst, _value]) => aUpdateURL = aUpdateURL.replace(_subst, _value));
// We do this last to make sure all pluses are converted
aUpdateURL = aUpdateURL.replace(/\+/g, "%2B");
return aUpdateURL;
}
};
/**
* Gets the locale from the update.locale file for replacing %LOCALE% in the
* update url. The update.locale file can be located in the application
* directory or the GRE directory with preference given to it being located in
* the application directory.
*/
XPCOMUtils.defineLazyGetter(UpdateUtils, "Locale", function() {
let channel;
let locale;
for (let res of ['app', 'gre']) {
channel = NetUtil.newChannel({
uri: "resource://" + res + "/" + FILE_UPDATE_LOCALE,
contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_XMLHTTPREQUEST,
loadUsingSystemPrincipal: true
});
try {
let inputStream = channel.open2();
locale = NetUtil.readInputStreamToString(inputStream, inputStream.available());
} catch (e) {}
if (locale)
return locale.trim();
}
Cu.reportError(FILE_UPDATE_LOCALE + " file doesn't exist in either the " +
"application or GRE directories");
return null;
});
#ifdef XP_WIN
/* Windows only getter that returns the processor architecture. */
XPCOMUtils.defineLazyGetter(this, "gWinCPUArch", function aus_gWinCPUArch() {
// Get processor architecture
let arch = "unknown";
const WORD = ctypes.uint16_t;
const DWORD = ctypes.uint32_t;
// This structure is described at:
// http://msdn.microsoft.com/en-us/library/ms724958%28v=vs.85%29.aspx
const SYSTEM_INFO = new ctypes.StructType('SYSTEM_INFO',
[
{wProcessorArchitecture: WORD},
{wReserved: WORD},
{dwPageSize: DWORD},
{lpMinimumApplicationAddress: ctypes.voidptr_t},
{lpMaximumApplicationAddress: ctypes.voidptr_t},
{dwActiveProcessorMask: DWORD.ptr},
{dwNumberOfProcessors: DWORD},
{dwProcessorType: DWORD},
{dwAllocationGranularity: DWORD},
{wProcessorLevel: WORD},
{wProcessorRevision: WORD}
]);
let kernel32 = false;
try {
kernel32 = ctypes.open("Kernel32");
} catch (ex) {
Cu.reportError("Unable to open kernel32! Exception: " + ex);
}
if (kernel32) {
try {
let GetNativeSystemInfo = kernel32.declare("GetNativeSystemInfo",
ctypes.default_abi,
ctypes.void_t,
SYSTEM_INFO.ptr);
let winSystemInfo = SYSTEM_INFO();
// Default to unknown
winSystemInfo.wProcessorArchitecture = 0xffff;
GetNativeSystemInfo(winSystemInfo.address());
switch (winSystemInfo.wProcessorArchitecture) {
case 9:
arch = "x64";
break;
case 6:
arch = "IA64";
break;
case 0:
arch = "x86";
break;
}
} catch (ex) {
Cu.reportError("Error getting processor architecture. " +
"Exception: " + ex);
} finally {
kernel32.close();
}
}
return arch;
});
#endif
XPCOMUtils.defineLazyGetter(UpdateUtils, "ABI", function() {
let abi = null;
try {
abi = Services.appinfo.XPCOMABI;
} catch (ex) {
Cu.reportError("XPCOM ABI unknown");
}
#ifdef XP_MACOSX
// Mac universal build should report a different ABI than either macppc
// or mactel.
let macutils = Cc["@mozilla.org/xpcom/mac-utils;1"].
getService(Ci.nsIMacUtils);
if (macutils.isUniversalBinary) {
abi += "-u-" + macutils.architecturesInBinary;
}
#endif
return abi;
});
XPCOMUtils.defineLazyGetter(UpdateUtils, "OSVersion", function() {
let osVersion;
try {
osVersion = Services.sysinfo.getProperty("name") + " " +
Services.sysinfo.getProperty("version");
} catch(ex) {
Cu.reportError("OS Version unknown.");
}
#ifdef XP_WIN
if (osVersion) {
let currentBuild = WindowsRegistry.readRegKey(WINREG_HKLM, WINREG_WINNT, "CurrentBuild");
let CSDBuildNumber = WindowsRegistry.readRegKey(WINREG_HKLM, WINREG_WINNT, "CSDBuildNumber");
if (!CSDBuildNumber) {
CSDBuildNumber = "0";
}
osVersion = osVersion.replace(/Windows_NT/g, "WINNT");
osVersion += "." + currentBuild + "." + CSDBuildNumber
// Add processor architecture
osVersion += " (" + gWinCPUArch + ")";
}
#endif
try {
osVersion += " (" + Services.sysinfo.getProperty("secondaryLibrary") + ")";
} catch(ex) {
// Not all platforms have a secondary widget library, so an error is nothing to worry about.
}
osVersion = encodeURIComponent(osVersion);
return osVersion;
});