toolkit/xre/nsUpdateDriver.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include <stdlib.h>
     8 #include <stdio.h>
     9 #include "nsUpdateDriver.h"
    10 #include "nsXULAppAPI.h"
    11 #include "nsAppRunner.h"
    12 #include "nsIWritablePropertyBag.h"
    13 #include "nsIFile.h"
    14 #include "nsIVariant.h"
    15 #include "nsCOMPtr.h"
    16 #include "nsString.h"
    17 #include "prproces.h"
    18 #include "prlog.h"
    19 #include "prenv.h"
    20 #include "nsVersionComparator.h"
    21 #include "nsXREDirProvider.h"
    22 #include "SpecialSystemDirectory.h"
    23 #include "nsDirectoryServiceDefs.h"
    24 #include "nsThreadUtils.h"
    25 #include "nsIXULAppInfo.h"
    26 #include "mozilla/Preferences.h"
    27 #include "nsPrintfCString.h"
    28 #include "mozilla/DebugOnly.h"
    30 #ifdef XP_MACOSX
    31 #include "nsILocalFileMac.h"
    32 #include "nsCommandLineServiceMac.h"
    33 #include "MacLaunchHelper.h"
    34 #endif
    36 #if defined(XP_WIN)
    37 # include <direct.h>
    38 # include <process.h>
    39 # include <windows.h>
    40 # include <shlwapi.h>
    41 # include "nsWindowsHelpers.h"
    42 # include "prprf.h"
    43 # define getcwd(path, size) _getcwd(path, size)
    44 # define getpid() GetCurrentProcessId()
    45 #elif defined(XP_UNIX)
    46 # include <unistd.h>
    47 #endif
    49 using namespace mozilla;
    51 //
    52 // We use execv to spawn the updater process on all UNIX systems except Mac OSX
    53 // since it is known to cause problems on the Mac.  Windows has execv, but it
    54 // is a faked implementation that doesn't really replace the current process.
    55 // Instead it spawns a new process, so we gain nothing from using execv on
    56 // Windows.
    57 //
    58 // On platforms where we are not calling execv, we may need to make the
    59 // updater executable wait for the calling process to exit.  Otherwise, the
    60 // updater may have trouble modifying our executable image (because it might
    61 // still be in use).  This is accomplished by passing our PID to the updater so
    62 // that it can wait for us to exit.  This is not perfect as there is a race
    63 // condition that could bite us.  It's possible that the calling process could
    64 // exit before the updater waits on the specified PID, and in the meantime a
    65 // new process with the same PID could be created.  This situation is unlikely,
    66 // however, given the way most operating systems recycle PIDs.  We'll take our
    67 // chances ;-)
    68 //
    69 // A similar #define lives in updater.cpp and should be kept in sync with this.
    70 //
    71 #if defined(XP_UNIX) && !defined(XP_MACOSX)
    72 #define USE_EXECV
    73 #endif
    75 #ifdef PR_LOGGING
    76 static PRLogModuleInfo *
    77 GetUpdateLog()
    78 {
    79   static PRLogModuleInfo *sUpdateLog;
    80   if (!sUpdateLog)
    81     sUpdateLog = PR_NewLogModule("updatedriver");
    82   return sUpdateLog;
    83 }
    84 #endif
    85 #define LOG(args) PR_LOG(GetUpdateLog(), PR_LOG_DEBUG, args)
    87 #ifdef XP_WIN
    88 static const char kUpdaterBin[] = "updater.exe";
    89 #else
    90 static const char kUpdaterBin[] = "updater";
    91 #endif
    92 static const char kUpdaterINI[] = "updater.ini";
    93 #ifdef XP_MACOSX
    94 static const char kUpdaterApp[] = "updater.app";
    95 #endif
    96 #if defined(XP_UNIX) && !defined(XP_MACOSX)
    97 static const char kUpdaterPNG[] = "updater.png";
    98 #endif
   100 #if defined(MOZ_WIDGET_GONK)
   101 #include <linux/ioprio.h>
   103 static const int kB2GServiceArgc = 2;
   104 static const char *kB2GServiceArgv[] = { "/system/bin/start", "b2g" };
   106 static const char kAppUpdaterPrio[]        = "app.update.updater.prio";
   107 static const char kAppUpdaterOomScoreAdj[] = "app.update.updater.oom_score_adj";
   108 static const char kAppUpdaterIOPrioClass[] = "app.update.updater.ioprio.class";
   109 static const char kAppUpdaterIOPrioLevel[] = "app.update.updater.ioprio.level";
   111 static const int  kAppUpdaterPrioDefault        = 19;     // -20..19 where 19 = lowest priority
   112 static const int  kAppUpdaterOomScoreAdjDefault = -1000;  // -1000 = Never kill
   113 static const int  kAppUpdaterIOPrioClassDefault = IOPRIO_CLASS_IDLE;
   114 static const int  kAppUpdaterIOPrioLevelDefault = 0;      // Doesn't matter for CLASS IDLE
   115 #endif
   117 static nsresult
   118 GetCurrentWorkingDir(char *buf, size_t size)
   119 {
   120   // Cannot use NS_GetSpecialDirectory because XPCOM is not yet initialized.
   121   // This code is duplicated from xpcom/io/SpecialSystemDirectory.cpp:
   123 #if defined(XP_WIN)
   124   wchar_t wpath[MAX_PATH];
   125   if (!_wgetcwd(wpath, size))
   126     return NS_ERROR_FAILURE;
   127   NS_ConvertUTF16toUTF8 path(wpath);
   128   strncpy(buf, path.get(), size);
   129 #else
   130   if(!getcwd(buf, size))
   131     return NS_ERROR_FAILURE;
   132 #endif
   133   return NS_OK;
   134 }
   137 #if defined(XP_WIN)
   138 #define PATH_SEPARATOR ";"
   140 // In Tor Browser, updater.exe depends on some DLLs that are located in the
   141 // app directory.  To allow the updater to run when it has been copied into
   142 // the update directory, we append the app directory to the PATH.
   143 static nsresult
   144 AdjustPathForUpdater(nsIFile *appDir)
   145 {
   146   nsAutoCString appPath;
   147   nsresult rv = appDir->GetNativePath(appPath);
   148   NS_ENSURE_SUCCESS(rv, rv);
   150   char *s = nullptr;
   151   char *pathValue = PR_GetEnv("PATH");
   152   if ((nullptr == pathValue) || ('\0' == *pathValue)) {
   153     s = PR_smprintf("PATH=%s", appPath.get());
   154   } else {
   155     s = PR_smprintf("PATH=%s" PATH_SEPARATOR "%s", pathValue, appPath.get());
   156   }
   158   // We intentionally leak the value that is passed into PR_SetEnv() because
   159   // the environment will hold a pointer to it.
   160   if ((nullptr == s) || (PR_SUCCESS != PR_SetEnv(s)))
   161     return NS_ERROR_FAILURE;
   163   return NS_OK;
   164 }
   165 #endif
   167 #ifdef DEBUG
   168 static void
   169 dump_argv(const char *aPrefix, char **argv, int argc)
   170 {
   171   printf("%s - %d args\n", aPrefix, argc);
   172   for (int i = 0; i < argc; ++i)
   173     printf("  %d: %s\n", i, argv[i]);
   174 }
   175 #endif
   178 #if defined(XP_MACOSX)
   179 // This is a copy of OS X's XRE_GetBinaryPath from nsAppRunner.cpp with the
   180 // gBinaryPath check removed so that the updater can reload the stub executable
   181 // instead of xulrunner-bin. See bug 349737.
   182 static nsresult
   183 GetXULRunnerStubPath(const char* argv0, nsIFile* *aResult)
   184 {
   185   // Works even if we're not bundled.
   186   CFBundleRef appBundle = ::CFBundleGetMainBundle();
   187   if (!appBundle)
   188     return NS_ERROR_FAILURE;
   190   CFURLRef bundleURL = ::CFBundleCopyExecutableURL(appBundle);
   191   if (!bundleURL)
   192     return NS_ERROR_FAILURE;
   194   nsCOMPtr<nsILocalFileMac> lfm;
   195   nsresult rv = NS_NewLocalFileWithCFURL(bundleURL, true, getter_AddRefs(lfm));
   197   ::CFRelease(bundleURL);
   199   if (NS_FAILED(rv))
   200     return rv;
   202   NS_ADDREF(*aResult = static_cast<nsIFile*>(lfm.get()));
   203   return NS_OK;
   204 }
   205 #endif /* XP_MACOSX */
   207 static bool
   208 GetFile(nsIFile *dir, const nsCSubstring &name, nsCOMPtr<nsIFile> &result)
   209 {
   210   nsresult rv;
   212   nsCOMPtr<nsIFile> file;
   213   rv = dir->Clone(getter_AddRefs(file));
   214   if (NS_FAILED(rv))
   215     return false;
   217   rv = file->AppendNative(name);
   218   if (NS_FAILED(rv))
   219     return false;
   221   result = do_QueryInterface(file, &rv);
   222   return NS_SUCCEEDED(rv);
   223 }
   225 static bool
   226 GetStatusFile(nsIFile *dir, nsCOMPtr<nsIFile> &result)
   227 {
   228   return GetFile(dir, NS_LITERAL_CSTRING("update.status"), result);
   229 }
   231 /**
   232  * Get the contents of the update.status file.
   233  *
   234  * @param statusFile the status file object.
   235  * @param buf        the buffer holding the file contents
   236  *
   237  * @return true if successful, false otherwise.
   238  */
   239 template <size_t Size>
   240 static bool
   241 GetStatusFileContents(nsIFile *statusFile, char (&buf)[Size])
   242 {
   243   // The buffer needs to be large enough to hold the known status codes
   244   PR_STATIC_ASSERT(Size > 16);
   246   PRFileDesc *fd = nullptr;
   247   nsresult rv = statusFile->OpenNSPRFileDesc(PR_RDONLY, 0660, &fd);
   248   if (NS_FAILED(rv))
   249     return false;
   251   const int32_t n = PR_Read(fd, buf, Size);
   252   PR_Close(fd);
   254   return (n >= 0);
   255 }
   257 typedef enum {
   258   eNoUpdateAction,
   259   ePendingUpdate,
   260   ePendingService,
   261   eAppliedUpdate,
   262   eAppliedService
   263 } UpdateStatus;
   265 /**
   266  * Returns a value indicating what needs to be done in order to handle an update.
   267  *
   268  * @param dir the directory in which we should look for an update.status file.
   269  * @param statusFile the update.status file found in the directory.
   270  *
   271  * @return the update action to be performed.
   272  */
   273 static UpdateStatus
   274 GetUpdateStatus(nsIFile* dir, nsCOMPtr<nsIFile> &statusFile)
   275 {
   276   if (GetStatusFile(dir, statusFile)) {
   277     char buf[32];
   278     if (GetStatusFileContents(statusFile, buf)) {
   279       const char kPending[] = "pending";
   280       const char kPendingService[] = "pending-service";
   281       const char kApplied[] = "applied";
   282       const char kAppliedService[] = "applied-service";
   283       if (!strncmp(buf, kPendingService, sizeof(kPendingService) - 1)) {
   284         return ePendingService;
   285       }
   286       if (!strncmp(buf, kPending, sizeof(kPending) - 1)) {
   287         return ePendingUpdate;
   288       }
   289       if (!strncmp(buf, kAppliedService, sizeof(kAppliedService) - 1)) {
   290         return eAppliedService;
   291       }
   292       if (!strncmp(buf, kApplied, sizeof(kApplied) - 1)) {
   293         return eAppliedUpdate;
   294       }
   295     }
   296   }
   297   return eNoUpdateAction;
   298 }
   300 static bool
   301 GetVersionFile(nsIFile *dir, nsCOMPtr<nsIFile> &result)
   302 {
   303   return GetFile(dir, NS_LITERAL_CSTRING("update.version"), result);
   304 }
   306 // Compares the current application version with the update's application
   307 // version.
   308 static bool
   309 IsOlderVersion(nsIFile *versionFile, const char *appVersion)
   310 {
   311   PRFileDesc *fd = nullptr;
   312   nsresult rv = versionFile->OpenNSPRFileDesc(PR_RDONLY, 0660, &fd);
   313   if (NS_FAILED(rv))
   314     return true;
   316   char buf[32];
   317   const int32_t n = PR_Read(fd, buf, sizeof(buf));
   318   PR_Close(fd);
   320   if (n < 0)
   321     return false;
   323   // Trim off the trailing newline
   324   if (buf[n - 1] == '\n')
   325     buf[n - 1] = '\0';
   327   // If the update xml doesn't provide the application version the file will
   328   // contain the string "null" and it is assumed that the update is not older.
   329   const char kNull[] = "null";
   330   if (strncmp(buf, kNull, sizeof(kNull) - 1) == 0)
   331     return false;
   333 #ifdef DEBUG
   334   printf("IsOlderVersion checking appVersion %s against updateVersion %s\n",
   335          appVersion, buf);
   336 #endif
   337   if (mozilla::Version(appVersion) > buf)
   338     return true;
   340   return false;
   341 }
   343 #if defined(XP_WIN) && defined(MOZ_METRO)
   344 static bool
   345 IsWindowsMetroUpdateRequest(int appArgc, char **appArgv)
   346 {
   347   for (int index = 0; index < appArgc; index++) {
   348     if (!strcmp(appArgv[index], "--metro-update")) {
   349       return true;
   350     }
   351   }
   352   return false;
   353 }
   354 #endif
   356 static bool
   357 CopyFileIntoUpdateDir(nsIFile *parentDir, const char *leafName, nsIFile *updateDir)
   358 {
   359   nsDependentCString leaf(leafName);
   360   nsCOMPtr<nsIFile> file;
   362   // Make sure there is not an existing file in the target location.
   363   nsresult rv = updateDir->Clone(getter_AddRefs(file));
   364   if (NS_FAILED(rv))
   365     return false;
   366   rv = file->AppendNative(leaf);
   367   if (NS_FAILED(rv))
   368     return false;
   369   file->Remove(true);
   371   // Now, copy into the target location.
   372   rv = parentDir->Clone(getter_AddRefs(file));
   373   if (NS_FAILED(rv))
   374     return false;
   375   rv = file->AppendNative(leaf);
   376   if (NS_FAILED(rv))
   377     return false;
   378   rv = file->CopyToNative(updateDir, EmptyCString());
   379   if (NS_FAILED(rv))
   380     return false;
   382   return true;
   383 }
   385 static bool
   386 CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir,
   387                          nsCOMPtr<nsIFile> &updater)
   388 {
   389   // Copy the updater application from the GRE and the updater ini from the app
   390 #if defined(XP_MACOSX)
   391   if (!CopyFileIntoUpdateDir(greDir, kUpdaterApp, updateDir))
   392     return false;
   393 #else
   394   if (!CopyFileIntoUpdateDir(greDir, kUpdaterBin, updateDir))
   395     return false;
   396 #endif
   397   CopyFileIntoUpdateDir(appDir, kUpdaterINI, updateDir);
   398 #if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(ANDROID)
   399   nsCOMPtr<nsIFile> iconDir;
   400   appDir->Clone(getter_AddRefs(iconDir));
   401   iconDir->AppendNative(NS_LITERAL_CSTRING("icons"));
   402   if (!CopyFileIntoUpdateDir(iconDir, kUpdaterPNG, updateDir))
   403     return false;
   404 #endif
   405   // Finally, return the location of the updater binary.
   406   nsresult rv = updateDir->Clone(getter_AddRefs(updater));
   407   if (NS_FAILED(rv))
   408     return false;
   409 #if defined(XP_MACOSX)
   410   rv  = updater->AppendNative(NS_LITERAL_CSTRING(kUpdaterApp));
   411   nsresult tmp = updater->AppendNative(NS_LITERAL_CSTRING("Contents"));
   412   if (NS_FAILED(tmp)) {
   413     rv = tmp;
   414   }
   415   tmp = updater->AppendNative(NS_LITERAL_CSTRING("MacOS"));
   416   if (NS_FAILED(tmp) || NS_FAILED(rv))
   417     return false;
   418 #endif
   419   rv = updater->AppendNative(NS_LITERAL_CSTRING(kUpdaterBin));
   420   return NS_SUCCEEDED(rv); 
   421 }
   423 /**
   424  * Switch an existing application directory to an updated version that has been
   425  * staged.
   426  *
   427  * @param greDir the GRE dir
   428  * @param updateDir the update root dir
   429  * @param statusFile the update.status file
   430  * @param appDir the app dir
   431  * @param appArgc the number of args to the application
   432  * @param appArgv the args to the application, used for restarting if needed
   433  */
   434 static void
   435 SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
   436                    nsIFile *appDir, int appArgc, char **appArgv)
   437 {
   438   nsresult rv;
   440   // Steps:
   441   //  - copy updater into temp dir
   442   //  - run updater with the correct arguments
   444   nsCOMPtr<nsIFile> tmpDir;
   445   GetSpecialSystemDirectory(OS_TemporaryDirectory,
   446                             getter_AddRefs(tmpDir));
   447   if (!tmpDir) {
   448     LOG(("failed getting a temp dir\n"));
   449     return;
   450   }
   452   // Try to create our own new temp directory in case there is already an
   453   // updater binary in the OS temporary location which we cannot write to.
   454   // Note that we don't check for errors here, as if this directory can't
   455   // be created, the following CopyUpdaterIntoUpdateDir call will fail.
   456   // We create the unique directory inside a subfolder of MozUpdater instead
   457   // of directly in the temp directory so we can efficiently delete everything
   458   // after updates.
   459   tmpDir->Append(NS_LITERAL_STRING("MozUpdater"));
   460   tmpDir->Append(NS_LITERAL_STRING("bgupdate"));
   461   tmpDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0755);
   463   nsCOMPtr<nsIFile> updater;
   464   if (!CopyUpdaterIntoUpdateDir(greDir, appDir, tmpDir, updater)) {
   465     LOG(("failed copying updater\n"));
   466     return;
   467   }
   469   // We need to use the value returned from XRE_GetBinaryPath when attempting
   470   // to restart the running application.
   471   nsCOMPtr<nsIFile> appFile;
   473 #if defined(XP_MACOSX)
   474   // On OS X we need to pass the location of the xulrunner-stub executable
   475   // rather than xulrunner-bin. See bug 349737.
   476   GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile));
   477 #else
   478   XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile));
   479 #endif
   481   if (!appFile)
   482     return;
   484 #ifdef XP_WIN
   485   nsAutoString appFilePathW;
   486   rv = appFile->GetPath(appFilePathW);
   487   if (NS_FAILED(rv))
   488     return;
   489   NS_ConvertUTF16toUTF8 appFilePath(appFilePathW);
   491   nsAutoString updaterPathW;
   492   rv = updater->GetPath(updaterPathW);
   493   if (NS_FAILED(rv))
   494     return;
   496   NS_ConvertUTF16toUTF8 updaterPath(updaterPathW);
   497 #else
   499   nsAutoCString appFilePath;
   500 #if defined(MOZ_WIDGET_GONK)
   501   appFilePath.Assign(kB2GServiceArgv[0]);
   502   appArgc = kB2GServiceArgc;
   503   appArgv = const_cast<char**>(kB2GServiceArgv);
   504 #else
   505   rv = appFile->GetNativePath(appFilePath);
   506   if (NS_FAILED(rv))
   507     return;
   508 #endif
   510   nsAutoCString updaterPath;
   511   rv = updater->GetNativePath(updaterPath);
   512   if (NS_FAILED(rv))
   513     return;
   514 #endif
   516   // Get the directory to which the update will be applied. On Mac OSX we need
   517   // to apply the update to the Updated.app directory under the Foo.app
   518   // directory which is the parent of the parent of the appDir. On other
   519   // platforms we will just apply to the appDir/updated.
   520   nsCOMPtr<nsIFile> updatedDir;
   521 #if defined(XP_MACOSX)
   522   nsAutoCString applyToDir;
   523   {
   524     nsCOMPtr<nsIFile> parentDir1, parentDir2;
   525     rv = appDir->GetParent(getter_AddRefs(parentDir1));
   526     if (NS_FAILED(rv))
   527       return;
   528     rv = parentDir1->GetParent(getter_AddRefs(parentDir2));
   529     if (NS_FAILED(rv))
   530       return;
   531     if (!GetFile(parentDir2, NS_LITERAL_CSTRING("Updated.app"), updatedDir))
   532       return;
   533     rv = updatedDir->GetNativePath(applyToDir);
   534   }
   535 #else
   536   if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir))
   537     return;
   538 #if defined(XP_WIN)
   539   nsAutoString applyToDirW;
   540   rv = updatedDir->GetPath(applyToDirW);
   542   NS_ConvertUTF16toUTF8 applyToDir(applyToDirW);
   543 #else
   544   nsAutoCString applyToDir;
   545   rv = updatedDir->GetNativePath(applyToDir);
   546 #endif
   547 #endif
   548   if (NS_FAILED(rv))
   549     return;
   551   // Make sure that the updated directory exists
   552   bool updatedDirExists = false;
   553   updatedDir->Exists(&updatedDirExists);
   554   if (!updatedDirExists) {
   555     return;
   556   }
   558 #if defined(XP_WIN)
   559   nsAutoString updateDirPathW;
   560   rv = updateDir->GetPath(updateDirPathW);
   562   NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW);
   563 #else
   564   nsAutoCString updateDirPath;
   565   rv = updateDir->GetNativePath(updateDirPath);
   566 #endif
   568   if (NS_FAILED(rv))
   569     return;
   571   // Get the current working directory.
   572   char workingDirPath[MAXPATHLEN];
   573   rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath));
   574   if (NS_FAILED(rv))
   575     return;
   577   // Construct the PID argument for this process.  If we are using execv, then
   578   // we pass "0" which is then ignored by the updater.
   579 #if defined(USE_EXECV)
   580   nsAutoCString pid("0");
   581 #else
   582   nsAutoCString pid;
   583   pid.AppendInt((int32_t) getpid());
   584 #endif
   586   // Append a special token to the PID in order to let the updater know that it
   587   // just needs to replace the update directory.
   588   pid.AppendLiteral("/replace");
   590   int immersiveArgc = 0;
   591 #if defined(XP_WIN) && defined(MOZ_METRO)
   592   // If this is desktop doing an update for metro, or if we're the metro browser
   593   // we want to launch the metro browser after we're finished.
   594   if (IsWindowsMetroUpdateRequest(appArgc, appArgv) || IsRunningInWindowsMetro()) {
   595     immersiveArgc = 1;
   596   }
   597 #endif
   598   int argc = appArgc + 5 + immersiveArgc;
   599   char **argv = new char*[argc + 1];
   600   if (!argv)
   601     return;
   602   argv[0] = (char*) updaterPath.get();
   603   argv[1] = (char*) updateDirPath.get();
   604   argv[2] = (char*) applyToDir.get();
   605   argv[3] = (char*) pid.get();
   606   if (appArgc) {
   607     argv[4] = workingDirPath;
   608     argv[5] = (char*) appFilePath.get();
   609     for (int i = 1; i < appArgc; ++i)
   610       argv[5 + i] = appArgv[i];
   611 #ifdef XP_WIN
   612     if (immersiveArgc) {
   613       argv[argc - 1] = "-ServerName:DefaultBrowserServer";
   614     }
   615 #endif
   616     argv[argc] = nullptr;
   617   } else {
   618     argc = 4;
   619     argv[4] = nullptr;
   620   }
   622   if (gSafeMode) {
   623     PR_SetEnv("MOZ_SAFE_MODE_RESTART=1");
   624   }
   626 #if defined(XP_WIN)
   627   nsresult rv2 = AdjustPathForUpdater(appDir);
   628   if (NS_FAILED(rv2)) {
   629     LOG(("SwitchToUpdatedApp -- AdjustPathForUpdater failed (0x%x)\n", rv2));
   630   }
   631 #endif
   633   LOG(("spawning updater process for replacing [%s]\n", updaterPath.get()));
   635 #if defined(USE_EXECV)
   636 # if defined(MOZ_WIDGET_GONK)
   637   // In Gonk, we preload libmozglue, which the updater process doesn't need.
   638   // Since the updater will move and delete libmozglue.so, this can actually
   639   // stop the /system mount from correctly being remounted as read-only.
   640   unsetenv("LD_PRELOAD");
   641 # endif
   642   execv(updaterPath.get(), argv);
   643 #elif defined(XP_WIN)
   644   // Switch the application using updater.exe
   645   if (!WinLaunchChild(updaterPathW.get(), argc, argv)) {
   646     return;
   647   }
   648   _exit(0);
   649 #elif defined(XP_MACOSX)
   650   CommandLineServiceMac::SetupMacCommandLine(argc, argv, true);
   651   // LaunchChildMac uses posix_spawnp and prefers the current
   652   // architecture when launching. It doesn't require a
   653   // null-terminated string but it doesn't matter if we pass one.
   654   LaunchChildMac(argc, argv);
   655   exit(0);
   656 #else
   657   PR_CreateProcessDetached(updaterPath.get(), argv, nullptr, nullptr);
   658   exit(0);
   659 #endif
   660 }
   662 #if defined(MOZ_WIDGET_GONK)
   663 static nsresult
   664 GetOSApplyToDir(nsACString& applyToDir)
   665 {
   666   nsCOMPtr<nsIProperties> ds =
   667     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
   668   NS_ASSERTION(ds, "Can't get directory service");
   670   nsCOMPtr<nsIFile> osApplyToDir;
   671   nsresult rv = ds->Get(XRE_OS_UPDATE_APPLY_TO_DIR, NS_GET_IID(nsIFile),
   672                                    getter_AddRefs(osApplyToDir));
   673   if (NS_FAILED(rv)) {
   674     LOG(("Can't get the OS applyTo dir"));
   675     return rv;
   676   }
   678   return osApplyToDir->GetNativePath(applyToDir);
   679 }
   681 static void
   682 SetOSApplyToDir(nsIUpdate* update, const nsACString& osApplyToDir)
   683 {
   684   nsresult rv;
   685   nsCOMPtr<nsIWritablePropertyBag> updateProperties =
   686     do_QueryInterface(update, &rv);
   688   if (NS_FAILED(rv)) {
   689     return;
   690   }
   692   nsCOMPtr<nsIWritableVariant> variant =
   693     do_CreateInstance("@mozilla.org/variant;1", &rv);
   694   if (NS_FAILED(rv)) {
   695     return;
   696   }
   698   rv = variant->SetAsACString(osApplyToDir);
   699   if (NS_FAILED(rv)) {
   700     return;
   701   }
   703   updateProperties->SetProperty(NS_LITERAL_STRING("osApplyToDir"), variant);
   704 }
   705 #endif
   707 /**
   708  * Apply an update. This applies to both normal and staged updates.
   709  *
   710  * @param greDir the GRE dir
   711  * @param updateDir the update root dir
   712  * @param statusFile the update.status file
   713  * @param appDir the app dir
   714  * @param appArgc the number of args to the application
   715  * @param appArgv the args to the application, used for restarting if needed
   716  * @param restart if true, apply the update in the foreground and restart the
   717  *                application when done.  otherwise, stage the update and don't
   718  *                restart the application.
   719  * @param outpid out parameter holding the handle to the updater application for
   720  *               staging updates.
   721  */
   722 static void
   723 ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile,
   724             nsIFile *appDir, int appArgc, char **appArgv,
   725             bool restart, bool isOSUpdate, nsIFile *osApplyToDir,
   726             ProcessType *outpid)
   727 {
   728   nsresult rv;
   730   // Steps:
   731   //  - mark update as 'applying'
   732   //  - copy updater into update dir
   733   //  - run updater w/ appDir as the current working dir
   735   nsCOMPtr<nsIFile> updater;
   736   if (!CopyUpdaterIntoUpdateDir(greDir, appDir, updateDir, updater)) {
   737     LOG(("failed copying updater\n"));
   738     return;
   739   }
   741   // We need to use the value returned from XRE_GetBinaryPath when attempting
   742   // to restart the running application.
   743   nsCOMPtr<nsIFile> appFile;
   745 #if defined(XP_MACOSX)
   746   // On OS X we need to pass the location of the xulrunner-stub executable
   747   // rather than xulrunner-bin. See bug 349737.
   748   GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile));
   749 #else
   750   XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile));
   751 #endif
   753   if (!appFile)
   754     return;
   756 #ifdef XP_WIN
   757   nsAutoString appFilePathW;
   758   rv = appFile->GetPath(appFilePathW);
   759   if (NS_FAILED(rv))
   760     return;
   761   NS_ConvertUTF16toUTF8 appFilePath(appFilePathW);
   763   nsAutoString updaterPathW;
   764   rv = updater->GetPath(updaterPathW);
   765   if (NS_FAILED(rv))
   766     return;
   768   NS_ConvertUTF16toUTF8 updaterPath(updaterPathW);
   770 #else
   771   nsAutoCString appFilePath;
   772   rv = appFile->GetNativePath(appFilePath);
   773   if (NS_FAILED(rv))
   774     return;
   776   nsAutoCString updaterPath;
   777   rv = updater->GetNativePath(updaterPath);
   778   if (NS_FAILED(rv))
   779     return;
   781 #endif
   783   // Get the directory to which the update will be applied. On Mac OSX we need
   784   // to apply the update to the Updated.app directory under the Foo.app
   785   // directory which is the parent of the parent of the appDir. On other
   786   // platforms we will just apply to the appDir/updated.
   787   nsCOMPtr<nsIFile> updatedDir;
   788 #if defined(XP_MACOSX)
   789   nsAutoCString applyToDir;
   790   {
   791     nsCOMPtr<nsIFile> parentDir1, parentDir2;
   792     rv = appDir->GetParent(getter_AddRefs(parentDir1));
   793     if (NS_FAILED(rv))
   794       return;
   795     rv = parentDir1->GetParent(getter_AddRefs(parentDir2));
   796     if (NS_FAILED(rv))
   797       return;
   798     if (restart) {
   799       // Use the correct directory if we're not staging the update.
   800       rv = parentDir2->GetNativePath(applyToDir);
   801     } else {
   802       if (!GetFile(parentDir2, NS_LITERAL_CSTRING("Updated.app"), updatedDir))
   803         return;
   804       rv = updatedDir->GetNativePath(applyToDir);
   805     }
   806   }
   807 #else
   808   if (restart) {
   809     // Use the correct directory if we're not staging the update.
   810     updatedDir = do_QueryInterface(appDir);
   811   } else if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) {
   812     return;
   813   }
   814 #if defined(XP_WIN)
   815   nsAutoString applyToDirW;
   816   rv = updatedDir->GetPath(applyToDirW);
   818   NS_ConvertUTF16toUTF8 applyToDir(applyToDirW);
   819 #else
   820   nsAutoCString applyToDir;
   822 #if defined(MOZ_WIDGET_GONK)
   823   if (isOSUpdate) {
   824     if (!osApplyToDir) {
   825       return;
   826     }
   828     rv = osApplyToDir->GetNativePath(applyToDir);
   829   } else {
   830 #endif // defined(MOZ_WIDGET_GONK)
   832     rv = updatedDir->GetNativePath(applyToDir);
   834 #if defined(MOZ_WIDGET_GONK)
   835   }
   836 #endif // defined(MOZ_WIDGET_GONK)
   838 #endif // defined(XP_WIN)
   839 #endif
   841   if (NS_FAILED(rv))
   842     return;
   844 #if defined(XP_WIN)
   845   nsAutoString updateDirPathW;
   846   rv = updateDir->GetPath(updateDirPathW);
   848   NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW);
   849 #else
   850   nsAutoCString updateDirPath;
   851   rv = updateDir->GetNativePath(updateDirPath);
   852 #endif
   854   if (NS_FAILED(rv))
   855     return;
   857   // Get the current working directory.
   858   char workingDirPath[MAXPATHLEN];
   859   rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath));
   860   if (NS_FAILED(rv))
   861     return;
   863   // We used to write out "Applying" to the update.status file here.
   864   // Instead we do this from within the updater application now.
   865   // This is so that we don't overwrite the status of pending-service
   866   // in the Windows case.  This change was made for all platforms so
   867   // that it stays consistent across all OS.
   869   // Construct the PID argument for this process.  If we are using execv, then
   870   // we pass "0" which is then ignored by the updater.
   871   nsAutoCString pid;
   872   if (!restart) {
   873     // Signal the updater application that it should stage the update.
   874     pid.AssignASCII("-1");
   875   } else {
   876 #if defined(USE_EXECV)
   877     pid.AssignASCII("0");
   878 #else
   879     pid.AppendInt((int32_t) getpid());
   880 #endif
   881   }
   883   int immersiveArgc = 0;
   884 #if defined(XP_WIN) && defined(MOZ_METRO)
   885   // If this is desktop doing an update for metro, or if we're the metro browser
   886   // we want to launch the metro browser after we're finished.
   887   if (IsWindowsMetroUpdateRequest(appArgc, appArgv) || IsRunningInWindowsMetro()) {
   888     immersiveArgc = 1;
   889   }
   890 #endif
   891   int argc = appArgc + 5 + immersiveArgc;
   892   char **argv = new char*[argc + 1 ];
   893   if (!argv)
   894     return;
   895   argv[0] = (char*) updaterPath.get();
   896   argv[1] = (char*) updateDirPath.get();
   897   argv[2] = (char*) applyToDir.get();
   898   argv[3] = (char*) pid.get();
   899   if (restart && appArgc) {
   900     argv[4] = workingDirPath;
   901     argv[5] = (char*) appFilePath.get();
   902     for (int i = 1; i < appArgc; ++i)
   903       argv[5 + i] = appArgv[i];
   904 #ifdef XP_WIN
   905     if (immersiveArgc) {
   906       argv[argc - 1] = "-ServerName:DefaultBrowserServer";
   907     }
   908 #endif
   909     argv[argc] = nullptr;
   910   } else {
   911     argc = 4;
   912     argv[4] = nullptr;
   913   }
   915   if (gSafeMode) {
   916     PR_SetEnv("MOZ_SAFE_MODE_RESTART=1");
   917   }
   919   if (isOSUpdate) {
   920     PR_SetEnv("MOZ_OS_UPDATE=1");
   921   }
   923 #if defined(XP_WIN)
   924   nsresult rv2 = AdjustPathForUpdater(appDir);
   925   if (NS_FAILED(rv2)) {
   926     LOG(("ApplyUpdate -- AdjustPathForUpdater failed (0x%x)\n", rv2));
   927   }
   928 #endif
   930 #if defined(MOZ_WIDGET_GONK)
   931   // We want the updater to be CPU friendly and not subject to being killed by
   932   // the low memory killer, so we pass in some preferences to allow it to
   933   // adjust its priority.
   935   int32_t prioVal = Preferences::GetInt(kAppUpdaterPrio,
   936                                         kAppUpdaterPrioDefault);
   937   int32_t oomScoreAdj = Preferences::GetInt(kAppUpdaterOomScoreAdj,
   938                                             kAppUpdaterOomScoreAdjDefault);
   939   int32_t ioprioClass = Preferences::GetInt(kAppUpdaterIOPrioClass,
   940                                             kAppUpdaterIOPrioClassDefault);
   941   int32_t ioprioLevel = Preferences::GetInt(kAppUpdaterIOPrioLevel,
   942                                             kAppUpdaterIOPrioLevelDefault);
   943   nsPrintfCString prioEnv("MOZ_UPDATER_PRIO=%d/%d/%d/%d",
   944                           prioVal, oomScoreAdj, ioprioClass, ioprioLevel);
   945   PR_SetEnv(prioEnv.get());
   946 #endif
   948   LOG(("spawning updater process [%s]\n", updaterPath.get()));
   949 #ifdef DEBUG
   950   dump_argv("ApplyUpdate updater", argv, argc);
   951 #endif
   953 #if defined(USE_EXECV)
   954   // Don't use execv when staging updates.
   955   if (restart) {
   956     execv(updaterPath.get(), argv);
   957   } else {
   958     *outpid = PR_CreateProcess(updaterPath.get(), argv, nullptr, nullptr);
   959   }
   960 #elif defined(XP_WIN)
   961   // Launch the update using updater.exe
   962   if (!WinLaunchChild(updaterPathW.get(), argc, argv, nullptr, outpid)) {
   963     return;
   964   }
   966   if (restart) {
   967     // We are going to process an update so we should exit now
   968     _exit(0);
   969   }
   970 #elif defined(XP_MACOSX)
   971   CommandLineServiceMac::SetupMacCommandLine(argc, argv, true);
   972   // LaunchChildMac uses posix_spawnp and prefers the current
   973   // architecture when launching. It doesn't require a
   974   // null-terminated string but it doesn't matter if we pass one.
   975 #ifdef DEBUG
   976   dump_argv("ApplyUpdate after SetupMacCommandLine", argv, argc);
   977 #endif
   978   LaunchChildMac(argc, argv, 0, outpid);
   979   if (restart) {
   980     exit(0);
   981   }
   982 #else
   983   *outpid = PR_CreateProcess(updaterPath.get(), argv, nullptr, nullptr);
   984   if (restart) {
   985     exit(0);
   986   }
   987 #endif
   988 }
   990 /**
   991  * Wait for a process until it terminates.  This call is blocking.
   992  */
   993 static void
   994 WaitForProcess(ProcessType pt)
   995 {
   996 #if defined(XP_WIN)
   997   WaitForSingleObject(pt, INFINITE);
   998   CloseHandle(pt);
   999 #elif defined(XP_MACOSX)
  1000   waitpid(pt, 0, 0);
  1001 #else
  1002   int32_t exitCode;
  1003   PR_WaitProcess(pt, &exitCode);
  1004   if (exitCode != 0) {
  1005     LOG(("Error while running the updater process, check update.log"));
  1007 #endif
  1010 nsresult
  1011 ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir,
  1012                int argc, char **argv, const char *appVersion,
  1013                bool restart, bool isOSUpdate, nsIFile *osApplyToDir,
  1014                ProcessType *pid)
  1016   nsresult rv;
  1018   nsCOMPtr<nsIFile> updatesDir;
  1019 #ifdef DEBUG
  1020   nsAutoCString path;
  1021   updRootDir->GetNativePath(path);
  1022   printf("ProcessUpdates updateRootDir: %s appVersion: %s\n",
  1023          path.get(), appVersion);
  1024 #endif
  1025   rv = updRootDir->Clone(getter_AddRefs(updatesDir));
  1026   if (NS_FAILED(rv))
  1027     return rv;
  1029   rv = updatesDir->AppendNative(NS_LITERAL_CSTRING("updates"));
  1030   if (NS_FAILED(rv))
  1031     return rv;
  1033   rv = updatesDir->AppendNative(NS_LITERAL_CSTRING("0"));
  1034   if (NS_FAILED(rv))
  1035     return rv;
  1037   ProcessType dummyPID; // this will only be used for MOZ_UPDATE_STAGING
  1038   const char *processingUpdates = PR_GetEnv("MOZ_PROCESS_UPDATES");
  1039   if (processingUpdates && *processingUpdates) {
  1040     // Enable the tests to request an update to be staged.
  1041     const char *stagingUpdate = PR_GetEnv("MOZ_UPDATE_STAGING");
  1042     if (stagingUpdate && *stagingUpdate) {
  1043       restart = false;
  1044       pid = &dummyPID;
  1048   nsCOMPtr<nsIFile> statusFile;
  1049   UpdateStatus status = GetUpdateStatus(updatesDir, statusFile);
  1050 #ifdef DEBUG
  1051   printf("ProcessUpdates status: %d\n", status);
  1052   updatesDir->GetNativePath(path);
  1053   printf("ProcessUpdates updatesDir: %s\n", path.get());
  1054 #endif
  1055   switch (status) {
  1056   case ePendingUpdate:
  1057   case ePendingService: {
  1058     nsCOMPtr<nsIFile> versionFile;
  1059     // Remove the update if the update application version file doesn't exist
  1060     // or if the update's application version is less than the current
  1061     // application version.
  1062     if (!GetVersionFile(updatesDir, versionFile) ||
  1063         IsOlderVersion(versionFile, appVersion)) {
  1064       updatesDir->Remove(true);
  1065     } else {
  1066       ApplyUpdate(greDir, updatesDir, statusFile,
  1067                   appDir, argc, argv, restart, isOSUpdate, osApplyToDir, pid);
  1069     break;
  1071   case eAppliedUpdate:
  1072   case eAppliedService:
  1073     // An update was staged and needs to be switched so the updated application
  1074     // is used.
  1075     SwitchToUpdatedApp(greDir, updatesDir, statusFile,
  1076                        appDir, argc, argv);
  1077     break;
  1078   case eNoUpdateAction:
  1079     // We don't need to do any special processing here, we'll just continue to
  1080     // startup the application.
  1081     break;
  1084   return NS_OK;
  1089 NS_IMPL_ISUPPORTS(nsUpdateProcessor, nsIUpdateProcessor)
  1091 nsUpdateProcessor::nsUpdateProcessor()
  1092   : mUpdaterPID(0)
  1096 NS_IMETHODIMP
  1097 nsUpdateProcessor::ProcessUpdate(nsIUpdate* aUpdate)
  1099   nsCOMPtr<nsIFile> greDir, appDir, updRoot;
  1100   nsAutoCString appVersion;
  1101   int argc;
  1102   char **argv;
  1104   nsAutoCString binPath;
  1105   nsXREDirProvider* dirProvider = nsXREDirProvider::GetSingleton();
  1106   if (dirProvider) { // Normal code path
  1107     // Check for and process any available updates
  1108     bool persistent;
  1109     nsresult rv = NS_ERROR_FAILURE; // Take the NS_FAILED path when non-GONK
  1110 #ifdef MOZ_WIDGET_GONK
  1111     // Check in the sdcard for updates first, since that's our preferred
  1112     // download location.
  1113     rv = dirProvider->GetFile(XRE_UPDATE_ARCHIVE_DIR, &persistent,
  1114                               getter_AddRefs(updRoot));
  1115 #endif
  1116     if (NS_FAILED(rv)) {
  1117       rv = dirProvider->GetFile(XRE_UPDATE_ROOT_DIR, &persistent,
  1118                                 getter_AddRefs(updRoot));
  1120     // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed
  1121     if (NS_FAILED(rv))
  1122       updRoot = dirProvider->GetAppDir();
  1124     greDir = dirProvider->GetGREDir();
  1125     nsCOMPtr<nsIFile> exeFile;
  1126     rv = dirProvider->GetFile(XRE_EXECUTABLE_FILE, &persistent,
  1127                               getter_AddRefs(exeFile));
  1128     if (NS_SUCCEEDED(rv))
  1129       rv = exeFile->GetParent(getter_AddRefs(appDir));
  1131     if (NS_FAILED(rv))
  1132       appDir = dirProvider->GetAppDir();
  1134 #ifdef TOR_BROWSER_UPDATE
  1135     appVersion = TOR_BROWSER_VERSION;
  1136 #else
  1137     appVersion = gAppData->version;
  1138 #endif
  1139     argc = gRestartArgc;
  1140     argv = gRestartArgv;
  1141   } else {
  1142     // In the xpcshell environment, the usual XRE_main is not run, so things
  1143     // like dirProvider and gAppData do not exist.  This code path accesses
  1144     // XPCOM (which is not available in the previous code path) in order to get
  1145     // the same information.
  1146     nsCOMPtr<nsIProperties> ds =
  1147       do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
  1148     if (!ds) {
  1149       NS_ABORT(); // There's nothing which we can do if this fails!
  1152     nsresult rv = ds->Get(NS_GRE_DIR, NS_GET_IID(nsIFile),
  1153                           getter_AddRefs(greDir));
  1154     NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the GRE dir");
  1155     appDir = greDir;
  1157     rv = ds->Get(XRE_UPDATE_ROOT_DIR, NS_GET_IID(nsIFile),
  1158                  getter_AddRefs(updRoot));
  1159     if (NS_FAILED(rv))
  1160       updRoot = appDir;
  1162     // To support Tor Browser Bundle updates from xpcshell, modify the
  1163     // following code to use the TBB version fron the configure process.
  1164     nsCOMPtr<nsIXULAppInfo> appInfo =
  1165       do_GetService("@mozilla.org/xre/app-info;1");
  1166     if (appInfo) {
  1167       rv = appInfo->GetVersion(appVersion);
  1168       NS_ENSURE_SUCCESS(rv, rv);
  1169     } else {
  1170       appVersion = MOZ_APP_VERSION;
  1173     // We need argv[0] to point to the current executable's name.  The rest of
  1174     // the entries in this array will be ignored if argc<2.  Therefore, for
  1175     // xpcshell, we only fill out that item, and leave the rest empty.
  1176     argc = 1;
  1177     nsCOMPtr<nsIFile> binary;
  1178     rv = ds->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile),
  1179                  getter_AddRefs(binary));
  1180     NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the binary path");
  1181     binary->GetNativePath(binPath);
  1184   // Copy the parameters to the StagedUpdateInfo structure shared with the
  1185   // watcher thread.
  1186   mInfo.mGREDir = greDir;
  1187   mInfo.mAppDir = appDir;
  1188   mInfo.mUpdateRoot = updRoot;
  1189   mInfo.mArgc = argc;
  1190   mInfo.mArgv = new char*[argc];
  1191   if (dirProvider) {
  1192     for (int i = 0; i < argc; ++i) {
  1193       const size_t length = strlen(argv[i]);
  1194       mInfo.mArgv[i] = new char[length + 1];
  1195       strcpy(mInfo.mArgv[i], argv[i]);
  1197   } else {
  1198     MOZ_ASSERT(argc == 1); // see above
  1199     const size_t length = binPath.Length();
  1200     mInfo.mArgv[0] = new char[length + 1];
  1201     strcpy(mInfo.mArgv[0], binPath.get());
  1203   mInfo.mAppVersion = appVersion;
  1205 #if defined(MOZ_WIDGET_GONK)
  1206   NS_ENSURE_ARG_POINTER(aUpdate);
  1208   bool isOSUpdate;
  1209   if (NS_SUCCEEDED(aUpdate->GetIsOSUpdate(&isOSUpdate)) &&
  1210       isOSUpdate) {
  1211     nsAutoCString osApplyToDir;
  1213     // This needs to be done on the main thread, so we pass it along in
  1214     // BackgroundThreadInfo
  1215     nsresult rv = GetOSApplyToDir(osApplyToDir);
  1216     if (NS_FAILED(rv)) {
  1217       LOG(("Can't get the OS apply to dir"));
  1218       return rv;
  1221     SetOSApplyToDir(aUpdate, osApplyToDir);
  1223     mInfo.mIsOSUpdate = true;
  1224     rv = NS_NewNativeLocalFile(osApplyToDir, false,
  1225                                getter_AddRefs(mInfo.mOSApplyToDir));
  1226     if (NS_FAILED(rv)) {
  1227       LOG(("Can't create nsIFile for OS apply to dir"));
  1228       return rv;
  1231 #endif
  1233   mUpdate = aUpdate;
  1235   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
  1236   return NS_NewThread(getter_AddRefs(mProcessWatcher),
  1237                       NS_NewRunnableMethod(this, &nsUpdateProcessor::StartStagedUpdate));
  1242 void
  1243 nsUpdateProcessor::StartStagedUpdate()
  1245   NS_ABORT_IF_FALSE(!NS_IsMainThread(), "main thread");
  1247   nsresult rv = ProcessUpdates(mInfo.mGREDir,
  1248                                mInfo.mAppDir,
  1249                                mInfo.mUpdateRoot,
  1250                                mInfo.mArgc,
  1251                                mInfo.mArgv,
  1252                                mInfo.mAppVersion.get(),
  1253                                false,
  1254                                mInfo.mIsOSUpdate,
  1255                                mInfo.mOSApplyToDir,
  1256                                &mUpdaterPID);
  1257   NS_ENSURE_SUCCESS_VOID(rv);
  1259   if (mUpdaterPID) {
  1260     // Track the state of the updater process while it is staging an update.
  1261     rv = NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, &nsUpdateProcessor::WaitForProcess));
  1262     NS_ENSURE_SUCCESS_VOID(rv);
  1263   } else {
  1264     // Failed to launch the updater process for some reason.
  1265     // We need to shutdown the current thread as there isn't anything more for
  1266     // us to do...
  1267     rv = NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsUpdateProcessor::ShutdownWatcherThread));
  1268     NS_ENSURE_SUCCESS_VOID(rv);
  1272 void
  1273 nsUpdateProcessor::ShutdownWatcherThread()
  1275   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
  1276   mProcessWatcher->Shutdown();
  1277   mProcessWatcher = nullptr;
  1278   mUpdate = nullptr;
  1281 void
  1282 nsUpdateProcessor::WaitForProcess()
  1284   NS_ABORT_IF_FALSE(!NS_IsMainThread(), "main thread");
  1285   ::WaitForProcess(mUpdaterPID);
  1286   NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsUpdateProcessor::UpdateDone));
  1289 void
  1290 nsUpdateProcessor::UpdateDone()
  1292   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
  1294   nsCOMPtr<nsIUpdateManager> um =
  1295     do_GetService("@mozilla.org/updates/update-manager;1");
  1296   if (um && mUpdate) {
  1297     um->RefreshUpdateStatus(mUpdate);
  1300   ShutdownWatcherThread();

mercurial