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 83771 457620c55eec932472a2849011a0175050243006
parent 83770 d5637e69d71ed290e6a7d7892b486a657f2a98ed
child 83772 ee4def38eede8560ea1a183bfc7ac143e92781d9
push id21792
push userbbondy@mozilla.com
push dateThu, 05 Jan 2012 04:20:59 +0000
treeherdermozilla-central@10894668e37f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrstrong
bugs708854
milestone12.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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,