Bug 1825917 - Have a ShutdownReason annotation and identify OS shutdown on Windows. r=xpcom-reviewers,gstoll,nika

Differential Revision: https://phabricator.services.mozilla.com/D174899
This commit is contained in:
Jens Stutte 2023-04-17 14:03:48 +00:00
Родитель 79e171fd9f
Коммит ca12388a58
5 изменённых файлов: 144 добавлений и 41 удалений

Просмотреть файл

@ -401,7 +401,13 @@ nsAppStartup::Quit(uint32_t aMode, int aExitCode, bool* aUserAllowedQuit) {
auto shutdownMode = ((aMode & eRestart) != 0)
? mozilla::AppShutdownMode::Restart
: mozilla::AppShutdownMode::Normal;
mozilla::AppShutdown::Init(shutdownMode, aExitCode);
// TODO: Add (or pass in) more reasons here for Mac and Linux, see
// bug 1827643 and bug 1827644.
// See as example the Windows WM_ENDSESSION handling.
auto shutdownReason = ((aMode & eRestart) != 0)
? mozilla::AppShutdownReason::AppRestart
: mozilla::AppShutdownReason::AppClose;
mozilla::AppShutdown::Init(shutdownMode, aExitCode, shutdownReason);
if (mozilla::AppShutdown::IsRestarting()) {
// Mark the next startup as a restart.

Просмотреть файл

@ -824,6 +824,13 @@ ShutdownProgress:
type: string
ping: true
ShutdownReason:
description: >
One out of "Unknown", "AppClose", "AppRestart", "OSForceClose",
"OSSessionEnd", "OSShutdown" or "WinUnexpectedMozQuit".
type: string
ping: true
StartupCrash:
description: >
If set to 1 then this crash occurred during startup.

Просмотреть файл

@ -5141,6 +5141,7 @@ bool nsWindow::ProcessMessageInternal(UINT msg, WPARAM& wParam, LPARAM& lParam,
static const bool sSwitchKeyboardLayout =
Preferences::GetBool("intl.keyboard.per_window_layout", false);
static Maybe<bool> sCanQuit;
AppShutdownReason shutdownReason = AppShutdownReason::Unknown;
// (Large blocks of code should be broken out into OnEvent handlers.)
switch (msg) {
@ -5177,45 +5178,77 @@ bool nsWindow::ProcessMessageInternal(UINT msg, WPARAM& wParam, LPARAM& lParam,
#endif
break;
case WM_ENDSESSION:
case MOZ_WM_APP_QUIT:
// For WM_ENDSESSION, wParam indicates whether the session is being ended
// (TRUE) or not (FALSE)
if (msg == MOZ_WM_APP_QUIT || (wParam && sCanQuit.valueOr(false))) {
// Let's fake a shutdown sequence without actually closing windows etc.
// to avoid Windows killing us in the middle. A proper shutdown would
// require having a chance to pump some messages. Unfortunately
// Windows won't let us do that. Bug 212316.
nsCOMPtr<nsIObserverService> obsServ =
mozilla::services::GetObserverService();
const char16_t* syncShutdown = u"syncShutdown";
const char16_t* quitType = GetQuitType();
AppShutdown::Init(AppShutdownMode::Normal, 0);
obsServ->NotifyObservers(nullptr, "quit-application-granted",
syncShutdown);
obsServ->NotifyObservers(nullptr, "quit-application-forced", nullptr);
AppShutdown::OnShutdownConfirmed();
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownConfirmed,
quitType);
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownNetTeardown,
nullptr);
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownTeardown,
nullptr);
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdown, nullptr);
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownQM,
nullptr);
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownTelemetry,
nullptr);
AppShutdown::DoImmediateExit();
case WM_ENDSESSION: {
// For WM_ENDSESSION, wParam indicates whether we need to shutdown
// (TRUE) or not (FALSE).
//
// TODO: It is not clear if checking sCanQuit here is the right thing
// to do. From the WM_ENDSESSION documentation it seems there are cases
// where we just need to quit, always. Windows might even have ignored
// the WM_QUERYENDSESSION result or sCanQuit might be unset if we did
// not pass through WM_QUERYENDSESSION at all ?
if (!(wParam && sCanQuit.valueOr(false))) {
sCanQuit.reset();
result = true;
break;
}
sCanQuit.reset();
result = true;
// According to WM_ENDSESSION lParam documentation:
// 0 -> OS shutdown or restart (no way to distinguish)
// ENDSESSION_LOGOFF -> User is logging off
// ENDSESSION_CLOSEAPP -> Application must shutdown
// ENDSESSION_CRITICAL -> Application is forced to shutdown
// The difference of the last two is not very clear.
if (lParam == 0) {
shutdownReason = AppShutdownReason::OSShutdown;
} else if (lParam & ENDSESSION_LOGOFF) {
shutdownReason = AppShutdownReason::OSSessionEnd;
} else if (lParam & (ENDSESSION_CLOSEAPP | ENDSESSION_CRITICAL)) {
shutdownReason = AppShutdownReason::OSForceClose;
} else {
MOZ_DIAGNOSTIC_ASSERT(false,
"Received WM_ENDSESSION with unknown flags.");
shutdownReason = AppShutdownReason::OSForceClose;
}
}
[[fallthrough]];
case MOZ_WM_APP_QUIT: {
if (shutdownReason == AppShutdownReason::Unknown) {
// TODO: We do not expect that these days anybody sends us
// MOZ_WM_APP_QUIT, see bug 1827807.
shutdownReason = AppShutdownReason::WinUnexpectedMozQuit;
}
// Let's fake a shutdown sequence without actually closing windows etc.
// to avoid Windows killing us in the middle. A proper shutdown would
// require having a chance to pump some messages. Unfortunately
// Windows won't let us do that. Bug 212316.
nsCOMPtr<nsIObserverService> obsServ =
mozilla::services::GetObserverService();
const char16_t* syncShutdown = u"syncShutdown";
const char16_t* quitType = GetQuitType();
AppShutdown::Init(AppShutdownMode::Normal, 0, shutdownReason);
obsServ->NotifyObservers(nullptr, "quit-application-granted",
syncShutdown);
obsServ->NotifyObservers(nullptr, "quit-application-forced", nullptr);
AppShutdown::OnShutdownConfirmed();
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownConfirmed,
quitType);
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownNetTeardown,
nullptr);
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownTeardown,
nullptr);
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdown, nullptr);
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownQM, nullptr);
AppShutdown::AdvanceShutdownPhase(ShutdownPhase::AppShutdownTelemetry,
nullptr);
AppShutdown::DoImmediateExit();
MOZ_ASSERT_UNREACHABLE("Our process was supposed to exit.");
break;
}
case WM_SYSCOLORCHANGE:
// No need to invalidate layout for system color changes, but we need to

Просмотреть файл

@ -26,6 +26,7 @@
#include "nsAppDirectoryServiceDefs.h"
#include "nsAppRunner.h"
#include "nsDirectoryServiceUtils.h"
#include "nsExceptionHandler.h"
#include "nsICertStorage.h"
#include "nsThreadUtils.h"
@ -193,10 +194,12 @@ wchar_t* CopyPathIntoNewWCString(nsIFile* aFile) {
}
#endif
void AppShutdown::Init(AppShutdownMode aMode, int aExitCode) {
void AppShutdown::Init(AppShutdownMode aMode, int aExitCode,
AppShutdownReason aReason) {
if (sShutdownMode == AppShutdownMode::Normal) {
sShutdownMode = aMode;
}
AppShutdown::AnnotateShutdownReason(aReason);
sExitCode = aExitCode;
@ -304,6 +307,36 @@ bool AppShutdown::IsRestarting() {
return sShutdownMode == AppShutdownMode::Restart;
}
void AppShutdown::AnnotateShutdownReason(AppShutdownReason aReason) {
auto key = CrashReporter::Annotation::ShutdownReason;
nsCString reasonStr;
switch (aReason) {
case AppShutdownReason::AppClose:
reasonStr = "AppClose"_ns;
break;
case AppShutdownReason::AppRestart:
reasonStr = "AppRestart"_ns;
break;
case AppShutdownReason::OSForceClose:
reasonStr = "OSForceClose"_ns;
break;
case AppShutdownReason::OSSessionEnd:
reasonStr = "OSSessionEnd"_ns;
break;
case AppShutdownReason::OSShutdown:
reasonStr = "OSShutdown"_ns;
break;
case AppShutdownReason::WinUnexpectedMozQuit:
reasonStr = "WinUnexpectedMozQuit"_ns;
break;
default:
MOZ_ASSERT_UNREACHABLE("We should know the given reason for shutdown.");
reasonStr = "Unknown"_ns;
break;
}
CrashReporter::AnnotateCrashReport(key, reasonStr);
}
#ifdef DEBUG
static bool sNotifyingShutdownObservers = false;
static bool sAdvancingShutdownPhase = false;

Просмотреть файл

@ -19,6 +19,23 @@ enum class AppShutdownMode {
Restart,
};
enum class AppShutdownReason {
// No reason.
Unknown,
// Normal application shutdown.
AppClose,
// The application wants to restart.
AppRestart,
// The OS is force closing us.
OSForceClose,
// The user is logging off from the OS session, the system may stay alive.
OSSessionEnd,
// The system is shutting down (and maybe restarting).
OSShutdown,
// We unexpectedly received MOZ_WM_APP_QUIT, see bug 1827807.
WinUnexpectedMozQuit,
};
class AppShutdown {
public:
static ShutdownPhase GetCurrentShutdownPhase();
@ -36,9 +53,11 @@ class AppShutdown {
static void SaveEnvVarsForPotentialRestart();
/**
* Init the shutdown with the requested shutdown mode and exit code.
* Init the shutdown with the requested shutdown mode, exit code and optional
* a reason (if missing it will be derived from aMode).
*/
static void Init(AppShutdownMode aMode, int aExitCode);
static void Init(AppShutdownMode aMode, int aExitCode,
AppShutdownReason aReason);
/**
* Confirm that we are in fact going to be shutting down.
@ -109,6 +128,11 @@ class AppShutdown {
#endif
private:
/**
* Set the shutdown reason annotation.
*/
static void AnnotateShutdownReason(AppShutdownReason aReason);
/**
* This will perform a fast shutdown via _exit(0) or similar if the user's
* prefs are configured to do so at this phase.