/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/ipc/GeckoChildProcessHost.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/Attributes.h"
#include "mozilla/Components.h"
#include "mozilla/FilePreferences.h"
#include "mozilla/ChaosMode.h"
#include "mozilla/CmdLineAndEnvUtils.h"
#include "mozilla/IOInterposer.h"
#include "mozilla/ipc/UtilityProcessChild.h"
#include "mozilla/Likely.h"
#include "mozilla/MemoryChecking.h"
#include "mozilla/Poison.h"
#include "mozilla/Preferences.h"
#include "mozilla/PreferenceSheet.h"
#include "mozilla/Printf.h"
#include "mozilla/ProcessType.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/RuntimeExceptionModule.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPrefs_browser.h"
#include "mozilla/StaticPrefs_fission.h"
#include "mozilla/StaticPrefs_webgl.h"
#include "mozilla/StaticPrefs_widget.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Try.h"
#include "mozilla/Utf8.h"
#include "mozilla/intl/LocaleService.h"
#include "mozilla/JSONWriter.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/glean/ToolkitMozappsUpdateSharedMetrics.h"
#include "mozilla/glean/ToolkitXreMetrics.h"
#include "mozilla/glean/GleanPings.h"
#include "mozilla/widget/TextRecognition.h"
#include "BaseProfiler.h"
#include "mozJSModuleLoader.h"
#include "nsAppRunner.h"
#include "mozilla/XREAppData.h"
#include "mozilla/Bootstrap.h"
#if defined(MOZ_UPDATER) && !
defined(MOZ_WIDGET_ANDROID)
# include
"nsUpdateDriver.h"
# include
"nsUpdateSyncManager.h"
#endif
#include "ProfileReset.h"
#ifdef XP_MACOSX
# include
"nsVersionComparator.h"
# include
"MacLaunchHelper.h"
# include
"MacApplicationDelegate.h"
# include
"MacAutoreleasePool.h"
# include
"MacRunFromDmgUtils.h"
// these are needed for sysctl
# include <sys/types.h>
# include <sys/sysctl.h>
#endif
#include "prnetdb.h"
#include "prprf.h"
#include "prproces.h"
#include "prenv.h"
#include "prtime.h"
#include "nsIAppStartup.h"
#include "nsCategoryManagerUtils.h"
#include "nsIMutableArray.h"
#include "nsCommandLine.h"
#include "nsIComponentRegistrar.h"
#include "nsIDialogParamBlock.h"
#include "mozilla/ModuleUtils.h"
#include "nsIIOService.h"
#include "nsIObserverService.h"
#include "nsINativeAppSupport.h"
#include "nsIPlatformInfo.h"
#include "nsIProcess.h"
#include "nsIProfileUnlocker.h"
#include "nsIPromptService.h"
#include "nsIPropertyBag2.h"
#include "nsIServiceManager.h"
#include "nsIStringBundle.h"
#include "nsISupportsPrimitives.h"
#include "nsIToolkitProfile.h"
#include "nsToolkitProfileService.h"
#include "nsIURI.h"
#include "nsIURL.h"
#include "nsIWindowCreator.h"
#include "nsIWindowWatcher.h"
#include "nsIXULAppInfo.h"
#include "nsIXULRuntime.h"
#include "nsPIDOMWindow.h"
#include "nsIWidget.h"
#include "nsAppShellCID.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/scache/StartupCache.h"
#include "gfxPlatform.h"
#include "PDMFactory.h"
#ifdef XP_MACOSX
# include
"gfxPlatformMac.h"
#endif
#include "mozilla/Unused.h"
#ifdef XP_WIN
# include
"nsIWinAppHelper.h"
# include <windows.h>
# include <intrin.h>
# include <math.h>
# include
"cairo/cairo-features.h"
# include
"detect_win32k_conflicts.h"
# include
"mozilla/PreXULSkeletonUI.h"
# include
"mozilla/DllPrefetchExperimentRegistryInfo.h"
# include
"mozilla/WindowsBCryptInitialization.h"
# include
"mozilla/WindowsDllBlocklist.h"
# include
"mozilla/WindowsMsctfInitialization.h"
# include
"mozilla/WindowsOleAut32Initialization.h"
# include
"mozilla/WindowsProcessMitigations.h"
# include
"mozilla/WindowsVersion.h"
# include
"mozilla/WinHeaderOnlyUtils.h"
# include
"mozilla/mscom/ProcessRuntime.h"
# include
"mozilla/mscom/ProfilerMarkers.h"
# include
"WinTokenUtils.h"
# if defined(MOZ_LAUNCHER_PROCESS)
# include
"mozilla/LauncherRegistryInfo.h"
# endif
# if defined(MOZ_DEFAULT_BROWSER_AGENT)
# include
"nsIWindowsRegKey.h"
# endif
# ifndef PROCESS_DEP_ENABLE
# define PROCESS_DEP_ENABLE 0x1
# endif
#endif
#if defined(MOZ_SANDBOX)
# include
"mozilla/SandboxSettings.h"
#endif
#ifdef ACCESSIBILITY
# include
"nsAccessibilityService.h"
# if defined(XP_WIN)
# include
"mozilla/a11y/Compatibility.h"
# include
"mozilla/a11y/Platform.h"
# endif
#endif
#include "nsCRT.h"
#include "nsCOMPtr.h"
#include "nsDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsEmbedCID.h"
#include "nsIDUtils.h"
#include "nsNetUtil.h"
#include "nsReadableUtils.h"
#include "nsXPCOM.h"
#include "nsXPCOMCIDInternal.h"
#include "nsString.h"
#include "nsPrintfCString.h"
#include "nsVersionComparator.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsXULAppAPI.h"
#include "nsXREDirProvider.h"
#include "nsINIParser.h"
#include "mozilla/Omnijar.h"
#include "mozilla/StartupTimeline.h"
#include "mozilla/LateWriteChecks.h"
#include <stdlib.h>
#include <locale.h>
#ifdef XP_UNIX
# include <errno.h>
# include <pwd.h>
# include <string.h>
# include <sys/resource.h>
# include <sys/stat.h>
# include <unistd.h>
#endif
#ifdef XP_WIN
# include <process.h>
# include <shlobj.h>
# include
"mozilla/WinDllServices.h"
# include
"nsThreadUtils.h"
# include
"WinUtils.h"
#endif
#ifdef XP_MACOSX
# include
"nsILocalFileMac.h"
# include
"nsCommandLineServiceMac.h"
#endif
// for X remote support
#if defined(MOZ_HAS_REMOTE)
# include
"nsRemoteService.h"
#endif
#if defined(DEBUG) &&
defined(XP_WIN)
# include <malloc.h>
#endif
#if defined(XP_MACOSX)
# include <Carbon/Carbon.h>
#endif
#ifdef DEBUG
# include
"mozilla/Logging.h"
#endif
#include "nsExceptionHandler.h"
#include "nsICrashReporter.h"
#include "nsIPrefService.h"
#include "nsIMemoryInfoDumper.h"
#include "js/String.h"
#if defined(XP_LINUX) && !
defined(ANDROID)
# include
"mozilla/widget/LSBUtils.h"
#endif
#include "base/command_line.h"
#include "GTestRunner.h"
#ifdef MOZ_WIDGET_ANDROID
# include
"gfxAndroidPlatform.h"
# include
"mozilla/java/GeckoAppShellWrappers.h"
#endif
#if defined(MOZ_SANDBOX)
# if defined(XP_LINUX) && !
defined(ANDROID)
# include
"mozilla/SandboxInfo.h"
# elif
defined(XP_WIN)
# include
"sandboxBroker.h"
# endif
#endif
#ifdef MOZ_CODE_COVERAGE
# include
"mozilla/CodeCoverageHandler.h"
#endif
#include "GMPProcessChild.h"
#include "SafeMode.h"
#ifdef MOZ_BACKGROUNDTASKS
# include
"mozilla/BackgroundTasks.h"
# include
"nsIPowerManagerService.h"
# include
"nsIStringBundle.h"
#endif
#ifdef USE_GLX_TEST
# include
"mozilla/GUniquePtr.h"
# include
"mozilla/GfxInfo.h"
#endif
#ifdef MOZ_WIDGET_GTK
# include
"nsAppShell.h"
#endif
#ifdef MOZ_ENABLE_DBUS
# include
"DBusService.h"
#endif
extern uint32_t gRestartMode;
extern void InstallSignalHandlers(
const char* ProgramName);
#define FILE_COMPATIBILITY_INFO
"compatibility.ini"_ns
#define FILE_INVALIDATE_CACHES
".purgecaches"_ns
#define FILE_STARTUP_INCOMPLETE u
".startup-incomplete"_ns
#if defined(MOZ_BLOCK_PROFILE_DOWNGRADE) ||
defined(MOZ_LAUNCHER_PROCESS) || \
defined(MOZ_DEFAULT_BROWSER_AGENT)
static const char kPrefHealthReportUploadEnabled[] =
"datareporting.healthreport.uploadEnabled";
#endif // defined(MOZ_BLOCK_PROFILE_DOWNGRADE) || defined(MOZ_LAUNCHER_PROCESS)
// || defined(MOZ_DEFAULT_BROWSER_AGENT)
#if defined(MOZ_DEFAULT_BROWSER_AGENT)
static const char kPrefDefaultAgentEnabled[] =
"default-browser-agent.enabled";
static const char kPrefServicesSettingsServer[] =
"services.settings.server";
static const char kPrefSetDefaultBrowserUserChoicePref[] =
"browser.shell.setDefaultBrowserUserChoice";
#endif // defined(MOZ_DEFAULT_BROWSER_AGENT)
#if defined(XP_WIN)
static const char kPrefThemeId[] =
"extensions.activeThemeID";
static const char kPrefBrowserStartupBlankWindow[] =
"browser.startup.blankWindow";
static const char kPrefPreXulSkeletonUI[] =
"browser.startup.preXulSkeletonUI";
#endif // defined(XP_WIN)
#if defined(MOZ_WIDGET_GTK)
constexpr nsLiteralCString kStartupTokenNames[] = {
"XDG_ACTIVATION_TOKEN"_ns,
"DESKTOP_STARTUP_ID"_ns,
};
#endif
int gArgc;
char** gArgv;
static const char gToolkitVersion[] = MOZ_STRINGIFY(GRE_MILESTONE);
// The gToolkitBuildID global is defined to MOZ_BUILDID via gen_buildid.py
// in toolkit/library. See related comment in toolkit/library/moz.build.
extern const char gToolkitBuildID[];
static nsIProfileLock* gProfileLock;
#if defined(MOZ_HAS_REMOTE)
MOZ_RUNINIT
static RefPtr<nsRemoteService> gRemoteService;
MOZ_RUNINIT
static RefPtr<nsStartupLock> gStartupLock;
#endif
int gRestartArgc;
char** gRestartArgv;
// If gRestartedByOS is set, we were automatically restarted by the OS.
bool gRestartedByOS =
false;
bool gIsGtest =
false;
bool gKioskMode =
false;
int gKioskMonitor = -1;
bool gAllowContentAnalysisArgPresent =
false;
MOZ_CONSTINIT nsString gAbsoluteArgv0Path;
#if defined(XP_WIN)
MOZ_CONSTINIT nsString gProcessStartupShortcut;
#endif
#if defined(MOZ_WIDGET_GTK)
# include <glib.h>
# include
"mozilla/WidgetUtilsGtk.h"
# include <gtk/gtk.h>
# ifdef MOZ_WAYLAND
# include <gdk/gdkwayland.h>
# include
"mozilla/widget/nsWaylandDisplay.h"
# include
"wayland-proxy.h"
# endif
# ifdef MOZ_X11
# include <gdk/gdkx.h>
# endif
/* MOZ_X11 */
#endif
#if defined(MOZ_WAYLAND)
MOZ_RUNINIT std::unique_ptr<WaylandProxy> gWaylandProxy;
#endif
#include "BinaryPath.h"
#ifdef FUZZING
# include
"FuzzerRunner.h"
namespace mozilla {
FuzzerRunner* fuzzerRunner = 0;
}
// namespace mozilla
# ifdef LIBFUZZER
void XRE_LibFuzzerSetDriver(LibFuzzerDriver aDriver) {
mozilla::fuzzerRunner->setParams(aDriver);
}
# endif
#endif // FUZZING
// Undo X11/X.h's definition of None
#undef None
namespace mozilla {
int (*RunGTest)(
int*,
char**) = 0;
bool RunningGTest() {
return RunGTest; }
}
// namespace mozilla
using namespace mozilla;
using namespace mozilla::widget;
using namespace mozilla::startup;
using mozilla::Unused;
using mozilla::dom::ContentChild;
using mozilla::dom::ContentParent;
using mozilla::dom::quota::QuotaManager;
using mozilla::intl::LocaleService;
using mozilla::scache::StartupCache;
// Save the given word to the specified environment variable.
static void MOZ_NEVER_INLINE SaveWordToEnv(
const char* name,
const nsACString& word) {
char* expr =
Smprintf(
"%s=%s", name, PromiseFlatCString(word).get()).release();
if (expr) PR_SetEnv(expr);
// We intentionally leak |expr| here since it is required by PR_SetEnv.
}
// Save the path of the given file to the specified environment variable.
static void SaveFileToEnv(
const char* name, nsIFile* file) {
#ifdef XP_WIN
nsAutoString path;
file->GetPath(path);
SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
#else
nsAutoCString path;
file->GetNativePath(path);
SaveWordToEnv(name, path);
#endif
}
static bool gIsExpectedExit =
false;
void MozExpectedExit() { gIsExpectedExit =
true; }
/**
* Runs atexit() to catch unexpected exit from 3rd party libraries like the
* Intel graphics driver calling exit in an error condition. When they
* call exit() to report an error we won't shutdown correctly and wont catch
* the issue with our crash reporter.
*/
static void UnexpectedExit() {
if (!gIsExpectedExit) {
gIsExpectedExit =
true;
// Don't risk re-entrency issues when crashing.
MOZ_CRASH(
"Exit called by third party code.");
}
}
#if defined(MOZ_WAYLAND)
bool IsWaylandEnabled() {
static bool isWaylandEnabled = []() {
const char* waylandDisplay = PR_GetEnv(
"WAYLAND_DISPLAY");
if (!waylandDisplay) {
return false;
}
if (!PR_GetEnv(
"DISPLAY")) {
// No X11 display, so try to run wayland.
return true;
}
// MOZ_ENABLE_WAYLAND is our primary Wayland on/off switch.
if (
const char* waylandPref = PR_GetEnv(
"MOZ_ENABLE_WAYLAND")) {
return *waylandPref ==
'1';
}
if (
const char* backendPref = PR_GetEnv(
"GDK_BACKEND")) {
if (!strncmp(backendPref,
"wayland", 7)) {
NS_WARNING(
"Wayland backend should be enabled by MOZ_ENABLE_WAYLAND=1."
"GDK_BACKEND is a Gtk3 debug variable and may cause issues.");
return true;
}
}
// Enable by default when we're running on a recent enough GTK version. We'd
// like to check further details like compositor version and so on ideally
// to make sure we don't enable it on old Mutter or what not, but we can't,
// so let's assume that if the user is running on a Wayland session by
// default we're ok, since either the distro has enabled Wayland by default,
// or the user has gone out of their way to use Wayland.
return !gtk_check_version(3, 24, 30);
}();
return isWaylandEnabled;
}
#else
bool IsWaylandEnabled() {
return false; }
#endif
/**
* Output a string to the user. This method is really only meant to be used to
* output last-ditch error messages designed for developers NOT END USERS.
*
* @param isError
* Pass true to indicate severe errors.
* @param fmt
* printf-style format string followed by arguments.
*/
static MOZ_FORMAT_PRINTF(2, 3)
void Output(
bool isError,
const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
#if defined(XP_WIN) && !MOZ_WINCONSOLE
SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
if (msg) {
UINT flags = MB_OK;
if (isError)
flags |= MB_ICONERROR;
else
flags |= MB_ICONINFORMATION;
wchar_t wide_msg[1024];
MultiByteToWideChar(CP_ACP, 0, msg.get(), -1, wide_msg,
sizeof(wide_msg) /
sizeof(
wchar_t));
wchar_t wide_caption[128];
MultiByteToWideChar(CP_ACP, 0, gAppData ? gAppData->name :
"XULRunner", -1,
wide_caption,
sizeof(wide_caption) /
sizeof(
wchar_t));
MessageBoxW(nullptr, wide_msg, wide_caption, flags);
}
#elif defined(MOZ_WIDGET_ANDROID)
SmprintfPointer msg = mozilla::Vsmprintf(fmt, ap);
if (msg) {
__android_log_print(isError ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO,
"GeckoRuntime",
"%s", msg.get());
}
#else
vfprintf(stderr, fmt, ap);
#endif
va_end(ap);
}
/**
* Check for a commandline flag. If the flag takes a parameter, the
* parameter is returned in aParam. Flags may be in the form -arg or
* --arg (or /arg on win32).
*
* @param aArg the parameter to check. Must be lowercase.
* @param aParam if non-null, the -arg <data> will be stored in this pointer.
* This is *not* allocated, but rather a pointer to the argv data.
* @param aFlags flags @see CheckArgFlag
*/
static ArgResult CheckArg(
const char* aArg,
const char** aParam = nullptr,
CheckArgFlag aFlags = CheckArgFlag::RemoveArg) {
MOZ_ASSERT(gArgv,
"gArgv must be initialized before CheckArg()");
return CheckArg(gArgc, gArgv, aArg, aParam, aFlags);
}
/**
* Check for a commandline flag. Ignore data that's passed in with the flag.
* Flags may be in the form -arg or --arg (or /arg on win32).
* Will not remove flag if found.
*
* @param aArg the parameter to check. Must be lowercase.
*/
static ArgResult CheckArgExists(
const char* aArg) {
return CheckArg(aArg, nullptr, CheckArgFlag::None);
}
bool gSafeMode =
false;
bool gFxREmbedded =
false;
enum E10sStatus {
kE10sEnabledByDefault,
kE10sForceDisabled,
};
static bool gBrowserTabsRemoteAutostart =
false;
static E10sStatus gBrowserTabsRemoteStatus;
static bool gBrowserTabsRemoteAutostartInitialized =
false;
namespace mozilla {
bool BrowserTabsRemoteAutostart() {
if (gBrowserTabsRemoteAutostartInitialized) {
return gBrowserTabsRemoteAutostart;
}
gBrowserTabsRemoteAutostartInitialized =
true;
// If we're not in the parent process, we are running E10s.
if (!XRE_IsParentProcess()) {
gBrowserTabsRemoteAutostart =
true;
return gBrowserTabsRemoteAutostart;
}
gBrowserTabsRemoteAutostart =
true;
E10sStatus status = kE10sEnabledByDefault;
// We are checking to ensure that either MOZILLA_OFFICIAL is undefined or that
// xpc::AreNonLocalConnectionsDisabled() is true. If either check matches,
// we move on to check the MOZ_FORCE_DISABLE_E10S environment variable which
// must equal "1" to proceed with disabling e10s.
#if defined(MOZILLA_OFFICIAL)
bool allowDisablingE10s = xpc::AreNonLocalConnectionsDisabled();
#else
bool allowDisablingE10s =
true;
#endif
if (gBrowserTabsRemoteAutostart && allowDisablingE10s) {
const char* forceDisable = PR_GetEnv(
"MOZ_FORCE_DISABLE_E10S");
if (forceDisable && !strcmp(forceDisable,
"1")) {
gBrowserTabsRemoteAutostart =
false;
status = kE10sForceDisabled;
}
}
gBrowserTabsRemoteStatus = status;
return gBrowserTabsRemoteAutostart;
}
}
// namespace mozilla
// Win32k Infrastructure ==============================================
// This bool tells us if we have initialized the following two statics
// upon startup.
static bool gWin32kInitialized =
false;
// Win32k Lockdown for the current session is determined once, at startup,
// and then remains the same for the duration of the session.
static nsIXULRuntime::ContentWin32kLockdownState gWin32kStatus;
// The status of the win32k experiment. It is determined once, at startup,
// and then remains the same for the duration of the session.
static nsIXULRuntime::ExperimentStatus gWin32kExperimentStatus =
nsIXULRuntime::eExperimentStatusUnenrolled;
#ifdef XP_WIN
// The states for win32k lockdown can be generalized to:
// - User doesn't meet requirements (bad OS, webrender, remotegl) aka
// PersistentRequirement
// - User has Safe Mode enabled, Win32k Disabled by Env Var, or E10S disabled
// by Env Var aka TemporaryRequirement
// - User has set the win32k pref to something non-default aka NonDefaultPref
// - User has been enrolled in the experiment and does what it says aka
// Enrolled
// - User does the default aka Default
//
// We expect the below behvaior. In the code, there may be references to these
// behaviors (e.g. [A]) but not always.
//
// [A] Becoming enrolled in the experiment while NonDefaultPref disqualifies
// you upon next browser start
// [B] Becoming enrolled in the experiment while PersistentRequirement
// disqualifies you upon next browser start
// [C] Becoming enrolled in the experiment while TemporaryRequirement does not
// disqualify you
// [D] Becoming enrolled in the experiment will only take effect after restart
// [E] While enrolled, becoming PersistentRequirement will not disqualify you
// until browser restart, but if the state is present at browser start,
// will disqualify you. Additionally, it will not affect the session value
// of gWin32kStatus.
// XXX(bobowen): I hope both webrender and wbgl.out-of-process require a
// restart to take effect!
// [F] While enrolled, becoming NonDefaultPref will disqualify you upon next
// browser start
// [G] While enrolled, becoming TemporaryRequirement will _not_ disqualify you,
// but the session status will prevent win32k lockdown from taking effect.
// The win32k pref
static const char kPrefWin32k[] =
"security.sandbox.content.win32k-disable";
// The current enrollment status as controlled by Normandy. This value is only
// stored in the default preference branch, and is not persisted across
// sessions by the preference service. It therefore isn't available early
// enough at startup, and needs to be synced to a preference in the user
// branch which is persisted across sessions.
static const char kPrefWin32kExperimentEnrollmentStatus[] =
"security.sandbox.content.win32k-experiment.enrollmentStatus";
// The enrollment status to be used at browser startup. This automatically
// synced from the above enrollmentStatus preference whenever the latter is
// changed. We reused the Fission experiment enum - it can have any of the
// values defined in the `nsIXULRuntime_ExperimentStatus` enum _except_ rollout.
// Meanings are documented in the declaration of
// `nsIXULRuntime.fissionExperimentStatus`
static const char kPrefWin32kExperimentStartupEnrollmentStatus[] =
"security.sandbox.content.win32k-experiment.startupEnrollmentStatus";
namespace mozilla {
bool Win32kExperimentEnrolled() {
MOZ_ASSERT(XRE_IsParentProcess());
return gWin32kExperimentStatus == nsIXULRuntime::eExperimentStatusControl ||
gWin32kExperimentStatus == nsIXULRuntime::eExperimentStatusTreatment;
}
}
// namespace mozilla
static bool Win32kRequirementsUnsatisfied(
nsIXULRuntime::ContentWin32kLockdownState aStatus) {
return aStatus == nsIXULRuntime::ContentWin32kLockdownState::
OperatingSystemNotSupported ||
aStatus ==
nsIXULRuntime::ContentWin32kLockdownState::MissingWebRender ||
aStatus ==
nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL ||
aStatus ==
nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote;
}
static void Win32kExperimentDisqualify() {
MOZ_ASSERT(XRE_IsParentProcess());
Preferences::SetUint(kPrefWin32kExperimentEnrollmentStatus,
nsIXULRuntime::eExperimentStatusDisqualified);
}
static void OnWin32kEnrollmentStatusChanged(
const char* aPref,
void* aData) {
auto newStatusInt =
Preferences::GetUint(kPrefWin32kExperimentEnrollmentStatus,
nsIXULRuntime::eExperimentStatusUnenrolled);
auto newStatus = newStatusInt < nsIXULRuntime::eExperimentStatusCount
? nsIXULRuntime::ExperimentStatus(newStatusInt)
: nsIXULRuntime::eExperimentStatusDisqualified;
// Set the startup pref for next browser start [D]
Preferences::SetUint(kPrefWin32kExperimentStartupEnrollmentStatus, newStatus);
}
namespace {
// This observer is notified during `profile-before-change`, and ensures that
// the experiment enrollment status is synced over before the browser shuts
// down, even if it was not modified since win32k was initialized.
class Win32kEnrollmentStatusShutdownObserver final :
public nsIObserver {
public:
NS_DECL_ISUPPORTS
NS_IMETHOD Observe(nsISupports* aSubject,
const char* aTopic,
const char16_t* aData) override {
MOZ_ASSERT(!strcmp(
"profile-before-change", aTopic));
OnWin32kEnrollmentStatusChanged(kPrefWin32kExperimentEnrollmentStatus,
nullptr);
return NS_OK;
}
private:
~Win32kEnrollmentStatusShutdownObserver() =
default;
};
NS_IMPL_ISUPPORTS(Win32kEnrollmentStatusShutdownObserver, nsIObserver)
}
// namespace
static void OnWin32kChanged(
const char* aPref,
void* aData) {
// If we're actively enrolled in the Win32k experiment, disqualify the user
// from the experiment if the Win32k pref is modified. [F]
if (Win32kExperimentEnrolled() && Preferences::HasUserValue(kPrefWin32k)) {
Win32kExperimentDisqualify();
}
}
#endif // XP_WIN
namespace mozilla {
void EnsureWin32kInitialized();
}
nsIXULRuntime::ContentWin32kLockdownState GetLiveWin32kLockdownState() {
#ifdef XP_WIN
// HasUserValue The Pref functions can only be called on main thread
MOZ_ASSERT(NS_IsMainThread());
# ifdef MOZ_BACKGROUNDTASKS
if (BackgroundTasks::IsBackgroundTaskMode()) {
// Let's bail out before loading all the graphics libs.
return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault;
}
# endif
mozilla::EnsureWin32kInitialized();
gfxPlatform::GetPlatform();
if (gSafeMode) {
return nsIXULRuntime::ContentWin32kLockdownState::DisabledBySafeMode;
}
if (EnvHasValue(
"MOZ_ENABLE_WIN32K")) {
return nsIXULRuntime::ContentWin32kLockdownState::DisabledByEnvVar;
}
if (!mozilla::BrowserTabsRemoteAutostart()) {
return nsIXULRuntime::ContentWin32kLockdownState::DisabledByE10S;
}
// Win32k lockdown is available on Win8+, but we are initially limiting it to
// Windows 10 v1709 (build 16299) or later. Before this COM initialization
// currently fails if user32.dll has loaded before it is called.
if (!IsWin10FallCreatorsUpdateOrLater()) {
return nsIXULRuntime::ContentWin32kLockdownState::
OperatingSystemNotSupported;
}
{
ConflictingMitigationStatus conflictingMitigationStatus = {};
if (!detect_win32k_conflicting_mitigations(&conflictingMitigationStatus)) {
return nsIXULRuntime::ContentWin32kLockdownState::
IncompatibleMitigationPolicy;
}
if (conflictingMitigationStatus.caller_check ||
conflictingMitigationStatus.sim_exec ||
conflictingMitigationStatus.stack_pivot) {
return nsIXULRuntime::ContentWin32kLockdownState::
IncompatibleMitigationPolicy;
}
}
// Win32k Lockdown requires Remote WebGL, but it may be disabled on
// certain hardware or virtual machines.
if (!gfx::gfxVars::AllowWebglOop() || !StaticPrefs::webgl_out_of_process()) {
return nsIXULRuntime::ContentWin32kLockdownState::MissingRemoteWebGL;
}
// Some (not sure exactly which) decoders are not compatible
if (!PDMFactory::AllDecodersAreRemote()) {
return nsIXULRuntime::ContentWin32kLockdownState::DecodersArentRemote;
}
bool prefSetByUser =
Preferences::HasUserValue(
"security.sandbox.content.win32k-disable");
bool prefValue = Preferences::GetBool(
"security.sandbox.content.win32k-disable",
false, PrefValueKind::User);
bool defaultValue = Preferences::GetBool(
"security.sandbox.content.win32k-disable",
false, PrefValueKind::
Default);
if (prefSetByUser) {
if (prefValue) {
return nsIXULRuntime::ContentWin32kLockdownState::EnabledByUserPref;
}
else {
return nsIXULRuntime::ContentWin32kLockdownState::DisabledByUserPref;
}
}
if (gWin32kExperimentStatus ==
nsIXULRuntime::ExperimentStatus::eExperimentStatusControl) {
return nsIXULRuntime::ContentWin32kLockdownState::DisabledByControlGroup;
}
else if (gWin32kExperimentStatus ==
nsIXULRuntime::ExperimentStatus::eExperimentStatusTreatment) {
return nsIXULRuntime::ContentWin32kLockdownState::EnabledByTreatmentGroup;
}
if (defaultValue) {
return nsIXULRuntime::ContentWin32kLockdownState::EnabledByDefault;
}
else {
return nsIXULRuntime::ContentWin32kLockdownState::DisabledByDefault;
}
#else
return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
#endif
}
namespace mozilla {
void EnsureWin32kInitialized() {
if (gWin32kInitialized) {
return;
}
gWin32kInitialized =
true;
#ifdef XP_WIN
// Initialize the Win32k experiment, configuring win32k's
// default, before checking other overrides. This allows opting-out of a
// Win32k experiment through about:preferences or about:config from a
// safemode session.
uint32_t experimentRaw =
Preferences::GetUint(kPrefWin32kExperimentStartupEnrollmentStatus,
nsIXULRuntime::eExperimentStatusUnenrolled);
gWin32kExperimentStatus =
experimentRaw < nsIXULRuntime::eExperimentStatusCount
? nsIXULRuntime::ExperimentStatus(experimentRaw)
: nsIXULRuntime::eExperimentStatusDisqualified;
// Watch the experiment enrollment status pref to detect experiment
// disqualification, and ensure it is propagated for the next restart.
Preferences::RegisterCallback(&OnWin32kEnrollmentStatusChanged,
kPrefWin32kExperimentEnrollmentStatus);
if (nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService()) {
nsCOMPtr<nsIObserver> shutdownObserver =
new Win32kEnrollmentStatusShutdownObserver();
observerService->AddObserver(shutdownObserver,
"profile-before-change",
false);
}
// If the user no longer qualifies because they edited a required pref, check
// that. [B] [E]
auto tmpStatus = GetLiveWin32kLockdownState();
if (Win32kExperimentEnrolled() && Win32kRequirementsUnsatisfied(tmpStatus)) {
Win32kExperimentDisqualify();
gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusDisqualified;
}
// If the user has overridden an active experiment by setting a user value for
// "security.sandbox.content.win32k-disable", disqualify the user from the
// experiment. [A] [F]
if (Preferences::HasUserValue(kPrefWin32k) && Win32kExperimentEnrolled()) {
Win32kExperimentDisqualify();
gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusDisqualified;
}
// Unlike Fission, we do not configure the default branch based on experiment
// enrollment status. Instead we check the startupEnrollmentPref in
// GetContentWin32kLockdownState()
Preferences::RegisterCallback(&OnWin32kChanged, kPrefWin32k);
// Set the state
gWin32kStatus = GetLiveWin32kLockdownState();
#else
gWin32kStatus =
nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
gWin32kExperimentStatus = nsIXULRuntime::eExperimentStatusUnenrolled;
#endif // XP_WIN
}
nsIXULRuntime::ContentWin32kLockdownState GetWin32kLockdownState() {
#ifdef XP_WIN
mozilla::EnsureWin32kInitialized();
return gWin32kStatus;
#else
return nsIXULRuntime::ContentWin32kLockdownState::OperatingSystemNotSupported;
#endif
}
}
// namespace mozilla
// End Win32k Infrastructure ==========================================
// Fission Infrastructure =============================================
// Fission enablement for the current session is determined once, at startup,
// and then remains the same for the duration of the session.
//
// The following factors determine whether or not Fission is enabled for a
// session, in order of precedence:
//
// - Safe mode: In safe mode, Fission is never enabled.
//
// - The MOZ_FORCE_ENABLE_FISSION environment variable: If set to any value,
// Fission will be enabled.
//
// - The 'fission.autostart' preference, if it has been configured by the user.
static const char kPrefFissionAutostart[] =
"fission.autostart";
// The computed FissionAutostart value for the session, read by content
// processes to initialize gFissionAutostart.
//
// This pref is locked, and only configured on the default branch, so should
// never be persisted in a profile.
static const char kPrefFissionAutostartSession[] =
"fission.autostart.session";
//
// The computed FissionAutostart value for the session, read by content
// processes to initialize gFissionAutostart.
static bool gFissionAutostart =
false;
static bool gFissionAutostartInitialized =
false;
static nsIXULRuntime::FissionDecisionStatus gFissionDecisionStatus;
static void EnsureFissionAutostartInitialized() {
if (gFissionAutostartInitialized) {
return;
}
gFissionAutostartInitialized =
true;
if (!XRE_IsParentProcess()) {
// This pref is configured for the current session by the parent process.
gFissionAutostart = Preferences::GetBool(kPrefFissionAutostartSession,
false, PrefValueKind::
Default);
return;
}
if (!BrowserTabsRemoteAutostart()) {
gFissionAutostart =
false;
if (gBrowserTabsRemoteStatus == kE10sForceDisabled) {
gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByE10sEnv;
}
else {
gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByE10sOther;
}
}
else if (EnvHasValue(
"MOZ_FORCE_ENABLE_FISSION")) {
gFissionAutostart =
true;
gFissionDecisionStatus = nsIXULRuntime::eFissionEnabledByEnv;
}
else if (EnvHasValue(
"MOZ_FORCE_DISABLE_FISSION")) {
gFissionAutostart =
false;
gFissionDecisionStatus = nsIXULRuntime::eFissionDisabledByEnv;
}
else {
// NOTE: This will take into account changes to the default due to
// `InitializeFissionExperimentStatus`.
gFissionAutostart = Preferences::GetBool(kPrefFissionAutostart,
false);
if (Preferences::HasUserValue(kPrefFissionAutostart)) {
gFissionDecisionStatus = gFissionAutostart
? nsIXULRuntime::eFissionEnabledByUserPref
: nsIXULRuntime::eFissionDisabledByUserPref;
}
else {
gFissionDecisionStatus = gFissionAutostart
? nsIXULRuntime::eFissionEnabledByDefault
: nsIXULRuntime::eFissionDisabledByDefault;
}
}
// Content processes cannot run the same logic as we're running in the parent
// process, as the current value of various preferences may have changed
// between launches. Instead, the content process will read the default branch
// of the locked `fission.autostart.session` preference to determine the value
// determined by this method.
Preferences::Unlock(kPrefFissionAutostartSession);
Preferences::ClearUser(kPrefFissionAutostartSession);
Preferences::SetBool(kPrefFissionAutostartSession, gFissionAutostart,
PrefValueKind::
Default);
Preferences::Lock(kPrefFissionAutostartSession);
}
namespace mozilla {
bool FissionAutostart() {
EnsureFissionAutostartInitialized();
return gFissionAutostart;
}
}
// namespace mozilla
// End Fission Infrastructure =========================================
namespace mozilla {
bool SessionHistoryInParent() {
return FissionAutostart() ||
!StaticPrefs::
fission_disableSessionHistoryInParent_AtStartup_DoNotUseDirectly();
}
bool SessionStorePlatformCollection() {
return SessionHistoryInParent() &&
!StaticPrefs::
browser_sessionstore_disable_platform_collection_AtStartup_DoNotUseDirectly();
}
bool BFCacheInParent() {
return SessionHistoryInParent() &&
StaticPrefs::fission_bfcacheInParent_DoNotUseDirectly();
}
}
// namespace mozilla
/**
* The nsXULAppInfo object implements nsIFactory so that it can be its own
* singleton.
*/
class nsXULAppInfo :
public nsIXULAppInfo,
#ifdef XP_WIN
public nsIWinAppHelper,
#endif
public nsICrashReporter,
public nsIFinishDumpingCallback,
public nsIXULRuntime
{
public:
constexpr nsXULAppInfo() =
default;
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIPLATFORMINFO
NS_DECL_NSIXULAPPINFO
NS_DECL_NSIXULRUNTIME
NS_DECL_NSICRASHREPORTER
NS_DECL_NSIFINISHDUMPINGCALLBACK
#ifdef XP_WIN
NS_DECL_NSIWINAPPHELPER
#endif
};
NS_INTERFACE_MAP_BEGIN(nsXULAppInfo)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULRuntime)
NS_INTERFACE_MAP_ENTRY(nsIXULRuntime)
#ifdef XP_WIN
NS_INTERFACE_MAP_ENTRY(nsIWinAppHelper)
#endif
NS_INTERFACE_MAP_ENTRY(nsICrashReporter)
NS_INTERFACE_MAP_ENTRY(nsIFinishDumpingCallback)
NS_INTERFACE_MAP_ENTRY(nsIPlatformInfo)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIXULAppInfo,
gAppData || XRE_IsContentProcess())
NS_INTERFACE_MAP_END
NS_IMETHODIMP_(MozExternalRefCountType)
nsXULAppInfo::AddRef() {
return 1; }
NS_IMETHODIMP_(MozExternalRefCountType)
nsXULAppInfo::Release() {
return 1; }
NS_IMETHODIMP
nsXULAppInfo::GetVendor(nsACString& aResult) {
if (XRE_IsContentProcess()) {
ContentChild* cc = ContentChild::GetSingleton();
aResult = cc->GetAppInfo().vendor;
return NS_OK;
}
aResult.Assign(gAppData->vendor);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetName(nsACString& aResult) {
if (XRE_IsContentProcess()) {
ContentChild* cc = ContentChild::GetSingleton();
aResult = cc->GetAppInfo().name;
return NS_OK;
}
#ifdef MOZ_WIDGET_ANDROID
nsCString name = java::GeckoAppShell::GetAppName()->ToCString();
aResult.Assign(std::move(name));
#else
aResult.Assign(gAppData->name);
#endif
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetID(nsACString& aResult) {
if (XRE_IsContentProcess()) {
ContentChild* cc = ContentChild::GetSingleton();
aResult = cc->GetAppInfo().ID;
return NS_OK;
}
aResult.Assign(gAppData->ID);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetVersion(nsACString& aResult) {
if (XRE_IsContentProcess()) {
ContentChild* cc = ContentChild::GetSingleton();
aResult = cc->GetAppInfo().version;
return NS_OK;
}
aResult.Assign(gAppData->version);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetPlatformVersion(nsACString& aResult) {
aResult.Assign(gToolkitVersion);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetAppBuildID(nsACString& aResult) {
if (XRE_IsContentProcess()) {
ContentChild* cc = ContentChild::GetSingleton();
aResult = cc->GetAppInfo().buildID;
return NS_OK;
}
aResult.Assign(gAppData->buildID);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetPlatformBuildID(nsACString& aResult) {
aResult.Assign(gToolkitBuildID);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetUAName(nsACString& aResult) {
if (XRE_IsContentProcess()) {
ContentChild* cc = ContentChild::GetSingleton();
aResult = cc->GetAppInfo().UAName;
return NS_OK;
}
aResult.Assign(gAppData->UAName);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetSourceURL(nsACString& aResult) {
if (XRE_IsContentProcess()) {
ContentChild* cc = ContentChild::GetSingleton();
aResult = cc->GetAppInfo().sourceURL;
return NS_OK;
}
aResult.Assign(gAppData->sourceURL);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetUpdateURL(nsACString& aResult) {
if (XRE_IsContentProcess()) {
ContentChild* cc = ContentChild::GetSingleton();
aResult = cc->GetAppInfo().updateURL;
return NS_OK;
}
aResult.Assign(gAppData->updateURL);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetLogConsoleErrors(
bool* aResult) {
*aResult = gLogConsoleErrors;
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::SetLogConsoleErrors(
bool aValue) {
gLogConsoleErrors = aValue;
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetInSafeMode(
bool* aResult) {
*aResult = gSafeMode;
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetOS(nsACString& aResult) {
aResult.AssignLiteral(OS_TARGET);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetXPCOMABI(nsACString& aResult) {
#ifdef TARGET_XPCOM_ABI
aResult.AssignLiteral(TARGET_XPCOM_ABI);
return NS_OK;
#else
return NS_ERROR_NOT_AVAILABLE;
#endif
}
NS_IMETHODIMP
nsXULAppInfo::GetWidgetToolkit(nsACString& aResult) {
aResult.AssignLiteral(MOZ_WIDGET_TOOLKIT);
return NS_OK;
}
// Ensure that the GeckoProcessType enum, defined in xpcom/build/nsXULAppAPI.h,
// is synchronized with the const unsigned longs defined in
// xpcom/system/nsIXULRuntime.idl.
#define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
process_bin_type, procinfo_typename, \
webidl_typename, allcaps_name) \
static_assert(nsIXULRuntime::PROCESS_TYPE_
##allcaps_name == \
static_cast<
int>(GeckoProcessType_
##enum_name), \
"GeckoProcessType in nsXULAppAPI.h not synchronized with " \
"nsIXULRuntime.idl");
#include "mozilla/GeckoProcessTypes.h"
#undef GECKO_PROCESS_TYPE
// .. and ensure that that is all of them:
static_assert(GeckoProcessType_Utility + 1 == GeckoProcessType_End,
"Did not find the final GeckoProcessType");
NS_IMETHODIMP
nsXULAppInfo::GetProcessType(uint32_t* aResult) {
NS_ENSURE_ARG_POINTER(aResult);
*aResult = XRE_GetProcessType();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetProcessID(uint32_t* aResult) {
#ifdef XP_WIN
*aResult = GetCurrentProcessId();
#else
*aResult = getpid();
#endif
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetUniqueProcessID(uint64_t* aResult) {
if (XRE_IsContentProcess()) {
ContentChild* cc = ContentChild::GetSingleton();
*aResult = cc->GetID();
}
else {
*aResult = 0;
}
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetRemoteType(nsACString& aRemoteType) {
if (XRE_IsContentProcess()) {
aRemoteType = ContentChild::GetSingleton()->GetRemoteType();
}
else {
aRemoteType = NOT_REMOTE_TYPE;
}
return NS_OK;
}
MOZ_CONSTINIT
static nsCString gLastAppVersion;
MOZ_CONSTINIT
static nsCString gLastAppBuildID;
NS_IMETHODIMP
nsXULAppInfo::GetLastAppVersion(nsACString& aResult) {
if (XRE_IsContentProcess()) {
return NS_ERROR_NOT_AVAILABLE;
}
if (!gLastAppVersion.IsVoid() && gLastAppVersion.IsEmpty()) {
NS_WARNING(
"Attempt to retrieve lastAppVersion before it has been set.");
return NS_ERROR_NOT_AVAILABLE;
}
aResult.Assign(gLastAppVersion);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetLastAppBuildID(nsACString& aResult) {
if (XRE_IsContentProcess()) {
return NS_ERROR_NOT_AVAILABLE;
}
if (!gLastAppBuildID.IsVoid() && gLastAppBuildID.IsEmpty()) {
NS_WARNING(
"Attempt to retrieve lastAppBuildID before it has been set.");
return NS_ERROR_NOT_AVAILABLE;
}
aResult.Assign(gLastAppBuildID);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetFissionAutostart(
bool* aResult) {
*aResult = FissionAutostart();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetWin32kExperimentStatus(ExperimentStatus* aResult) {
if (!XRE_IsParentProcess()) {
return NS_ERROR_NOT_AVAILABLE;
}
EnsureWin32kInitialized();
*aResult = gWin32kExperimentStatus;
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetWin32kLiveStatusTestingOnly(
nsIXULRuntime::ContentWin32kLockdownState* aResult) {
if (!XRE_IsParentProcess()) {
return NS_ERROR_NOT_AVAILABLE;
}
EnsureWin32kInitialized();
*aResult = GetLiveWin32kLockdownState();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetWin32kSessionStatus(
nsIXULRuntime::ContentWin32kLockdownState* aResult) {
if (!XRE_IsParentProcess()) {
return NS_ERROR_NOT_AVAILABLE;
}
EnsureWin32kInitialized();
*aResult = gWin32kStatus;
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetFissionDecisionStatus(FissionDecisionStatus* aResult) {
if (!XRE_IsParentProcess()) {
return NS_ERROR_NOT_AVAILABLE;
}
EnsureFissionAutostartInitialized();
MOZ_ASSERT(gFissionDecisionStatus != eFissionStatusUnknown);
*aResult = gFissionDecisionStatus;
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetFissionDecisionStatusString(nsACString& aResult) {
if (!XRE_IsParentProcess()) {
return NS_ERROR_NOT_AVAILABLE;
}
EnsureFissionAutostartInitialized();
switch (gFissionDecisionStatus) {
case eFissionDisabledByE10sEnv:
aResult =
"disabledByE10sEnv";
break;
case eFissionEnabledByEnv:
aResult =
"enabledByEnv";
break;
case eFissionDisabledByEnv:
aResult =
"disabledByEnv";
break;
case eFissionEnabledByDefault:
aResult =
"enabledByDefault";
break;
case eFissionDisabledByDefault:
aResult =
"disabledByDefault";
break;
case eFissionEnabledByUserPref:
aResult =
"enabledByUserPref";
break;
case eFissionDisabledByUserPref:
aResult =
"disabledByUserPref";
break;
case eFissionDisabledByE10sOther:
aResult =
"disabledByE10sOther";
break;
default:
MOZ_ASSERT_UNREACHABLE(
"Unexpected enum value");
}
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetSessionHistoryInParent(
bool* aResult) {
*aResult = SessionHistoryInParent();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetSessionStorePlatformCollection(
bool* aResult) {
*aResult = SessionStorePlatformCollection();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetBrowserTabsRemoteAutostart(
bool* aResult) {
*aResult = BrowserTabsRemoteAutostart();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetMaxWebProcessCount(uint32_t* aResult) {
*aResult = mozilla::GetMaxWebProcessCount();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetAccessibilityEnabled(
bool* aResult) {
#ifdef ACCESSIBILITY
*aResult = GetAccService() != nullptr;
#else
*aResult =
false;
#endif
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetAccessibilityInstantiator(nsAString& aInstantiator) {
#if defined(ACCESSIBILITY) &&
defined(XP_WIN)
if (!GetAccService()) {
aInstantiator.Truncate();
return NS_OK;
}
nsAutoString ipClientInfo;
a11y::Compatibility::GetHumanReadableConsumersStr(ipClientInfo);
aInstantiator.Append(ipClientInfo);
aInstantiator.AppendLiteral(
"|");
nsCOMPtr<nsIFile> oopClientExe;
if (a11y::GetInstantiator(getter_AddRefs(oopClientExe))) {
nsAutoString oopClientInfo;
if (NS_SUCCEEDED(oopClientExe->GetPath(oopClientInfo))) {
aInstantiator.Append(oopClientInfo);
}
}
#else
aInstantiator.Truncate();
#endif
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetIs64Bit(
bool* aResult) {
#ifdef HAVE_64BIT_BUILD
*aResult =
true;
#else
*aResult =
false;
#endif
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetIsTextRecognitionSupported(
bool* aResult) {
*aResult = widget::TextRecognition::IsSupported();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::InvalidateCachesOnRestart() {
nsCOMPtr<nsIFile> file;
nsresult rv =
NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP, getter_AddRefs(file));
if (NS_FAILED(rv))
return rv;
if (!file)
return NS_ERROR_NOT_AVAILABLE;
file->AppendNative(FILE_COMPATIBILITY_INFO);
nsINIParser parser;
rv = parser.Init(file);
if (NS_FAILED(rv)) {
// This fails if compatibility.ini is not there, so we'll
// flush the caches on the next restart anyways.
return NS_OK;
}
nsAutoCString buf;
rv = parser.GetString(
"Compatibility",
"InvalidateCaches", buf);
if (NS_FAILED(rv)) {
PRFileDesc* fd;
rv = file->OpenNSPRFileDesc(PR_RDWR | PR_APPEND, 0600, &fd);
if (NS_FAILED(rv)) {
NS_ERROR(
"could not create output stream");
return NS_ERROR_NOT_AVAILABLE;
}
static const char kInvalidationHeader[] =
NS_LINEBREAK
"InvalidateCaches=1" NS_LINEBREAK;
PR_Write(fd, kInvalidationHeader,
sizeof(kInvalidationHeader) - 1);
PR_Close(fd);
}
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetReplacedLockTime(PRTime* aReplacedLockTime) {
if (!gProfileLock)
return NS_ERROR_NOT_AVAILABLE;
gProfileLock->GetReplacedLockTime(aReplacedLockTime);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetDefaultUpdateChannel(nsACString& aResult) {
aResult.AssignLiteral(MOZ_STRINGIFY(MOZ_UPDATE_CHANNEL));
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetDistributionID(nsACString& aResult) {
aResult.AssignLiteral(MOZ_DISTRIBUTION_ID);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetWindowsDLLBlocklistStatus(
bool* aResult) {
#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;
}
NS_IMETHODIMP
nsXULAppInfo::GetChromeColorSchemeIsDark(
bool* aResult) {
PreferenceSheet::EnsureInitialized();
*aResult = PreferenceSheet::ColorSchemeForChrome() == ColorScheme::Dark;
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetContentThemeDerivedColorSchemeIsDark(
bool* aResult) {
*aResult =
PreferenceSheet::ThemeDerivedColorSchemeForContent() == ColorScheme::Dark;
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetPrefersReducedMotion(
bool* aResult) {
*aResult =
LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedMotion, 0) == 1;
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetDrawInTitlebar(
bool* aResult) {
*aResult = LookAndFeel::DrawInTitlebar();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetDesktopEnvironment(nsACString& aDesktopEnvironment) {
#ifdef MOZ_WIDGET_GTK
aDesktopEnvironment.Assign(GetDesktopEnvironmentIdentifier());
#endif
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetIsWayland(
bool* aResult) {
#ifdef MOZ_WIDGET_GTK
*aResult = GdkIsWaylandDisplay();
#else
*aResult =
false;
#endif
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetProcessStartupShortcut(nsAString& aShortcut) {
#if defined(XP_WIN)
if (XRE_IsParentProcess()) {
aShortcut.Assign(gProcessStartupShortcut);
return NS_OK;
}
#endif
return NS_ERROR_NOT_AVAILABLE;
}
#if defined(XP_WIN) &&
defined(MOZ_LAUNCHER_PROCESS)
// Forward declaration
void SetupLauncherProcessPref();
static Maybe<LauncherRegistryInfo::EnabledState> gLauncherProcessState;
#endif // defined(XP_WIN) && defined(MOZ_LAUNCHER_PROCESS)
NS_IMETHODIMP
nsXULAppInfo::GetLauncherProcessState(uint32_t* aResult) {
#if defined(XP_WIN) &&
defined(MOZ_LAUNCHER_PROCESS)
SetupLauncherProcessPref();
if (!gLauncherProcessState) {
return NS_ERROR_UNEXPECTED;
}
*aResult =
static_cast<uint32_t>(gLauncherProcessState.value());
return NS_OK;
#else
return NS_ERROR_NOT_AVAILABLE;
#endif
}
#ifdef XP_WIN
NS_IMETHODIMP
nsXULAppInfo::GetUserCanElevate(
bool* aUserCanElevate) {
HANDLE rawToken;
if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &rawToken)) {
*aUserCanElevate =
false;
return NS_OK;
}
nsAutoHandle token(rawToken);
LauncherResult<TOKEN_ELEVATION_TYPE> elevationType = GetElevationType(token);
if (elevationType.isErr()) {
*aUserCanElevate =
false;
return NS_OK;
}
// The possible values returned for elevationType and their meanings are:
// TokenElevationTypeDefault: The token does not have a linked token
// (e.g. UAC disabled or a standard user, so they can't be elevated)
// TokenElevationTypeFull: The token is linked to an elevated token
// (e.g. UAC is enabled and the user is already elevated so they can't
// be elevated again)
// TokenElevationTypeLimited: The token is linked to a limited token
// (e.g. UAC is enabled and the user is not elevated, so they can be
// elevated)
*aUserCanElevate = (elevationType.inspect() == TokenElevationTypeLimited);
return NS_OK;
}
#endif
NS_IMETHODIMP
nsXULAppInfo::GetCrashReporterEnabled(
bool* aEnabled) {
*aEnabled = CrashReporter::GetEnabled();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::SetEnabled(
bool aEnabled) {
if (aEnabled) {
if (CrashReporter::GetEnabled()) {
// no point in erroring for double-enabling
return NS_OK;
}
nsCOMPtr<nsIFile> greBinDir;
NS_GetSpecialDirectory(NS_GRE_BIN_DIR, getter_AddRefs(greBinDir));
if (!greBinDir) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIFile> xreBinDirectory = greBinDir;
if (!xreBinDirectory) {
return NS_ERROR_FAILURE;
}
return CrashReporter::SetExceptionHandler(xreBinDirectory,
true);
}
if (!CrashReporter::GetEnabled()) {
// no point in erroring for double-disabling
return NS_OK;
}
return CrashReporter::UnsetExceptionHandler();
}
NS_IMETHODIMP
nsXULAppInfo::GetServerURL(nsIURL** aServerURL) {
NS_ENSURE_ARG_POINTER(aServerURL);
if (!CrashReporter::GetEnabled())
return NS_ERROR_NOT_INITIALIZED;
nsAutoCString data;
if (!CrashReporter::GetServerURL(data)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), data);
if (!uri)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIURL> url;
url = do_QueryInterface(uri);
NS_ADDREF(*aServerURL = url);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::SetServerURL(nsIURL* aServerURL) {
// Only allow https or http URLs
if (!aServerURL->SchemeIs(
"http") && !aServerURL->SchemeIs(
"https")) {
return NS_ERROR_INVALID_ARG;
}
nsAutoCString spec;
nsresult rv = aServerURL->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
return CrashReporter::SetServerURL(spec);
}
NS_IMETHODIMP
nsXULAppInfo::GetMinidumpPath(nsIFile** aMinidumpPath) {
if (!CrashReporter::GetEnabled()) {
return NS_ERROR_NOT_INITIALIZED;
}
nsAutoString path;
if (!CrashReporter::GetMinidumpPath(path)) {
return NS_ERROR_FAILURE;
}
return NS_NewLocalFile(path, aMinidumpPath);
}
NS_IMETHODIMP
nsXULAppInfo::SetMinidumpPath(nsIFile* aMinidumpPath) {
nsAutoString path;
nsresult rv = aMinidumpPath->GetPath(path);
NS_ENSURE_SUCCESS(rv, rv);
return CrashReporter::SetMinidumpPath(path);
}
NS_IMETHODIMP
nsXULAppInfo::GetMinidumpForID(
const nsAString& aId, nsIFile** aMinidump) {
if (!CrashReporter::GetMinidumpForID(aId, aMinidump)) {
return NS_ERROR_FILE_NOT_FOUND;
}
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::GetExtraFileForID(
const nsAString& aId, nsIFile** aExtraFile) {
if (!CrashReporter::GetExtraFileForID(aId, aExtraFile)) {
return NS_ERROR_FILE_NOT_FOUND;
}
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::AnnotateCrashReport(
const nsACString& key,
JS::Handle<JS::Value> data, JSContext* cx) {
auto annotation = CrashReporter::AnnotationFromString(key);
NS_ENSURE_TRUE(annotation.isSome(), NS_ERROR_INVALID_ARG);
switch (data.type()) {
case JS::ValueType::Int32:
CrashReporter::RecordAnnotationU32(*annotation, data.toInt32());
break;
case JS::ValueType::Boolean:
CrashReporter::RecordAnnotationBool(*annotation, data.toBoolean());
break;
case JS::ValueType::String: {
JSString* value = data.toString();
size_t length = (JS_GetStringLength(value) * 3) + 1;
nsCString buffer;
auto res = JS_EncodeStringToUTF8BufferPartial(
cx, value, buffer.GetMutableData(length));
if (!res) {
return NS_ERROR_OUT_OF_MEMORY;
}
size_t written;
std::tie(std::ignore, written) = *res;
buffer.SetLength(written);
CrashReporter::RecordAnnotationNSCString(*annotation, buffer);
}
break;
default:
return NS_ERROR_INVALID_ARG;
}
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::RemoveCrashReportAnnotation(
const nsACString& key) {
auto annotation = CrashReporter::AnnotationFromString(key);
NS_ENSURE_TRUE(annotation.isSome(), NS_ERROR_INVALID_ARG);
CrashReporter::UnrecordAnnotation(*annotation);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::IsAnnotationAllowedForPing(
const nsACString& aValue,
bool* aIsAllowed) {
auto annotation = CrashReporter::AnnotationFromString(aValue);
NS_ENSURE_TRUE(annotation.isSome(), NS_ERROR_INVALID_ARG);
*aIsAllowed = CrashReporter::IsAnnotationAllowedForPing(*annotation);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::AppendAppNotesToCrashReport(
const nsACString& data) {
return CrashReporter::AppendAppNotesToCrashReport(data);
}
NS_IMETHODIMP
nsXULAppInfo::RegisterAppMemory(uint64_t pointer, uint64_t len) {
return CrashReporter::RegisterAppMemory((
void*)pointer, len);
}
NS_IMETHODIMP
nsXULAppInfo::WriteMinidumpForException(
void* aExceptionInfo) {
#ifdef XP_WIN
return CrashReporter::WriteMinidumpForException(
static_cast<EXCEPTION_POINTERS*>(aExceptionInfo));
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
NS_IMETHODIMP
nsXULAppInfo::AppendObjCExceptionInfoToAppNotes(
void* aException) {
#ifdef XP_MACOSX
return CrashReporter::AppendObjCExceptionInfoToAppNotes(aException);
#else
return NS_ERROR_NOT_IMPLEMENTED;
#endif
}
NS_IMETHODIMP
nsXULAppInfo::GetSubmitReports(
bool* aEnabled) {
return CrashReporter::GetSubmitReports(aEnabled);
}
NS_IMETHODIMP
nsXULAppInfo::SetSubmitReports(
bool aEnabled) {
return CrashReporter::SetSubmitReports(aEnabled);
}
NS_IMETHODIMP
nsXULAppInfo::UpdateCrashEventsDir() {
CrashReporter::UpdateCrashEventsDir();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::SaveMemoryReport() {
if (!CrashReporter::GetEnabled()) {
return NS_ERROR_NOT_INITIALIZED;
}
nsCOMPtr<nsIFile> file;
nsresult rv = CrashReporter::GetDefaultMemoryReportFile(getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsString path;
file->GetPath(path);
nsCOMPtr<nsIMemoryInfoDumper> dumper =
do_GetService(
"@mozilla.org/memory-info-dumper;1");
if (NS_WARN_IF(!dumper)) {
return NS_ERROR_UNEXPECTED;
}
rv = dumper->DumpMemoryReportsToNamedFile(
path,
this, file,
true /* anonymize */, false /* minimizeMemoryUsage */);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
// This method is from nsIFInishDumpingCallback.
NS_IMETHODIMP
nsXULAppInfo::Callback(nsISupports* aData) {
nsCOMPtr<nsIFile> file = do_QueryInterface(aData);
MOZ_ASSERT(file);
CrashReporter::SetMemoryReportFile(file);
return NS_OK;
}
static const nsXULAppInfo kAppInfo;
namespace mozilla {
nsresult AppInfoConstructor(REFNSIID aIID,
void** aResult) {
return const_cast<nsXULAppInfo*>(&kAppInfo)->QueryInterface(aIID, aResult);
}
}
// namespace mozilla
bool gLogConsoleErrors =
false;
#define NS_ENSURE_TRUE_LOG(x, ret) \
PR_BEGIN_MACRO \
if (MOZ_UNLIKELY(!(x))) { \
NS_WARNING(
"NS_ENSURE_TRUE(" #x ") failed"); \
gLogConsoleErrors =
true; \
return ret; \
} \
PR_END_MACRO
#define NS_ENSURE_SUCCESS_LOG(res, ret) \
NS_ENSURE_TRUE_LOG(NS_SUCCEEDED(res), ret)
/**
* Because we're starting/stopping XPCOM several times in different scenarios,
* this class is a stack-based critter that makes sure that XPCOM is shut down
* during early returns.
*/
class ScopedXPCOMStartup {
public:
ScopedXPCOMStartup() : mServiceManager(nullptr) {}
~ScopedXPCOMStartup();
nsresult Initialize(
bool aInitJSContext =
true);
nsresult SetWindowCreator(nsINativeAppSupport* native);
private:
nsIServiceManager* mServiceManager;
static nsINativeAppSupport* gNativeAppSupport;
friend already_AddRefed<nsINativeAppSupport> NS_GetNativeAppSupport();
};
ScopedXPCOMStartup::~ScopedXPCOMStartup() {
NS_IF_RELEASE(gNativeAppSupport);
if (mServiceManager) {
#ifdef XP_MACOSX
// On OS X, we need a pool to catch cocoa objects that are autoreleased
// during teardown.
mozilla::MacAutoreleasePool pool;
#endif
nsCOMPtr<nsIAppStartup> appStartup(components::AppStartup::Service());
if (appStartup) appStartup->DestroyHiddenWindow();
gDirServiceProvider->DoShutdown();
PROFILER_MARKER_UNTYPED(
"Shutdown early", OTHER);
WriteConsoleLog();
NS_ShutdownXPCOM(mServiceManager);
mServiceManager = nullptr;
}
}
nsresult ScopedXPCOMStartup::Initialize(
bool aInitJSContext) {
NS_ASSERTION(gDirServiceProvider,
"Should not get here!");
nsresult rv;
rv = NS_InitXPCOM(&mServiceManager, gDirServiceProvider->GetAppDir(),
gDirServiceProvider, aInitJSContext);
if (NS_FAILED(rv)) {
NS_ERROR(
"Couldn't start xpcom!");
mServiceManager = nullptr;
}
else {
#ifdef DEBUG
nsCOMPtr<nsIComponentRegistrar> reg = do_QueryInterface(mServiceManager);
NS_ASSERTION(reg,
"Service Manager doesn't QI to Registrar.");
#endif
}
return rv;
}
/**
* This is a little factory class that serves as a singleton-service-factory
* for the nativeappsupport object.
*/
class nsSingletonFactory final :
public nsIFactory {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIFACTORY
explicit nsSingletonFactory(nsISupports* aSingleton);
private:
~nsSingletonFactory() =
default;
nsCOMPtr<nsISupports> mSingleton;
};
nsSingletonFactory::nsSingletonFactory(nsISupports* aSingleton)
: mSingleton(aSingleton) {
NS_ASSERTION(mSingleton,
"Singleton was null!");
}
NS_IMPL_ISUPPORTS(nsSingletonFactory, nsIFactory)
NS_IMETHODIMP
nsSingletonFactory::CreateInstance(
const nsIID& aIID,
void** aResult) {
return mSingleton->QueryInterface(aIID, aResult);
}
/**
* Set our windowcreator on the WindowWatcher service.
*/
nsresult ScopedXPCOMStartup::SetWindowCreator(nsINativeAppSupport* native) {
nsresult rv;
NS_IF_ADDREF(gNativeAppSupport = native);
nsCOMPtr<nsIWindowCreator> creator(components::AppStartup::Service());
if (!creator)
return NS_ERROR_UNEXPECTED;
nsCOMPtr<nsIWindowWatcher> wwatch(
do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv));
NS_ENSURE_SUCCESS(rv, rv);
return wwatch->SetWindowCreator(creator);
}
/* static */ already_AddRefed<nsINativeAppSupport> NS_GetNativeAppSupport() {
if (!ScopedXPCOMStartup::gNativeAppSupport) {
return nullptr;
}
return do_AddRef(ScopedXPCOMStartup::gNativeAppSupport);
}
#ifdef MOZ_HAS_REMOTE
/* static */ already_AddRefed<nsIRemoteService> GetRemoteService() {
AssertIsOnMainThread();
if (!gRemoteService) {
gRemoteService =
new nsRemoteService();
}
nsCOMPtr<nsIRemoteService> remoteService = gRemoteService.get();
return remoteService.forget();
}
#endif
nsINativeAppSupport* ScopedXPCOMStartup::gNativeAppSupport;
static void DumpArbitraryHelp() {
nsresult rv;
ScopedLogging log;
{
ScopedXPCOMStartup xpcom;
xpcom.Initialize();
nsCOMPtr<nsICommandLineRunner> cmdline(
new nsCommandLine());
nsCString text;
rv = cmdline->GetHelpText(text);
if (NS_SUCCEEDED(rv)) printf(
"%s", text.get());
}
}
// English text needs to go into a dtd file.
// But when this is called we have no components etc. These strings must either
// be here, or in a native resource file.
static void DumpHelp() {
printf(
"Usage: %s [ options ... ] [URL]\n"
" where options include:\n\n",
gArgv[0]);
#ifdef MOZ_X11
printf(
"X11 options\n"
" --display=DISPLAY X display to use\n"
" --sync Make X calls synchronous\n");
#endif
#ifdef XP_UNIX
printf(
" --g-fatal-warnings Make all warnings fatal\n"
"\n%s options\n",
(
const char*)gAppData->name);
#endif
printf(
" -h or --help Print this message.\n"
" -v or --version Print %s version.\n"
" --full-version Print %s version, build and platform build ids.\n"
" -P Start with .\n"
" --profile Start with profile at .\n"
" --migration Start with migration wizard.\n"
" --ProfileManager Start with ProfileManager.\n"
" --origin-to-force-quic-on \n"
" Force to use QUIC for the specified origin.\n"
#ifdef MOZ_HAS_REMOTE
" --new-instance Open new instance, not a new window in running "
"instance.\n"
#endif
" --safe-mode Disables extensions and themes for this session.\n"
#ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
" --allow-downgrade Allows downgrading a profile.\n"
#endif
" --MOZ_LOG= Treated as MOZ_LOG= environment "
"variable,\n"
" overrides it.\n"
" --MOZ_LOG_FILE= Treated as MOZ_LOG_FILE= environment "
"variable,\n"
" overrides it. If MOZ_LOG_FILE is not specified as "
"an\n"
" argument or as an environment variable, logging "
"will be\n"
" written to stdout.\n",
(
const char*)gAppData->name, (
const char*)gAppData->name);
#if defined(XP_WIN)
printf(
" --console Start %s with a debugging console.\n",
(
const char*)gAppData->name);
#endif
#if defined(XP_WIN) ||
defined(MOZ_WIDGET_GTK) ||
defined(XP_MACOSX)
printf(
" --headless Run without a GUI.\n");
#endif
#if defined(MOZ_ENABLE_DBUS)
printf(
" --dbus-service Run as DBus service for "
"org.freedesktop.Application and\n"
" set a launcher (usually /usr/bin/appname "
"script) for it.\n");
#endif
// this works, but only after the components have registered. so if you drop
// in a new command line handler, --help won't not until the second run. out
// of the bug, because we ship a component.reg file, it works correctly.
DumpArbitraryHelp();
}
static inline void DumpVersion() {
if (gAppData->vendor && *gAppData->vendor) {
printf(
"%s ", (
const char*)gAppData->vendor);
}
printf(
"%s ", (
const char*)gAppData->name);
// Use the displayed version
// For example, for beta, we would display 42.0b2 instead of 42.0
printf(
"%s", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
if (gAppData->copyright && *gAppData->copyright) {
printf(
", %s", (
const char*)gAppData->copyright);
}
printf(
"\n");
}
static inline void DumpFullVersion() {
if (gAppData->vendor && *gAppData->vendor) {
printf(
"%s ", (
const char*)gAppData->vendor);
}
printf(
"%s ", (
const char*)gAppData->name);
// Use the displayed version
// For example, for beta, we would display 42.0b2 instead of 42.0
printf(
"%s ", MOZ_STRINGIFY(MOZ_APP_VERSION_DISPLAY));
printf(
"%s ", (
const char*)gAppData->buildID);
printf(
"%s ", (
const char*)PlatformBuildID());
if (gAppData->copyright && *gAppData->copyright) {
printf(
", %s", (
const char*)gAppData->copyright);
}
printf(
"\n");
}
void XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni) {
mozilla::Omnijar::Init(greOmni, appOmni);
}
nsresult XRE_GetBinaryPath(nsIFile** aResult) {
return mozilla::BinaryPath::GetFile(aResult);
}
#ifdef XP_WIN
# include
"nsWindowsRestart.cpp"
# include <shellapi.h>
typedef BOOL(WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
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
--> --------------------
--> maximum size reached
--> --------------------