/* 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/. */

#include "nsISupports.idl"

interface nsIRequest;
interface nsIRequestObserver;
interface nsISimpleEnumerator;
interface nsIFile;

webidl Element;
webidl Document;

/**
 * An interface that describes an object representing a patch file that can
 * be downloaded and applied to a version of this application so that it
 * can be updated.
 */
[scriptable, uuid(dc8fb8a9-3a53-4031-9469-2a5197ea30e7)]
interface nsIUpdatePatch : nsISupports
{
  /**
   * The type of this patch:
   * "partial"      A binary difference between two application versions
   * "complete"     A complete patch containing all of the replacement files
   *                to update to the new version
   */
  readonly attribute AString type;

  /**
   * The URL this patch was being downloaded from
   */
  readonly attribute AString URL;

  /**
   * The final URL this patch was being downloaded from
   */
  attribute AString finalURL;

  /**
   * The size of this file, in bytes.
   */
  readonly attribute unsigned long size;

  /**
   * The state of this patch
   */
  attribute AString state;

  /**
   * A numeric error code that conveys additional information about the state of
   * a failed update. If the update is not in the "failed" state the value is
   * zero. The possible values are located in common/updatererrors.h and values between
   * 80 and 99 are in nsUpdateService.js.
   */
  attribute long errorCode;

  /**
   * true if this patch is currently selected as the patch to be downloaded and
   * installed for this update transaction, false if another patch from this
   * update has been selected.
   */
  attribute boolean selected;

  /**
   * Serializes this patch object into a DOM Element
   * @param   updates
   *          The document to serialize into
   * @returns The DOM Element created by the serialization process
   */
  Element serialize(in Document updates);
};

/**
 * An interface that describes an object representing an available update to
 * the current application - this update may have several available patches
 * from which one must be selected to download and install, for example we
 * might select a binary difference patch first and attempt to apply that,
 * then if the application process fails fall back to downloading a complete
 * file-replace patch. This object also contains information about the update
 * that the front end and other application services can use to learn more
 * about what is going on.
 */
[scriptable, uuid(e094c045-f4ff-41fd-92da-cd2effd2c7c9)]
interface nsIUpdate : nsISupports
{
  /**
   * The type of update:
   *   "major"  A major new version of the Application
   *   "minor"  A minor update to the Application (e.g. security update)
   */
  readonly attribute AString type;

  /**
   * The name of the update, or "<Application Name> <Update Version>"
   */
  readonly attribute AString name;

  /**
   * The string to display in the user interface for the version. If you want
   * a real version number use appVersion.
   */
  readonly attribute AString displayVersion;

  /**
   * The Application version of this update.
   */
  readonly attribute AString appVersion;

  /**
   * The platform version of this update.
   */
  readonly attribute AString platformVersion;

  /**
   * The Application version prior to the application being updated.
   */
  readonly attribute AString previousAppVersion;

  /**
   * The Build ID of this update. Used to determine a particular build, down
   * to the hour, minute and second of its creation. This allows the system
   * to differentiate between several nightly builds with the same |version|
   * for example.
   */
  readonly attribute AString buildID;

  /**
   * The URL to a page which offers details about the content of this
   * update. Ideally, this page is not the release notes but some other page
   * that summarizes the differences between this update and the previous,
   * which also links to the release notes.
   */
  readonly attribute AString detailsURL;

  /**
   * The URL to the Update Service that supplied this update.
   */
  readonly attribute AString serviceURL;

  /**
   * The channel used to retrieve this update from the Update Service.
   */
  readonly attribute AString channel;

  /**
   * Whether the update is no longer supported on this system.
   */
  readonly attribute boolean unsupported;

  /**
   * Allows overriding the default amount of time in seconds before prompting the
   * user to apply an update. If not specified, the value of
   * app.update.promptWaitTime will be used.
   */
  attribute long long promptWaitTime;

  /**
   * Whether or not the update being downloaded is a complete replacement of
   * the user's existing installation or a patch representing the difference
   * between the new version and the previous version.
   */
  attribute boolean isCompleteUpdate;

  /**
   * When the update was installed.
   */
  attribute long long installDate;

  /**
   * A message associated with this update, if any.
   */
  attribute AString statusText;

  /**
   * The currently selected patch for this update.
   */
  readonly attribute nsIUpdatePatch selectedPatch;

  /**
   * The state of the selected patch:
   *   "downloading"        The update is being downloaded.
   *   "pending"            The update is ready to be applied.
   *   "pending-service"    The update is ready to be applied with the service.
   *   "pending-elevate"    The update is ready to be applied but requires elevation.
   *   "applying"           The update is being applied.
   *   "applied"            The update is ready to be switched to.
   *   "applied-service"    The update is ready to be switched to with the service.
   *   "succeeded"          The update was successfully applied.
   *   "download-failed"    The update failed to be downloaded.
   *   "failed"             The update failed to be applied.
   */
  attribute AString state;

  /**
   * A numeric error code that conveys additional information about the state of
   * a failed update. If the update is not in the "failed" state the value is
   * zero. The possible values are located in common/updatererrors.h and values between
   * 80 and 99 are in nsUpdateService.js.
   */
  attribute long errorCode;

  /**
   * Whether an elevation failure has been encountered for this update.
   */
  attribute boolean elevationFailure;

  /**
   * The number of patches supplied by this update.
   */
  readonly attribute unsigned long patchCount;

  /**
   * Retrieves a patch.
   * @param   index
   *          The index of the patch to retrieve.
   * @returns The nsIUpdatePatch at the specified index.
   */
  nsIUpdatePatch getPatchAt(in unsigned long index);

  /**
   * Serializes this update object into a DOM Element
   * @param   updates
   *          The document to serialize into
   * @returns The DOM Element created by the serialization process
   */
  Element serialize(in Document updates);
};

/**
 * An interface describing the result of an update check.
 */
[scriptable, uuid(bff08110-e79f-4a9f-a56c-348170f9208a)]
interface nsIUpdateCheckResult : nsISupports
{
  /**
   * True if update checks are allowed. otherwise false.
   */
  readonly attribute boolean checksAllowed;

  /**
   * True if the update check succeeded, otherwise false. Guaranteed to be false
   * if checksAllowed is false.
   */
  readonly attribute boolean succeeded;

  /**
   * The XMLHttpRequest handling the update check. Depending on exactly how the
   * check failed, it's possible for this to be null.
   */
  readonly attribute jsval request;

  /**
   * If `!checksAllowed`, this will always be an empty array.
   *
   * If `succeeded`, this will be an array of nsIUpdate objects listing
   * available updates. The length will be 0 if there are no available updates.
   *
   * If `checksAllowed && !succeeded`, this will be an array containing exactly
   * one nsIUpdate object. Most of the attributes will have no useful value
   * since we did not successfully retrieve an update, but `errorCode` and
   * `statusText` will be set to values that describe the error encountered when
   * checking for updates.
   */
  readonly attribute Array<nsIUpdate> updates;
};

/**
 * An interface describing an update check that may still be in-progress or may
 * be completed.
 */
[scriptable, uuid(2620aa24-27aa-463a-b6d2-0734695c1f7a)]
interface nsIUpdateCheck : nsISupports
{
  /**
   * An id that represents a particular update check. Can be passed to
   * nsIUpdateChecker::stopCheck.
   *
   * Ids are guaranteed to be truthy (non-zero) and non-repeating. This is
   * just for caller convenience so that (a) it's not an error to cancel a check
   * that already completed and (b) they can easily check `if (idVar)` to see if
   * they stored an id.
   */
  readonly attribute long id;

  /**
   * A promise that resolves to the results of the update check, which will be
   * of type nsIUpdateCheckResult.
   */
  readonly attribute Promise result;
};

/**
 * An interface into the internals of the update checker. These should only be
 * accessed from within update code and tests.
 */
[scriptable, uuid(e27f0336-ad86-4c31-bfee-1d96100521f5)]
interface nsIUpdateCheckerInternal : nsISupports
{
  /**
   * This is identical to the corresponding function in `nsIUpdateChecker`, but
   * this version does not ensure the update system has been initialized before
   * being called.
   */
  nsIUpdateCheck checkForUpdates(in long checkType);
};

/**
 * An interface describing an object that knows how to check for updates. It can
 * perform multiple update checks simultaneously or consolidate multiple check
 * requests into a single web request, depending on whether the parameters
 * specified for update checking match.
 */
[scriptable, uuid(877ace25-8bc5-452a-8586-9c1cf2871994)]
interface nsIUpdateChecker : nsISupports
{
  /**
   * Enumerated constants. See the `checkType` parameter of `checkForUpdates`
   * for details.
   */
  const long BACKGROUND_CHECK                                             = 1;
  const long FOREGROUND_CHECK                                             = 2;

  /**
   * Checks for available updates.
   * @param   checkType
   *          Must be either BACKGROUND_CHECK or FOREGROUND_CHECK. If
   *          FOREGROUND_CHECK is specified, the normal
   *          nsIApplicationUpdateService.canCheckForUpdates check will be
   *          overridden and the "force" parameter will be included in the
   *          update URL.
   *
   *          Regarding the "force" parameter:
   *          Sometimes the update server throttles updates, arbitrarily
   *          refraining from returning the newest version to some clients. The
   *          force parameter overrides this behavior and tells it to
   *          unconditionally return the newest available version.
   *
   *          It's worth noting that the update server technically supports
   *          forcing the decision in the other direction too, preventing
   *          the newest version from being returned, but this interface doesn't
   *          actually support setting the force parameter this way. If the
   *          force parameter is used, it always forces getting the newest
   *          version.
   * @returns An nsIUpdateCheck object that describes the update check and
   *          provides a Promise that resolves to the update check results.
   */
  nsIUpdateCheck checkForUpdates(in long checkType);

  /**
   * Gets the update URL.
   * @param   checkType
   *          Must be either BACKGROUND_CHECK or FOREGROUND_CHECK. See the
   *          checkType parameter of nsIUpdateChecker.checkForUpdates for more
   *          details.
   * @returns A Promise that resolves to the URL to be used to check for
   *          updates, as a string. This URL should resolve to an XML describing
   *          the updates that are available to the current Firefox
   *          installation.
   */
  Promise getUpdateURL(in long checkType);

  /**
   * Ends a pending update check. Has no effect if the id is invalid or the
   * check corresponding to the id has already completed.
   *
   * Note that because `nsIUpdateChecker` potentially combines multiple update
   * checks, it is not guaranteed that this will actually cause the update
   * request to be aborted. It also doesn't guarantee that
   * `nsIUpdateCheck.result` will resolve when this is called. This merely marks
   * the check id as cancelled and only if there are no other check ids waiting
   * on the request does it abort it.
   *
   * @param   id
   *          The id of a check to stop (accessible via nsIUpdateCheck).
   */
  void stopCheck(in long id);

  /**
   * Ends all pending update checks.
   */
  void stopAllChecks();

  /**
   * See nsIUpdateCheckerInternal for details.
   */
  readonly attribute nsIUpdateCheckerInternal internal;
};

/**
 * An interface into the internals of the update service. These should only be
 * accessed from within update code and tests.
 */
[scriptable, uuid(7f39bc95-eaf8-4adc-990b-0fc0734f85fa)]
interface nsIApplicationUpdateServiceInternal : nsISupports
{
  /**
   * To initialize the update system, use the init method on
   * `nsIApplicationUpdateService` or `nsIApplicationUpdateServiceStub`. This
   * method is invoked as part of the update initialization process, but is not
   * an entry point to it.
   *
   * @param   force
   *          If `true`, run the initialization again, even if we already have.
   *          Should only be used in testing.
   * @returns Promise<undefined>
   */
  Promise init(in boolean force);

  /**
   * These are identical to the corresponding functions in
   * `nsIApplicationUpdateService`, but these versions do not ensure the update
   * system has been initialized before being called.
   */
  Promise downloadUpdate(in nsIUpdate update);
  Promise stopDownload();
};

/**
 * An interface describing a global application service that handles performing
 * background update checks and provides utilities for selecting and
 * downloading update patches.
 */
[scriptable, uuid(1107d207-a263-403a-b268-05772ec10757)]
interface nsIApplicationUpdateService : nsISupports
{
  /**
   * Initializes the update system. It is typically not necessary to call this
   * since the public methods that require initialization to be meaningful
   * ensure that initialization has been performed. But this can be useful to
   * spur the updater to resume or complete any in-progress updates from
   * previous browser sessions.
   *
   * @returns Promise<undefined>
   */
  Promise init();

  /**
   * Checks for available updates in the background using the listener provided
   * by the application update service for background checks.
   * @returns A promise resolving to `true` if the update check was started, or
   *          one resolving to `false` if not. Note that the check starting does
   *          not necessarily mean that the check will succeed or that an
   *          update will be downloaded.
   */
  Promise checkForBackgroundUpdates();

  /**
   * Selects the best update to install from a list of available updates.
   * @param   updates
   *          An array of updates that are available
   * @returns Promise<nsIUpdate>
   *          Resolves with the best update to install.
   */
  Promise selectUpdate(in Array<nsIUpdate> updates);

  /**
   * Adds a listener that receives progress and state information about the
   * update that is currently being downloaded, e.g. to update a user
   * interface. Registered listeners will be called for all downloads and all
   * updates during a browser session; they are not automatically removed
   * following the first (successful or failed) download.
   * @param   listener
   *          An object implementing nsIRequestObserver and optionally
   *          nsIProgressEventSink that is to be notified of state and
   *          progress information as the update is downloaded.
   */
  void addDownloadListener(in nsIRequestObserver listener);

  /**
   * Removes a listener that is receiving progress and state information
   * about the update that is currently being downloaded.
   * @param   listener
   *          The listener object to remove.
   */
  void removeDownloadListener(in nsIRequestObserver listener);

  /**
   * The below are the possible return values for `downloadUpdate()`.
   */
  // An update download was started.
  const long DOWNLOAD_SUCCESS                                             = 1;
  // The update download is already in-progress but it is using a download
  // method that we can't use in the background and Firefox is currently running
  // as a background task.
  const long DOWNLOAD_FAILURE_CANNOT_RESUME_IN_BACKGROUND                 = 2;
  // The update download cannot be started for a reason that doesn't have a more
  // specific failure code.
  const long DOWNLOAD_FAILURE_GENERIC                                     = 3;
  // The update download cannot be started because the update state could not
  // be written to the update directory.
  const long DOWNLOAD_FAILURE_CANNOT_WRITE_STATE                          = 4;

  /**
   * Starts downloading the update passed. Once the update is downloaded, it
   * will automatically be prepared for installation.
   *
   * @param   update
   *          The update to download.
   * @returns A promise that resolves with the integer value of one of the
   *          `DOWNLOAD_*` constants above indicating whether or not the
   *          download was started.
   */
  Promise downloadUpdate(in nsIUpdate update);

  /**
   * This is the function called internally by the Application Update Service
   * when an update check is complete. Though this can be used to potentially
   * start an update download, `downloadUpdate` should used for that.
   * This is mostly exposed in the interface in order to make it accessible for
   * testing.
   */
  Promise onCheckComplete(in nsIUpdateCheckResult result);

  /**
   * Stop the active update download process. This is the equivalent of
   * calling nsIRequest::Cancel on the download's nsIRequest. When downloading
   * with nsIIncrementalDownload, this will leave the partial download in place.
   * When downloading with BITS, any partial download progress will be removed.
   *
   * @returns A Promise that resolves once the download has been stopped.
   */
  Promise stopDownload();

  /**
   * There are a few things that can disable the Firefox updater at runtime
   * such as Enterprise Policies. If this attribute is set to true, update
   * should not be performed and most update interfaces will return errors.
   */
  readonly attribute boolean disabled;

  /**
   * Whether or not the Update Service can usually check for updates. This is a
   * function of whether or not application update is disabled by the
   * application and the platform the application is running on.
   */
  readonly attribute boolean canUsuallyCheckForUpdates;

  /**
   * Whether or not the Update Service can check for updates right now. This is
   * a function of whether or not application update is disabled by the
   * application, the platform the application is running on, and transient
   * factors such as whether other instances are running.
   */
  readonly attribute boolean canCheckForUpdates;

  /**
   * Whether or not the installation requires elevation. Currently only
   * implemented on OSX, returns false on other platforms.
   */
  readonly attribute boolean elevationRequired;

  /**
   * Whether or not the Update Service can usually download and install updates.
   * On Windows, this is a function of whether or not the maintenance service
   * is installed and enabled. On other systems, and as a fallback on Windows,
   * this depends on whether the current user has write access to the install
   * directory.
   */
  readonly attribute boolean canUsuallyApplyUpdates;

  /**
   * Whether or not the Update Service can download and install updates right now.
   * On Windows, this is a function of whether or not the maintenance service
   * is installed and enabled. On other systems, and as a fallback on Windows,
   * this depends on whether the current user has write access to the install
   * directory. On all systems, this includes transient factors such as whether
   * other instances are running.
   */
  readonly attribute boolean canApplyUpdates;

  /**
   * Whether or not a different instance is handling updates of this
   * installation.  This currently only ever returns true on Windows
   * when 2 instances of an application are open. Only one of the instances
   * will actually handle updates for the installation.
   */
  readonly attribute boolean isOtherInstanceHandlingUpdates;

  /**
   * Whether the Update Service is usually able to stage updates.
   */
  readonly attribute boolean canUsuallyStageUpdates;

  /**
   * Whether the Update Service is able to stage updates right now.  On all
   * systems, this includes transient factors such as whether other instances
   * are running.
   */
  readonly attribute boolean canStageUpdates;

  /**
   * On Windows, whether the Update Service can usually use BITS.
   */
  readonly attribute boolean canUsuallyUseBits;

  /**
   * On Windows, whether the Update Service can use BITS right now.  This
   * includes transient factors such as whether other instances are running.
   */
  readonly attribute boolean canUseBits;

  /**
   * Indicates whether or not the enterprise policy that allows only manual
   * updating is active. One of the features of this policy is not being
   * notified of updates; you are intended to need to manually tell Firefox
   * that you want to update each time that you want to do so.
   *
   * This policy has some implications for the way that update checks work. We
   * don't want to do background update checks. Without being able to notify
   * the user, there's not really anything to do if we find one. However, we
   * will allow "automatic" update checks when loading the update interfaces
   * in about:preferences, the About Dialog, etc. When those interfaces are
   * open, we do have a way of telling the user about an update without
   * bothering them with a doorhanger.
   */
  readonly attribute boolean manualUpdateOnly;

  /**
   * Determines if the base directory is writable. If not, we assume that
   * further permissions are required and that we are dealing with an elevated
   * installation.
   */
  readonly attribute boolean isAppBaseDirWritable;

  /**
   * This can be set to true to prevent updates being processed beyond starting
   * an update download. This should only be used when we are being run as a
   * background task.
   * This exists to prevent a particularly fast update download from beginning
   * to stage while the background task is shutting down.
   */
  attribute boolean onlyDownloadUpdatesThisSession;

  /**
   * Enumerated constants describing the update states that the updater can be
   * in.
   * Note that update checking is not part of the states that this interface
   * can recognize and report. This is for two reasons: 1) there are multiple
   * kinds of update checks (ex: foreground and background) and it would make
   * the current update state more complicated if we wanted to track both, and
   * 2) there isn't really any reason to concern ourselves with current update
   * checks because nsIUpdateChecker will seamlessly combine multiple identical
   * update checks into a single request without the caller having to worry
   * about its internal state.
   */
  // An update download hasn't started yet, or we failed at some point in the
  // update process and aborted.
  const long STATE_IDLE                                                   = 1;
  // An update is currently being downloaded.
  // This state begins once nsIApplicationUpdateService.downloadUpdate resolves
  // to `true`.
  // Note that we may be downloading an update but not be in this state because
  // we can download a second update while we have an update ready. But there
  // isn't much reason for currentState to track the second update. We know that
  // it will always be in the downloading state until it finishes downloading
  // and becomes the ready update. See STATE_UPDATE_SWAP for more details.
  const long STATE_DOWNLOADING                                            = 2;
  // An update is currently being staged. Note that we do not always stage
  // updates.
  const long STATE_STAGING                                                = 4;
  // An update is pending. If the browser restarts now, it will be installed.
  // Note that although "pending" is one of the potential update statuses, this
  // does not correspond to exactly that status.
  const long STATE_PENDING                                                = 5;
  // We had an update pending. Then we downloaded another update. Now we are
  // in the process of removing the old update and swapping the new update into
  // its place.
  // Note that when the state initially changes to `STATE_SWAP`, the new update
  // will be in `nsIUpdateManager.downloadingUpdate` but it will be moved into
  // `nsIUpdateManager.readyUpdate` before moving to the next state.
  const long STATE_SWAP                                                   = 6;

  // An update download was attempted but failed
  const long STATE_DOWNLOAD_FAILED                                        = 7;

  /**
   * Gets a string describing the state (mostly intended to be make console
   * logs easier to read).
   */
  AString getStateName(in long state);

  /**
   * The current state of the application updater. Returns one of the enumerated
   * constants, above.
   *
   * The expected flow looks like this:
   *   STATE_IDLE -> STATE_DOWNLOADING -> STATE_STAGING -> STATE_PENDING
   * If a failure is encountered at some time, we go back to STATE_IDLE.
   * If staging is not enabled, STATE_STAGING will be skipped.
   *
   * We may download additional updates after we reach STATE_PENDING. If we do,
   * the state will remain at STATE_PENDING while we download the new update. If
   * we restart during that time, the pending update will be installed and the
   * partially downloaded update will be discarded. If a download completes
   * successfully, there will be a brief period where STATE_PENDING is no longer
   * correct, because the Update Service is in the process of removing the old
   * update and replacing it with the new update. So if we restart during that
   * period, the update will not be correctly installed. Thus, we switch away
   * from STATE_PENDING to STATE_SWAP during that time. Assuming that the swap
   * is successful, the state will then switch back STATE_STAGING (assuming that
   * staging is enabled), then to STATE_PENDING. So the full expected state flow
   * looks more like this:
   *   STATE_IDLE -> STATE_DOWNLOADING -> STATE_STAGING -> STATE_PENDING ->
   *   STATE_SWAP -> STATE_STAGING -> STATE_PENDING ->
   *   STATE_SWAP -> STATE_STAGING -> STATE_PENDING -> ...
   * (Omitting STATE_STAGING if staging is not enabled).
   */
  readonly attribute long currentState;

  /**
   * A Promise that resolves immediately after `currentState` changes.
   */
  readonly attribute Promise stateTransition;

  /**
   * See nsIApplicationUpdateServiceInternal for details.
   */
  readonly attribute nsIApplicationUpdateServiceInternal internal;
};

/**
 * An interface describing a component which handles the job of processing
 * an update after it's been downloaded.
 */
[scriptable, uuid(74439497-d796-4915-8cef-3dfe43027e4d)]
interface nsIUpdateProcessor : nsISupports
{
  /**
   * Stages an update while the application is running.
   */
  void processUpdate();

  /**
   * The installer writes an installation-specific registry key if the
   * Maintenance Service can be used for this installation. This function checks
   * for that key's existence (it does not read or verify the key's contents).
   *
   * This function should only be called on Windows.
   *
   * @returns true if the registry key exists, false if it does not.
   * @throws  NS_ERROR_NOT_AVAILABLE
   *          If registry access fails.
   * @throws  NS_ERROR_NOT_IMPLEMENTED
   *          If this is called on a non-Windows platform.
   */
  boolean getServiceRegKeyExists();

  /**
  * Attempts to restart the application manually on program exit with the same
  * arguments it was started with, while accepting additional arguments.
  *
  * This function should only be called on Windows.
  *
  * @param    argvExtra
  *           An array of strings to be passed to the application upon
  *           restart as additional arguments.
  * @returns  pidRet
  *           Returns the pid of a newly spawned child process. This value
  *           is only valid if the function returns successfully.
  * @throws   NS_ERROR_ABORT
  *           If the child process failed to spawn correctly.
  * @throws   NS_ERROR_NOT_IMPLEMENTED
  *           If this is called on a non-Windows platform.
  * @throws   NS_ERROR_NOT_AVAILABLE
  *           If the command line cannot be read.
  */
  long attemptAutomaticApplicationRestartWithLaunchArgs(in Array<AString> argvExtra);

  /**
  *   This function is meant to be used in conjunction with
  *   RegisterApplicationRestartWithLaunchArgs() if you want the child process
  *   that invokes this function to wait for the parent process
  *   to finish execution. When the application has the argument
  *   -restart-pid <pid> this function waits for the application with
  *   <pid> to exit.
  *
  * This function should only be called on Windows.
  *
  *   @param   pid
  *            Which process ID to wait for.
  *   @param   timeoutMS
  *            How long to wait for the process to exit in milliseconds.
  *   @throws  NS_OK
  *            On successful wait.
  *   @throws  NS_ERROR_NOT_IMPLEMENTED
  *            If this is called on a non-Windows platform.
  *   @throws  NS_ERROR_INVALID_ARG
  *            If -restart-pid has no pid parameter.
  *   @throws  NS_ERROR_ILLEGAL_VALUE
  *            If pid cannot be converted into unsigned int.
  *   @throws  NS_ERROR_FAILURE
  *            If timeout elapses without process exit.
  */
  void waitForProcessExit(in unsigned long pid, in unsigned long timeoutMS);
};

/**
 * Upon creation, which should happen early during startup, the sync manager
 * creates/opens and locks a file. All other running instances of the same
 * installation of the app also open the same lock, so we can use it to
 * determine whether any other instance is running. If so, we'll temporarily
 * hold off on performing update tasks until there are no other instances or
 * until a timeout expires, whichever comes first. That way we can avoid
 * updating behind the back of copies that are still running, so we don't force
 * all running instances to restart (see bug 1366808, where an error was added
 * informing the user of the need to restart any running instances that have
 * been updated).
 */
[scriptable, uuid(cf4c4487-66d9-4e18-a2e9-39002245332f)]
interface nsIUpdateSyncManager : nsISupports
{
  /**
   * Returns whether another instance of this application is running.
   * @returns true if another instance has the lock open, false if not
   */
  boolean isOtherInstanceRunning();

  /**
   * Should only be used for testing.
   *
   * Closes and reopens the lock file, possibly under a different name if a
   * parameter is given (or the path hash has changed, which should only happen
   * if a test is forcing it).
   */
  void resetLock([optional] in nsIFile anAppFile);
};

/**
  * An object interface suitable for acquiring the update mutex for the current
  * installation path.
  *
  * The update mutex gives protection against 2 instances running from the same
  * installation path updating at the same time:
  * 1) By running multiple profiles from the same installation path.
  * 2) By running in 2 different user sessions from the same installation path.
  *
  * nsIUpdateMutex objects do not hold the update mutex when they are created:
  * acquiring the update mutex requires an explicit call to tryLock().
  *
  * The update mutex is automatically released if the application instance
  * holding it dies. This is guaranteed by the primitives that are used under
  * the hood by nsIUpdateMutex objects.
  *
  * nsIUpdateMutex objects are independent of one another. If acquisition is
  * successful through one object, any attempt to acquire the update mutex
  * through another object will fail, until the update mutex is released
  * through the first object or the instance where the object lives dies. This
  * applies even if both objects live in the same instance.
  */
[scriptable, uuid(dbfa19d2-f3d3-4354-a992-e99f75c22c4a)]
interface nsIUpdateMutex : nsISupports
{
  /**
   * Checks the current acquisition status for the current object.
   *
   * @returns true if the update mutex for the current installation is being
   *               held by the current instance through the current object.
   */
  boolean isLocked();

  /**
   * Attempts to acquire the update mutex for the current installation path.
   *
   * @returns true if the update mutex was successfully acquired or was already
   *          held by the current instance through the current object.
   */
  boolean tryLock();

  /**
   * Manually releases the update mutex for the current installation path. Does
   * nothing if the update mutex is not being held by the current instance
   * through the current object.
   */
  void unlock();
};

/**
 * An interface into the internals of the update manager. These should only be
 * accessed from within update code and tests.
 */
[scriptable, uuid(a5739dda-b94f-47e1-a6f3-224d46d6cb8c)]
interface nsIUpdateManagerInternal : nsISupports
{
  /**
   * Reloads the update manager's data.
   * @param skipFiles
   *        If `true`, don't reload data from the XMLs, just clear out existing
   *        data.
   *
   * @returns Promise<undefined>
   */
  Promise reload(in boolean skipFiles);

  /**
   * These are identical to the functions with the same name in
   * `nsIUpdateManager`, but these versions do not ensure the update system has
   * been initialized before being called.
   */
  Array<nsIUpdate> getHistory();
  void addUpdateToHistory(in nsIUpdate update);
  // Corresponds to `nsIUpdateManager.getReadyUpdate()`, but also provides
  // write access.
  attribute nsIUpdate readyUpdate;
  // Corresponds to `nsIUpdateManager.getDownloadingUpdate()`, but also provides
  // write access.
  attribute nsIUpdate downloadingUpdate;
  Promise refreshUpdateStatus();
};

/**
 * An interface describing a global application service that maintains a list
 * of updates previously performed as well as the current active update.
 */
[scriptable, uuid(0f1098e9-a447-4af9-b030-6f8f35c85f89)]
interface nsIUpdateManager : nsISupports
{
  /**
   * @returns Promise<Array<nsIUpdate>>
   *          Resolves with an array describing the update history. The first
   *          element in the array represents the most recent item in the
   *          history.
   */
  Promise getHistory();

  /**
   * Returns a Promise that resolves with the nsIUpdate that has been
   * downloaded, or null if there isn't one.
   */
  Promise getReadyUpdate();

  /**
   * Returns a Promise that resolves with the nsIUpdate that is currently
   * downloading, or null if there isn't one.
   * An update is no longer considered to be downloading once onStopRequest is
   * called. This means that both onStopRequest handlers for download listeners
   * and observers of the "update-downloaded" topic should expect the update
   * that was just downloaded to be stored in readyUpdate, not
   * downloadingUpdate.
   */
  Promise getDownloadingUpdate();

  /**
   * Returns a Promise that resolves with the update that Firefox installed at the
   * launch of the current session. If no update was installed, null will be returned
   * @returns Promise<nsIUpdate>
   */
  Promise updateInstalledAtStartup();

  /**
   * Returns a Promise that resolves with the most recent update that has been installed,
   * the value will be null if it does not exist
   * @returns Promise<nsIUpdate>
   */
  Promise lastUpdateInstalled();

  /**
   * Adds the specified update to the update history. The update history is
   * limited to 10 items, so this may also remove the last item from the
   * history.
   * @param update
   *        The update to add to the history.
   * @returns Promise<undefined>
   */
  Promise addUpdateToHistory(in nsIUpdate update);

  /**
   * Saves all updates to disk.
   */
  void saveUpdates();

  /**
   * Refresh the update status based on the information in update.status.
   *
   * @returns A Promise that resolves after the update status is refreshed.
   */
  Promise refreshUpdateStatus();

  /**
   * The user agreed to proceed with an elevated update and we are now
   * permitted to show an elevation prompt.
   *
   * @returns Promise<undefined>
   */
  Promise elevationOptedIn();

  /**
   * These functions clean up and remove an active update without applying
   * it. The first function does this for the update that is currently being
   * downloaded. The second function does this for the update that has already
   * been downloaded. The third function does this for both updates.
   * @returns Promise<undefined>
   */
  Promise cleanupDownloadingUpdate();
  Promise cleanupReadyUpdate();
  Promise cleanupActiveUpdates();

  /**
   * Runs cleanup that ought to happen on a Firefox paveover install to
   * prevent a stale update from being processed when Firefox is first
   * launched.
   * This is best-effort. It will not throw on cleanup failure.
   *
   * The returned promise does not resolve with any particular value. It simply
   * conveys that the cleanup has completed.
   */
  Promise doInstallCleanup();

  /**
   * Runs cleanup that ought to happen when Firefox is uninstalled to clean up
   * old update data that is no longer needed.
   * This is best-effort. It will not throw on cleanup failure.
   *
   * The returned promise does not resolve with any particular value. It simply
   * conveys that the cleanup has completed.
   */
  Promise doUninstallCleanup();

  /**
   * See nsIUpdateManagerInternal for details.
   */
  readonly attribute nsIUpdateManagerInternal internal;
};

/**
 * A lightweight interface that we can load early in startup that gives us very
 * limited access to the update system without the startup costs of loading
 * nsIApplicationUpdateService.
 */
[scriptable, uuid(3ca17ada-8501-496f-bbe7-6a9f1c28eb2d)]
interface nsIApplicationUpdateServiceStub : nsISupports
{
  /**
   * This does the standard initialization of the update service stub. The
   * primary effect of this is to initialize the update system (the same effect
   * as `initUpdate`), but only if there are updates from a previous browser
   * session. This allows us to avoid loading the update system so early if it
   * would just be sitting idle until the update timer fires or the user visits
   * the update UI.
   *
   * @returns Promise<undefined>
   */
  Promise init();

  /**
   * This is identical to `nsIApplicationUpdateService.init()`.
   *
   * @returns Promise<undefined>
   */
  Promise initUpdate();

  /**
   * This is identical to `nsIApplicationUpdateService.disabled`.
   */
  readonly attribute boolean updateDisabled;

  /**
   * This will be `true` if update is disabled specifically because we are
   * running a test that didn't opt-in to updating.
   */
  readonly attribute boolean updateDisabledForTesting;
};
