/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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"ShutdownPhase.h" #ifdef XP_WIN # include <windows.h> # include "mozilla/PreXULSkeletonUI.h" #else # include <unistd.h> #endif
// These environment variable strings are all deliberately copied and leaked // due to requirements of PR_SetEnv and similar. staticchar* sSavedXulAppFile = nullptr; #ifdef XP_WIN staticwchar_t* sSavedProfDEnvVar = nullptr; staticwchar_t* sSavedProfLDEnvVar = nullptr; #else staticchar* sSavedProfDEnvVar = nullptr; staticchar* sSavedProfLDEnvVar = nullptr; #endif
ShutdownPhase GetShutdownPhaseFromPrefValue(int32_t aPrefValue) { switch (aPrefValue) { case 1: return ShutdownPhase::CCPostLastCycleCollection; case 2: return ShutdownPhase::XPCOMShutdownThreads; case 3: return ShutdownPhase::XPCOMShutdown; // NOTE: the remaining values from the ShutdownPhase enum will be added // when we're at least reasonably confident that the world won't come // crashing down if we do a fast shutdown at that point.
} return ShutdownPhase::NotInShutdown;
}
void AppShutdown::MaybeDoRestart() { if (sShutdownMode == AppShutdownMode::Restart) {
StopLateWriteChecks();
// Since we'll be launching our child while we're still alive, make sure // we've unlocked the profile first, otherwise the child could hit its // profile lock check before we've exited and thus released our lock.
UnlockProfile();
if (sSavedXulAppFile) {
PR_SetEnv(sSavedXulAppFile);
}
#ifdef XP_WIN if (sSavedProfDEnvVar && !EnvHasValue("XRE_PROFILE_PATH")) {
SetEnvironmentVariableW(L"XRE_PROFILE_PATH", sSavedProfDEnvVar);
} if (sSavedProfLDEnvVar && !EnvHasValue("XRE_PROFILE_LOCAL_PATH")) {
SetEnvironmentVariableW(L"XRE_PROFILE_LOCAL_PATH", sSavedProfLDEnvVar);
}
Unused << NotePreXULSkeletonUIRestarting(); #else if (sSavedProfDEnvVar && !EnvHasValue("XRE_PROFILE_PATH")) {
PR_SetEnv(sSavedProfDEnvVar);
} if (sSavedProfLDEnvVar && !EnvHasValue("XRE_PROFILE_LOCAL_PATH")) {
PR_SetEnv(sSavedProfLDEnvVar);
} #endif
LaunchChild(true);
}
}
#ifdef XP_WIN wchar_t* CopyPathIntoNewWCString(nsIFile* aFile) { wchar_t* result = nullptr;
nsAutoString resStr;
aFile->GetPath(resStr); if (resStr.Length() > 0) {
result = (wchar_t*)malloc((resStr.Length() + 1) * sizeof(wchar_t)); if (result) {
wcscpy(result, resStr.get());
result[resStr.Length()] = 0;
}
}
return result;
} #endif
void AppShutdown::Init(AppShutdownMode aMode, int aExitCode,
AppShutdownReason aReason) { if (sShutdownMode == AppShutdownMode::Normal) {
sShutdownMode = aMode;
}
AppShutdown::AnnotateShutdownReason(aReason);
sExitCode = aExitCode;
#ifndef ANDROID
sTerminator = new nsTerminator(); #endif
// Late-write checks needs to find the profile directory, so it has to // be initialized before services::Shutdown or (because of // xpcshell tests replacing the service) modules being unloaded.
InitLateWriteChecks();
// Very early shutdowns can happen before the startup cache is even // initialized; don't bother initializing it during shutdown. if (auto* cache = scache::StartupCache::GetSingletonNoInit()) {
cache->MaybeInitShutdownWrite();
}
}
void AppShutdown::MaybeFastShutdown(ShutdownPhase aPhase) { // For writes which we want to ensure are recorded, we don't want to trip // the late write checking code. Anything that writes to disk and which // we don't want to skip should be listed out explicitly in this section. if (aPhase == sFastShutdownPhase || aPhase == sLateWriteChecksPhase) { if (auto* cache = scache::StartupCache::GetSingletonNoInit()) {
cache->EnsureShutdownWriteComplete();
}
bool AppShutdown::IsNoOrLegalShutdownTopic(constchar* aTopic) { if (!XRE_IsParentProcess()) { // Until we know what to do with AppShutdown for child processes, // we ignore them for now. See bug 1697745. returntrue;
}
ShutdownPhase phase = GetShutdownPhaseFromTopic(aTopic); return phase == ShutdownPhase::NotInShutdown ||
(sNotifyingShutdownObservers && phase == sCurrentShutdownPhase);
} #endif
// We ensure that we can move only forward. We cannot // MOZ_ASSERT here as there are some tests that fire // notifications out of shutdown order. // See for example test_sss_sanitizeOnShutdown.js if (sCurrentShutdownPhase >= aPhase) { return;
}
// AppShutdownConfirmed is special in some ways as // - we can be called on top of a nested event loop (and it is the phase for // which SpinEventLoopUntilOrQuit breaks, so we want to return soon) // - we can be called from a sync marionette function that wants immediate // feedback, too // - in general, AppShutdownConfirmed will fire the "quit-application" // notification which in turn will cause an event to be dispatched that // runs all the rest of our shutdown sequence which we do not want to be // processed on top of the running event. // Thus we never do any NS_ProcessPendingEvents for it. bool mayProcessPending = (aPhase > ShutdownPhase::AppShutdownConfirmed);
// Give runnables dispatched between two calls to AdvanceShutdownPhase // a chance to run before actually advancing the phase. As we excluded // AppShutdownConfirmed above we can be sure that the processing is // covered by the terminator's timer of the previous phase during normal // shutdown (except out-of-order calls from some test). // Note that this affects only main thread runnables, such that the correct // way of ensuring shutdown processing remains to have an async shutdown // blocker. if (mayProcessPending && thread) {
NS_ProcessPendingEvents(thread);
}
// From now on any IsInOrBeyond checks will find the new phase set.
sCurrentShutdownPhase = aPhase;
#ifndef ANDROID if (sTerminator) {
sTerminator->AdvancePhase(aPhase);
} #endif
AppShutdown::MaybeFastShutdown(aPhase);
// This will null out the gathered pointers for this phase synchronously. // Note that we keep the old order here to avoid breakage, so be aware that // the notifications fired below will find these already cleared in case // you expected the opposite.
mozilla::KillClearOnShutdown(aPhase);
// Empty our MT event queue to process any side effects thereof. if (mayProcessPending && thread) {
NS_ProcessPendingEvents(thread);
}
if (doNotify) { constchar* aTopic = AppShutdown::GetObserverKey(aPhase); if (aTopic) {
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService(); if (obsService) { #ifdef DEBUG
sNotifyingShutdownObservers = true; auto reset = MakeScopeExit([] { sNotifyingShutdownObservers = false; }); #endif
obsService->NotifyObservers(aNotificationSubject, aTopic,
aNotificationData); // Empty our MT event queue again after the notification has finished if (mayProcessPending && thread) {
NS_ProcessPendingEvents(thread);
}
}
}
}
}
/** * XXX: Before tackling bug 1697745 we need the * possibility to advance the phase without notification * in the content process.
*/ void AppShutdown::AdvanceShutdownPhaseWithoutNotify(ShutdownPhase aPhase) {
AdvanceShutdownPhaseInternal(aPhase, /* doNotify */ false, nullptr, nullptr);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.