Bug 1686838 [wpt PR 27194] - [webcodecs] Deprecate VideoFrame.destroy()., a=testonly
[gecko.git] / xpcom / base / AppShutdown.cpp
blobbf47f0c76c1cc6ea6b4787842df92de331ddb6d3
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "AppShutdown.h"
9 #ifdef XP_WIN
10 # include <windows.h>
11 #else
12 # include <unistd.h>
13 #endif
15 #include "GeckoProfiler.h"
16 #include "mozilla/CmdLineAndEnvUtils.h"
17 #include "mozilla/PoisonIOInterposer.h"
18 #include "mozilla/Printf.h"
19 #include "mozilla/scache/StartupCache.h"
20 #include "mozilla/SpinEventLoopUntil.h"
21 #include "mozilla/StartupTimeline.h"
22 #include "mozilla/StaticPrefs_toolkit.h"
23 #include "mozilla/LateWriteChecks.h"
24 #include "nsAppDirectoryServiceDefs.h"
25 #include "nsAppRunner.h"
26 #include "nsDirectoryServiceUtils.h"
27 #include "nsICertStorage.h"
28 #include "nsThreadUtils.h"
29 #include "prenv.h"
31 #ifdef MOZ_NEW_XULSTORE
32 # include "mozilla/XULStore.h"
33 #endif
35 namespace mozilla {
37 static ShutdownPhase sFastShutdownPhase = ShutdownPhase::NotInShutdown;
38 static ShutdownPhase sLateWriteChecksPhase = ShutdownPhase::NotInShutdown;
39 static AppShutdownMode sShutdownMode = AppShutdownMode::Normal;
40 static Atomic<bool, MemoryOrdering::Relaxed> sIsShuttingDown;
41 static int sExitCode = 0;
43 // These environment variable strings are all deliberately copied and leaked
44 // due to requirements of PR_SetEnv and similar.
45 static char* sSavedXulAppFile = nullptr;
46 #ifdef XP_WIN
47 static wchar_t* sSavedProfDEnvVar = nullptr;
48 static wchar_t* sSavedProfLDEnvVar = nullptr;
49 #else
50 static char* sSavedProfDEnvVar = nullptr;
51 static char* sSavedProfLDEnvVar = nullptr;
52 #endif
54 ShutdownPhase GetShutdownPhaseFromPrefValue(int32_t aPrefValue) {
55 switch (aPrefValue) {
56 case 1:
57 return ShutdownPhase::ShutdownPostLastCycleCollection;
58 case 2:
59 return ShutdownPhase::ShutdownThreads;
60 case 3:
61 return ShutdownPhase::Shutdown;
62 // NOTE: the remaining values from the ShutdownPhase enum will be added
63 // when we're at least reasonably confident that the world won't come
64 // crashing down if we do a fast shutdown at that point.
66 return ShutdownPhase::NotInShutdown;
69 bool AppShutdown::IsShuttingDown() { return sIsShuttingDown; }
71 int AppShutdown::GetExitCode() { return sExitCode; }
73 void AppShutdown::SaveEnvVarsForPotentialRestart() {
74 const char* s = PR_GetEnv("XUL_APP_FILE");
75 if (s) {
76 sSavedXulAppFile = Smprintf("%s=%s", "XUL_APP_FILE", s).release();
77 MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(sSavedXulAppFile);
81 void AppShutdown::MaybeDoRestart() {
82 if (sShutdownMode == AppShutdownMode::Restart) {
83 StopLateWriteChecks();
85 // Since we'll be launching our child while we're still alive, make sure
86 // we've unlocked the profile first, otherwise the child could hit its
87 // profile lock check before we've exited and thus released our lock.
88 UnlockProfile();
90 if (sSavedXulAppFile) {
91 PR_SetEnv(sSavedXulAppFile);
94 #ifdef XP_WIN
95 if (sSavedProfDEnvVar && !EnvHasValue("XRE_PROFILE_PATH")) {
96 SetEnvironmentVariableW(L"XRE_PROFILE_PATH", sSavedProfDEnvVar);
98 if (sSavedProfLDEnvVar && !EnvHasValue("XRE_PROFILE_LOCAL_PATH")) {
99 SetEnvironmentVariableW(L"XRE_PROFILE_LOCAL_PATH", sSavedProfLDEnvVar);
101 #else
102 if (sSavedProfDEnvVar && !EnvHasValue("XRE_PROFILE_PATH")) {
103 PR_SetEnv(sSavedProfDEnvVar);
105 if (sSavedProfLDEnvVar && !EnvHasValue("XRE_PROFILE_LOCAL_PATH")) {
106 PR_SetEnv(sSavedProfLDEnvVar);
108 #endif
110 LaunchChild(true);
114 #ifdef XP_WIN
115 wchar_t* CopyPathIntoNewWCString(nsIFile* aFile) {
116 wchar_t* result = nullptr;
117 nsAutoString resStr;
118 aFile->GetPath(resStr);
119 if (resStr.Length() > 0) {
120 result = (wchar_t*)malloc((resStr.Length() + 1) * sizeof(wchar_t));
121 if (result) {
122 wcscpy(result, resStr.get());
123 result[resStr.Length()] = 0;
127 return result;
129 #endif
131 void AppShutdown::Init(AppShutdownMode aMode, int aExitCode) {
132 if (sShutdownMode == AppShutdownMode::Normal) {
133 sShutdownMode = aMode;
136 sExitCode = aExitCode;
138 // Late-write checks needs to find the profile directory, so it has to
139 // be initialized before services::Shutdown or (because of
140 // xpcshell tests replacing the service) modules being unloaded.
141 InitLateWriteChecks();
143 int32_t fastShutdownPref = StaticPrefs::toolkit_shutdown_fastShutdownStage();
144 sFastShutdownPhase = GetShutdownPhaseFromPrefValue(fastShutdownPref);
145 int32_t lateWriteChecksPref =
146 StaticPrefs::toolkit_shutdown_lateWriteChecksStage();
147 sLateWriteChecksPhase = GetShutdownPhaseFromPrefValue(lateWriteChecksPref);
149 // Very early shutdowns can happen before the startup cache is even
150 // initialized; don't bother initializing it during shutdown.
151 if (auto* cache = scache::StartupCache::GetSingletonNoInit()) {
152 cache->MaybeInitShutdownWrite();
156 void AppShutdown::MaybeFastShutdown(ShutdownPhase aPhase) {
157 // For writes which we want to ensure are recorded, we don't want to trip
158 // the late write checking code. Anything that writes to disk and which
159 // we don't want to skip should be listed out explicitly in this section.
160 if (aPhase == sFastShutdownPhase || aPhase == sLateWriteChecksPhase) {
161 if (auto* cache = scache::StartupCache::GetSingletonNoInit()) {
162 cache->EnsureShutdownWriteComplete();
165 nsresult rv;
166 #ifdef MOZ_NEW_XULSTORE
167 rv = XULStore::Shutdown();
168 NS_ASSERTION(NS_SUCCEEDED(rv), "XULStore::Shutdown() failed.");
169 #endif
171 nsCOMPtr<nsICertStorage> certStorage =
172 do_GetService("@mozilla.org/security/certstorage;1", &rv);
173 if (NS_SUCCEEDED(rv)) {
174 SpinEventLoopUntil([&]() {
175 int32_t remainingOps;
176 nsresult rv = certStorage->GetRemainingOperationCount(&remainingOps);
177 NS_ASSERTION(NS_SUCCEEDED(rv),
178 "nsICertStorage::getRemainingOperationCount failed during "
179 "shutdown");
180 return NS_FAILED(rv) || remainingOps <= 0;
184 if (aPhase == sFastShutdownPhase) {
185 StopLateWriteChecks();
186 RecordShutdownEndTimeStamp();
187 MaybeDoRestart();
189 #ifdef MOZ_GECKO_PROFILER
190 profiler_shutdown(IsFastShutdown::Yes);
191 #endif
193 DoImmediateExit(sExitCode);
194 } else if (aPhase == sLateWriteChecksPhase) {
195 #ifdef XP_MACOSX
196 OnlyReportDirtyWrites();
197 #endif /* XP_MACOSX */
198 BeginLateWriteChecks();
202 void AppShutdown::OnShutdownConfirmed() {
203 sIsShuttingDown = true;
204 // If we're restarting, we need to save environment variables correctly
205 // while everything is still alive to do so.
206 if (sShutdownMode == AppShutdownMode::Restart) {
207 nsCOMPtr<nsIFile> profD;
208 nsCOMPtr<nsIFile> profLD;
209 NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profD));
210 NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR,
211 getter_AddRefs(profLD));
212 #ifdef XP_WIN
213 sSavedProfDEnvVar = CopyPathIntoNewWCString(profD);
214 sSavedProfLDEnvVar = CopyPathIntoNewWCString(profLD);
215 #else
216 nsAutoCString profDStr;
217 profD->GetNativePath(profDStr);
218 sSavedProfDEnvVar =
219 Smprintf("XRE_PROFILE_PATH=%s", profDStr.get()).release();
220 nsAutoCString profLDStr;
221 profLD->GetNativePath(profLDStr);
222 sSavedProfLDEnvVar =
223 Smprintf("XRE_PROFILE_LOCAL_PATH=%s", profLDStr.get()).release();
224 #endif
225 MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(sSavedProfDEnvVar);
226 MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(sSavedProfLDEnvVar);
230 void AppShutdown::DoImmediateExit(int aExitCode) {
231 #ifdef XP_WIN
232 HANDLE process = ::GetCurrentProcess();
233 if (::TerminateProcess(process, aExitCode)) {
234 ::WaitForSingleObject(process, INFINITE);
236 MOZ_CRASH("TerminateProcess failed.");
237 #else
238 _exit(aExitCode);
239 #endif
242 bool AppShutdown::IsRestarting() {
243 return sShutdownMode == AppShutdownMode::Restart;
246 } // namespace mozilla