diff options
Diffstat (limited to 'toolkit/mozapps/update/nsUpdateService.js')
-rw-r--r-- | toolkit/mozapps/update/nsUpdateService.js | 294 |
1 files changed, 43 insertions, 251 deletions
diff --git a/toolkit/mozapps/update/nsUpdateService.js b/toolkit/mozapps/update/nsUpdateService.js index 0cf7b8938..4e2d66a5c 100644 --- a/toolkit/mozapps/update/nsUpdateService.js +++ b/toolkit/mozapps/update/nsUpdateService.js @@ -35,15 +35,13 @@ const PREF_APP_UPDATE_LOG = "app.update.log"; const PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED = "app.update.notifiedUnsupported"; const PREF_APP_UPDATE_POSTUPDATE = "app.update.postupdate"; const PREF_APP_UPDATE_PROMPTWAITTIME = "app.update.promptWaitTime"; -const PREF_APP_UPDATE_SERVICE_ENABLED = "app.update.service.enabled"; -const PREF_APP_UPDATE_SERVICE_ERRORS = "app.update.service.errors"; -const PREF_APP_UPDATE_SERVICE_MAXERRORS = "app.update.service.maxErrors"; const PREF_APP_UPDATE_SILENT = "app.update.silent"; const PREF_APP_UPDATE_SOCKET_MAXERRORS = "app.update.socket.maxErrors"; const PREF_APP_UPDATE_SOCKET_RETRYTIMEOUT = "app.update.socket.retryTimeout"; const PREF_APP_UPDATE_STAGING_ENABLED = "app.update.staging.enabled"; const PREF_APP_UPDATE_URL = "app.update.url"; const PREF_APP_UPDATE_URL_DETAILS = "app.update.url.details"; +const PREF_APP_UPDATE_URL_OVERRIDE = "app.update.url.override"; const PREFBRANCH_APP_UPDATE_NEVER = "app.update.never."; @@ -72,12 +70,10 @@ const FILE_UPDATE_VERSION = "update.version"; const STATE_NONE = "null"; const STATE_DOWNLOADING = "downloading"; const STATE_PENDING = "pending"; -const STATE_PENDING_SERVICE = "pending-service"; const STATE_PENDING_ELEVATE = "pending-elevate"; const STATE_APPLYING = "applying"; const STATE_APPLIED = "applied"; const STATE_APPLIED_OS = "applied-os"; -const STATE_APPLIED_SERVICE = "applied-service"; const STATE_SUCCEEDED = "succeeded"; const STATE_DOWNLOAD_FAILED = "download-failed"; const STATE_FAILED = "failed"; @@ -85,22 +81,9 @@ const STATE_FAILED = "failed"; // The values below used by this code are from common/errors.h const WRITE_ERROR = 7; const ELEVATION_CANCELED = 9; -const SERVICE_UPDATER_COULD_NOT_BE_STARTED = 24; -const SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS = 25; -const SERVICE_UPDATER_SIGN_ERROR = 26; -const SERVICE_UPDATER_COMPARE_ERROR = 27; -const SERVICE_UPDATER_IDENTITY_ERROR = 28; -const SERVICE_STILL_APPLYING_ON_SUCCESS = 29; -const SERVICE_STILL_APPLYING_ON_FAILURE = 30; -const SERVICE_UPDATER_NOT_FIXED_DRIVE = 31; -const SERVICE_COULD_NOT_LOCK_UPDATER = 32; -const SERVICE_INSTALLDIR_ERROR = 33; const WRITE_ERROR_ACCESS_DENIED = 35; const WRITE_ERROR_CALLBACK_APP = 37; const FILESYSTEM_MOUNT_READWRITE_ERROR = 43; -const SERVICE_COULD_NOT_COPY_UPDATER = 49; -const SERVICE_STILL_APPLYING_TERMINATED = 50; -const SERVICE_STILL_APPLYING_NO_EXIT_CODE = 51; const WRITE_ERROR_FILE_COPY = 61; const WRITE_ERROR_DELETE_FILE = 62; const WRITE_ERROR_OPEN_PATCH_FILE = 63; @@ -127,21 +110,6 @@ const WRITE_ERRORS = [WRITE_ERROR, WRITE_ERROR_DELETE_BACKUP, WRITE_ERROR_EXTRACT]; -// Array of write errors to simplify checks for service errors -const SERVICE_ERRORS = [SERVICE_UPDATER_COULD_NOT_BE_STARTED, - SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS, - SERVICE_UPDATER_SIGN_ERROR, - SERVICE_UPDATER_COMPARE_ERROR, - SERVICE_UPDATER_IDENTITY_ERROR, - SERVICE_STILL_APPLYING_ON_SUCCESS, - SERVICE_STILL_APPLYING_ON_FAILURE, - SERVICE_UPDATER_NOT_FIXED_DRIVE, - SERVICE_COULD_NOT_LOCK_UPDATER, - SERVICE_INSTALLDIR_ERROR, - SERVICE_COULD_NOT_COPY_UPDATER, - SERVICE_STILL_APPLYING_TERMINATED, - SERVICE_STILL_APPLYING_NO_EXIT_CODE]; - // Error codes 80 through 99 are reserved for nsUpdateService.js and are not // defined in common/errors.h const FOTA_GENERAL_ERROR = 80; @@ -164,10 +132,6 @@ const DOWNLOAD_FOREGROUND_INTERVAL = 0; const UPDATE_WINDOW_NAME = "Update:Wizard"; -// The number of consecutive failures when updating using the service before -// setting the app.update.service.enabled preference to false. -const DEFAULT_SERVICE_MAX_ERRORS = 10; - // The number of consecutive socket errors to allow before falling back to // downloading a different MAR file or failing if already downloading the full. const DEFAULT_SOCKET_MAX_ERRORS = 10; @@ -392,15 +356,7 @@ function getElevationRequired() { * @return true if an update can be applied, false otherwise */ function getCanApplyUpdates() { - let useService = false; - if (shouldUseService()) { - // No need to perform directory write checks, the maintenance service will - // be able to write to all directories. - LOG("getCanApplyUpdates - bypass the write checks because we'll use the service"); - useService = true; - } - - if (!useService && AppConstants.platform != "macosx") { + if (AppConstants.platform != "macosx") { try { let updateTestFile = getUpdateFile([FILE_UPDATE_TEST]); LOG("getCanApplyUpdates - testing write access " + updateTestFile.path); @@ -478,7 +434,7 @@ function getCanApplyUpdates() { // No write privileges to install directory return false; } - } // if (!useService) + } LOG("getCanApplyUpdates - able to apply updates"); return true; @@ -544,13 +500,6 @@ function getCanStageUpdates() { return false; } - if (AppConstants.platform == "win" && shouldUseService()) { - // No need to perform directory write checks, the maintenance service will - // be able to write to all directories. - LOG("getCanStageUpdates - able to stage updates using the service"); - return true; - } - if (!hasUpdateMutex()) { LOG("getCanStageUpdates - unable to apply updates because another " + "instance of the application is already handling updates for this " + @@ -778,120 +727,6 @@ function writeVersionFile(dir, version) { } /** - * Determines if the service should be used to attempt an update - * or not. - * - * @return true if the service should be used for updates. - */ -function shouldUseService() { - // This function will return true if the mantenance service should be used if - // all of the following conditions are met: - // 1) This build was done with the maintenance service enabled - // 2) The maintenance service is installed - // 3) The pref for using the service is enabled - // 4) The Windows version is XP Service Pack 3 or above (for SHA-2 support) - // The maintenance service requires SHA-2 support because we sign our binaries - // with a SHA-2 certificate and the certificate is verified before the binary - // is launched. - if (!AppConstants.MOZ_MAINTENANCE_SERVICE || !isServiceInstalled() || - !getPref("getBoolPref", PREF_APP_UPDATE_SERVICE_ENABLED, false) || - !AppConstants.isPlatformAndVersionAtLeast("win", "5.1") /* WinXP */) { - return false; - } - - // If it's newer than XP, then the service pack doesn't matter. - if (Services.sysinfo.getProperty("version") != "5.1") { - return true; - } - - // If the Windows version is XP, we also need to check the service pack. - // We'll return false if only < SP3 is installed, or if we can't tell. - // Check the service pack level by calling GetVersionEx via ctypes. - const BYTE = ctypes.uint8_t; - const WORD = ctypes.uint16_t; - const DWORD = ctypes.uint32_t; - const WCHAR = ctypes.char16_t; - const BOOL = ctypes.int; - // This structure is described at: - // http://msdn.microsoft.com/en-us/library/ms724833%28v=vs.85%29.aspx - const SZCSDVERSIONLENGTH = 128; - const OSVERSIONINFOEXW = new ctypes.StructType('OSVERSIONINFOEXW', - [ - {dwOSVersionInfoSize: DWORD}, - {dwMajorVersion: DWORD}, - {dwMinorVersion: DWORD}, - {dwBuildNumber: DWORD}, - {dwPlatformId: DWORD}, - {szCSDVersion: ctypes.ArrayType(WCHAR, SZCSDVERSIONLENGTH)}, - {wServicePackMajor: WORD}, - {wServicePackMinor: WORD}, - {wSuiteMask: WORD}, - {wProductType: BYTE}, - {wReserved: BYTE} - ]); - - let kernel32 = false; - try { - kernel32 = ctypes.open("Kernel32"); - } catch (e) { - Cu.reportError("Unable to open kernel32! " + e); - return false; - } - - if (kernel32) { - try { - try { - let GetVersionEx = kernel32.declare("GetVersionExW", - ctypes.default_abi, - BOOL, - OSVERSIONINFOEXW.ptr); - let winVer = OSVERSIONINFOEXW(); - winVer.dwOSVersionInfoSize = OSVERSIONINFOEXW.size; - - if (0 !== GetVersionEx(winVer.address())) { - return winVer.wServicePackMajor >= 3; - } - Cu.reportError("Unknown failure in GetVersionEX (returned 0)"); - return false; - } catch (e) { - Cu.reportError("Error getting service pack information. Exception: " + e); - return false; - } - } finally { - kernel32.close(); - } - } - - // If the service pack check couldn't be done, assume we can't use the service. - return false; -} - -/** - * Determines if the service is is installed. - * - * @return true if the service is installed. - */ -function isServiceInstalled() { - if (AppConstants.MOZ_MAINTENANCE_SERVICE && AppConstants.platform == "win") { - let installed = 0; - try { - let wrk = Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(Ci.nsIWindowsRegKey); - wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE, - "SOFTWARE\\Mozilla\\MaintenanceService", - wrk.ACCESS_READ | wrk.WOW64_64); - installed = wrk.readIntValue("Installed"); - wrk.close(); - } catch (e) { - } - installed = installed == 1; // convert to bool - LOG("isServiceInstalled = " + installed); - return installed; - } - return false; -} - -/** * Removes the contents of the updates patch directory and rotates the update * logs when present. If the update.log exists in the patch directory this will * move the last-update.log if it exists to backup-update.log in the parent @@ -1102,35 +937,6 @@ function handleUpdateFailure(update, errorCode) { Services.prefs.clearUserPref(PREF_APP_UPDATE_CANCELATIONS_OSX); } - // Replace with Array.prototype.includes when it has stabilized. - if (SERVICE_ERRORS.indexOf(update.errorCode) != -1) { - var failCount = getPref("getIntPref", - PREF_APP_UPDATE_SERVICE_ERRORS, 0); - var maxFail = getPref("getIntPref", - PREF_APP_UPDATE_SERVICE_MAXERRORS, - DEFAULT_SERVICE_MAX_ERRORS); - // Prevent the preference from setting a value greater than 10. - maxFail = Math.min(maxFail, 10); - // As a safety, when the service reaches maximum failures, it will - // disable itself and fallback to using the normal update mechanism - // without the service. - if (failCount >= maxFail) { - Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, false); - Services.prefs.clearUserPref(PREF_APP_UPDATE_SERVICE_ERRORS); - } else { - failCount++; - Services.prefs.setIntPref(PREF_APP_UPDATE_SERVICE_ERRORS, - failCount); - } - - writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING); - return true; - } - - if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SERVICE_ERRORS)) { - Services.prefs.clearUserPref(PREF_APP_UPDATE_SERVICE_ERRORS); - } - return false; } @@ -1189,9 +995,6 @@ function pingStateAndStatusCodes(aUpdate, aStartup, aStatus) { case STATE_PENDING: stateCode = 4; break; - case STATE_PENDING_SERVICE: - stateCode = 5; - break; case STATE_APPLYING: stateCode = 6; break; @@ -1201,9 +1004,6 @@ function pingStateAndStatusCodes(aUpdate, aStartup, aStatus) { case STATE_APPLIED_OS: stateCode = 8; break; - case STATE_APPLIED_SERVICE: - stateCode = 9; - break; case STATE_SUCCEEDED: stateCode = 10; break; @@ -1831,8 +1631,8 @@ UpdateService.prototype = { // version and nsUpdateDriver.cpp skipped updating due to the version being // older than the current version. if (update && update.appVersion && - (status == STATE_PENDING || status == STATE_PENDING_SERVICE || - status == STATE_APPLIED || status == STATE_APPLIED_SERVICE || + (status == STATE_PENDING || + status == STATE_APPLIED || status == STATE_PENDING_ELEVATE)) { if (Services.vc.compare(update.appVersion, Services.appinfo.version) < 0 || Services.vc.compare(update.appVersion, Services.appinfo.version) == 0 && @@ -1870,9 +1670,7 @@ UpdateService.prototype = { // that state to "applying" and we just wait and hope for the best. // If it's "applying", we know that we've already been here once, so // we really want to start from a clean state. - if (update && - (update.state == STATE_PENDING || - update.state == STATE_PENDING_SERVICE)) { + if (update && (update.state == STATE_PENDING)) { LOG("UpdateService:_postUpdateProcessing - patch found in applying " + "state for the first time"); update.state = STATE_APPLYING; @@ -2121,27 +1919,13 @@ UpdateService.prototype = { this._pingSuffix, PREF_APP_UPDATE_CANCELATIONS_OSX, 0, 0); } - if (AppConstants.MOZ_MAINTENANCE_SERVICE) { - // Histogram IDs: - // UPDATE_NOT_PREF_UPDATE_SERVICE_ENABLED_EXTERNAL - // UPDATE_NOT_PREF_UPDATE_SERVICE_ENABLED_NOTIFY - AUSTLMY.pingBoolPref("UPDATE_NOT_PREF_UPDATE_SERVICE_ENABLED_" + - this._pingSuffix, - PREF_APP_UPDATE_SERVICE_ENABLED, true); - // Histogram IDs: - // UPDATE_PREF_SERVICE_ERRORS_EXTERNAL - // UPDATE_PREF_SERVICE_ERRORS_NOTIFY - AUSTLMY.pingIntPref("UPDATE_PREF_SERVICE_ERRORS_" + this._pingSuffix, - PREF_APP_UPDATE_SERVICE_ERRORS, 0, 0); - if (AppConstants.platform == "win") { - // Histogram IDs: - // UPDATE_SERVICE_INSTALLED_EXTERNAL - // UPDATE_SERVICE_INSTALLED_NOTIFY - // UPDATE_SERVICE_MANUALLY_UNINSTALLED_EXTERNAL - // UPDATE_SERVICE_MANUALLY_UNINSTALLED_NOTIFY - AUSTLMY.pingServiceInstallStatus(this._pingSuffix, isServiceInstalled()); - } - } + let prefType = Services.prefs.getPrefType(PREF_APP_UPDATE_URL_OVERRIDE); + let overridePrefHasValue = prefType != Ci.nsIPrefBranch.PREF_INVALID; + // Histogram IDs: + // UPDATE_HAS_PREF_URL_OVERRIDE_EXTERNAL + // UPDATE_HAS_PREF_URL_OVERRIDE_NOTIFY + AUSTLMY.pingGeneric("UPDATE_HAS_PREF_URL_OVERRIDE_" + this._pingSuffix, + overridePrefHasValue, false); // If a download is in progress or the patch has been staged do nothing. if (this.isDownloading) { @@ -2151,7 +1935,7 @@ UpdateService.prototype = { if (this._downloader && this._downloader.patchIsStaged) { let readState = readStatusFile(getUpdatesDir()); - if (readState == STATE_PENDING || readState == STATE_PENDING_SERVICE || + if (readState == STATE_PENDING || readState == STATE_PENDING_ELEVATE) { AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_IS_DOWNLOADED); } else { @@ -2173,8 +1957,18 @@ UpdateService.prototype = { } else if (!UpdateUtils.ABI) { AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_NO_OS_ABI); } else if (!validUpdateURL) { - AUSTLMY.pingCheckCode(this._pingSuffix, - AUSTLMY.CHK_INVALID_DEFAULT_URL); + if (overridePrefHasValue) { + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_URL_OVERRIDE)) { + AUSTLMY.pingCheckCode(this._pingSuffix, + AUSTLMY.CHK_INVALID_USER_OVERRIDE_URL); + } else { + AUSTLMY.pingCheckCode(this._pingSuffix, + AUSTLMY.CHK_INVALID_DEFAULT_OVERRIDE_URL); + } + } else { + AUSTLMY.pingCheckCode(this._pingSuffix, + AUSTLMY.CHK_INVALID_DEFAULT_URL); + } } else if (!getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true)) { AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_PREF_DISABLED); } else if (!hasUpdateMutex()) { @@ -2885,8 +2679,8 @@ UpdateManager.prototype = { for (let i = updates.length - 1; i >= 0; --i) { let state = updates[i].state; if (state == STATE_NONE || state == STATE_DOWNLOADING || - state == STATE_APPLIED || state == STATE_APPLIED_SERVICE || - state == STATE_PENDING || state == STATE_PENDING_SERVICE || + state == STATE_APPLIED || + state == STATE_PENDING || state == STATE_PENDING_ELEVATE) { updates.splice(i, 1); } @@ -2931,9 +2725,6 @@ UpdateManager.prototype = { update.QueryInterface(Ci.nsIWritablePropertyBag); update.setProperty("stagingFailed", "true"); } - if (update.state == STATE_APPLIED && shouldUseService()) { - writeStatusFile(getUpdatesDir(), update.state = STATE_APPLIED_SERVICE); - } // Send an observer notification which the update wizard uses in // order to update its UI. @@ -2949,9 +2740,7 @@ UpdateManager.prototype = { } if (update.state == STATE_APPLIED || - update.state == STATE_APPLIED_SERVICE || update.state == STATE_PENDING || - update.state == STATE_PENDING_SERVICE || update.state == STATE_PENDING_ELEVATE) { // Notify the user that an update has been staged and is ready for // installation (i.e. that they should restart the application). @@ -3023,11 +2812,16 @@ Checker.prototype = { getUpdateURL: function UC_getUpdateURL(force) { this._forced = force; - let url; - try { - url = Services.prefs.getDefaultBranch(null). - getCharPref(PREF_APP_UPDATE_URL); - } catch (e) { + // Use the override URL if specified. + let url = getPref("getCharPref", PREF_APP_UPDATE_URL_OVERRIDE, null); + + // Otherwise, construct the update URL from component parts. + if (!url) { + try { + url = Services.prefs.getDefaultBranch(null). + getCharPref(PREF_APP_UPDATE_URL); + } catch (e) { + } } if (!url || url == "") { @@ -3309,9 +3103,9 @@ Downloader.prototype = { // Note that if we decide to download and apply new updates after another // update has been successfully applied in the background, we need to stop // checking for the APPLIED state here. - return readState == STATE_PENDING || readState == STATE_PENDING_SERVICE || + return readState == STATE_PENDING || readState == STATE_PENDING_ELEVATE || - readState == STATE_APPLIED || readState == STATE_APPLIED_SERVICE; + readState == STATE_APPLIED; }, /** @@ -3428,7 +3222,7 @@ Downloader.prototype = { return selectedPatch; } - if (state == STATE_PENDING || state == STATE_PENDING_SERVICE || + if (state == STATE_PENDING || state == STATE_PENDING_ELEVATE) { LOG("Downloader:_selectPatch - already downloaded and staged"); return null; @@ -3721,9 +3515,7 @@ Downloader.prototype = { "max fail: " + maxFail + ", " + "retryTimeout: " + retryTimeout); if (Components.isSuccessCode(status)) { if (this._verifyDownload()) { - if (shouldUseService()) { - state = STATE_PENDING_SERVICE; - } else if (getElevationRequired()) { + if (getElevationRequired()) { state = STATE_PENDING_ELEVATE; } else { state = STATE_PENDING; @@ -3873,7 +3665,7 @@ Downloader.prototype = { return; } - if (state == STATE_PENDING || state == STATE_PENDING_SERVICE || + if (state == STATE_PENDING || state == STATE_PENDING_ELEVATE) { if (getCanStageUpdates()) { LOG("Downloader:onStopRequest - attempting to stage update: " + |