Bug 603903 - Part 1: add RegisterApplicationRestart
MozReview-Commit-ID: Eb389ih7CIn
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1280,16 +1280,26 @@ pref("browser.library.activity-stream.en
// Enable the DOM fullscreen API.
pref("full-screen-api.enabled", true);
// Startup Crash Tracking
// number of startup crashes that can occur before starting into safe mode automatically
// (this pref has no effect if more than 6 hours have passed since the last crash)
pref("toolkit.startup.max_resumed_crashes", 3);
+// Whether to use RegisterApplicationRestart to restart the browser and resume
+// the session on next Windows startup
+#if defined(XP_WIN)
+#if defined(NIGHTLY_BUILD)
+pref("toolkit.winRegisterApplicationRestart", true);
+#else
+pref("toolkit.winRegisterApplicationRestart", false);
+#endif
+#endif
+
// Whether we use pdfium to view content with the pdf mime type.
// Note: if the pref is set to false while Firefox is open, it won't
// take effect until there are no open pdfium tabs.
pref("pdfium.enabled", false);
// Completely disable pdf.js as an option to preview pdfs within firefox.
// Note: if this is not disabled it does not necessarily mean pdf.js is the pdf
// handler just that it is an option.
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -253,16 +253,19 @@ char **gArgv;
static const char gToolkitVersion[] = NS_STRINGIFY(GRE_MILESTONE);
static const char gToolkitBuildID[] = NS_STRINGIFY(MOZ_BUILDID);
static nsIProfileLock* gProfileLock;
int gRestartArgc;
char **gRestartArgv;
+// If gRestartedByOS is set, we were automatically restarted by the OS.
+bool gRestartedByOS = false;
+
bool gIsGtest = false;
nsString gAbsoluteArgv0Path;
#if defined(MOZ_WIDGET_GTK)
#include <glib.h>
#if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING)
#define CLEANUP_MEMORY 1
@@ -1024,16 +1027,23 @@ nsXULAppInfo::GetWindowsDLLBlocklistStat
#if defined(HAS_DLL_BLOCKLIST)
*aResult = DllBlocklist_CheckStatus();
#else
*aResult = false;
#endif
return NS_OK;
}
+NS_IMETHODIMP
+nsXULAppInfo::GetRestartedByOS(bool* aResult)
+{
+ *aResult = gRestartedByOS;
+ return NS_OK;
+}
+
#ifdef XP_WIN
// Matches the enum in WinNT.h for the Vista SDK but renamed so that we can
// safely build with the Vista SDK and without it.
typedef enum
{
VistaTokenElevationTypeDefault = 1,
VistaTokenElevationTypeFull,
VistaTokenElevationTypeLimited
@@ -1748,17 +1758,54 @@ XRE_GetBinaryPath(nsIFile* *aResult)
return mozilla::BinaryPath::GetFile(aResult);
}
#ifdef XP_WIN
#include "nsWindowsRestart.cpp"
#include <shellapi.h>
typedef BOOL (WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
-#endif
+
+static void
+RegisterApplicationRestartChanged(const char* aPref, void* aData) {
+ DWORD cchCmdLine = 0;
+ HRESULT rc =
+ ::GetApplicationRestartSettings(::GetCurrentProcess(), nullptr, &cchCmdLine, nullptr);
+ bool wasRegistered = false;
+ if (rc == S_OK) {
+ wasRegistered = true;
+ }
+
+ if (Preferences::GetBool(PREF_WIN_REGISTER_APPLICATION_RESTART, false) && !wasRegistered) {
+ // Make the command line to use when restarting.
+ // Excludes argv[0] because RegisterApplicationRestart adds the
+ // executable name, replace that temporarily with -os-restarted
+ char* exeName = gRestartArgv[0];
+ gRestartArgv[0] = "-os-restarted";
+ wchar_t** restartArgvConverted =
+ AllocConvertUTF8toUTF16Strings(gRestartArgc, gRestartArgv);
+ gRestartArgv[0] = exeName;
+
+ mozilla::UniquePtr<wchar_t[]> restartCommandLine;
+ if (restartArgvConverted) {
+ restartCommandLine = mozilla::MakeCommandLine(gRestartArgc, restartArgvConverted);
+ FreeAllocStrings(gRestartArgc, restartArgvConverted);
+ }
+
+ if (restartCommandLine) {
+ // Flags RESTART_NO_PATCH and RESTART_NO_REBOOT are not set, so we
+ // should be restarted if terminated by an update or restart.
+ ::RegisterApplicationRestart(restartCommandLine.get(), RESTART_NO_CRASH |
+ RESTART_NO_HANG);
+ }
+ } else if (wasRegistered) {
+ ::UnregisterApplicationRestart();
+ }
+}
+#endif // XP_WIN
// If aBlankCommandLine is true, then the application will be launched with a
// blank command line instead of being launched with the same command line that
// it was initially started with.
static nsresult LaunchChild(nsINativeAppSupport* aNative,
bool aBlankCommandLine = false)
{
aNative->Quit(); // release DDE mutex, if we're holding it
@@ -3433,16 +3480,22 @@ XREMain::XRE_mainInit(bool* aExitFlag)
ProcessSerialNumber psn;
if (::GetCurrentProcess(&psn) == noErr)
::SetFrontProcess(&psn);
}
#endif
SaveToEnv("MOZ_LAUNCHED_CHILD=");
+ // On Windows, the -os-restarted command line switch lets us know when we are
+ // restarted via RegisterApplicationRestart. May be used for other OSes later.
+ if (CheckArg("os-restarted", nullptr, CheckArgFlag::RemoveArg) == ARG_FOUND) {
+ gRestartedByOS = true;
+ }
+
gRestartArgc = gArgc;
gRestartArgv = (char**) malloc(sizeof(char*) * (gArgc + 1 + (override ? 2 : 0)));
if (!gRestartArgv) {
return 1;
}
int i;
for (i = 0; i < gArgc; ++i) {
@@ -4559,16 +4612,21 @@ XREMain::XRE_mainRun()
SaveToEnv("NO_EM_RESTART=");
SaveToEnv("XUL_APP_FILE=");
SaveToEnv("XRE_BINARY_PATH=");
if (!mShuttingDown) {
rv = appStartup->CreateHiddenWindow();
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+#ifdef XP_WIN
+ Preferences::RegisterCallbackAndCall(RegisterApplicationRestartChanged,
+ PREF_WIN_REGISTER_APPLICATION_RESTART);
+#endif
+
#if defined(HAVE_DESKTOP_STARTUP_ID) && defined(MOZ_WIDGET_GTK)
nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
if (toolkit && !mDesktopStartupID.IsEmpty()) {
toolkit->SetDesktopStartupID(mDesktopStartupID);
}
// Clear the environment variable so it won't be inherited by
// child processes and confuse things.
g_unsetenv ("DESKTOP_STARTUP_ID");
--- a/toolkit/xre/nsAppRunner.h
+++ b/toolkit/xre/nsAppRunner.h
@@ -100,16 +100,18 @@ MozExpectedExit();
#ifdef XP_WIN
void
UseParentConsole();
BOOL
WinLaunchChild(const wchar_t *exePath, int argc,
char **argv, HANDLE userToken = nullptr,
HANDLE *hProcess = nullptr);
+
+#define PREF_WIN_REGISTER_APPLICATION_RESTART "toolkit.winRegisterApplicationRestart"
#endif
#define NS_NATIVEAPPSUPPORT_CONTRACTID "@mozilla.org/toolkit/native-app-support;1"
namespace mozilla {
namespace startup {
Result<nsCOMPtr<nsIFile>, nsresult> GetIncompleteStartupFile(nsIFile* aProfLD);
--- a/toolkit/xre/nsWindowsRestart.cpp
+++ b/toolkit/xre/nsWindowsRestart.cpp
@@ -45,16 +45,32 @@ FreeAllocStrings(int argc, wchar_t **arg
while (argc) {
--argc;
delete [] argv[argc];
}
delete [] argv;
}
+static wchar_t**
+AllocConvertUTF8toUTF16Strings(int argc, char **argv)
+{
+ wchar_t **argvConverted = new wchar_t*[argc];
+ if (!argvConverted)
+ return nullptr;
+
+ for (int i = 0; i < argc; ++i) {
+ argvConverted[i] = reinterpret_cast<wchar_t*>(AllocConvertUTF8toUTF16(argv[i]));
+ if (!argvConverted[i]) {
+ FreeAllocStrings(i, argvConverted);
+ return nullptr;
+ }
+ }
+ return argvConverted;
+}
/**
* Launch a child process with the specified arguments.
* @note argv[0] is ignored
* @note The form of this function that takes char **argv expects UTF-8
*/
@@ -65,28 +81,20 @@ WinLaunchChild(const wchar_t *exePath,
HANDLE *hProcess = nullptr);
BOOL
WinLaunchChild(const wchar_t *exePath,
int argc, char **argv,
HANDLE userToken,
HANDLE *hProcess)
{
- wchar_t** argvConverted = new wchar_t*[argc];
+ wchar_t **argvConverted = AllocConvertUTF8toUTF16Strings(argc, argv);
if (!argvConverted)
return FALSE;
- for (int i = 0; i < argc; ++i) {
- argvConverted[i] = reinterpret_cast<wchar_t*>(AllocConvertUTF8toUTF16(argv[i]));
- if (!argvConverted[i]) {
- FreeAllocStrings(i, argvConverted);
- return FALSE;
- }
- }
-
BOOL ok = WinLaunchChild(exePath, argc, argvConverted, userToken, hProcess);
FreeAllocStrings(argc, argvConverted);
return ok;
}
BOOL
WinLaunchChild(const wchar_t *exePath,
int argc,
--- a/xpcom/system/nsIXULRuntime.idl
+++ b/xpcom/system/nsIXULRuntime.idl
@@ -189,9 +189,15 @@ interface nsIXULRuntime : nsISupports
*/
readonly attribute AUTF8String distributionID;
/**
* True if Windows DLL blocklist initialized correctly. This is
* primarily for automated testing purposes.
*/
readonly attribute boolean windowsDLLBlocklistStatus;
+
+ /**
+ * True if this application was started by the OS as part of an automatic
+ * restart mechanism (such as RegisterApplicationRestart on Windows).
+ */
+ readonly attribute boolean restartedByOS;
};