Background Updates

From MozillaWiki
Jump to: navigation, search

This page describes the technical plan to move the process of applying the updates in Firefox to the background as opposed to at startup. In order to get a clear idea about the scope of the project, please see the Goals and Non-Goals sections below.

Goals

  1. Moving the update process to the background
  2. Initiating the update process as soon as an update is downloaded
  3. Being able to apply a newer update if Firefox was not restarted since the previous update was applied in the background
  4. Try to do as little as possible at startup
  5. Eliminate the progress bar UI that the current updater shows

Non-Goals

  1. Handling UAC prompts on Windows (covered in this project)
  2. Changing the frequency of checking for updates, our handling of major/minor updates, or the way we check for add-ons compatibility (covered in this project)
  3. Eliminating the UI we display in Item 2 (parts of it covered in this project)
  4. Changing how updates work on Android
  5. Downloading and/or apply update while Firefox is not running
  6. Any of the other projects falling under the "silent update" umbrella

Implementation

Background updates

Here is a proposal for how background updates will be implemented. Please note that the parts in italics explain what currently happens, and those parts are not changed under this proposal. They are only mentioned here for completeness.

  • The process will start by Firefox checking for an update in the foreground or background.
  • Once an update is found
    • If the user needs to prompted for some reason, we show that prompt at the normal time. (e.g, on idle). If the user declines, we bail out.
    • Otherwise, we go ahead and download the update (as a complete/partial MAR file).
  • Once the download is finished, Firefox launches the updater binary in the background with the UI display disabled. Searching for new updates will be paused during this time.
    • The target of the update will be known FIREFOX_NEW from now on.
      • On Windows, if Firefox is installed to "C:\path\to\Mozilla Firefox", FIREFOX_NEW will be "C:\path\to\Mozilla Firefox\updated".
      • On Mac, if Firefox is installed to "/path/to/Firefox.app", FIREFOX_NEW will be "/path/to/Firefox.app/Updated.app". In other words, the updated version of Firefox will be installed as a bundle inside the existing Firefox bundle.
      • On Linux, if Firefox is installed to a flat directory like "/path/to/firefox", FIREFOX_NEW will be "/path/to/firefox/updated". If it's installed in a non-flat directory structure (like /usr/bin for example), the details of where FIREFOX_NEW will be is TBD.
    • The manifest file is the "update.status" file used by the updater service.
  • The updater binary checks to see if there is an existing manifest file.
    • If this file exists, and it contains "applied", its content is changed to "applying". Otherwise, the background update stops.
  • The updater binary checks to see if there is an existing FIREFOX_NEW directory.
    • If this directory exists, it will be removed.
  • The existing installation will be copied into FIREFOX_NEW.
  • The updater binary will go ahead and apply the update to the FIREFOX_NEW directory using the existing installation directory as the base. Any errors happening during this phase (such as running out of disk space or failing to write to disk) will be handled by the updater process by removing the FIREFOX_NEW directory and aborting. The updater binary will also write to the manifest file "failed: n" where n is the reason code.
  • The updater binary will write "applied" to the manifest file.
  • The updater binary will shutdown, and signal the Firefox main process.
  • The Firefox main process will search for new updates when the next update interval is reached.

Firefox startup

The following needs to happen at Firefox startup time in order for the applied update to be used.

  • Firefox checks for the manifest file in the installation directory. If it's not found, or its content does not equal "applied", then startup continues as normal.
  • If the manifest file is found and its content is "applied", Firefox looks for the known FIREFOX_NEW directory. If that directory is not found, Firefox writes "failed: ERROR_CODE" to the manifest file and continues to startup as normal.
  • If the FIREFOX_NEW is found, Firefox "replaces" the existing installation direcotry with the new FIREFOX_NEW directory, and removes the FIREFOX_NEW directory, and restarts using the new binary. The details of this phase depends on the platform, and is documented below.

Replacing the existing installation

Windows

On Windows, it is not possible to remove or rename files and directories which are being used. In order to handle this, we need to add a little complexity.

  • The Firefox executable will launch a helper application copied to somewhere outside of the installation directory, most likely the system's temporary directory.
  • The helper application renames the existing installation directory to a new directory with ".tmp" appended to its path name. If the rename operation fails in the middle of the operation because of a file being open by another application, it reverts the change.
  • If the first rename is successful, the helper app renames the FIREFOX_NEW directory to the name of the existing installation. If something goes wrong in this phase, the FIREFOX_NEW directory and the one created in this phase are both removed and the ".tmp" directory is restored back to the state it was before the helper application was launched.
  • If the previous operation was successful, the helper app removes the ".tmp" diectory.
  • At the end of its run, the helper app relaunches Firefox as a non elevated process from the path name of the existing installation, whatever it was.

Mac

On Mac, we basically move the Contents directory in the FIREFOX_NEW directory over to the Contents directory in the existing installation, remove the now empty FIREFOX_NEW directory, write "succeeded" to the manifest file, and restart Firefox.

Linux

On Linux, we basically move the FIREFOX_NEW over the existing installation directory, write "succeeded" to the manifest file, and restart Firefox.

Considered alternatives

A number of other approaches have been considered before writing this proposal. One such approach is to make FIREFOX_NEW live inside the existing installation directory. That will cause a lot of pain on Windows where we can't overwrite files that are currently open in another application.

We have also considered keeping two versions of Firefox in versioned side-by-side directory. That will also lead into a number of problems because the directory from which Firefox is going to be launched is going to change over and over again.

Downgrade

Firefox currently supports downgrading to older versions by installing an old installer over the new installation directory. The way that it works is that the Firefox installer first uninstalls the old version and then proceeds with the rest of the installation. This can be made possible in the face of background updates by relying on the uninstaller to know about the manifest file, and making the installer aware of the FIREFOX_NEW directory. The uninstaller should remove the FIREFOX_NEW directory as part of the uninstall process. The same handling is enough to correctly handle Firefox being uninstalled explicitly as well.