Bug 708854 - No longer use session ID for work item files. r=rstrong.
authorBrian R. Bondy <netzen@gmail.com>
Wed, 04 Jan 2012 23:19:15 -0500
changeset 84996 457620c55eec932472a2849011a0175050243006
parent 84995 d5637e69d71ed290e6a7d7892b486a657f2a98ed
child 84997 ee4def38eede8560ea1a183bfc7ac143e92781d9
push idunknown
push userunknown
push dateunknown
reviewersrstrong
bugs708854
milestone12.0a1
Bug 708854 - No longer use session ID for work item files. r=rstrong.
toolkit/components/maintenanceservice/Makefile.in
toolkit/components/maintenanceservice/servicebase.h
toolkit/components/maintenanceservice/workmonitor.cpp
toolkit/mozapps/update/common/Makefile.in
toolkit/mozapps/update/common/launchwinprocess.cpp
toolkit/mozapps/update/common/launchwinprocess.h
toolkit/mozapps/update/common/updatehelper.cpp
toolkit/mozapps/update/common/updatehelper.h
toolkit/mozapps/update/nsUpdateService.js
toolkit/mozapps/update/updater/updater.cpp
toolkit/xre/nsAppRunner.h
toolkit/xre/nsUpdateDriver.cpp
toolkit/xre/nsWindowsRestart.cpp
--- a/toolkit/components/maintenanceservice/Makefile.in
+++ b/toolkit/components/maintenanceservice/Makefile.in
@@ -48,18 +48,17 @@ CPPSRCS = \
   workmonitor.cpp \
   certificatecheck.cpp \
   servicebase.cpp \
   registrycertificates.cpp \
   pathhash.cpp \
   $(NULL)
 
 # For debugging purposes only
-#DEFINES += -DDISABLE_SERVICE_AUTHENTICODE_CHECK \
-#  -DDISABLE_CALLBACK_AUTHENTICODE_CHECK
+#DEFINES += -DDISABLE_UPDATER_AUTHENTICODE_CHECK
 
 PROGRAM = maintenanceservice$(BIN_SUFFIX)
 DIST_PROGRAM = maintenanceservice$(BIN_SUFFIX)
 
 # Don't link the maintenanceservice against libmozutils. See bug 687139
 MOZ_UTILS_LDFLAGS =
 MOZ_UTILS_PROGRAM_LDFLAGS =
 
--- a/toolkit/components/maintenanceservice/servicebase.h
+++ b/toolkit/components/maintenanceservice/servicebase.h
@@ -34,10 +34,8 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <windows.h>
 #include "updatelogging.h"
 
 BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra);
-
-#define SERVICE_EVENT_NAME L"Global\\moz-5b780de9-065b-4341-a04f-ddd94b3723e5"
--- a/toolkit/components/maintenanceservice/workmonitor.cpp
+++ b/toolkit/components/maintenanceservice/workmonitor.cpp
@@ -48,82 +48,62 @@
 #include "nsWindowsHelpers.h"
 #include "nsAutoPtr.h"
 
 #include "workmonitor.h"
 #include "serviceinstall.h"
 #include "servicebase.h"
 #include "registrycertificates.h"
 #include "uachelper.h"
-#include "launchwinprocess.h"
+#include "updatehelper.h"
 
 extern BOOL gServiceStopping;
 
 // Wait 15 minutes for an update operation to run at most.
 // Updates usually take less than a minute so this seems like a 
 // significantly large and safe amount of time to wait.
 static const int TIME_TO_WAIT_ON_UPDATER = 15 * 60 * 1000;
 PRUnichar* MakeCommandLine(int argc, PRUnichar **argv);
 BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode);
-BOOL WriteStatusPending(LPCWSTR updateDirPath);
-BOOL StartCallbackApp(int argcTmp, LPWSTR *argvTmp, DWORD callbackSessionID);
 BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer,  LPCWSTR siblingFilePath, 
                             LPCWSTR newFileName);
 
 // The error codes start from 16000 since Windows system error 
 // codes only go up to 15999
 const int SERVICE_UPDATER_COULD_NOT_BE_STARTED = 16000;
 const int SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS = 16001;
 const int SERVICE_UPDATER_SIGN_ERROR = 16002;
-const int SERVICE_CALLBACK_SIGN_ERROR = 16003;
 
 /**
- * Runs an update process in the specified sessionID as an elevated process.
+ * Runs an update process as the service using the SYSTEM account.
  *
- * @param  updaterPath   The path to the update process to start.
- * @param  workingDir    The working directory to execute the update process
- * @param  cmdLine       in. The command line parameters to pass to the update
- *                       process. If they specify a callback application, it
- *                       will be executed with an associated unelevated token 
- *                       for the sessionID.
- * @param processStarted Returns TRUE if the process was started.
- * @param  callbackSessionID 
- *                       If 0 and Windows Vista, the callback application will
- *                       not be run.  If non zero the callback application will
- *                       be injected into the user's session as a non-elevated 
- *                       process.
+ * @param  updaterPath    The path to the update process to start.
+ * @param  workingDir     The working directory to execute the update process in
+ * @param  cmdLine        The command line parameters to pass to updater.exe
+ * @param  processStarted Set to TRUE if the process was started.
  * @return TRUE if the update process was run had a return code of 0.
  */
 BOOL
 StartUpdateProcess(LPCWSTR updaterPath, 
                    LPCWSTR workingDir, 
                    int argcTmp,
                    LPWSTR *argvTmp,
-                   BOOL &processStarted,
-                   DWORD callbackSessionID = 0)
+                   BOOL &processStarted)
 {
-  DWORD myProcessID = GetCurrentProcessId();
-  DWORD mySessionID = 0;
-  ProcessIdToSessionId(myProcessID, &mySessionID);
-
   STARTUPINFO si = {0};
   si.cb = sizeof(STARTUPINFO);
   si.lpDesktop = L"winsta0\\Default";
   PROCESS_INFORMATION pi = {0};
 
-  LOG(("Starting process in an elevated session.  Service "
-       "session ID: %d; Requested callback session ID: %d\n", 
-       mySessionID, callbackSessionID));
+  LOG(("Starting update process as the service in session 0."));
 
   // The updater command line is of the form:
   // updater.exe update-dir apply [wait-pid [callback-dir callback-path args]]
   // So update callback-dir is the 4th, callback-path is the 5th and its args 
-  // are the 6th index.  So that we can execute the callback out of line we
-  // won't call updater.exe with those callback args and we will manage the
-  // callback ourselves.
+  // are the 6th index.
   LPWSTR cmdLine = MakeCommandLine(argcTmp, argvTmp);
 
   // If we're about to start the update process from session 0,
   // then we should not show a GUI.  This only really needs to be done
   // on Vista and higher, but it's better to keep everything consistent
   // across all OS if it's of no harm.
   if (argcTmp >= 2 ) {
     // Setting the desktop to blank will ensure no GUI is displayed
@@ -144,28 +124,30 @@ StartUpdateProcess(LPCWSTR updaterPath,
   // We use the updater.ini from the same directory as the updater.exe
   // because of background updates.
   if (PathGetSiblingFilePath(updaterINI, argvTmp[0], L"updater.ini") &&
       PathGetSiblingFilePath(updaterINITemp, argvTmp[0], L"updater.tmp")) {
     selfHandlePostUpdate = MoveFileEx(updaterINI, updaterINITemp, 
                                       MOVEFILE_REPLACE_EXISTING);
   }
 
-  // Create an environment block for the process we're about to start using
-  // the user's token.
+  // Create an environment block for the updater.exe process we're about to 
+  // start.  Indicate that MOZ_USING_SERVICE is set so the updater.exe can
+  // do anything special that it needs to do for service updates.
+  // Search in updater.cpp for more info on MOZ_USING_SERVICE.
   WCHAR envVarString[32];
-  wsprintf(envVarString, L"MOZ_SESSION_ID=%d", callbackSessionID); 
+  wsprintf(envVarString, L"MOZ_USING_SERVICE=1"); 
   _wputenv(envVarString);
   LPVOID environmentBlock = NULL;
   if (!CreateEnvironmentBlock(&environmentBlock, NULL, TRUE)) {
     LOG(("Could not create an environment block, setting it to NULL.\n"));
     environmentBlock = NULL;
   }
   // Empty value on _wputenv is how you remove an env variable in Windows
-  _wputenv(L"MOZ_SESSION_ID=");
+  _wputenv(L"MOZ_USING_SERVICE=");
   processStarted = CreateProcessW(updaterPath, cmdLine, 
                                   NULL, NULL, FALSE, 
                                   CREATE_DEFAULT_ERROR_MODE | 
                                   CREATE_UNICODE_ENVIRONMENT, 
                                   environmentBlock, 
                                   workingDir, &si, &pi);
   if (environmentBlock) {
     DestroyEnvironmentBlock(environmentBlock);
@@ -205,25 +187,26 @@ StartUpdateProcess(LPCWSTR updaterPath,
   if (selfHandlePostUpdate) {
     MoveFileEx(updaterINITemp, updaterINI, MOVEFILE_REPLACE_EXISTING);
 
     // Only run the PostUpdate if the update was successful and if we have
     // a callback application.  This is the same thing updater.exe does.
     if (updateWasSuccessful && argcTmp > 5) {
       LPCWSTR callbackApplication = argvTmp[5];
       LPCWSTR updateInfoDir = argvTmp[1];
-      // Launch the PostUpdate process with SYSTEM in session 0. We force sync
-      // because we run this twice and we want to make sure the uninstaller
-      // keys get added to HKLM before the ones try to get added to HKCU.  If
-      // we did it async we'd have a race condition that would sometimes lead
-      // to 2 uninstall icons.
+
+      // Launch the PostProcess with admin access in session 0.  This is
+      // actually launching the post update process but it takes in the 
+      // callback app path to figure out where to apply to.
+      // The PostUpdate process with user only access will be done inside
+      // the unelevated updater.exe after the update process is complete
+      // from the service.  We don't know here which session to start
+      // the user PostUpdate process from.
+      LOG(("Launching post update process as the service in session 0."));
       LaunchWinPostProcess(callbackApplication, updateInfoDir, true, NULL);
-      nsAutoHandle userToken(UACHelper::OpenUserToken(callbackSessionID));
-      LaunchWinPostProcess(callbackApplication, 
-                           updateInfoDir, false, userToken);
     }
   }
 
   free(cmdLine);
   return updateWasSuccessful;
 }
 
 /**
@@ -251,73 +234,70 @@ ProcessWorkItem(LPCWSTR monitoringBasePa
                       notifyInfo.FileName[filenameLength - 2] == L'm' &&
                       notifyInfo.FileName[filenameLength - 1] == L'z';
   if (!haveWorkItem) {
     // We don't have a work item, keep looking
     return FALSE;
   }
 
   // Indicate that the service is busy and shouldn't be used by anyone else
-  // by creating a named event.  Programs should check if this event exists 
-  // before writing a work item out.
-  nsAutoHandle serviceRunning(CreateEventW(NULL, TRUE, 
-                                           FALSE, SERVICE_EVENT_NAME));
+  // by opening or creating a named event.  Programs should check if this 
+  // event exists before writing a work item out.  It should already be
+  // created by updater.exe so CreateEventW will lead to an open named event.
+  nsAutoHandle serviceRunningEvent(CreateEventW(NULL, TRUE, 
+                                                FALSE, SERVICE_EVENT_NAME));
 
   LOG(("Processing new command meta file: %ls\n", notifyInfo.FileName));
   WCHAR fullMetaUpdateFilePath[MAX_PATH + 1];
   wcscpy(fullMetaUpdateFilePath, monitoringBasePath);
 
   // We only support file paths in monitoring directories that are MAX_PATH
   // chars or less.
   if (!PathAppendSafe(fullMetaUpdateFilePath, notifyInfo.FileName)) {
-    // Cannot process update, skipfileSize it.
+    SetEvent(serviceRunningEvent);
     return TRUE;
   }
 
   nsAutoHandle metaUpdateFile(CreateFile(fullMetaUpdateFilePath, 
                                          GENERIC_READ, 
                                          FILE_SHARE_READ | 
                                          FILE_SHARE_WRITE | 
                                          FILE_SHARE_DELETE, 
                                          NULL, 
                                          OPEN_EXISTING,
                                          0, NULL));
   if (metaUpdateFile == INVALID_HANDLE_VALUE) {
     LOG(("Could not open command meta file: %ls\n", notifyInfo.FileName));
+    SetEvent(serviceRunningEvent);
     return TRUE;
   }
 
   DWORD fileSize = GetFileSize(metaUpdateFile, NULL);
-  DWORD sessionID = 0, commandID = 0;
+  DWORD commandID = 0;
   // The file should be in wide characters so if it's of odd size it's
   // an invalid file.
   const int kSanityCheckFileSize = 1024 * 64;
   if (fileSize == INVALID_FILE_SIZE || 
       (fileSize %2) != 0 ||
       fileSize > kSanityCheckFileSize ||
       fileSize < sizeof(DWORD)) {
     LOG(("Could not obtain file size or an improper file size was encountered "
          "for command meta file: %ls\n", 
         notifyInfo.FileName));
+    SetEvent(serviceRunningEvent);
     return TRUE;
   }
 
   // The first 4 bytes are for the command ID.
   // Currently only command ID 1 which is for updates is supported.
   DWORD commandIDCount;
   BOOL result = ReadFile(metaUpdateFile, &commandID, 
                          sizeof(DWORD), &commandIDCount, NULL);
   fileSize -= sizeof(DWORD);
 
-  // The next 4 bytes are for the process ID
-  DWORD sessionIDCount;
-  result |= ReadFile(metaUpdateFile, &sessionID, 
-                     sizeof(DWORD), &sessionIDCount, NULL);
-  fileSize -= sizeof(DWORD);
-
   // The next MAX_PATH wchar's are for the app to start
   WCHAR updaterPath[MAX_PATH + 1];
   ZeroMemory(updaterPath, sizeof(updaterPath));
   DWORD updaterPathCount;
   result |= ReadFile(metaUpdateFile, updaterPath, 
                      MAX_PATH * sizeof(WCHAR), &updaterPathCount, NULL);
   fileSize -= updaterPathCount;
 
@@ -341,131 +321,94 @@ ProcessWorkItem(LPCWSTR monitoringBasePa
   if (!DeleteFileW(fullMetaUpdateFilePath)) {
     LOG(("Could not delete work item file: %ls. (%d)\n", 
          fullMetaUpdateFilePath, GetLastError()));
   }
 
   if (!result ||
       commandID != 1 ||
       commandIDCount != sizeof(DWORD) ||
-      sessionIDCount != sizeof(DWORD) ||
       updaterPathCount != MAX_PATH * sizeof(WCHAR) ||
       workingDirectoryCount != MAX_PATH * sizeof(WCHAR) ||
       fileSize != 0) {
     LOG(("Could not read command data for command meta file: %ls\n", 
          notifyInfo.FileName));
+    SetEvent(serviceRunningEvent);
     return TRUE;
   }
   cmdlineBuffer[cmdLineBufferRead] = '\0';
   cmdlineBuffer[cmdLineBufferRead + 1] = '\0';
   WCHAR *cmdlineBufferWide = reinterpret_cast<WCHAR*>(cmdlineBuffer.get());
   LOG(("An update command was detected and is being processed for command meta "
-       "file: %ls\n", 
-      notifyInfo.FileName));
+       "file: %ls\n", notifyInfo.FileName));
 
   int argcTmp = 0;
   LPWSTR* argvTmp = CommandLineToArgvW(cmdlineBufferWide, &argcTmp);
 
-  // Check for callback application sign problems
-  BOOL callbackSignProblem = FALSE;
-#ifndef DISABLE_CALLBACK_AUTHENTICODE_CHECK
-  // If we have less than 6 params, then there is no callback to check, so
-  // we have no callback sign problem.
-  if (argcTmp > 5) {
-    LPWSTR callbackApplication = argvTmp[5];
-    callbackSignProblem = 
-      !DoesBinaryMatchAllowedCertificates(argvTmp[2], callbackApplication);
-  }
-#endif
-
-    // Check for updater.exe sign problems
+  // Check for updater.exe sign problems
   BOOL updaterSignProblem = FALSE;
-#ifndef DISABLE_SERVICE_AUTHENTICODE_CHECK
+#ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK
   if (argcTmp > 2) {
     updaterSignProblem = !DoesBinaryMatchAllowedCertificates(argvTmp[2], 
                                                              updaterPath);
   }
 #endif
 
   // In order to proceed with the update we need at least 3 command line
   // parameters and no sign problems.
-  if (argcTmp > 2 && !updaterSignProblem && !callbackSignProblem) {
+  if (argcTmp > 2 && !updaterSignProblem) {
     BOOL updateProcessWasStarted = FALSE;
     if (StartUpdateProcess(updaterPath, workingDirectory, 
                            argcTmp, argvTmp,
-                           updateProcessWasStarted,
-                           sessionID)) {
+                           updateProcessWasStarted)) {
       LOG(("updater.exe was launched and run successfully!\n"));
       StartServiceUpdate(argcTmp, argvTmp);
     } else {
-      LOG(("Error running process in session %d.  "
-           "Updating update.status.  Last error: %d\n",
-           sessionID, GetLastError()));
+      LOG(("Error running update process. Updating update.status"
+           " Last error: %d\n", GetLastError()));
 
       // If the update process was started, then updater.exe is responsible for
-      // setting the failure code and running the callback.  If it could not 
-      // be started then we do the work.  We set an error instead of directly
-      // setting status pending so that the app.update.service.errors
-      // pref can be updated when the callback app restarts.
+      // setting the failure code.  If it could not be started then we do the 
+      // work.  We set an error instead of directly setting status pending 
+      // so that the app.update.service.errors pref can be updated when 
+      // the callback app restarts.
       if (!updateProcessWasStarted) {
         if (!WriteStatusFailure(argvTmp[1], 
                                 SERVICE_UPDATER_COULD_NOT_BE_STARTED)) {
           LOG(("Could not write update.status service update failure."
                "Last error: %d\n", GetLastError()));
         }
-
-        // We only hit this condition when there is no callback sign error
-        // so we don't need to check it.
-        StartCallbackApp(argcTmp, argvTmp, sessionID);
       }
     }
   } else if (argcTmp <= 2) {
     LOG(("Not enough command line parameters specified. "
          "Updating update.status.\n"));
 
-    // We can't start the callback in this case because there
-    // are not enough command line parameters. We set an error instead of
-    // directly setting status pending so that the app.update.service.errors
-    // pref can be updated when the callback app restarts.
+    // We can only update update.status if argvTmp[1] exists.  argvTmp[1] is
+    // the directory where the update.status file exists.
     if (argcTmp != 2 || 
         !WriteStatusFailure(argvTmp[1], 
                             SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS)) {
       LOG(("Could not write update.status service update failure."
            "Last error: %d\n", GetLastError()));
     }
-  } else if (callbackSignProblem) {
-    LOG(("Will not run updater nor callback due to callback sign error "
-         "in session %d. Updating update.status.  Last error: %d\n",
-         sessionID, GetLastError()));
-
-    // When there is a certificate check error on the callback application, we
-    // want to write out the error.
-    if (!WriteStatusFailure(argvTmp[1], 
-                            SERVICE_CALLBACK_SIGN_ERROR)) {
-      LOG(("Could not write pending state to update.status.  (%d)\n", 
-           GetLastError()));
-    }
   } else {
     LOG(("Could not start process due to certificate check error on "
          "updater.exe. Updating update.status.  Last error: %d\n", GetLastError()));
 
     // When there is a certificate check error on the updater.exe application,
     // we want to write out the error.
     if (!WriteStatusFailure(argvTmp[1], 
                             SERVICE_UPDATER_SIGN_ERROR)) {
       LOG(("Could not write pending state to update.status.  (%d)\n", 
            GetLastError()));
     }
-
-    // On certificate check errors on updater.exe, updater.exe won't run at all
-    // so we need to manually start the callback application ourselves.
-    // This condition will only be hit when the callback app has no sign errors
-    StartCallbackApp(argcTmp, argvTmp, sessionID);
   }
   LocalFree(argvTmp);
+  SetEvent(serviceRunningEvent);
 
   // We processed a work item, whether or not it was successful.
   return TRUE;
 }
 
 /**
  * Starts monitoring the update directory for work items.
  *
@@ -539,109 +482,8 @@ StartDirectoryChangeMonitor()
       if (0 == notifyInfo.NextEntryOffset) {
         break;
       }
     }
   }
 
   return TRUE;
 }
-
-/**
- * Starts the callback application from the updater.exe command line arguments.
- *
- * @param  argcTmp           The argc value normally sent to updater.exe
- * @param  argvTmp           The argv value normally sent to updater.exe
- * @param  callbackSessionID The session ID to start the callback with
- * @return TRUE if successful
- */
-BOOL
-StartCallbackApp(int argcTmp, LPWSTR *argvTmp, DWORD callbackSessionID) 
-{
-  if (0 == callbackSessionID  && UACHelper::IsVistaOrLater()) {
-    LOG(("Attempted to run callback application in session 0, not allowed.\n"));
-    LOG(("Session 0 is only for services on Vista and up.\n"));
-    return FALSE;
-  }
-
-  if (argcTmp < 5) {
-    LOG(("No callback application specified.\n"));
-    return FALSE;
-  }
-
-  LPWSTR callbackArgs = NULL;
-  LPWSTR callbackDirectory = argvTmp[4];
-  LPWSTR callbackApplication = argvTmp[5];
-  if (argcTmp > 6) {
-    // Make room for all of the ending args minus the first 6 
-    // + 1 for the app itself
-    const size_t callbackCommandLineLen = argcTmp - 5;
-    WCHAR **params = new WCHAR*[callbackCommandLineLen];
-    params[0] = callbackApplication;
-    for (size_t i = 1; i < callbackCommandLineLen; ++i) {
-      params[i] = argvTmp[5 + i];
-    }
-    callbackArgs = MakeCommandLine(callbackCommandLineLen, params);
-    delete[] params;
-  }
-
-  if (!callbackApplication) {
-    LOG(("Callback application is NULL.\n"));
-    if (callbackArgs) {
-      free(callbackArgs);
-    }
-    return FALSE;
-  }
-
-  nsAutoHandle unelevatedToken(UACHelper::OpenUserToken(callbackSessionID));
-  if (!unelevatedToken) {
-    LOG(("Could not obtain unelevated token for callback app.\n"));
-    if (callbackArgs) {
-      free(callbackArgs);
-    }
-    return FALSE;
-  }
-
-  // Create an environment block for the process we're about to start using
-  // the user's token.
-  LPVOID environmentBlock = NULL;
-  if (!CreateEnvironmentBlock(&environmentBlock, unelevatedToken, TRUE)) {
-    LOG(("Could not create an environment block, setting it to NULL.\n"));
-    environmentBlock = NULL;
-  }
-
-  STARTUPINFOW si = {0};
-  si.cb = sizeof(STARTUPINFOW);
-  si.lpDesktop = L"winsta0\\Default";
-  PROCESS_INFORMATION pi = {0};
-  if (CreateProcessAsUserW(unelevatedToken, 
-                            callbackApplication, 
-                            callbackArgs, 
-                            NULL, NULL, FALSE,
-                            CREATE_DEFAULT_ERROR_MODE |
-#ifdef DEBUG
-                            CREATE_NEW_CONSOLE |
-#endif
-                            CREATE_UNICODE_ENVIRONMENT,
-                            environmentBlock, 
-                            callbackDirectory, 
-                            &si, &pi)) {
-    LOG(("Callback app was run successfully.\n"));
-    CloseHandle(pi.hProcess);
-    CloseHandle(pi.hThread);
-    if (environmentBlock) {
-      DestroyEnvironmentBlock(environmentBlock);
-    }
-    if (callbackArgs) {
-      free(callbackArgs);
-    }
-    return TRUE;
-  } 
-  
-  LOG(("Could not run callback app, last error: %d", GetLastError()));
-  if (environmentBlock) {
-    DestroyEnvironmentBlock(environmentBlock);
-  }
-  if (callbackArgs) {
-    free(callbackArgs);
-  }
-  return FALSE;
-}
--- a/toolkit/mozapps/update/common/Makefile.in
+++ b/toolkit/mozapps/update/common/Makefile.in
@@ -54,19 +54,19 @@ CPPSRCS = \
   updatelogging.cpp \
   $(NULL)
 
 EXPORTS = updatelogging.h \
   updatedefines.h \
   $(NULL)
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
-CPPSRCS += launchwinprocess.cpp \
+CPPSRCS += updatehelper.cpp \
   uachelper.cpp \
   $(NULL)
 
-EXPORTS = launchwinprocess.h \
+EXPORTS = updatehelper.h \
   uachelper.h \
   $(NULL)
 endif
 
 include $(topsrcdir)/config/rules.mk
 
rename from toolkit/mozapps/update/common/launchwinprocess.cpp
rename to toolkit/mozapps/update/common/updatehelper.cpp
--- a/toolkit/mozapps/update/common/launchwinprocess.cpp
+++ b/toolkit/mozapps/update/common/updatehelper.cpp
@@ -31,20 +31,54 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <windows.h>
+#include <stdio.h>
+#include "shlobj.h"
+
+// Needed for PathAppendW
 #include <shlwapi.h>
+#pragma comment(lib, "shlwapi.lib") 
 
+WCHAR*
+MakeCommandLine(int argc, WCHAR **argv);
 BOOL PathAppendSafe(LPWSTR base, LPCWSTR extra);
 
+/**
+ * Obtains the directory path to store work item files.
+ * 
+ * @param  path The buffer of size MAX_PATH to store the update directory to
+ * @return TRUE if the path was obtained successfully.
+*/
+BOOL
+GetUpdateDirectoryPath(LPWSTR path) 
+{
+  HRESULT hr = SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 
+                                SHGFP_TYPE_CURRENT, path);
+  if (FAILED(hr)) {
+    return FALSE;
+  }
+  if (!PathAppendSafe(path, L"Mozilla")) {
+    return FALSE;
+  }
+  // The directory should already be created from the installer, but
+  // just to be safe in case someone deletes.
+  CreateDirectoryW(path, NULL);
+
+  if (!PathAppendSafe(path, L"updates")) {
+    return FALSE;
+  }
+  CreateDirectoryW(path, NULL);
+  return TRUE;
+}
 
 /**
  * Obtains the path of a file in the same directory as the specified file.
  *
  * @param  destinationBuffer A buffer of size MAX_PATH + 1 to store the result.
  * @param  siblingFIlePath   The path of another file in the same directory
  * @param  newFileName       The filename of another file in the same directory
  * @return TRUE if successful
@@ -77,16 +111,17 @@ PathGetSiblingFilePath(LPWSTR destinatio
  * account and the current user account.
  *
  * @param  appExe        The path to the callback application binary.
  * @param  updateInfoDir The directory where update info is stored.
  * @param  forceSync     If true even if the ini file specifies async, the
  *                       process will wait for termination of PostUpdate.
  * @param  userToken     The user token to run as, if NULL the current user
  *                       will be used.
+ * @return TRUE if there was no error starting the process.
  */
 BOOL
 LaunchWinPostProcess(const WCHAR *appExe,
                      const WCHAR *updateInfoDir,
                      bool forceSync,
                      HANDLE userToken)
 {
   WCHAR workingDirectory[MAX_PATH + 1];
@@ -107,23 +142,25 @@ LaunchWinPostProcess(const WCHAR *appExe
   WCHAR exeasync[10];
   bool async = true;
   if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeRelPath", NULL, exefile,
                                 MAX_PATH + 1, inifile)) {
     return FALSE;
   }
 
   if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeArg", NULL, exearg,
-                                MAX_PATH + 1, inifile))
+                                MAX_PATH + 1, inifile)) {
     return FALSE;
+  }
 
   if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeAsync", L"TRUE", 
                                 exeasync,
-                                sizeof(exeasync)/sizeof(exeasync[0]), inifile))
+                                sizeof(exeasync)/sizeof(exeasync[0]), inifile)) {
     return FALSE;
+  }
 
   WCHAR exefullpath[MAX_PATH + 1];
   if (!PathGetSiblingFilePath(exefullpath, appExe, exefile)) {
     return FALSE;
   }
 
   WCHAR dlogFile[MAX_PATH + 1];
   if (!PathGetSiblingFilePath(dlogFile, exefullpath, L"uninstall.update")) {
@@ -252,8 +289,265 @@ StartServiceUpdate(int argc, LPWSTR *arg
                                                 CREATE_UNICODE_ENVIRONMENT, 
                                                 NULL, argv[2], &si, &pi);
   if (svcUpdateProcessStarted) {
     CloseHandle(pi.hProcess);
     CloseHandle(pi.hThread);
   }
   return svcUpdateProcessStarted;
 }
+
+
+/**
+ * Determines if the maintenance service is running or not.
+ * 
+ * @return TRUE if the maintenance service is running.
+*/
+BOOL 
+EnsureWindowsServiceRunning() 
+{
+  // Get a handle to the SCM database.
+  SC_HANDLE serviceManager = OpenSCManager(NULL, NULL, 
+                                           SC_MANAGER_CONNECT | 
+                                           SC_MANAGER_ENUMERATE_SERVICE);
+  if (!serviceManager)  {
+    return FALSE;
+  }
+
+  // Get a handle to the service.
+  SC_HANDLE service = OpenServiceW(serviceManager, 
+                                   L"MozillaMaintenance", 
+                                   SERVICE_QUERY_STATUS | SERVICE_START);
+  if (!service) {
+    CloseServiceHandle(serviceManager);
+    return FALSE;
+  }
+
+  // Make sure the service is not stopped.
+  SERVICE_STATUS_PROCESS ssp;
+  DWORD bytesNeeded;
+  if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
+                            sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
+    CloseServiceHandle(service);
+    CloseServiceHandle(serviceManager);
+    return FALSE;
+  }
+
+  if (ssp.dwCurrentState == SERVICE_STOPPED) {
+    if (!StartService(service, 0, NULL)) {
+      CloseServiceHandle(service);
+      CloseServiceHandle(serviceManager);
+      return FALSE;
+    }
+
+    // Make sure we can get into a started state without waiting too long.
+    // This usually starts instantly but the extra code is just in case it
+    // takes longer.
+    DWORD totalWaitTime = 0;
+    static const int maxWaitTime = 1000 * 5; // Never wait more than 5 seconds
+    while (QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
+                                sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
+      if (ssp.dwCurrentState == SERVICE_RUNNING) {
+        break;
+      }
+      
+      if (ssp.dwCurrentState == SERVICE_START_PENDING &&
+          totalWaitTime > maxWaitTime) {
+        // We will probably eventually start, but we can't wait any longer.
+        break;
+      }
+      
+      if (ssp.dwCurrentState != SERVICE_START_PENDING) {
+        CloseServiceHandle(service);
+        CloseServiceHandle(serviceManager);
+        return FALSE;
+      }
+
+      Sleep(ssp.dwWaitHint);
+      // Increment by at least 10 milliseconds to ensure we always make 
+      // progress towards maxWaitTime in case dwWaitHint is 0.
+      totalWaitTime += (ssp.dwWaitHint + 10);
+    }
+  }
+
+  CloseServiceHandle(service);
+  CloseServiceHandle(serviceManager);
+  return ssp.dwCurrentState == SERVICE_RUNNING;
+}
+
+/**
+ * Launch a service initiated action with the specified arguments.
+ *
+ * @param  exePath The path of the executable to run
+ * @param  argc    The total number of arguments in argv
+ * @param  argv    An array of null terminated strings to pass to the exePath, 
+ *                 argv[0] is ignored
+ * @return TRUE if successful
+ */
+BOOL
+WinLaunchServiceCommand(LPCWSTR exePath, int argc, LPWSTR* argv)
+{
+  // Ensure the service is running, if not we should try to start it, if it is
+  // not in a running state we cannot execute a service command.
+  if (!EnsureWindowsServiceRunning()) {
+    return FALSE;
+  }
+
+  WCHAR updateData[MAX_PATH + 1];
+  if (!GetUpdateDirectoryPath(updateData)) {
+    return FALSE;
+  }
+
+  // Get a unique filename
+  WCHAR tempFilePath[MAX_PATH + 1];
+  const int USE_SYSTEM_TIME = 0;
+  if (!GetTempFileNameW(updateData, L"moz", USE_SYSTEM_TIME, tempFilePath)) {
+    return FALSE;
+  }
+  
+  const int FILE_SHARE_NONE = 0;
+  HANDLE updateMetaFile = CreateFileW(tempFilePath, GENERIC_WRITE, 
+                                      FILE_SHARE_NONE, NULL, CREATE_ALWAYS, 
+                                      0, NULL);
+  if (updateMetaFile == INVALID_HANDLE_VALUE) {
+    return FALSE;
+  }
+
+  // Write out the command ID.
+  // Command ID 1 is for an update work item file, which is the only supported
+  // command at this time.
+  DWORD commandID = 1, commandIDWrote;
+  BOOL result = WriteFile(updateMetaFile, &commandID, 
+                          sizeof(DWORD), 
+                          &commandIDWrote, NULL);
+
+  // Write out the command line arguments that are passed to updater.exe
+  WCHAR *commandLineBuffer = MakeCommandLine(argc, argv);
+  if (!commandLineBuffer) {
+    return FALSE;
+  }
+
+  WCHAR appBuffer[MAX_PATH + 1];
+  ZeroMemory(appBuffer, sizeof(appBuffer));
+  wcscpy(appBuffer, exePath);
+  DWORD appBufferWrote;
+  result |= WriteFile(updateMetaFile, appBuffer, 
+                      MAX_PATH * sizeof(WCHAR), 
+                      &appBufferWrote, NULL);
+
+  WCHAR workingDirectory[MAX_PATH + 1];
+  ZeroMemory(workingDirectory, sizeof(appBuffer));
+  GetCurrentDirectoryW(sizeof(workingDirectory) / sizeof(workingDirectory[0]), 
+                       workingDirectory);
+  DWORD workingDirectoryWrote;
+  result |= WriteFile(updateMetaFile, workingDirectory, 
+                      MAX_PATH * sizeof(WCHAR), 
+                      &workingDirectoryWrote, NULL);
+
+  DWORD commandLineLength = wcslen(commandLineBuffer) * sizeof(WCHAR);
+  DWORD commandLineWrote;
+  result |= WriteFile(updateMetaFile, commandLineBuffer, 
+                      commandLineLength, 
+                      &commandLineWrote, NULL);
+  free(commandLineBuffer);
+  if (!result ||
+      commandIDWrote != sizeof(DWORD) ||
+      appBufferWrote != MAX_PATH * sizeof(WCHAR) ||
+      workingDirectoryWrote != MAX_PATH * sizeof(WCHAR) ||
+      commandLineWrote != commandLineLength) {
+    CloseHandle(updateMetaFile);
+    DeleteFileW(tempFilePath);
+    return FALSE;
+  }
+
+  // Note we construct the 'service work' meta object with a .tmp extension,
+  // When we want the service to start processing it we simply rename it to
+  // have a .mz extension.  This ensures that the service will never try to
+  // process a partial update work meta file. 
+  CloseHandle(updateMetaFile);
+  WCHAR completedMetaFilePath[MAX_PATH + 1];
+  wcscpy(completedMetaFilePath, tempFilePath);
+
+  // Change the file extension of the temp file path from .tmp to .mz
+  LPWSTR extensionPart = 
+    &(completedMetaFilePath[wcslen(completedMetaFilePath) - 3]);
+  wcscpy(extensionPart, L"mz");
+  return MoveFileExW(tempFilePath, completedMetaFilePath, 
+                     MOVEFILE_REPLACE_EXISTING);
+}
+
+/**
+ * Joins a base directory path with a filename.
+ *
+ * @param  base  The base directory path of size MAX_PATH + 1
+ * @param  extra The filename to append
+ * @return TRUE if the file name was successful appended to base
+ */
+BOOL
+PathAppendSafe(LPWSTR base, LPCWSTR extra)
+{
+  if (wcslen(base) + wcslen(extra) >= MAX_PATH) {
+    return FALSE;
+  }
+
+  return PathAppendW(base, extra);
+}
+
+/**
+ * Sets update.status to pending so that the next startup will not use
+ * the service and instead will attempt an update the with a UAC prompt.
+ *
+ * @param  updateDirPath The path of the update directory
+ * @return TRUE if successful
+ */
+BOOL
+WriteStatusPending(LPCWSTR updateDirPath)
+{
+  WCHAR updateStatusFilePath[MAX_PATH + 1];
+  wcscpy(updateStatusFilePath, updateDirPath);
+  if (!PathAppendSafe(updateStatusFilePath, L"update.status")) {
+    return FALSE;
+  }
+
+  const char pending[] = "pending";
+  HANDLE statusFile = CreateFileW(updateStatusFilePath, GENERIC_WRITE, 0, 
+                                  NULL, CREATE_ALWAYS, 0, NULL);
+  if (statusFile == INVALID_HANDLE_VALUE) {
+    return FALSE;
+  }
+
+  DWORD wrote;
+  BOOL ok = WriteFile(statusFile, pending, 
+                      sizeof(pending) - 1, &wrote, NULL); 
+  CloseHandle(statusFile);
+  return ok && (wrote == sizeof(pending) - 1);
+}
+
+/**
+ * Sets update.status to a specific failure code
+ *
+ * @param  updateDirPath The path of the update directory
+ * @return TRUE if successful
+ */
+BOOL
+WriteStatusFailure(LPCWSTR updateDirPath, int errorCode) 
+{
+  WCHAR updateStatusFilePath[MAX_PATH + 1];
+  wcscpy(updateStatusFilePath, updateDirPath);
+  if (!PathAppendSafe(updateStatusFilePath, L"update.status")) {
+    return FALSE;
+  }
+
+  HANDLE statusFile = CreateFileW(updateStatusFilePath, GENERIC_WRITE, 0, 
+                                  NULL, CREATE_ALWAYS, 0, NULL);
+  if (statusFile == INVALID_HANDLE_VALUE) {
+    return FALSE;
+  }
+  char failure[32];
+  sprintf(failure, "failed: %d", errorCode);
+
+  DWORD toWrite = strlen(failure);
+  DWORD wrote;
+  BOOL ok = WriteFile(statusFile, failure, 
+                      toWrite, &wrote, NULL); 
+  CloseHandle(statusFile);
+  return ok && wrote == toWrite;
+}
rename from toolkit/mozapps/update/common/launchwinprocess.h
rename to toolkit/mozapps/update/common/updatehelper.h
--- a/toolkit/mozapps/update/common/launchwinprocess.h
+++ b/toolkit/mozapps/update/common/updatehelper.h
@@ -35,8 +35,13 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 BOOL LaunchWinPostProcess(const WCHAR *appExe, 
                           const WCHAR *updateInfoDir, 
                           bool forceSync,
                           HANDLE userToken);
 BOOL StartServiceUpdate(int argc, LPWSTR *argv);
+BOOL GetUpdateDirectoryPath(LPWSTR path);
+BOOL WinLaunchServiceCommand(LPCWSTR exePath, int argc, WCHAR **argv);
+BOOL WriteStatusFailure(LPCWSTR updateDirPath, int errorCode);
+BOOL WriteStatusPending(LPCWSTR updateDirPath);
+#define SERVICE_EVENT_NAME L"Global\\moz-5b780de9-065b-4341-a04f-ddd94b3723e5"
--- a/toolkit/mozapps/update/nsUpdateService.js
+++ b/toolkit/mozapps/update/nsUpdateService.js
@@ -141,17 +141,16 @@ const STATE_FAILED          = "failed";
 
 // From updater/errors.h:
 const WRITE_ERROR        = 7;
 const UNEXPECTED_ERROR   = 8;
 const ELEVATION_CANCELED = 9;
 const SERVICE_UPDATER_COULD_NOT_BE_STARTED = 16000;
 const SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS = 16001;
 const SERVICE_UPDATER_SIGN_ERROR           = 16002;
-const SERVICE_CALLBACK_SIGN_ERROR          = 16003;
 
 const CERT_ATTR_CHECK_FAILED_NO_UPDATE  = 100;
 const CERT_ATTR_CHECK_FAILED_HAS_UPDATE = 101;
 const BACKGROUNDCHECK_MULTIPLE_FAILURES = 110;
 
 const DOWNLOAD_CHUNK_SIZE           = 300000; // bytes
 const DOWNLOAD_BACKGROUND_INTERVAL  = 600;    // seconds
 const DOWNLOAD_FOREGROUND_INTERVAL  = 0;
@@ -1431,18 +1430,17 @@ UpdateService.prototype = {
 
         if (update.errorCode == ELEVATION_CANCELED) {
           writeStatusFile(getUpdatesDir(), update.state = STATE_PENDING);
           return;
         }
 
         if (update.errorCode == SERVICE_UPDATER_COULD_NOT_BE_STARTED ||
             update.errorCode == SERVICE_NOT_ENOUGH_COMMAND_LINE_ARGS ||
-            update.errorCode == SERVICE_UPDATER_SIGN_ERROR || 
-            update.errorCode == SERVICE_CALLBACK_SIGN_ERROR) {
+            update.errorCode == SERVICE_UPDATER_SIGN_ERROR) {
           var failCount = getPref("getIntPref", 
                                   PREF_APP_UPDATE_SERVICE_ERRORS, 0);
           var maxFail = getPref("getIntPref", 
                                 PREF_APP_UPDATE_SERVICE_MAX_ERRORS, 
                                 DEFAULT_SERVICE_MAX_ERRORS);
 
           // As a safety, when the service reaches maximum failures, it will
           // disable itself and fallback to using the normal update mechanism
--- a/toolkit/mozapps/update/updater/updater.cpp
+++ b/toolkit/mozapps/update/updater/updater.cpp
@@ -114,17 +114,17 @@ void LaunchMacPostProcess(const char* aA
 
 // We want to use execv to invoke the callback executable on platforms where
 // we were launched using execv.  See nsUpdateDriver.cpp.
 #if defined(XP_UNIX) && !defined(XP_MACOSX)
 #define USE_EXECV
 #endif
 
 #ifdef XP_WIN
-#include "launchwinprocess.h"
+#include "updatehelper.h"
 
 // Closes the handle if valid and if the updater is elevated returns with the
 // return code specified. This prevents multiple launches of the callback
 // application by preventing the elevated process from launching the callback.
 #define EXIT_WHEN_ELEVATED(path, handle, retCode) \
   { \
       if (handle != INVALID_HANDLE_VALUE) { \
         CloseHandle(handle); \
@@ -1397,35 +1397,16 @@ LaunchCallbackApp(const NS_tchar *workin
   if (NS_tchdir(workingDir) != 0) {
     LOG(("Warning: chdir failed\n"));
   }
 
 #if defined(USE_EXECV)
   execv(argv[0], argv);
 #elif defined(XP_MACOSX)
   LaunchChild(argc, argv);
-#elif defined(MOZ_MAINTENANCE_SERVICE)
-  // If updater.exe is run as session ID 0 and we have a MOZ_SESSION_ID 
-  // set, then get the unelevated token and use that to start the callback
-  // application.  Getting tokens will only work if the process is running
-  // as the system account.
-  DWORD myProcessID = GetCurrentProcessId();
-  DWORD mySessionID = 0;
-  ProcessIdToSessionId(myProcessID, &mySessionID);
-  nsAutoHandle unelevatedToken(NULL);
-  if (mySessionID == 0) {
-    WCHAR *sessionIDStr = _wgetenv(L"MOZ_SESSION_ID");
-    if (sessionIDStr) {
-      // Remove the env var now that we have its value.
-      int callbackSessionID = _wtoi(sessionIDStr);
-      _wputenv(L"MOZ_SESSION_ID=");
-      unelevatedToken.own(UACHelper::OpenUserToken(callbackSessionID));
-    }
-  }
-  WinLaunchChild(argv[0], argc, argv, unelevatedToken);
 #elif defined(XP_WIN)
   WinLaunchChild(argv[0], argc, argv, NULL);
 #else
 # warning "Need implementaton of LaunchCallbackApp"
 #endif
 }
 
 static void
@@ -1448,16 +1429,98 @@ WriteStatusFile(int status)
     text = "succeeded\n";
   } else {
     snprintf(buf, sizeof(buf)/sizeof(buf[0]), "failed: %d\n", status);
     text = buf;
   }
   fwrite(text, strlen(text), 1, file);
 }
 
+static bool
+WriteStatusApplying()
+{
+  NS_tchar filename[MAXPATHLEN];
+  NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
+               NS_T("%s/update.status"), gSourcePath);
+
+  AutoFile file = NS_tfopen(filename, NS_T("wb+"));
+  if (file == NULL)
+    return false;
+
+  static const char kApplying[] = "Applying\n";
+  if (fwrite(kApplying, strlen(kApplying), 1, file) != 1)
+    return false;
+
+  return true;
+}
+
+/* 
+ * Read the update.status file and sets isPendingService to true if
+ * the status is set to pending-service.
+ *
+ * @param  isPendingService Out parameter for specifying if the status
+ *         is set to pending-service or not.
+ * @return true if the information was retrieved and it is pending
+ *         or pending-service.
+*/
+static bool
+IsUpdateStatusPending(bool &isPendingService)
+{
+  bool isPending = false;
+  isPendingService = false;
+  NS_tchar filename[MAXPATHLEN];
+  NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
+               NS_T("%s/update.status"), gSourcePath);
+
+  AutoFile file = NS_tfopen(filename, NS_T("rb"));
+  if (file == NULL)
+    return false;
+
+  char buf[32] = { 0 };
+  fread(buf, sizeof(buf), 1, file);
+
+  const char kPending[] = "pending";
+  const char kPendingService[] = "pending-service";
+  isPending = strncmp(buf, kPending, 
+                      sizeof(kPending) - 1) == 0;
+
+  isPendingService = strncmp(buf, kPendingService, 
+                             sizeof(kPendingService) - 1) == 0;
+  return isPending;
+}
+
+/* 
+ * Read the update.status file and sets isSuccess to true if
+ * the status is set to succeeded.
+ *
+ * @param  isSucceeded Out parameter for specifying if the status
+ *         is set to succeeded or not.
+ * @return true if the information was retrieved and it is succeeded.
+*/
+static bool
+IsUpdateStatusSucceeded(bool &isSucceeded)
+{
+  isSucceeded = false;
+  NS_tchar filename[MAXPATHLEN];
+  NS_tsnprintf(filename, sizeof(filename)/sizeof(filename[0]),
+               NS_T("%s/update.status"), gSourcePath);
+
+  AutoFile file = NS_tfopen(filename, NS_T("rb"));
+  if (file == NULL)
+    return false;
+
+  char buf[32] = { 0 };
+  fread(buf, sizeof(buf), 1, file);
+
+  const char kSucceeded[] = "succeeded";
+  isSucceeded = strncmp(buf, kSucceeded, 
+                        sizeof(kSucceeded) - 1) == 0;
+  return true;
+}
+
 static void
 UpdateThreadFunc(void *param)
 {
   // open ZIP archive and process...
 
   NS_tchar dataFile[MAXPATHLEN];
   NS_tsnprintf(dataFile, sizeof(dataFile)/sizeof(dataFile[0]),
                NS_T("%s/update.mar"), gSourcePath);
@@ -1519,16 +1582,33 @@ int NS_main(int argc, NS_tchar **argv)
     return 1;
   }
 
   // Change current directory to the directory where we need to apply the update.
   if (NS_tchdir(argv[2]) != 0) {
     return 1;
   }
 
+  // The directory containing the update information.
+  gSourcePath = argv[1];
+
+#ifdef XP_WIN
+  bool useService = false;
+  // We never want the service to be used unless we build with
+  // the maintenance service.
+#ifdef MOZ_MAINTENANCE_SERVICE
+  IsUpdateStatusPending(useService);
+#endif
+#endif
+
+  if (!WriteStatusApplying()) {
+    LOG(("failed setting status to 'applying'\n"));
+    return 1;
+  }
+
 #ifdef XP_WIN
   // Remove everything except close window from the context menu
   {
     HKEY hkApp;
     RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\Classes\\Applications",
                     0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL,
                     &hkApp, NULL);
     RegCloseKey(hkApp);
@@ -1562,19 +1642,16 @@ int NS_main(int argc, NS_tchar **argv)
     }
 #else
     int pid = atoi(argv[3]);
     if (pid != 0)
       waitpid(pid, NULL, 0);
 #endif
   }
 
-  // The directory containing the update information.
-  gSourcePath = argv[1];
-
   // The callback is the remaining arguments starting at callbackIndex.
   // The argument specified by callbackIndex is the callback executable and the
   // argument prior to callbackIndex is the working directory.
   const int callbackIndex = 5;
 
 #if defined(XP_WIN)
   // Launch a second instance of the updater with the runas verb on Windows
   // when write access is denied to the installation directory.
@@ -1629,36 +1706,90 @@ int NS_main(int argc, NS_tchar **argv)
       }
 
       PRUnichar *cmdLine = MakeCommandLine(argc - 1, argv + 1);
       if (!cmdLine) {
         CloseHandle(elevatedFileHandle);
         return 1;
       }
 
-      SHELLEXECUTEINFO sinfo;
-      memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO));
-      sinfo.cbSize       = sizeof(SHELLEXECUTEINFO);
-      sinfo.fMask        = SEE_MASK_FLAG_NO_UI |
-                           SEE_MASK_FLAG_DDEWAIT |
-                           SEE_MASK_NOCLOSEPROCESS;
-      sinfo.hwnd         = NULL;
-      sinfo.lpFile       = argv[0];
-      sinfo.lpParameters = cmdLine;
-      sinfo.lpVerb       = L"runas";
-      sinfo.nShow        = SW_SHOWNORMAL;
+      HANDLE serviceInUseEvent = NULL;
+      if (useService) {
+        // Make sure the service isn't already busy processing another work item.
+        // This event will also be used by the service who will signal it when
+        // it is done with the udpate.
+        serviceInUseEvent = CreateEventW(NULL, TRUE, 
+                                         FALSE, SERVICE_EVENT_NAME);
+
+        // Only use the service if we know the event can be created and
+        // doesn't already exist.
+        if (!serviceInUseEvent) {
+          useService = false;
+        }
+      }
+
+      // Originally we used to write "pending" to update.status before
+      // launching the service command.  This is no longer needed now
+      // since the service command is launched from updater.exe.  If anything
+      // fails in between, we can fall back to using the normal update process
+      // on our own.
+
+      // If we still want to use the service try to launch the service 
+      // comamnd for the update.
+      if (useService) {
+        // If the update couldn't be started, then set useService to false so
+        // we do the update the old way.
+        useService = WinLaunchServiceCommand(argv[0], argc, argv);
+
+        // The command was launched, so we should wait for the work to be done.
+        // The service will set the event we wait on when it is done.
+        if (useService) {
+          WaitForSingleObject(serviceInUseEvent, INFINITE);
+          CloseHandle(serviceInUseEvent);
+        }
+      }
 
-      bool result = ShellExecuteEx(&sinfo);
-      free(cmdLine);
+      // If we started the service command, and it finished, check the
+      // update.status file to make sure it succeeded, and if it did
+      // we need to manually start the PostUpdate process from the
+      // current user's session of this unelevated updater.exe the
+      // current process is running as.
+      if (useService) {
+        bool updateStatusSucceeded = false;
+        if (IsUpdateStatusSucceeded(updateStatusSucceeded) && 
+            updateStatusSucceeded) {
+          LaunchWinPostProcess(argv[callbackIndex], gSourcePath, false, NULL);
+        }
+      }
 
-      if (result) {
-        WaitForSingleObject(sinfo.hProcess, INFINITE);
-        CloseHandle(sinfo.hProcess);
-      } else {
-        WriteStatusFile(ELEVATION_CANCELED);
+      // If we didn't want to use the service at all, or if an update was 
+      // already happening, or launching the service command failed, then 
+      // launch the elevated updater.exe as we used to without the service.
+      if (!useService) {
+        SHELLEXECUTEINFO sinfo;
+        memset(&sinfo, 0, sizeof(SHELLEXECUTEINFO));
+        sinfo.cbSize       = sizeof(SHELLEXECUTEINFO);
+        sinfo.fMask        = SEE_MASK_FLAG_NO_UI |
+                             SEE_MASK_FLAG_DDEWAIT |
+                             SEE_MASK_NOCLOSEPROCESS;
+        sinfo.hwnd         = NULL;
+        sinfo.lpFile       = argv[0];
+        sinfo.lpParameters = cmdLine;
+        sinfo.lpVerb       = L"runas";
+        sinfo.nShow        = SW_SHOWNORMAL;
+
+        bool result = ShellExecuteEx(&sinfo);
+        free(cmdLine);
+
+        if (result) {
+          WaitForSingleObject(sinfo.hProcess, INFINITE);
+          CloseHandle(sinfo.hProcess);
+        } else {
+          WriteStatusFile(ELEVATION_CANCELED);
+        }
       }
 
       if (argc > callbackIndex) {
         LaunchCallbackApp(argv[4], argc - callbackIndex, argv + callbackIndex);
       }
 
       CloseHandle(elevatedFileHandle);
       return 0;
@@ -1830,19 +1961,19 @@ int NS_main(int argc, NS_tchar **argv)
 #if defined(XP_WIN)
     if (gSucceeded) {
       // The service update will only be executed if it is already installed.
       // For first time installs of the service, the install will happen from
       // the PostUpdate process. We do the service update process here 
       // because it's possible we are updating with updater.exe without the 
       // service if the service failed to apply the update. We want to update
       // the service to a newer version in that case. If we are not running
-      // through the service, then MOZ_SESSION_ID will not exist.
-      WCHAR *sessionIDStr = _wgetenv(L"MOZ_SESSION_ID");
-      if (!sessionIDStr) {
+      // through the service, then MOZ_USING_SERVICE will not exist.
+      WCHAR *usingService = _wgetenv(L"MOZ_USING_SERVICE");
+      if (!usingService) {
         if (!LaunchWinPostProcess(argv[2], gSourcePath, false, NULL)) {
           LOG(("NS_main: The post update process could not be launched.\n"));
         }
         StartServiceUpdate(argc, argv);
       }
     }
     EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 0);
 #endif /* XP_WIN */
--- a/toolkit/xre/nsAppRunner.h
+++ b/toolkit/xre/nsAppRunner.h
@@ -134,20 +134,16 @@ NS_LockProfilePath(nsILocalFile* aPath, 
 
 NS_HIDDEN_(void)
 WriteConsoleLog();
 
 #ifdef XP_WIN
 BOOL
 WinLaunchChild(const PRUnichar *exePath, int argc, 
                char **argv, HANDLE userToken = NULL);
-BOOL
-WinLaunchServiceCommand(const PRUnichar *exePath, int argc, char **argv);
-BOOL
-WriteStatusPending(LPCWSTR updateDirPath);
 #endif
 
 #define NS_NATIVEAPPSUPPORT_CONTRACTID "@mozilla.org/toolkit/native-app-support;1"
 
 // Like nsXREAppData, but releases all strong refs/allocated memory
 // in the destructor.
 class ScopedAppData : public nsXREAppData
 {
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -186,56 +186,33 @@ GetFile(nsIFile *dir, const nsCSubstring
 
 static bool
 GetStatusFile(nsIFile *dir, nsCOMPtr<nsILocalFile> &result)
 {
   return GetFile(dir, NS_LITERAL_CSTRING("update.status"), result);
 }
 
 static bool
-IsPending(nsILocalFile *statusFile, bool &isPendingService)
+IsPending(nsILocalFile *statusFile)
 {
   PRFileDesc *fd = nsnull;
   nsresult rv = statusFile->OpenNSPRFileDesc(PR_RDONLY, 0660, &fd);
   if (NS_FAILED(rv))
     return false;
 
   char buf[32];
   const PRInt32 n = PR_Read(fd, buf, sizeof(buf));
   PR_Close(fd);
 
   if (n < 0)
     return false;
   
   const char kPending[] = "pending";
   bool isPending = (strncmp(buf, kPending, sizeof(kPending) - 1) == 0);
-
-  const char kPendingService[] = "pending-service";
-  isPendingService = (strncmp(buf, kPendingService, 
-                      sizeof(kPendingService) - 1) == 0);
-
-  return isPending || isPendingService;
-}
-
-static bool
-SetStatusApplying(nsILocalFile *statusFile)
-{
-  PRFileDesc *fd = nsnull;
-  nsresult rv = statusFile->OpenNSPRFileDesc(PR_WRONLY | 
-                                             PR_TRUNCATE | 
-                                             PR_CREATE_FILE, 
-                                             0660, &fd);
-  if (NS_FAILED(rv))
-    return false;
-
-  static const char kApplying[] = "Applying\n";
-  PR_Write(fd, kApplying, sizeof(kApplying) - 1);
-  PR_Close(fd);
-
-  return true;
+  return isPending;
 }
 
 static bool
 GetVersionFile(nsIFile *dir, nsCOMPtr<nsILocalFile> &result)
 {
   return GetFile(dir, NS_LITERAL_CSTRING("update.version"), result);
 }
 
@@ -339,17 +316,17 @@ CopyUpdaterIntoUpdateDir(nsIFile *greDir
     return false;
 #endif
   rv = updater->AppendNative(NS_LITERAL_CSTRING(kUpdaterBin));
   return NS_SUCCEEDED(rv); 
 }
 
 static void
 ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsILocalFile *statusFile,
-            nsIFile *appDir, int appArgc, char **appArgv, bool isPendingService)
+            nsIFile *appDir, int appArgc, char **appArgv)
 {
   nsresult rv;
 
   // Steps:
   //  - mark update as 'applying'
   //  - copy updater into update dir
   //  - run updater w/ appDir as the current working dir
 
@@ -442,20 +419,21 @@ ApplyUpdate(nsIFile *greDir, nsIFile *up
     return;
 
   // Get the current working directory.
   char workingDirPath[MAXPATHLEN];
   rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath));
   if (NS_FAILED(rv))
     return;
 
-  if (!SetStatusApplying(statusFile)) {
-    LOG(("failed setting status to 'applying'\n"));
-    return;
-  }
+  // We used to write out "Applying" to the update.status file here.
+  // Instead we do this from within the updater application now.
+  // This is so that we don't overwrite the status of pending-service
+  // in the Windows case.  This change was made for all platforms so
+  // that it stays consistent across all OS.
 
   // Construct the PID argument for this process.  If we are using execv, then
   // we pass "0" which is then ignored by the updater.
 #if defined(USE_EXECV)
   NS_NAMED_LITERAL_CSTRING(pid, "0");
 #else
   nsCAutoString pid;
   pid.AppendInt((PRInt32) getpid());
@@ -486,48 +464,19 @@ ApplyUpdate(nsIFile *greDir, nsIFile *up
   }
 
   LOG(("spawning updater process [%s]\n", updaterPath.get()));
 
 #if defined(USE_EXECV)
   execv(updaterPath.get(), argv);
 #elif defined(XP_WIN)
 
-#ifndef MOZ_MAINTENANCE_SERVICE
-  // We never want the service to be used unless we have Firefox
-  isPendingService = false;
-#endif
-
-  if (isPendingService) {
-    // Make sure the service isn't already busy processing another work item.
-    SetLastError(ERROR_SUCCESS);
-    HANDLE serviceRunningEvent = 
-      OpenEvent(EVENT_ALL_ACCESS, 
-                FALSE, 
-                L"Global\\moz-5b780de9-065b-4341-a04f-ddd94b3723e5");
-    // Only use the service if we know the event exists.
-    // If we have a non NULL handle, or if ERROR_ACCESS_DENIED is returned,
-    // then the event exists.
-    isPendingService = !serviceRunningEvent && 
-                       GetLastError() != ERROR_ACCESS_DENIED;
-    if (serviceRunningEvent) {
-      CloseHandle(serviceRunningEvent);
-    }
-  }
-
-  // Launch the update operation using the service if the status file said so.
-  // We also set the status to pending to ensure we never attempt to use the 
-  // service more than once in a row for a single update.
-  if (!isPendingService || 
-      !WriteStatusPending(NS_ConvertUTF8toUTF16(updateDirPath).get()) ||
-      !WinLaunchServiceCommand(updaterPathW.get(), argc, argv)) {
-    // Launch the update using updater.exe
-    if (!WinLaunchChild(updaterPathW.get(), argc, argv)) {
-      return;
-    }
+  // Launch the update using updater.exe
+  if (!WinLaunchChild(updaterPathW.get(), argc, argv)) {
+    return;
   }
 
   // We are going to process an update so we should exit now
   _exit(0);
 #elif defined(XP_MACOSX)
   CommandLineServiceMac::SetupMacCommandLine(argc, argv, true);
   // LaunchChildMac uses posix_spawnp and prefers the current
   // architecture when launching. It doesn't require a
@@ -582,28 +531,27 @@ ProcessUpdates(nsIFile *greDir, nsIFile 
         return rv;
       }
       NS_RELEASE(appDir);
       NS_ADDREF(appDir = overrideDir);
     }
   }
 
   nsCOMPtr<nsILocalFile> statusFile;
-  bool isPendingService;
   if (GetStatusFile(updatesDir, statusFile) && 
-      IsPending(statusFile, isPendingService)) {
+      IsPending(statusFile)) {
     nsCOMPtr<nsILocalFile> versionFile;
     nsCOMPtr<nsILocalFile> channelChangeFile;
     // Remove the update if the update application version file doesn't exist
     // or if the update's application version is less than the current
     // application version.
     if (!GetChannelChangeFile(updatesDir, channelChangeFile) &&
         (!GetVersionFile(updatesDir, versionFile) ||
          IsOlderVersion(versionFile, appVersion))) {
       updatesDir->Remove(true);
     } else {
       ApplyUpdate(greDir, updatesDir, statusFile, appDir, 
-                  argc, argv, isPendingService);
+                  argc, argv);
     }
   }
 
   return NS_OK;
 }
--- a/toolkit/xre/nsWindowsRestart.cpp
+++ b/toolkit/xre/nsWindowsRestart.cpp
@@ -42,46 +42,23 @@
 
 #ifdef nsWindowsRestart_cpp
 #error "nsWindowsRestart.cpp is not a header file, and must only be included once."
 #else
 #define nsWindowsRestart_cpp
 #endif
 
 #include "nsUTF8Utils.h"
-#include "nsWindowsHelpers.h"
 
 #include <shellapi.h>
-#include <shlwapi.h>
-#include <shlobj.h>
-#include <stdio.h>
-#include <wchar.h>
-#include <rpc.h>
+
+// Needed for CreateEnvironmentBlock
 #include <userenv.h>
-
-#pragma comment(lib, "shlwapi.lib")
-#pragma comment(lib, "rpcrt4.lib")
 #pragma comment(lib, "userenv.lib")
 
-#ifndef ERROR_ELEVATION_REQUIRED
-#define ERROR_ELEVATION_REQUIRED 740L
-#endif
-
-BOOL (WINAPI *pCreateProcessWithTokenW)(HANDLE,
-                                        DWORD,
-                                        LPCWSTR,
-                                        LPWSTR,
-                                        DWORD,
-                                        LPVOID,
-                                        LPCWSTR,
-                                        LPSTARTUPINFOW,
-                                        LPPROCESS_INFORMATION);
-
-BOOL (WINAPI *pIsUserAnAdmin)(VOID);
-
 /**
  * Get the length that the string will take and takes into account the
  * additional length if the string needs to be quoted and if characters need to
  * be escaped.
  */
 static int ArgStrLen(const PRUnichar *s)
 {
   int backslashes = 0;
@@ -232,322 +209,16 @@ FreeAllocStrings(int argc, PRUnichar **a
     --argc;
     delete [] argv[argc];
   }
 
   delete [] argv;
 }
 
 /**
- * Determines if the maintenance service is running or not.
- * 
- * @return TRUE if the maintenance service is running.
-*/
-BOOL 
-EnsureWindowsServiceRunning() {
-  // Get a handle to the SCM database.
-  nsAutoServiceHandle serviceManager(OpenSCManager(NULL, NULL, 
-                                                   SC_MANAGER_CONNECT | 
-                                                   SC_MANAGER_ENUMERATE_SERVICE));
-  if (!serviceManager)  {
-    return FALSE;
-  }
-
-  // Get a handle to the service.
-  nsAutoServiceHandle service(OpenServiceW(serviceManager, 
-                                           L"MozillaMaintenance", 
-                                           SERVICE_QUERY_STATUS | SERVICE_START));
-  if (!service) { 
-    return FALSE;
-  }
-
-  // Make sure the service is not stopped.
-  SERVICE_STATUS_PROCESS ssp;
-  DWORD bytesNeeded;
-  if (!QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
-                            sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
-    return FALSE;
-  }
-
-  if (ssp.dwCurrentState == SERVICE_STOPPED) {
-    if (!StartService(service, 0, NULL)) {
-      return FALSE;
-    }
-
-    // Make sure we can get into a started state without waiting too long.
-    // This usually starts instantly but the extra code is just in case it
-    // takes longer.
-    DWORD totalWaitTime = 0;
-    static const int maxWaitTime = 1000 * 5; // Never wait more than 5 seconds
-    while (QueryServiceStatusEx(service, SC_STATUS_PROCESS_INFO, (LPBYTE)&ssp,
-                                sizeof(SERVICE_STATUS_PROCESS), &bytesNeeded)) {
-      if (ssp.dwCurrentState == SERVICE_RUNNING) {
-        break;
-      }
-      
-      if (ssp.dwCurrentState == SERVICE_START_PENDING &&
-          totalWaitTime > maxWaitTime) {
-        // We will probably eventually start, but we can't wait any longer.
-        break;
-      }
-      
-      if (ssp.dwCurrentState != SERVICE_START_PENDING) {
-        return FALSE;
-      }
-
-      Sleep(ssp.dwWaitHint);
-      // Increment by at least 10 milliseconds to ensure we always make 
-      // progress towards maxWaitTime in case dwWaitHint is 0.
-      totalWaitTime += (ssp.dwWaitHint + 10);
-    }
-  }
-
-  return ssp.dwCurrentState == SERVICE_RUNNING;
-}
-
-/**
- * Joins a base directory path with a filename.
- *
- * @param  base  The base directory path of size MAX_PATH + 1
- * @param  extra The filename to append
- * @return TRUE if the file name was successful appended to base
- */
-BOOL
-PathAppendSafe(LPWSTR base, LPCWSTR extra)
-{
-  if (wcslen(base) + wcslen(extra) >= MAX_PATH) {
-    return FALSE;
-  }
-
-  return PathAppendW(base, extra);
-}
-
-/**
- * Obtains the directory path to store work item files.
- * 
- * @return TRUE if the path was obtained successfully.
-*/
-BOOL
-GetUpdateDirectoryPath(PRUnichar *path) 
-{
-  HRESULT hr = SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 
-    SHGFP_TYPE_CURRENT, path);
-  if (FAILED(hr)) {
-    return FALSE;
-  }
-
-  if (!PathAppendSafe(path, L"Mozilla")) {
-    return FALSE;
-  }
-  // The directory should already be created from the installer, but
-  // just to be safe in case someone deletes.
-  CreateDirectoryW(path, NULL);
-
-  if (!PathAppendSafe(path, L"updates")) {
-    return FALSE;
-  }
-  CreateDirectoryW(path, NULL);
-  return TRUE;
-}
-
-/**
- * Launch a service initiated action with the specified arguments.
- *
- * @param  exePath The path of the executable to run
- * @param  argc    The total number of arguments in argv
- * @param  argv    An array of null terminated strings to pass to the exePath,
- *                 argv[0] is ignored
- * @return TRUE if successful
- */
-BOOL
-WinLaunchServiceCommand(const PRUnichar *exePath, int argc, PRUnichar **argv)
-{
-  // Ensure the service is running, if not we should try to start it, if it is
-  // not in a running state we cannot execute a service command.
-  if (!EnsureWindowsServiceRunning()) {
-    return FALSE;
-  }
-
-  PRUnichar updateData[MAX_PATH + 1];
-  if (!GetUpdateDirectoryPath(updateData)) {
-    return FALSE;
-  }
-
-  // Get a unique filename
-  PRUnichar tempFilePath[MAX_PATH + 1];
-  const int USE_SYSTEM_TIME = 0;
-  if (!GetTempFileNameW(updateData, L"moz", USE_SYSTEM_TIME, tempFilePath)) {
-    return FALSE;
-  }
-  
-  const int FILE_SHARE_NONE = 0;
-  nsAutoHandle updateMetaFile(CreateFileW(tempFilePath, GENERIC_WRITE, 
-                                          FILE_SHARE_NONE, NULL, CREATE_ALWAYS, 
-                                          0, NULL));
-  if (updateMetaFile == INVALID_HANDLE_VALUE) {
-    return FALSE;
-  }
-
-  // Write out the command ID.
-  // Command ID 1 is for an update work item file, which is the only supported
-  // command at this time.
-  DWORD commandID = 1, commandIDWrote;
-  BOOL result = WriteFile(updateMetaFile, &commandID, 
-                          sizeof(DWORD), 
-                          &commandIDWrote, NULL);
-
-  // Write out the command line arguments that are passed to updater.exe
-  PRUnichar *commandLineBuffer = MakeCommandLine(argc, argv);
-  DWORD sessionID, sessionIDWrote;
-  ProcessIdToSessionId(GetCurrentProcessId(), &sessionID);
-  result |= WriteFile(updateMetaFile, &sessionID, 
-                      sizeof(DWORD), 
-                      &sessionIDWrote, NULL);
-
-  PRUnichar appBuffer[MAX_PATH + 1];
-  ZeroMemory(appBuffer, sizeof(appBuffer));
-  wcscpy(appBuffer, exePath);
-  DWORD appBufferWrote;
-  result |= WriteFile(updateMetaFile, appBuffer, 
-                      MAX_PATH * sizeof(PRUnichar), 
-                      &appBufferWrote, NULL);
-
-  PRUnichar workingDirectory[MAX_PATH + 1];
-  ZeroMemory(workingDirectory, sizeof(appBuffer));
-  GetCurrentDirectoryW(sizeof(workingDirectory) / sizeof(workingDirectory[0]), 
-                       workingDirectory);
-  DWORD workingDirectoryWrote;
-  result |= WriteFile(updateMetaFile, workingDirectory, 
-                      MAX_PATH * sizeof(PRUnichar), 
-                      &workingDirectoryWrote, NULL);
-
-  DWORD commandLineLength = wcslen(commandLineBuffer) * sizeof(PRUnichar);
-  DWORD commandLineWrote;
-  result |= WriteFile(updateMetaFile, commandLineBuffer, 
-                      commandLineLength, 
-                      &commandLineWrote, NULL);
-  free(commandLineBuffer);
-  if (!result ||
-      sessionIDWrote != sizeof(DWORD) ||
-      commandIDWrote != sizeof(DWORD) ||
-      appBufferWrote != MAX_PATH * sizeof(PRUnichar) ||
-      workingDirectoryWrote != MAX_PATH * sizeof(PRUnichar) ||
-      commandLineWrote != commandLineLength) {
-    updateMetaFile.reset();
-    DeleteFileW(tempFilePath);
-    return FALSE;
-  }
-
-  // Note we construct the 'service work' meta object with a .tmp extension,
-  // When we want the service to start processing it we simply rename it to
-  // have a .mz extension.  This ensures that the service will never try to
-  // process a partial update work meta file. 
-  updateMetaFile.reset();
-  PRUnichar completedMetaFilePath[MAX_PATH + 1];
-  wcscpy(completedMetaFilePath, tempFilePath);
-
-  // Change the file extension of the temp file path from .tmp to .mz
-  LPWSTR extensionPart = 
-    &(completedMetaFilePath[wcslen(completedMetaFilePath) - 3]);
-  wcscpy(extensionPart, L"mz");
-  return MoveFileExW(tempFilePath, completedMetaFilePath, 
-                     MOVEFILE_REPLACE_EXISTING);
-}
-
-/**
- * Sets update.status to pending so that the next startup will not use
- * the service and instead will attempt an update the with a UAC prompt.
- *
- * @param  updateDirPath The path of the update directory
- * @return TRUE if successful
- */
-BOOL
-WriteStatusPending(LPCWSTR updateDirPath)
-{
-  PRUnichar updateStatusFilePath[MAX_PATH + 1];
-  wcscpy(updateStatusFilePath, updateDirPath);
-  if (!PathAppendSafe(updateStatusFilePath, L"update.status")) {
-    return FALSE;
-  }
-
-  const char pending[] = "pending";
-  nsAutoHandle statusFile(CreateFileW(updateStatusFilePath, GENERIC_WRITE, 0, 
-                                      NULL, CREATE_ALWAYS, 0, NULL));
-  if (statusFile == INVALID_HANDLE_VALUE) {
-    return FALSE;
-  }
-
-  DWORD wrote;
-  BOOL ok = WriteFile(statusFile, pending, 
-                      sizeof(pending) - 1, &wrote, NULL); 
-  return ok && (wrote == sizeof(pending) - 1);
-}
-
-/**
- * Sets update.status to a specific failure code
- *
- * @param  updateDirPath The path of the update directory
- * @return TRUE if successful
- */
-BOOL
-WriteStatusFailure(LPCWSTR updateDirPath, int errorCode) 
-{
-  PRUnichar updateStatusFilePath[MAX_PATH + 1];
-  wcscpy(updateStatusFilePath, updateDirPath);
-  if (!PathAppendSafe(updateStatusFilePath, L"update.status")) {
-    return FALSE;
-  }
-
-  nsAutoHandle statusFile(CreateFileW(updateStatusFilePath, GENERIC_WRITE, 0, 
-                                      NULL, CREATE_ALWAYS, 0, NULL));
-  if (statusFile == INVALID_HANDLE_VALUE) {
-    return FALSE;
-  }
-  char failure[32];
-  sprintf(failure, "failed: %d", errorCode);
-
-  DWORD toWrite = strlen(failure);
-  DWORD wrote;
-  BOOL ok = WriteFile(statusFile, failure, 
-                      toWrite, &wrote, NULL); 
-  return ok && wrote == toWrite;
-}
-
-/**
- * Launch a service initiated action with the specified arguments.
- *
- * @param  exePath The path of the executable to run
- * @param  argc    The total number of arguments in argv
- * @param  argv    An array of null terminated strings to pass to the exePath,
- *                 argv[0] is ignored
- * @return TRUE if successful
- */
-BOOL
-WinLaunchServiceCommand(const PRUnichar *exePath, int argc, char **argv)
-{
-  PRUnichar** argvConverted = new PRUnichar*[argc];
-  if (!argvConverted)
-    return FALSE;
-
-  for (int i = 0; i < argc; ++i) {
-    argvConverted[i] = AllocConvertUTF8toUTF16(argv[i]);
-    if (!argvConverted[i]) {
-      FreeAllocStrings(i, argvConverted);
-      return FALSE;
-    }
-  }
-
-  BOOL ok = WinLaunchServiceCommand(exePath, argc, argvConverted);
-  FreeAllocStrings(argc, argvConverted);
-  return ok;
-}
-
-
-
-/**
  * Launch a child process with the specified arguments.
  * @note argv[0] is ignored
  * @note The form of this function that takes char **argv expects UTF-8
  */
 
 BOOL
 WinLaunchChild(const PRUnichar *exePath, 
                int argc, PRUnichar **argv,