mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-10-29 15:36:32 +02:00
Bug 1923376 - Add an argument to the updater to convey which updater instance it is r=bytesized a=diannaS
Note that this patch does not implement the proper usage of the argument. It reads the argument but then does nothing with it. Original Revision: https://phabricator.services.mozilla.com/D225421 Differential Revision: https://phabricator.services.mozilla.com/D242449
This commit is contained in:
parent
1457d46de4
commit
0721e5dda6
3 changed files with 150 additions and 45 deletions
|
|
@ -2086,14 +2086,16 @@ function runUpdate(
|
|||
|
||||
setAppBundleModTime();
|
||||
|
||||
let args = [updatesDirPath, installDirPath];
|
||||
if (aSwitchApp) {
|
||||
args[2] = stageDirPath;
|
||||
args[3] = pid + "/replace";
|
||||
} else {
|
||||
args[2] = applyToDirPath;
|
||||
args[3] = pid;
|
||||
}
|
||||
// The version 3 argument format looks like
|
||||
// updater 3 patch-dir install-dir apply-to-dir which-invocation [wait-pid [callback-working-dir callback-path args...]]
|
||||
let args = [
|
||||
"3",
|
||||
updatesDirPath,
|
||||
installDirPath,
|
||||
aSwitchApp ? stageDirPath : applyToDirPath,
|
||||
"first",
|
||||
aSwitchApp ? pid + "/replace" : pid,
|
||||
];
|
||||
|
||||
let launchBin = gIsServiceTest && isInvalidArgTest ? callbackApp : gUpdateBin;
|
||||
|
||||
|
|
@ -2101,6 +2103,8 @@ function runUpdate(
|
|||
args = args.concat([callbackApp.parent.path, callbackApp.path]);
|
||||
args = args.concat(gCallbackArgs);
|
||||
} else if (gIsServiceTest) {
|
||||
// We are jumping straight to the second invocation in this case
|
||||
args[4] = "second";
|
||||
args = ["launch-service", gUpdateBin.path].concat(args);
|
||||
} else if (aCallbackPath) {
|
||||
args = args.concat([callbackApp.parent.path, aCallbackPath]);
|
||||
|
|
|
|||
|
|
@ -144,6 +144,60 @@ BOOL PathGetSiblingFilePath(LPWSTR destinationBuffer, LPCWSTR siblingFilePath,
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This enum and its related functions are intended for interpreting the passed
|
||||
* parameter and using it to determine whether this is the first or second
|
||||
* invocation of the updater.
|
||||
*/
|
||||
enum class UpdaterInvocation {
|
||||
// The initial invocation of the updater. This may apply the update, or it may
|
||||
// start the second invocation of the updater to update depending on whether
|
||||
// elevation is required.
|
||||
// This invocation always does all modifications of the update directory and
|
||||
// calls the callback application, even if another updater is launched.
|
||||
First,
|
||||
// The second invocation of the updater. This basically applies the update to
|
||||
// the installation directory, calls PostUpdate (on Windows) and exits.
|
||||
Second,
|
||||
// It cannot be determined that we are doing either of the above invocations.
|
||||
// This generally represents an uninitialized value or an error.
|
||||
Unknown,
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a human-readable representation of an `UpdaterInvocation`.
|
||||
*/
|
||||
const char* getUpdaterInvocationString(UpdaterInvocation value) {
|
||||
switch (value) {
|
||||
case UpdaterInvocation::First:
|
||||
return "UpdaterInvocation::First";
|
||||
case UpdaterInvocation::Second:
|
||||
return "UpdaterInvocation::Second";
|
||||
case UpdaterInvocation::Unknown:
|
||||
return "UpdaterInvocation::Unknown";
|
||||
}
|
||||
MOZ_CRASH("impossible value for UpdaterInvocation");
|
||||
}
|
||||
|
||||
const NS_tchar* firstUpdateInvocationArg = NS_T("first");
|
||||
const NS_tchar* secondUpdateInvocationArg = NS_T("second");
|
||||
|
||||
/**
|
||||
* Gets which updater invocation this is based on the value passed to this
|
||||
* function by the caller.
|
||||
*/
|
||||
static UpdaterInvocation getUpdaterInvocationFromArg(const NS_tchar* argument) {
|
||||
if (NS_tstrcmp(argument, firstUpdateInvocationArg) == 0) {
|
||||
return UpdaterInvocation::First;
|
||||
}
|
||||
if (NS_tstrcmp(argument, secondUpdateInvocationArg) == 0) {
|
||||
return UpdaterInvocation::Second;
|
||||
}
|
||||
return UpdaterInvocation::Unknown;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This BZ2_crc32Table variable lives in libbz2. We just took the
|
||||
// data structure from bz2 and created crctables.h
|
||||
|
||||
|
|
@ -287,18 +341,30 @@ static bool sUsingService = false;
|
|||
// with `gIsElevated == false`. If it is run an additional time with elevation,
|
||||
// that iteration will run with `gIsElevated == true`.
|
||||
static bool gIsElevated = false;
|
||||
// When the updater needs to elevate, we generally run the updater again with
|
||||
// elevation. These two invocations differ in many important ways. The elevated
|
||||
// updater doesn't touch any files that don't require that elevation, it
|
||||
// basically just changes the installation directory, runs PostUpdate
|
||||
// (on Windows), and exits to let the first updater invocation finalize the
|
||||
// update (write its own logs, conditionally move the elevated updater
|
||||
// logs/status to the update directory, call the callback application, etc).
|
||||
static UpdaterInvocation gInvocation = UpdaterInvocation::Unknown;
|
||||
|
||||
// `argv` indices for standard invocation. Does not apply to other methods of
|
||||
// invocation including when `--openAppBundle`, or `-dmgInstall` are used.
|
||||
static const int kPatchDirIndex = 1;
|
||||
static const int kInstallDirIndex = 2;
|
||||
static const int kApplyToDirIndex = 3;
|
||||
// Note that `argv[1]` is the argument version, which is needed by the MMS, but
|
||||
// not by the updater since it is guaranteed to be the same version as the
|
||||
// application launching it.
|
||||
static const int kPatchDirIndex = 2;
|
||||
static const int kInstallDirIndex = 3;
|
||||
static const int kApplyToDirIndex = 4;
|
||||
static const int kWhichInvocationIndex = 5;
|
||||
// Note that this is the first optional argument.
|
||||
static const int kWaitPidIndex = 4;
|
||||
static const int kCallbackWorkingDirIndex = 5;
|
||||
static const int kWaitPidIndex = 6;
|
||||
static const int kCallbackWorkingDirIndex = 7;
|
||||
// This indicates the entry in `argv` that is the callback binary path. All
|
||||
// arguments after this one are treated as arguments to the callback.
|
||||
static const int kCallbackIndex = 6;
|
||||
static const int kCallbackIndex = 8;
|
||||
|
||||
// This string contains the MAR channel IDs that are later extracted by one of
|
||||
// the `ReadMARChannelIDsFrom` variants.
|
||||
|
|
@ -2994,6 +3060,16 @@ bool ShouldRunSilently(int argc, NS_tchar** argv) {
|
|||
}
|
||||
|
||||
int NS_main(int argc, NS_tchar** argv) {
|
||||
// We may need to tweak our argument list when we launch the Second Updater
|
||||
// Invocation (SUI), so we are going to make a copy of our arguments to
|
||||
// modify.
|
||||
int suiArgc = argc;
|
||||
mozilla::UniquePtr<const NS_tchar*[]> suiArgv =
|
||||
mozilla::MakeUnique<const NS_tchar*[]>(suiArgc);
|
||||
for (int argIndex = 0; argIndex < suiArgc; argIndex++) {
|
||||
suiArgv.get()[argIndex] = argv[argIndex];
|
||||
}
|
||||
|
||||
#ifdef MOZ_MAINTENANCE_SERVICE
|
||||
sUsingService = EnvHasValue("MOZ_USING_SERVICE");
|
||||
putenv(const_cast<char*>("MOZ_USING_SERVICE="));
|
||||
|
|
@ -3064,23 +3140,25 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
#endif
|
||||
|
||||
// To process an update the updater command line must at a minimum have the
|
||||
// directory path containing the updater.mar file to process as the first
|
||||
// argument, the install directory as the second argument, and the directory
|
||||
// to apply the update to as the third argument. When the updater is
|
||||
// launched by another process the PID of the parent process should be
|
||||
// provided in the optional fourth argument and the updater will wait on the
|
||||
// parent process to exit if the value is non-zero and the process is
|
||||
// present. This is necessary due to not being able to update files that are
|
||||
// in use on Windows. The optional fifth argument is the callback's working
|
||||
// directory and the optional sixth argument is the callback path. The
|
||||
// callback is the application to launch after updating and it will be
|
||||
// launched when these arguments are provided whether the update was
|
||||
// successful or not. All remaining arguments are optional and are passed to
|
||||
// the callback when it is launched.
|
||||
// argument version as the first argument, the directory path containing the
|
||||
// updater.mar file to process as the second argument, the install directory
|
||||
// as the third argument, the directory to apply the update to as the fourth
|
||||
// argument, and which updater invocation this is as the fifth argument.
|
||||
// When the updater is launched by another process, the PID of the parent
|
||||
// process should be provided in the optional sixth argument and the updater
|
||||
// will wait on the parent process to exit if the value is non-zero and the
|
||||
// process is present. This is necessary due to not being able to update
|
||||
// files that are in use on Windows. The optional seventh argument is the
|
||||
// callback's working directory and the optional eighth argument is the
|
||||
// callback path. The callback is the application to launch after updating
|
||||
// and it will be launched when these arguments are provided whether the
|
||||
// update was successful or not. All remaining arguments are optional and
|
||||
// are passed to the callback when it is launched.
|
||||
if (argc < kWaitPidIndex) {
|
||||
fprintf(stderr,
|
||||
"Usage: updater patch-dir install-dir apply-to-dir [wait-pid "
|
||||
"[callback-working-dir callback-path args...]]\n");
|
||||
"Usage: updater arg-version patch-dir install-dir apply-to-dir "
|
||||
"which-invocation [wait-pid [callback-working-dir callback-path "
|
||||
"args...]]\n");
|
||||
#ifdef XP_MACOSX
|
||||
if (isElevated) {
|
||||
freeArguments(argc, argv);
|
||||
|
|
@ -3101,7 +3179,26 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
}
|
||||
#endif
|
||||
|
||||
} // if (!isDMGInstall)
|
||||
gInvocation = getUpdaterInvocationFromArg(argv[kWhichInvocationIndex]);
|
||||
switch (gInvocation) {
|
||||
case UpdaterInvocation::Unknown:
|
||||
fprintf(stderr, "Invalid which-invocation value: " LOG_S "\n",
|
||||
argv[kWhichInvocationIndex]);
|
||||
return 1;
|
||||
case UpdaterInvocation::First:
|
||||
suiArgv.get()[kWhichInvocationIndex] = secondUpdateInvocationArg;
|
||||
break;
|
||||
default:
|
||||
// There is no good reason we should be launching a third updater, but
|
||||
// assign something recognizable and unlikely to be used in the future
|
||||
// to make any bugs here a bit easier to understand.
|
||||
suiArgv.get()[kWhichInvocationIndex] = NS_T("third???");
|
||||
break;
|
||||
}
|
||||
} else { /* else if (isDMGInstall) */
|
||||
// We already exited in the other case.
|
||||
gInvocation = UpdaterInvocation::First;
|
||||
}
|
||||
|
||||
// The directory containing the update information.
|
||||
NS_tstrncpy(gPatchDirPath, argv[kPatchDirIndex], MAXPATHLEN);
|
||||
|
|
@ -3405,6 +3502,7 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
LOG(("useService=%s", useService ? "true" : "false"));
|
||||
#endif
|
||||
LOG(("gIsElevated=%s", gIsElevated ? "true" : "false"));
|
||||
LOG(("gInvocation=%s", getUpdaterInvocationString(gInvocation)));
|
||||
|
||||
if (!WriteStatusFile("applying")) {
|
||||
LOG(("failed setting status to 'applying'"));
|
||||
|
|
@ -3585,7 +3683,7 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
(noServiceFallback || forceServiceFallback))) {
|
||||
LOG(("Can't open lock file - seems like we need elevation"));
|
||||
|
||||
auto cmdLine = mozilla::MakeCommandLine(argc - 1, argv + 1);
|
||||
auto cmdLine = mozilla::MakeCommandLine(suiArgc - 1, suiArgv.get() + 1);
|
||||
if (!cmdLine) {
|
||||
LOG(("Failed to make command line! Exiting"));
|
||||
output_finish();
|
||||
|
|
@ -3676,18 +3774,18 @@ int NS_main(int argc, NS_tchar** argv) {
|
|||
WriteStatusFile(SERVICE_UPDATE_STATUS_UNCHANGED);
|
||||
|
||||
int serviceArgc = argc;
|
||||
if (forceServiceFallback && serviceArgc > 2) {
|
||||
if (forceServiceFallback && serviceArgc > kPatchDirIndex) {
|
||||
// To force the service to fail, we can just pass it too few
|
||||
// arguments. However, we don't want to pass it no arguments,
|
||||
// because then it won't have enough information to write out the
|
||||
// update status file telling us that it failed.
|
||||
serviceArgc = 2;
|
||||
serviceArgc = kPatchDirIndex + 1;
|
||||
}
|
||||
|
||||
// If the update couldn't be started, then set useService to false so
|
||||
// we do the update the old way.
|
||||
DWORD ret =
|
||||
LaunchServiceSoftwareUpdateCommand(serviceArgc, (LPCWSTR*)argv);
|
||||
DWORD ret = LaunchServiceSoftwareUpdateCommand(
|
||||
serviceArgc, (LPCWSTR*)suiArgv.get());
|
||||
useService = (ret == ERROR_SUCCESS);
|
||||
// If the command was launched then wait for the service to be done.
|
||||
if (useService) {
|
||||
|
|
|
|||
|
|
@ -507,9 +507,10 @@ static void ApplyUpdate(nsIFile* greDir, nsIFile* updateDir, nsIFile* appDir,
|
|||
pid.AssignLiteral("-1");
|
||||
}
|
||||
|
||||
int argc = 5;
|
||||
int argc = 7;
|
||||
if (restart) {
|
||||
argc = appArgc + 6;
|
||||
argc += 1; // callback working directory
|
||||
argc += appArgc;
|
||||
if (gRestartedByOS) {
|
||||
argc += 1;
|
||||
}
|
||||
|
|
@ -519,20 +520,22 @@ static void ApplyUpdate(nsIFile* greDir, nsIFile* updateDir, nsIFile* appDir,
|
|||
return;
|
||||
}
|
||||
argv[0] = (char*)updaterPath.get();
|
||||
argv[1] = (char*)updateDirPath.get();
|
||||
argv[2] = (char*)installDirPath.get();
|
||||
argv[3] = (char*)applyToDirPath.get();
|
||||
argv[4] = (char*)pid.get();
|
||||
argv[1] = const_cast<char*>("3");
|
||||
argv[2] = (char*)updateDirPath.get();
|
||||
argv[3] = (char*)installDirPath.get();
|
||||
argv[4] = (char*)applyToDirPath.get();
|
||||
argv[5] = const_cast<char*>("first");
|
||||
argv[6] = (char*)pid.get();
|
||||
if (restart && appArgc) {
|
||||
argv[5] = (char*)workingDirPath.get();
|
||||
argv[6] = (char*)appFilePath.get();
|
||||
argv[7] = (char*)workingDirPath.get();
|
||||
argv[8] = (char*)appFilePath.get();
|
||||
for (int i = 1; i < appArgc; ++i) {
|
||||
argv[6 + i] = appArgv[i];
|
||||
argv[8 + i] = appArgv[i];
|
||||
}
|
||||
if (gRestartedByOS) {
|
||||
// We haven't truly started up, restore this argument so that we will have
|
||||
// it upon restart.
|
||||
argv[6 + appArgc] = const_cast<char*>("-os-restarted");
|
||||
argv[8 + appArgc] = const_cast<char*>("-os-restarted");
|
||||
}
|
||||
}
|
||||
argv[argc] = nullptr;
|
||||
|
|
|
|||
Loading…
Reference in a new issue