diff --git a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js index 8c1000da1ace..86cfb5e44249 100644 --- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js +++ b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js @@ -772,6 +772,8 @@ function setupTestCommon() { let caller = Components.stack.caller; gTestID = caller.filename.toString().split("/").pop().split(".")[0]; + createAppInfo("xpcshell@tests.mozilla.org", APP_INFO_NAME, "1.0", "2.0"); + // Tests that don't work with XULRunner. const XUL_RUNNER_INCOMPATIBLE = ["marAppApplyUpdateAppBinInUseStageSuccess_win", "marAppApplyUpdateStageSuccess", @@ -1105,7 +1107,6 @@ function checkPostUpdateRunningFile(aShouldExist) { * update service stub. */ function standardInit() { - createAppInfo("xpcshell@tests.mozilla.org", APP_INFO_NAME, "1.0", "2.0"); // Initialize the update service stub component initUpdateServiceStub(); } @@ -1892,10 +1893,15 @@ function stageUpdate(aCheckSvcLog) { setAppBundleModTime(); setEnvironment(); - // Stage the update. - Cc["@mozilla.org/updates/update-processor;1"]. - createInstance(Ci.nsIUpdateProcessor). - processUpdate(gUpdateManager.activeUpdate); + try { + // Stage the update. + Cc["@mozilla.org/updates/update-processor;1"]. + createInstance(Ci.nsIUpdateProcessor). + processUpdate(gUpdateManager.activeUpdate); + } catch (e) { + Assert.ok(false, + "error thrown while calling processUpdate, exception: " + e); + } // The environment is not reset here because processUpdate in // nsIUpdateProcessor uses a new thread and clearing the environment diff --git a/toolkit/mozapps/update/updater/automounter_gonk.cpp b/toolkit/mozapps/update/updater/automounter_gonk.cpp deleted file mode 100644 index 3dff2a1337a1..000000000000 --- a/toolkit/mozapps/update/updater/automounter_gonk.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "automounter_gonk.h" -#include "updatedefines.h" -#include "updatelogging.h" - -#define LOG_TAG "GonkAutoMounter" - -#define GONK_LOG(level, format, ...) \ - LOG((LOG_TAG ": " format "\n", ##__VA_ARGS__)); \ - __android_log_print(level, LOG_TAG, format, ##__VA_ARGS__) - -#define LOGI(format, ...) GONK_LOG(ANDROID_LOG_INFO, format, ##__VA_ARGS__) -#define LOGE(format, ...) GONK_LOG(ANDROID_LOG_ERROR, format, ##__VA_ARGS__) - -const char *kGonkMountsPath = "/proc/mounts"; -const char *kGonkSystemPath = "/system"; - -GonkAutoMounter::GonkAutoMounter() : mDevice(nullptr), mAccess(Unknown) -{ - if (!RemountSystem(ReadWrite)) { - LOGE("Could not remount %s as read-write.", kGonkSystemPath); - } -} - -GonkAutoMounter::~GonkAutoMounter() -{ - bool result = RemountSystem(ReadOnly); - free(mDevice); - - if (!result) { - // Don't take any chances when remounting as read-only fails, just reboot. - Reboot(); - } -} - -void -GonkAutoMounter::Reboot() -{ - // The android_reboot wrapper provides more safety, doing fancier read-only - // remounting and attempting to sync() the filesystem first. If this fails - // our only hope is to force a reboot directly without these protections. - // For more, see system/core/libcutils/android_reboot.c - LOGE("Could not remount %s as read-only, forcing a system reboot.", - kGonkSystemPath); - LogFlush(); - - if (android_reboot(ANDROID_RB_RESTART, 0, nullptr) != 0) { - LOGE("Safe system reboot failed, attempting to force"); - LogFlush(); - - if (reboot(RB_AUTOBOOT) != 0) { - LOGE("CRITICAL: Failed to force restart"); - } - } -} - -static const char * -MountAccessToString(MountAccess access) -{ - switch (access) { - case ReadOnly: return "read-only"; - case ReadWrite: return "read-write"; - default: return "unknown"; - } -} - -bool -GonkAutoMounter::RemountSystem(MountAccess access) -{ - if (!UpdateMountStatus()) { - return false; - } - - if (mAccess == access) { - return true; - } - - unsigned long flags = MS_REMOUNT; - if (access == ReadOnly) { - flags |= MS_RDONLY; - // Give the system a chance to flush file buffers - sync(); - } - - if (!MountSystem(flags)) { - return false; - } - - // Check status again to verify /system has been properly remounted - if (!UpdateMountStatus()) { - return false; - } - - if (mAccess != access) { - LOGE("Updated mount status %s should be %s", - MountAccessToString(mAccess), - MountAccessToString(access)); - return false; - } - - return true; -} - -bool -GonkAutoMounter::UpdateMountStatus() -{ - FILE *mountsFile = NS_tfopen(kGonkMountsPath, "r"); - - if (mountsFile == nullptr) { - LOGE("Error opening %s: %s", kGonkMountsPath, strerror(errno)); - return false; - } - - // /proc/mounts returns a 0 size from fstat, so we use the same - // pre-allocated buffer size that ADB does here - const int mountsMaxSize = 4096; - char mountData[mountsMaxSize]; - size_t read = fread(mountData, 1, mountsMaxSize - 1, mountsFile); - mountData[read + 1] = '\0'; - - if (ferror(mountsFile)) { - LOGE("Error reading %s, %s", kGonkMountsPath, strerror(errno)); - fclose(mountsFile); - return false; - } - - char *token, *tokenContext; - bool foundSystem = false; - - for (token = strtok_r(mountData, "\n", &tokenContext); - token; - token = strtok_r(nullptr, "\n", &tokenContext)) - { - if (ProcessMount(token)) { - foundSystem = true; - break; - } - } - - fclose(mountsFile); - - if (!foundSystem) { - LOGE("Couldn't find %s mount in %s", kGonkSystemPath, kGonkMountsPath); - } - return foundSystem; -} - -bool -GonkAutoMounter::ProcessMount(const char *mount) -{ - const int strSize = 256; - char mountDev[strSize]; - char mountDir[strSize]; - char mountAccess[strSize]; - - int rv = sscanf(mount, "%255s %255s %*s %255s %*d %*d\n", - mountDev, mountDir, mountAccess); - mountDev[strSize - 1] = '\0'; - mountDir[strSize - 1] = '\0'; - mountAccess[strSize - 1] = '\0'; - - if (rv != 3) { - return false; - } - - if (strcmp(kGonkSystemPath, mountDir) != 0) { - return false; - } - - free(mDevice); - mDevice = strdup(mountDev); - mAccess = Unknown; - - char *option, *optionContext; - for (option = strtok_r(mountAccess, ",", &optionContext); - option; - option = strtok_r(nullptr, ",", &optionContext)) - { - if (strcmp("ro", option) == 0) { - mAccess = ReadOnly; - break; - } else if (strcmp("rw", option) == 0) { - mAccess = ReadWrite; - break; - } - } - - return true; -} - -/* - * Mark the given block device as read-write or read-only, using the BLKROSET - * ioctl. - */ -static void SetBlockReadWriteStatus(const char *blockdev, bool setReadOnly) { - int fd; - int roMode = setReadOnly ? 1 : 0; - - fd = open(blockdev, O_RDONLY); - if (fd < 0) { - return; - } - - if (ioctl(fd, BLKROSET, &roMode) == -1) { - LOGE("Error setting read-only mode on %s to %s: %s", blockdev, - setReadOnly ? "true": "false", strerror(errno)); - } - close(fd); -} - - -bool -GonkAutoMounter::MountSystem(unsigned long flags) -{ - if (!mDevice) { - LOGE("No device was found for %s", kGonkSystemPath); - return false; - } - - // Without setting the block device ro mode to false, we get a permission - // denied error while trying to remount it in read-write. - SetBlockReadWriteStatus(mDevice, (flags & MS_RDONLY)); - - const char *readOnly = flags & MS_RDONLY ? "read-only" : "read-write"; - int result = mount(mDevice, kGonkSystemPath, "none", flags, nullptr); - - if (result != 0) { - LOGE("Error mounting %s as %s: %s", kGonkSystemPath, readOnly, - strerror(errno)); - return false; - } - - LOGI("Mounted %s partition as %s", kGonkSystemPath, readOnly); - return true; -} diff --git a/toolkit/mozapps/update/updater/automounter_gonk.h b/toolkit/mozapps/update/updater/automounter_gonk.h deleted file mode 100644 index e40cacbc2e15..000000000000 --- a/toolkit/mozapps/update/updater/automounter_gonk.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef AUTOMOUNTER_GONK_H__ -#define AUTOMOUNTER_GONK_H__ - -typedef enum { - ReadOnly, - ReadWrite, - Unknown -} MountAccess; - -/** - * This class will remount the /system partition as read-write in Gonk to allow - * the updater write access. Upon destruction, /system will be remounted back to - * read-only. If something causes /system to remain read-write, this class will - * reboot the device and allow the system to mount as read-only. - * - * Code inspired from AOSP system/core/adb/remount_service.c - */ -class GonkAutoMounter -{ -public: - GonkAutoMounter(); - ~GonkAutoMounter(); - - MountAccess GetAccess() const - { - return mAccess; - } - -private: - bool RemountSystem(MountAccess access); - bool ForceRemountReadOnly(); - bool UpdateMountStatus(); - bool ProcessMount(const char *mount); - bool MountSystem(unsigned long flags); - void Reboot(); - -private: - char *mDevice; - MountAccess mAccess; -}; - -#endif // AUTOMOUNTER_GONK_H__ diff --git a/toolkit/mozapps/update/updater/progressui_gonk.cpp b/toolkit/mozapps/update/updater/progressui_gonk.cpp deleted file mode 100644 index f77d0af6338a..000000000000 --- a/toolkit/mozapps/update/updater/progressui_gonk.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * vim: sw=2 ts=8 et : - */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include -#include - -#include - -#include "android/log.h" - -#include "progressui.h" - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoUpdater" , ## args) - -using namespace std; - -int InitProgressUI(int *argc, char ***argv) -{ - return 0; -} - -int ShowProgressUI() -{ - LOG("Starting to apply update ...\n"); - return 0; -} - -void QuitProgressUI() -{ - LOG("Finished applying update\n"); -} - -void UpdateProgressUI(float progress) -{ - assert(0.0f <= progress && progress <= 100.0f); - - static const size_t kProgressBarLength = 50; - static size_t sLastNumBars; - size_t numBars = size_t(float(kProgressBarLength) * progress / 100.0f); - if (numBars == sLastNumBars) { - return; - } - sLastNumBars = numBars; - - size_t numSpaces = kProgressBarLength - numBars; - string bars(numBars, '='); - string spaces(numSpaces, ' '); - LOG("Progress [ %s%s ]\n", bars.c_str(), spaces.c_str()); -} diff --git a/toolkit/mozapps/update/updater/updater-common.build b/toolkit/mozapps/update/updater/updater-common.build index 2d0a9c8ee70a..228d87011799 100644 --- a/toolkit/mozapps/update/updater/updater-common.build +++ b/toolkit/mozapps/update/updater/updater-common.build @@ -90,17 +90,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': LOCAL_INCLUDES += [ '/toolkit/xre', ] -elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - have_progressui = 1 - srcs += [ - 'automounter_gonk.cpp', - 'progressui_gonk.cpp', - ] - DISABLE_STL_WRAPPING = True - OS_LIBS += [ - 'cutils', - 'sysutils', - ] if have_progressui == 0: srcs += [ diff --git a/toolkit/mozapps/update/updater/updater.cpp b/toolkit/mozapps/update/updater/updater.cpp index 521d759bd53d..f7ed1da653f8 100644 --- a/toolkit/mozapps/update/updater/updater.cpp +++ b/toolkit/mozapps/update/updater/updater.cpp @@ -110,33 +110,8 @@ struct UpdateServerThreadArgs #define USE_EXECV #endif -#if defined(MOZ_WIDGET_GONK) -# include "automounter_gonk.h" -# include -# include -# include -# include - -#if ANDROID_VERSION < 21 -// The only header file in bionic which has a function prototype for ioprio_set -// is libc/include/sys/linux-unistd.h. However, linux-unistd.h conflicts -// badly with unistd.h, so we declare the prototype for ioprio_set directly. -extern "C" MOZ_EXPORT int ioprio_set(int which, int who, int ioprio); -#else -# include -static int ioprio_set(int which, int who, int ioprio) { - return syscall(__NR_ioprio_set, which, who, ioprio); -} -#endif - -# define MAYBE_USE_HARD_LINKS 1 -static bool sUseHardLinks = true; -#else -# define MAYBE_USE_HARD_LINKS 0 -#endif - #if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \ - !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK) + !defined(XP_MACOSX) #include "nss.h" #include "prerror.h" #endif @@ -314,7 +289,6 @@ static bool gSucceeded = false; static bool sStagedUpdate = false; static bool sReplaceRequest = false; static bool sUsingService = false; -static bool sIsOSUpdate = false; #ifdef XP_WIN // The current working directory specified in the command line. @@ -375,12 +349,20 @@ mstrtok(const NS_tchar *delims, NS_tchar **str) return ret; } +#if defined(TEST_UPDATER) +#define HAS_ENV_CHECK 1 +#elif defined(MOZ_MAINTENANCE_SERVICE) +#define HAS_ENV_CHECK 1 +#endif + +#if defined(HAS_ENV_CHECK) static bool EnvHasValue(const char *name) { const char *val = getenv(name); return (val && *val); } +#endif /** * Coverts a relative update path to a full path. @@ -688,25 +670,6 @@ static int ensure_copy_symlink(const NS_tchar *path, const NS_tchar *dest) } #endif -#if MAYBE_USE_HARD_LINKS -/* - * Creates a hardlink (destFilename) which points to the existing file - * (srcFilename). - * - * @return 0 if successful, an error otherwise - */ - -static int -create_hard_link(const NS_tchar *srcFilename, const NS_tchar *destFilename) -{ - if (link(srcFilename, destFilename) < 0) { - LOG(("link(%s, %s) failed errno = %d", srcFilename, destFilename, errno)); - return WRITE_ERROR; - } - return OK; -} -#endif - // Copy the file named path onto a new file named dest. static int ensure_copy(const NS_tchar *path, const NS_tchar *dest) { @@ -734,16 +697,6 @@ static int ensure_copy(const NS_tchar *path, const NS_tchar *dest) } #endif -#if MAYBE_USE_HARD_LINKS - if (sUseHardLinks) { - if (!create_hard_link(path, dest)) { - return OK; - } - // Since we failed to create the hard link, fall through and copy the file. - sUseHardLinks = false; - } -#endif - AutoFile infile(ensure_open(path, NS_T("rb"), ss.st_mode)); if (!infile) { LOG(("ensure_copy: failed to open the file for reading: " LOG_S ", err: %d", @@ -2476,44 +2429,8 @@ ReadMARChannelIDs(const NS_tchar *path, MARChannelStringTable *results) static int GetUpdateFileName(NS_tchar *fileName, int maxChars) { -#if defined(MOZ_WIDGET_GONK) - // If an update.link file exists, then it will contain the name - // of the update file (terminated by a newline). - - NS_tchar linkFileName[MAXPATHLEN]; - NS_tsnprintf(linkFileName, sizeof(linkFileName)/sizeof(linkFileName[0]), - NS_T("%s/update.link"), gPatchDirPath); - AutoFile linkFile(NS_tfopen(linkFileName, NS_T("rb"))); - if (linkFile == nullptr) { - NS_tsnprintf(fileName, maxChars, - NS_T("%s/update.mar"), gPatchDirPath); - return OK; - } - - char dataFileName[MAXPATHLEN]; - size_t bytesRead; - - if ((bytesRead = fread(dataFileName, 1, sizeof(dataFileName)-1, linkFile)) <= 0) { - *fileName = NS_T('\0'); - return READ_ERROR; - } - if (dataFileName[bytesRead-1] == '\n') { - // Strip trailing newline (for \n and \r\n) - bytesRead--; - } - if (dataFileName[bytesRead-1] == '\r') { - // Strip trailing CR (for \r, \r\n) - bytesRead--; - } - dataFileName[bytesRead] = '\0'; - - strncpy(fileName, dataFileName, maxChars-1); - fileName[maxChars-1] = '\0'; -#else - // We currently only support update.link files under GONK NS_tsnprintf(fileName, maxChars, NS_T("%s/update.mar"), gPatchDirPath); -#endif return OK; } @@ -2595,7 +2512,7 @@ UpdateThreadFunc(void *param) } #endif - if (rv == OK && sStagedUpdate && !sIsOSUpdate) { + if (rv == OK && sStagedUpdate) { #ifdef TEST_UPDATER // The MOZ_TEST_SKIP_UPDATE_STAGE environment variable prevents copying // the files in dist/bin in the test updater when staging an update since @@ -2757,26 +2674,7 @@ int NS_main(int argc, NS_tchar **argv) } #endif -#if defined(MOZ_WIDGET_GONK) - if (EnvHasValue("LD_PRELOAD")) { - // If the updater is launched with LD_PRELOAD set, then we wind up - // preloading libmozglue.so. Under some circumstances, this can cause - // the remount of /system to fail when going from rw to ro, so if we - // detect LD_PRELOAD we unsetenv it and relaunch ourselves without it. - // This will cause the offending preloaded library to be closed. - // - // For a variety of reasons, this is really hard to do in a safe manner - // in the parent process, so we do it here. - unsetenv("LD_PRELOAD"); - execv(argv[0], argv); - __android_log_print(ANDROID_LOG_INFO, "updater", - "execve failed: errno: %d. Exiting...", errno); - _exit(1); - } -#endif - -#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \ - !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK) +#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && !defined(XP_MACOSX) // On Windows and Mac we rely on native APIs to do verifications so we don't // need to initialize NSS at all there. // Otherwise, minimize the amount of NSS we depend on by avoiding all the NSS @@ -2929,11 +2827,6 @@ int NS_main(int argc, NS_tchar **argv) } #endif - if (EnvHasValue("MOZ_OS_UPDATE")) { - sIsOSUpdate = true; - putenv(const_cast("MOZ_OS_UPDATE=")); - } - LogInit(gPatchDirPath, NS_T("update.log")); if (!WriteStatusFile("applying")) { @@ -2988,36 +2881,6 @@ int NS_main(int argc, NS_tchar **argv) } #endif -#ifdef MOZ_WIDGET_GONK - const char *prioEnv = getenv("MOZ_UPDATER_PRIO"); - if (prioEnv) { - int32_t prioVal; - int32_t oomScoreAdj; - int32_t ioprioClass; - int32_t ioprioLevel; - if (sscanf(prioEnv, "%d/%d/%d/%d", - &prioVal, &oomScoreAdj, &ioprioClass, &ioprioLevel) == 4) { - LOG(("MOZ_UPDATER_PRIO=%s", prioEnv)); - if (setpriority(PRIO_PROCESS, 0, prioVal)) { - LOG(("setpriority(%d) failed, errno = %d", prioVal, errno)); - } - if (ioprio_set(IOPRIO_WHO_PROCESS, 0, - IOPRIO_PRIO_VALUE(ioprioClass, ioprioLevel))) { - LOG(("ioprio_set(%d,%d) failed: errno = %d", - ioprioClass, ioprioLevel, errno)); - } - FILE *fs = fopen("/proc/self/oom_score_adj", "w"); - if (fs) { - fprintf(fs, "%d", oomScoreAdj); - fclose(fs); - } else { - LOG(("Unable to open /proc/self/oom_score_adj for writing, errno = %d", - errno)); - } - } - } -#endif - #ifdef XP_WIN if (pid > 0) { HANDLE parent = OpenProcess(SYNCHRONIZE, false, (DWORD) pid); @@ -3342,27 +3205,6 @@ int NS_main(int argc, NS_tchar **argv) } #endif -#if defined(MOZ_WIDGET_GONK) - // In gonk, the master b2g process sets its umask to 0027 because - // there's no reason for it to ever create world-readable files. - // The updater binary, however, needs to do this, and it inherits - // the master process's cautious umask. So we drop down a bit here. - umask(0022); - - // Remount the /system partition as read-write for gonk. The destructor will - // remount /system as read-only. We add an extra level of scope here to avoid - // calling LogFinish() before the GonkAutoMounter destructor has a chance - // to be called - { -#if !defined(TEST_UPDATER) - GonkAutoMounter mounter; - if (mounter.GetAccess() != MountAccess::ReadWrite) { - WriteStatusFile(FILESYSTEM_MOUNT_READWRITE_ERROR); - return 1; - } -#endif -#endif - if (sStagedUpdate) { // When staging updates, blow away the old installation directory and create // it from scratch. @@ -3662,10 +3504,6 @@ int NS_main(int argc, NS_tchar **argv) } #endif /* XP_WIN */ -#if defined(MOZ_WIDGET_GONK) - } // end the extra level of scope for the GonkAutoMounter -#endif - #ifdef XP_MACOSX // When the update is successful remove the precomplete file in the root of // the application bundle and move the distribution directory from @@ -4177,10 +4015,6 @@ GetManifestContents(const NS_tchar *manifest) int AddPreCompleteActions(ActionList *list) { - if (sIsOSUpdate) { - return OK; - } - #ifdef XP_MACOSX mozilla::UniquePtr manifestPath(get_full_path( NS_T("Contents/Resources/precomplete"))); diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 1423170a5ab5..e4adbde5924a 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -3965,7 +3965,7 @@ XREMain::XRE_mainStartup(bool* aExitFlag) } #endif -#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) +#if defined(MOZ_UPDATER) && !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK) // Check for and process any available updates nsCOMPtr updRoot; bool persistent; diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp index fcbdcb9e08ad..7551f9aee751 100644 --- a/toolkit/xre/nsUpdateDriver.cpp +++ b/toolkit/xre/nsUpdateDriver.cpp @@ -18,8 +18,6 @@ #include "mozilla/Logging.h" #include "prenv.h" #include "nsVersionComparator.h" -#include "nsXREDirProvider.h" -#include "SpecialSystemDirectory.h" #include "nsDirectoryServiceDefs.h" #include "nsThreadUtils.h" #include "nsIXULAppInfo.h" @@ -40,7 +38,6 @@ # include # include # include -# include "nsWindowsHelpers.h" # define getcwd(path, size) _getcwd(path, size) # define getpid() GetCurrentProcessId() #elif defined(XP_UNIX) @@ -68,23 +65,6 @@ static LazyLogModule sUpdateLog("updatedriver"); #define UPDATER_PNG "updater.png" #endif -#if defined(MOZ_WIDGET_GONK) -#include - -static const int kB2GServiceArgc = 2; -static const char *kB2GServiceArgv[] = { "/system/bin/start", "b2g" }; - -static const char kAppUpdaterPrio[] = "app.update.updater.prio"; -static const char kAppUpdaterOomScoreAdj[] = "app.update.updater.oom_score_adj"; -static const char kAppUpdaterIOPrioClass[] = "app.update.updater.ioprio.class"; -static const char kAppUpdaterIOPrioLevel[] = "app.update.updater.ioprio.level"; - -static const int kAppUpdaterPrioDefault = 19; // -20..19 where 19 = lowest priority -static const int kAppUpdaterOomScoreAdjDefault = -1000; // -1000 = Never kill -static const int kAppUpdaterIOPrioClassDefault = IOPRIO_CLASS_IDLE; -static const int kAppUpdaterIOPrioLevelDefault = 0; // Doesn't matter for CLASS IDLE -#endif - #ifdef XP_MACOSX static void UpdateDriverSetupMacCommandLine(int& argc, char**& argv, bool restart) @@ -376,7 +356,7 @@ static bool CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir, nsCOMPtr &updater) { - // Copy the updater application from the GRE and the updater ini from the app + // Copy the updater application from the GRE and the updater ini from the app. #if defined(XP_MACOSX) if (!CopyFileIntoUpdateDir(appDir, NS_LITERAL_CSTRING(UPDATER_APP), updateDir)) return false; @@ -417,8 +397,7 @@ CopyUpdaterIntoUpdateDir(nsIFile *greDir, nsIFile *appDir, nsIFile *updateDir, * * @param pathToAppend A new library path to prepend to LD_LIBRARY_PATH */ -#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \ - !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK) +#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && !defined(XP_MACOSX) #include "prprf.h" #define PATH_SEPARATOR ":" #define LD_LIBRARY_PATH_ENVVAR_NAME "LD_LIBRARY_PATH" @@ -443,439 +422,193 @@ AppendToLibPath(const char *pathToAppend) #endif /** - * Switch an existing application directory to an updated version that has been - * staged. + * Applies, switches, or stages an update. * - * @param greDir the GRE dir - * @param updateDir the update dir where the mar file is located - * @param appDir the app dir - * @param appArgc the number of args to the application - * @param appArgv the args to the application, used for restarting if needed + * @param greDir the GRE directory + * @param updateDir the update root directory + * @param appDir the application directory + * @param appArgc the number of args passed to the application + * @param appArgv the args passed to the application + * (used for restarting the application when necessary) + * @param restart true when a restart is necessary. + * @param isStaged true when the update has already been staged + * @param outpid (out) parameter holding the handle to the updater application + * when staging updates */ static void -SwitchToUpdatedApp(nsIFile *greDir, nsIFile *updateDir, - nsIFile *appDir, int appArgc, char **appArgv) +ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *appDir, int appArgc, + char **appArgv, bool restart, bool isStaged, ProcessType *outpid) { + // The following determines the update operation to perform. + // 1. When restart is false the update will be staged. + // 2. When restart is true and isStaged is false the update will apply the mar + // file to the installation directory. + // 3. When restart is true and isStaged is true the update will switch the + // staged update with the installation directory. + nsresult rv; - // Steps: - // - copy updater into updates/0/MozUpdater/bgupdate/ dir on all platforms - // except Windows - // - run updater with the correct arguments -#ifndef XP_WIN - nsCOMPtr mozUpdaterDir; - rv = updateDir->Clone(getter_AddRefs(mozUpdaterDir)); - if (NS_FAILED(rv)) { - LOG(("failed cloning update dir\n")); - return; - } - - // Create a new directory named MozUpdater in the updates/0 directory to copy - // the updater files to that will be used to replace the installation with the - // staged application that has been updated. Note that we don't check for - // directory creation errors since the call to CopyUpdaterIntoUpdateDir will - // fail if the creation of the directory fails. A unique directory is created - // in MozUpdater in case a previous attempt locked the directory or files. - mozUpdaterDir->Append(NS_LITERAL_STRING("MozUpdater")); - mozUpdaterDir->Append(NS_LITERAL_STRING("bgupdate")); - rv = mozUpdaterDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0755); - if (NS_FAILED(rv)) { - LOG(("failed creating unique dir\n")); - return; - } - nsCOMPtr updater; - if (!CopyUpdaterIntoUpdateDir(greDir, appDir, mozUpdaterDir, updater)) { - LOG(("failed copying updater\n")); - return; - } -#endif - - // We need to use the value returned from XRE_GetBinaryPath when attempting - // to restart the running application. - nsCOMPtr appFile; - -#if defined(XP_MACOSX) - // On OS X we need to pass the location of the xulrunner-stub executable - // rather than xulrunner-bin. See bug 349737. - GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile)); -#else - XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile)); -#endif - - if (!appFile) - return; - -#ifdef XP_WIN - nsAutoString appFilePathW; - rv = appFile->GetPath(appFilePathW); - if (NS_FAILED(rv)) { - return; - } - NS_ConvertUTF16toUTF8 appFilePath(appFilePathW); - - nsCOMPtr updater; - rv = greDir->Clone(getter_AddRefs(updater)); - if (NS_FAILED(rv)) { - return; - } - - rv = updater->AppendNative(NS_LITERAL_CSTRING(UPDATER_BIN)); - if (NS_FAILED(rv)) { + nsAutoCString updaterPath; + nsAutoCString updateDirPath; +#if defined(XP_WIN) + // Get an nsIFile reference for the updater in the installation dir. + if (!GetFile(greDir, NS_LITERAL_CSTRING(UPDATER_BIN), updater)) { return; } + // Get the path to the updater. nsAutoString updaterPathW; rv = updater->GetPath(updaterPathW); if (NS_FAILED(rv)) { return; } - NS_ConvertUTF16toUTF8 updaterPath(updaterPathW); -#else + updaterPath = NS_ConvertUTF16toUTF8(updaterPathW); - nsAutoCString appFilePath; -#if defined(MOZ_WIDGET_GONK) - appFilePath.Assign(kB2GServiceArgv[0]); - appArgc = kB2GServiceArgc; - appArgv = const_cast(kB2GServiceArgv); -#else - rv = appFile->GetNativePath(appFilePath); - if (NS_FAILED(rv)) - return; -#endif - - nsAutoCString updaterPath; - rv = updater->GetNativePath(updaterPath); - if (NS_FAILED(rv)) - return; -#endif - - nsAutoCString installDirPath; - rv = GetInstallDirPath(appDir, installDirPath); - if (NS_FAILED(rv)) { - return; - } - - // Get the directory where the update will be staged. - nsAutoCString applyToDir; - nsCOMPtr updatedDir; -#ifdef XP_MACOSX - if (!GetFile(updateDir, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) { -#else - if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) { -#endif - return; - } -#ifdef XP_WIN - nsAutoString applyToDirW; - rv = updatedDir->GetPath(applyToDirW); - if (NS_FAILED(rv)) { - return; - } - applyToDir = NS_ConvertUTF16toUTF8(applyToDirW); -#else - rv = updatedDir->GetNativePath(applyToDir); -#endif - if (NS_FAILED(rv)) { - return; - } - - // Make sure that the updated directory exists - bool updatedDirExists = false; - updatedDir->Exists(&updatedDirExists); - if (!updatedDirExists) { - return; - } - -#if defined(XP_WIN) + // Get the path to the update dir. nsAutoString updateDirPathW; rv = updateDir->GetPath(updateDirPathW); - NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW); + if (NS_FAILED(rv)) { + return; + } + updateDirPath = NS_ConvertUTF16toUTF8(updateDirPathW); #else - nsAutoCString updateDirPath; + if (isStaged) { + nsCOMPtr mozUpdaterDir; + rv = updateDir->Clone(getter_AddRefs(mozUpdaterDir)); + if (NS_FAILED(rv)) { + LOG(("failed cloning update dir\n")); + return; + } + + // Create a new directory named MozUpdater in the updates/0 directory to copy + // the updater files to that will be used to replace the installation with the + // staged application that has been updated. Note that we don't check for + // directory creation errors since the call to CopyUpdaterIntoUpdateDir will + // fail if the creation of the directory fails. A unique directory is created + // in MozUpdater in case a previous attempt locked the directory or files. + mozUpdaterDir->Append(NS_LITERAL_STRING("MozUpdater")); + mozUpdaterDir->Append(NS_LITERAL_STRING("bgupdate")); + rv = mozUpdaterDir->CreateUnique(nsIFile::DIRECTORY_TYPE, 0755); + if (NS_FAILED(rv)) { + LOG(("failed creating unique dir\n")); + return; + } + + // Copy the updater and files needed to update into the MozUpdater/bgupdate + // directory in the update dir and get an nsIFile reference to the copied + // updater. + if (!CopyUpdaterIntoUpdateDir(greDir, appDir, mozUpdaterDir, updater)) { + LOG(("failed copying updater\n")); + return; + } + } else { + // Copy the updater and files needed to update into the update directory and + // get an nsIFile reference to the copied updater. + if (!CopyUpdaterIntoUpdateDir(greDir, appDir, updateDir, updater)) { + LOG(("failed copying updater\n")); + return; + } + } + + // Get the path to the updater that will be used. + rv = updater->GetNativePath(updaterPath); + if (NS_FAILED(rv)) { + return; + } + + // Get the path to the update dir. rv = updateDir->GetNativePath(updateDirPath); + if (NS_FAILED(rv)) { + return; + } #endif - if (NS_FAILED(rv)) - return; - // Get the current working directory. + // appFilePath and workingDirPath are only used when the application will be + // restarted. + nsAutoCString appFilePath; char workingDirPath[MAXPATHLEN]; - rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath)); - if (NS_FAILED(rv)) - return; + if (restart) { + // Get the path to the current working directory. + rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath)); + if (NS_FAILED(rv)) { + return; + } - // Construct the PID argument for this process. We start the updater using - // execv on all Unix platforms except Mac, so on those platforms we pass 0 - // instead of a good PID to signal the updater not to try and wait for us. -#if defined(XP_UNIX) & !defined(XP_MACOSX) - nsAutoCString pid("0"); + // Get the application file path used by the updater to restart the + // application after the update has finished. + nsCOMPtr appFile; +#if defined(XP_MACOSX) + // On OS X we need to pass the location of the xulrunner-stub executable + // rather than xulrunner-bin. See bug 349737. + GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile)); #else - nsAutoCString pid; - pid.AppendInt((int32_t) getpid()); + XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile)); #endif + if (!appFile) { + return; + } - // Append a special token to the PID in order to let the updater know that it - // just needs to replace the update directory. - pid.AppendLiteral("/replace"); - - int immersiveArgc = 0; - int argc = appArgc + 6 + immersiveArgc; - char **argv = new char*[argc + 1]; - if (!argv) - return; - argv[0] = (char*) updaterPath.get(); - argv[1] = (char*) updateDirPath.get(); - argv[2] = (char*) installDirPath.get(); - argv[3] = (char*) applyToDir.get(); - argv[4] = (char*) pid.get(); - if (appArgc) { - argv[5] = workingDirPath; - argv[6] = (char*) appFilePath.get(); - for (int i = 1; i < appArgc; ++i) - argv[6 + i] = appArgv[i]; -#ifdef XP_WIN - if (immersiveArgc) { - argv[argc - 1] = "-ServerName:DefaultBrowserServer"; +#if defined(XP_WIN) + nsAutoString appFilePathW; + rv = appFile->GetPath(appFilePathW); + if (NS_FAILED(rv)) { + return; + } + appFilePath = NS_ConvertUTF16toUTF8(appFilePathW); +#else + rv = appFile->GetNativePath(appFilePath); + if (NS_FAILED(rv)) { + return; } #endif - argv[argc] = nullptr; - } else { - argc = 5; - argv[5] = nullptr; } - if (gSafeMode) { - PR_SetEnv("MOZ_SAFE_MODE_RESTART=1"); - } -#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \ - !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK) - AppendToLibPath(installDirPath.get()); -#endif - - LOG(("spawning updater process for replacing [%s]\n", updaterPath.get())); - -#if defined(XP_UNIX) & !defined(XP_MACOSX) -# if defined(MOZ_WIDGET_GONK) - // In Gonk, we preload libmozglue, which the updater process doesn't need. - // Since the updater will move and delete libmozglue.so, this can actually - // stop the /system mount from correctly being remounted as read-only. - unsetenv("LD_PRELOAD"); -# endif - exit(execv(updaterPath.get(), argv)); -#elif defined(XP_WIN) - // Switch the application using updater.exe - if (!WinLaunchChild(updaterPathW.get(), argc, argv)) { - return; - } - _exit(0); -#elif defined(XP_MACOSX) - UpdateDriverSetupMacCommandLine(argc, argv, true); - LaunchChildMac(argc, argv); - exit(0); -#else - PR_CreateProcessDetached(updaterPath.get(), argv, nullptr, nullptr); - exit(0); -#endif -} - -#if defined(MOZ_WIDGET_GONK) -static nsresult -GetOSApplyToDir(nsACString& applyToDir) -{ - nsCOMPtr ds = - do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); - NS_ASSERTION(ds, "Can't get directory service"); - - nsCOMPtr osApplyToDir; - nsresult rv = ds->Get(XRE_OS_UPDATE_APPLY_TO_DIR, NS_GET_IID(nsIFile), - getter_AddRefs(osApplyToDir)); - if (NS_FAILED(rv)) { - LOG(("Can't get the OS applyTo dir")); - return rv; - } - - return osApplyToDir->GetNativePath(applyToDir); -} - -static void -SetOSApplyToDir(nsIUpdate* update, const nsACString& osApplyToDir) -{ - nsresult rv; - nsCOMPtr updateProperties = - do_QueryInterface(update, &rv); - - if (NS_FAILED(rv)) { - return; - } - - RefPtr variant = new nsVariant(); - rv = variant->SetAsACString(osApplyToDir); - if (NS_FAILED(rv)) { - return; - } - - updateProperties->SetProperty(NS_LITERAL_STRING("osApplyToDir"), variant); -} -#endif - -/** - * Apply an update. This applies to both normal and staged updates. - * - * @param greDir the GRE dir - * @param updateDir the update root dir - * @param statusFile the update.status file - * @param appDir the app dir - * @param appArgc the number of args to the application - * @param appArgv the args to the application, used for restarting if needed - * @param restart if true, apply the update in the foreground and restart the - * application when done. otherwise, stage the update and don't - * restart the application. - * @param outpid out parameter holding the handle to the updater application for - * staging updates. - */ -static void -ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile, - nsIFile *appDir, int appArgc, char **appArgv, - bool restart, bool isOSUpdate, nsIFile *osApplyToDir, - ProcessType *outpid) -{ - nsresult rv; - - // Steps: - // - mark update as 'applying' - // - copy updater into update dir on all platforms except Windows - // - run updater w/ appDir as the current working dir -#ifndef XP_WIN - nsCOMPtr updater; - if (!CopyUpdaterIntoUpdateDir(greDir, appDir, updateDir, updater)) { - LOG(("failed copying updater\n")); - return; - } -#endif - - // We need to use the value returned from XRE_GetBinaryPath when attempting - // to restart the running application. - nsCOMPtr appFile; - -#if defined(XP_MACOSX) - // On OS X we need to pass the location of the xulrunner-stub executable - // rather than xulrunner-bin. See bug 349737. - GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile)); -#else - XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile)); -#endif - - if (!appFile) - return; - -#ifdef XP_WIN - nsAutoString appFilePathW; - rv = appFile->GetPath(appFilePathW); - if (NS_FAILED(rv)) { - return; - } - NS_ConvertUTF16toUTF8 appFilePath(appFilePathW); - - nsCOMPtr updater; - rv = greDir->Clone(getter_AddRefs(updater)); - if (NS_FAILED(rv)) { - return; - } - - rv = updater->AppendNative(NS_LITERAL_CSTRING(UPDATER_BIN)); - if (NS_FAILED(rv)) { - return; - } - - nsAutoString updaterPathW; - rv = updater->GetPath(updaterPathW); - if (NS_FAILED(rv)) { - return; - } - NS_ConvertUTF16toUTF8 updaterPath(updaterPathW); -#else - nsAutoCString appFilePath; - rv = appFile->GetNativePath(appFilePath); - if (NS_FAILED(rv)) - return; - - nsAutoCString updaterPath; - rv = updater->GetNativePath(updaterPath); - if (NS_FAILED(rv)) - return; - -#endif - + // Get the installation directory path. nsAutoCString installDirPath; rv = GetInstallDirPath(appDir, installDirPath); - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return; + } - // Get the directory where the update was staged for replace and GONK OS - // Updates or where it will be applied. -#ifndef MOZ_WIDGET_GONK - // OS Updates are only supported on GONK so force it to false on everything - // but GONK to simplify the following logic. - isOSUpdate = false; -#endif - nsAutoCString applyToDir; + nsAutoCString applyToDirPath; nsCOMPtr updatedDir; - if (restart && !isOSUpdate) { - applyToDir.Assign(installDirPath); + if (restart && !isStaged) { + // The install directory is the same as the apply to directory. + applyToDirPath.Assign(installDirPath); } else { -#ifdef XP_MACOSX + // Get the directory where the update is staged or will be staged. +#if defined(XP_MACOSX) if (!GetFile(updateDir, NS_LITERAL_CSTRING("Updated.app"), updatedDir)) { #else if (!GetFile(appDir, NS_LITERAL_CSTRING("updated"), updatedDir)) { #endif return; } -#ifdef XP_WIN - nsAutoString applyToDirW; - rv = updatedDir->GetPath(applyToDirW); +#if defined(XP_WIN) + nsAutoString applyToDirPathW; + rv = updatedDir->GetPath(applyToDirPathW); if (NS_FAILED(rv)) { return; } - applyToDir = NS_ConvertUTF16toUTF8(applyToDirW); -#elif MOZ_WIDGET_GONK - if (isOSUpdate) { - if (!osApplyToDir) { - return; - } - rv = osApplyToDir->GetNativePath(applyToDir); - } else { - rv = updatedDir->GetNativePath(applyToDir); - } + applyToDirPath = NS_ConvertUTF16toUTF8(applyToDirPathW); + rv = updatedDir->GetNativePath(applyToDirPath); #else - rv = updatedDir->GetNativePath(applyToDir); + rv = updatedDir->GetNativePath(applyToDirPath); #endif } - if (NS_FAILED(rv)) - return; - -#if defined(XP_WIN) - nsAutoString updateDirPathW; - rv = updateDir->GetPath(updateDirPathW); - NS_ConvertUTF16toUTF8 updateDirPath(updateDirPathW); -#else - nsAutoCString updateDirPath; - rv = updateDir->GetNativePath(updateDirPath); -#endif if (NS_FAILED(rv)) { - return; + return; } - // Get the current working directory. - char workingDirPath[MAXPATHLEN]; - rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath)); - if (NS_FAILED(rv)) - 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. + if (restart && isStaged) { + // When the update should already be staged make sure that the updated + // directory exists. + bool updatedDirExists = false; + if (NS_FAILED(updatedDir->Exists(&updatedDirExists)) || !updatedDirExists) { + return; + } + } // On platforms where we are not calling execv, we may need to make the // updater executable wait for the calling process to exit. Otherwise, the @@ -887,78 +620,58 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile, // new process with the same PID could be created. This situation is unlikely, // however, given the way most operating systems recycle PIDs. We'll take our // chances ;-) - // Construct the PID argument for this process. If we are using execv, then - // we pass "0" which is then ignored by the updater. + // Construct the PID argument for this process to pass to the updater. nsAutoCString pid; - if (!restart) { - // Signal the updater application that it should stage the update. - pid.AssignASCII("-1"); - } else { + if (restart) { #if defined(XP_UNIX) & !defined(XP_MACOSX) + // When execv is used for an update that requires a restart 0 is passed + // which is ignored by the updater. pid.AssignASCII("0"); #else pid.AppendInt((int32_t) getpid()); #endif + if (isStaged) { + // Append a special token to the PID in order to inform the updater that + // it should replace install with the updated directory. + pid.AppendLiteral("/replace"); + } + } else { + // Signal the updater application that it should stage the update. + pid.AssignASCII("-1"); } - int immersiveArgc = 0; - int argc = appArgc + 6 + immersiveArgc; - char **argv = new char*[argc + 1 ]; - if (!argv) + int argc = 5; + if (restart) { + argc = appArgc + 6; + } + char **argv = new char*[argc + 1]; + if (!argv) { return; + } argv[0] = (char*) updaterPath.get(); argv[1] = (char*) updateDirPath.get(); argv[2] = (char*) installDirPath.get(); - argv[3] = (char*) applyToDir.get(); + argv[3] = (char*) applyToDirPath.get(); argv[4] = (char*) pid.get(); if (restart && appArgc) { argv[5] = workingDirPath; argv[6] = (char*) appFilePath.get(); - for (int i = 1; i < appArgc; ++i) + for (int i = 1; i < appArgc; ++i) { argv[6 + i] = appArgv[i]; -#ifdef XP_WIN - if (immersiveArgc) { - argv[argc - 1] = "-ServerName:DefaultBrowserServer"; } -#endif argv[argc] = nullptr; } else { - argc = 5; argv[5] = nullptr; } - if (gSafeMode) { + if (restart && gSafeMode) { PR_SetEnv("MOZ_SAFE_MODE_RESTART=1"); } -#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && \ - !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK) + +#if defined(MOZ_VERIFY_MAR_SIGNATURE) && !defined(XP_WIN) && !defined(XP_MACOSX) AppendToLibPath(installDirPath.get()); #endif - if (isOSUpdate) { - PR_SetEnv("MOZ_OS_UPDATE=1"); - } -#if defined(MOZ_WIDGET_GONK) - // We want the updater to be CPU friendly and not subject to being killed by - // the low memory killer, so we pass in some preferences to allow it to - // adjust its priority. - - int32_t prioVal = Preferences::GetInt(kAppUpdaterPrio, - kAppUpdaterPrioDefault); - int32_t oomScoreAdj = Preferences::GetInt(kAppUpdaterOomScoreAdj, - kAppUpdaterOomScoreAdjDefault); - int32_t ioprioClass = Preferences::GetInt(kAppUpdaterIOPrioClass, - kAppUpdaterIOPrioClassDefault); - int32_t ioprioLevel = Preferences::GetInt(kAppUpdaterIOPrioLevel, - kAppUpdaterIOPrioLevelDefault); - nsPrintfCString prioEnv("MOZ_UPDATER_PRIO=%d/%d/%d/%d", - prioVal, oomScoreAdj, ioprioClass, ioprioLevel); - // Note: we allocate a new string on heap and pass that to PR_SetEnv, since - // the string can be used after this function returns. This means that we - // will intentionally leak this buffer. - PR_SetEnv(ToNewCString(prioEnv)); -#endif - LOG(("spawning updater process [%s]\n", updaterPath.get())); #if defined(XP_UNIX) && !defined(XP_MACOSX) @@ -977,35 +690,39 @@ ApplyUpdate(nsIFile *greDir, nsIFile *updateDir, nsIFile *statusFile, exit(execv(updaterPath.get(), argv)); } #elif defined(XP_WIN) - // Launch the update using updater.exe - if (!WinLaunchChild(updaterPathW.get(), argc, argv, nullptr, outpid)) { - return; - } - - if (restart) { - // We are going to process an update so we should exit now - _exit(0); + if (isStaged) { + // Launch the updater to replace the installation with the staged updated. + if (!WinLaunchChild(updaterPathW.get(), argc, argv)) { + return; + } + } else { + // Launch the updater to either stage or apply an update. + if (!WinLaunchChild(updaterPathW.get(), argc, argv, nullptr, outpid)) { + return; + } } #elif defined(XP_MACOSX) UpdateDriverSetupMacCommandLine(argc, argv, restart); - // We need to detect whether elevation is required for this update. This can - // occur when an admin user installs the application, but another admin - // user attempts to update (see bug 394984). - if (restart && !IsRecursivelyWritable(installDirPath.get())) { - if (!LaunchElevatedUpdate(argc, argv, outpid)) { - LOG(("Failed to launch elevated update!")); - exit(1); - } - exit(0); + // LaunchChildMac uses posix_spawnp and prefers the current + // architecture when launching. It doesn't require a + // null-terminated string but it doesn't matter if we pass one. + if (isStaged) { + // Launch the updater to replace the installation with the staged updated. + LaunchChildMac(argc, argv); } else { - if (restart) { - LaunchChildMac(argc, argv); - exit(0); - } + // Launch the updater to either stage or apply an update. LaunchChildMac(argc, argv, outpid); } #else - *outpid = PR_CreateProcess(updaterPath.get(), argv, nullptr, nullptr); + if (isStaged) { + // Launch the updater to replace the installation with the staged updated. + PR_CreateProcessDetached(updaterPath.get(), argv, nullptr, nullptr); + } else { + // Launch the updater to either stage or apply an update. + *outpid = PR_CreateProcess(updaterPath.get(), argv, nullptr, nullptr); + } +#endif +#if !defined(USE_EXECV) if (restart) { exit(0); } @@ -1061,23 +778,25 @@ ProcessHasTerminated(ProcessType pt) nsresult ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir, int argc, char **argv, const char *appVersion, - bool restart, bool isOSUpdate, nsIFile *osApplyToDir, - ProcessType *pid) + bool restart, ProcessType *pid) { nsresult rv; nsCOMPtr updatesDir; rv = updRootDir->Clone(getter_AddRefs(updatesDir)); - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return rv; + } rv = updatesDir->AppendNative(NS_LITERAL_CSTRING("updates")); - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return rv; + } rv = updatesDir->AppendNative(NS_LITERAL_CSTRING("0")); - if (NS_FAILED(rv)) + if (NS_FAILED(rv)) { return rv; + } nsCOMPtr statusFile; UpdateStatus status = GetUpdateStatus(updatesDir, statusFile); @@ -1105,8 +824,7 @@ ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir, IsOlderVersion(versionFile, appVersion)) { updatesDir->Remove(true); } else { - ApplyUpdate(greDir, updatesDir, statusFile, - appDir, argc, argv, restart, isOSUpdate, osApplyToDir, pid); + ApplyUpdate(greDir, updatesDir, appDir, argc, argv, restart, false, pid); } break; } @@ -1114,7 +832,7 @@ ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir, case eAppliedService: // An update was staged and needs to be switched so the updated application // is used. - SwitchToUpdatedApp(greDir, updatesDir, appDir, argc, argv); + ApplyUpdate(greDir, updatesDir, appDir, argc, argv, restart, true, pid); break; case eNoUpdateAction: // We don't need to do any special processing here, we'll just continue to @@ -1141,140 +859,54 @@ nsUpdateProcessor::~nsUpdateProcessor() NS_IMETHODIMP nsUpdateProcessor::ProcessUpdate(nsIUpdate* aUpdate) { - nsCOMPtr greDir, appDir, updRoot; - nsAutoCString appVersion; - int argc; - char **argv; + nsresult rv; - nsAutoCString binPath; - nsXREDirProvider* dirProvider = nsXREDirProvider::GetSingleton(); - if (dirProvider) { // Normal code path - // Check for and process any available updates - bool persistent; - nsresult rv = NS_ERROR_FAILURE; // Take the NS_FAILED path when non-GONK -#ifdef MOZ_WIDGET_GONK - // Check in the sdcard for updates first, since that's our preferred - // download location. - rv = dirProvider->GetFile(XRE_UPDATE_ARCHIVE_DIR, &persistent, - getter_AddRefs(updRoot)); -#endif - if (NS_FAILED(rv)) { - rv = dirProvider->GetFile(XRE_UPDATE_ROOT_DIR, &persistent, - getter_AddRefs(updRoot)); - } - // XRE_UPDATE_ROOT_DIR may fail. Fallback to appDir if failed - if (NS_FAILED(rv)) - updRoot = dirProvider->GetAppDir(); + nsCOMPtr ds = + do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); - greDir = dirProvider->GetGREDir(); - nsCOMPtr exeFile; - rv = dirProvider->GetFile(XRE_EXECUTABLE_FILE, &persistent, - getter_AddRefs(exeFile)); - if (NS_SUCCEEDED(rv)) - rv = exeFile->GetParent(getter_AddRefs(appDir)); + nsCOMPtr exeFile; + rv = ds->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile), + getter_AddRefs(exeFile)); + NS_ENSURE_SUCCESS(rv, rv); - if (NS_FAILED(rv)) - appDir = dirProvider->GetAppDir(); + nsCOMPtr appDir; + rv = exeFile->GetParent(getter_AddRefs(appDir)); + NS_ENSURE_SUCCESS(rv, rv); - appVersion = gAppData->version; - argc = gRestartArgc; - argv = gRestartArgv; - } else { - // In the xpcshell environment, the usual XRE_main is not run, so things - // like dirProvider and gAppData do not exist. This code path accesses - // XPCOM (which is not available in the previous code path) in order to get - // the same information. - nsCOMPtr ds = - do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID); - if (!ds) { - NS_ABORT(); // There's nothing which we can do if this fails! - } + nsCOMPtr greDir; + rv = ds->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir)); + NS_ENSURE_SUCCESS(rv, rv); - nsresult rv = ds->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), - getter_AddRefs(greDir)); - NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the GRE dir"); + nsCOMPtr updRoot; + rv = ds->Get(XRE_UPDATE_ROOT_DIR, NS_GET_IID(nsIFile), + getter_AddRefs(updRoot)); + NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the UpdRootD dir"); - nsCOMPtr exeFile; - rv = ds->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile), - getter_AddRefs(exeFile)); - if (NS_SUCCEEDED(rv)) - rv = exeFile->GetParent(getter_AddRefs(appDir)); - - NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the XREExeF parent dir"); - - rv = ds->Get(XRE_UPDATE_ROOT_DIR, NS_GET_IID(nsIFile), - getter_AddRefs(updRoot)); - NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the UpdRootD dir"); - - nsCOMPtr appInfo = - do_GetService("@mozilla.org/xre/app-info;1"); - if (appInfo) { - rv = appInfo->GetVersion(appVersion); - NS_ENSURE_SUCCESS(rv, rv); - } else { - appVersion = MOZ_APP_VERSION; - } - - // We need argv[0] to point to the current executable's name. The rest of - // the entries in this array will be ignored if argc<2. Therefore, for - // xpcshell, we only fill out that item, and leave the rest empty. - argc = 1; - nsCOMPtr binary; - rv = ds->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile), - getter_AddRefs(binary)); - NS_ASSERTION(NS_SUCCEEDED(rv), "Can't get the binary path"); - binary->GetNativePath(binPath); + // XRE_UPDATE_ROOT_DIR should not fail but if it does fallback to the + // application directory just to be safe. + if (NS_FAILED(rv)) { + rv = appDir->Clone(getter_AddRefs(updRoot)); + NS_ENSURE_SUCCESS(rv, rv); } + nsCOMPtr appInfo = + do_GetService("@mozilla.org/xre/app-info;1", &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsAutoCString appVersion; + rv = appInfo->GetVersion(appVersion); + NS_ENSURE_SUCCESS(rv, rv); + // Copy the parameters to the StagedUpdateInfo structure shared with the // watcher thread. mInfo.mGREDir = greDir; mInfo.mAppDir = appDir; mInfo.mUpdateRoot = updRoot; - mInfo.mArgc = argc; - mInfo.mArgv = new char*[argc]; - if (dirProvider) { - for (int i = 0; i < argc; ++i) { - const size_t length = strlen(argv[i]); - mInfo.mArgv[i] = new char[length + 1]; - strcpy(mInfo.mArgv[i], argv[i]); - } - } else { - MOZ_ASSERT(argc == 1); // see above - const size_t length = binPath.Length(); - mInfo.mArgv[0] = new char[length + 1]; - strcpy(mInfo.mArgv[0], binPath.get()); - } + mInfo.mArgc = 0; + mInfo.mArgv = nullptr; mInfo.mAppVersion = appVersion; -#if defined(MOZ_WIDGET_GONK) - NS_ENSURE_ARG_POINTER(aUpdate); - - bool isOSUpdate; - if (NS_SUCCEEDED(aUpdate->GetIsOSUpdate(&isOSUpdate)) && - isOSUpdate) { - nsAutoCString osApplyToDir; - - // This needs to be done on the main thread, so we pass it along in - // BackgroundThreadInfo - nsresult rv = GetOSApplyToDir(osApplyToDir); - if (NS_FAILED(rv)) { - LOG(("Can't get the OS apply to dir")); - return rv; - } - - SetOSApplyToDir(aUpdate, osApplyToDir); - - mInfo.mIsOSUpdate = true; - rv = NS_NewNativeLocalFile(osApplyToDir, false, - getter_AddRefs(mInfo.mOSApplyToDir)); - if (NS_FAILED(rv)) { - LOG(("Can't create nsIFile for OS apply to dir")); - return rv; - } - } -#endif - MOZ_ASSERT(NS_IsMainThread(), "not main thread"); nsCOMPtr r = NewRunnableMethod(this, &nsUpdateProcessor::StartStagedUpdate); return NS_NewNamedThread("Update Watcher", getter_AddRefs(mProcessWatcher), @@ -1295,8 +927,6 @@ nsUpdateProcessor::StartStagedUpdate() mInfo.mArgv, mInfo.mAppVersion.get(), false, - mInfo.mIsOSUpdate, - mInfo.mOSApplyToDir, &mUpdaterPID); NS_ENSURE_SUCCESS_VOID(rv); diff --git a/toolkit/xre/nsUpdateDriver.h b/toolkit/xre/nsUpdateDriver.h index ed877519804b..56036c9460e2 100644 --- a/toolkit/xre/nsUpdateDriver.h +++ b/toolkit/xre/nsUpdateDriver.h @@ -46,14 +46,9 @@ class nsIFile; * * This function does not modify appDir. */ -nsresult ProcessUpdates(nsIFile *greDir, nsIFile *appDir, - nsIFile *updRootDir, - int argc, char **argv, - const char *appVersion, - bool restart = true, - bool isOSUpdate = false, - nsIFile *osApplyToDir = nullptr, - ProcessType *pid = nullptr); +nsresult ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir, + int argc, char **argv, const char *appVersion, + bool restart = true, ProcessType *pid = nullptr); // The implementation of the update processor handles the task of loading the // updater application for staging an update.