1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsXULAppAPI.h"
7 #include "mozilla/CmdLineAndEnvUtils.h"
8 #include "mozilla/XREAppData.h"
9 #include "XREShellData.h"
10 #include "application.ini.h"
11 #include "mozilla/Bootstrap.h"
15 #elif defined(XP_UNIX)
16 # include <sys/resource.h>
27 # include "mozilla/PreXULSkeletonUI.h"
28 # include "freestanding/SharedSection.h"
29 # include "LauncherProcessWin.h"
30 # include "mozilla/WindowsDllBlocklist.h"
31 # include "mozilla/WindowsDpiInitialization.h"
33 # define XRE_WANT_ENVIRON
34 # define strcasecmp _stricmp
36 # include "mozilla/sandboxing/SandboxInitialization.h"
39 #include "BinaryPath.h"
41 #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
43 #include "mozilla/Sprintf.h"
44 #include "mozilla/StartupTimeline.h"
45 #include "BaseProfiler.h"
48 # include "FuzzerDefs.h"
51 #ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR
53 # include "mozilla/Unused.h"
55 static bool IsSSE2Available() {
56 // The rest of the app has been compiled to assume that SSE2 is present
57 // unconditionally, so we can't use the normal copy of SSE.cpp here.
58 // Since SSE.cpp caches the results and we need them only transiently,
59 // instead of #including SSE.cpp here, let's just inline the specific check
61 unsigned int level
= 1u;
62 unsigned int eax
, ebx
, ecx
, edx
;
63 unsigned int bits
= (1u << 26);
64 unsigned int max
= __get_cpuid_max(0, nullptr);
68 __cpuid_count(level
, 0, eax
, ebx
, ecx
, edx
);
69 return (edx
& bits
) == bits
;
72 static const char sSSE2Message
[] =
73 "This browser version requires a processor with the SSE2 instruction "
74 "set extension.\nYou may be able to obtain a version that does not "
75 "require SSE2 from your Linux distribution.\n";
77 __attribute__((constructor
)) static void SSE2Check() {
78 if (IsSSE2Available()) {
81 // Using write() in order to avoid jemalloc-based buffering. Ignoring return
82 // values, since there isn't much we could do on failure and there is no
83 // point in trying to recover from errors.
85 write(STDERR_FILENO
, sSSE2Message
, MOZ_ARRAY_LENGTH(sSSE2Message
) - 1));
86 // _exit() instead of exit() to avoid running the usual "at exit" code.
91 #if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID)
92 # define MOZ_BROWSER_CAN_BE_CONTENTPROC
93 # include "../../ipc/contentproc/plugin-container.cpp"
96 using namespace mozilla
;
99 # define kOSXResourcesFolder "Resources"
101 #define kDesktopFolder "browser"
103 static MOZ_FORMAT_PRINTF(1, 2) void Output(const char* fmt
, ...) {
108 vfprintf(stderr
, fmt
, ap
);
111 vsnprintf_s(msg
, _countof(msg
), _TRUNCATE
, fmt
, ap
);
113 wchar_t wide_msg
[2048];
114 MultiByteToWideChar(CP_UTF8
, 0, msg
, -1, wide_msg
, _countof(wide_msg
));
116 fwprintf_s(stderr
, wide_msg
);
118 // Linking user32 at load-time interferes with the DLL blocklist (bug 932100).
119 // This is a rare codepath, so we can load user32 at run-time instead.
120 HMODULE user32
= LoadLibraryW(L
"user32.dll");
122 decltype(MessageBoxW
)* messageBoxW
=
123 (decltype(MessageBoxW
)*)GetProcAddress(user32
, "MessageBoxW");
125 messageBoxW(nullptr, wide_msg
, L
"Firefox",
126 MB_OK
| MB_ICONERROR
| MB_SETFOREGROUND
);
137 * Return true if |arg| matches the given argument name.
139 static bool IsArg(const char* arg
, const char* s
) {
141 if (*++arg
== '-') ++arg
;
142 return !strcasecmp(arg
, s
);
146 if (*arg
== '/') return !strcasecmp(++arg
, s
);
152 Bootstrap::UniquePtr gBootstrap
;
154 static int do_main(int argc
, char* argv
[], char* envp
[]) {
155 // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
156 // Note that -app must be the *first* argument.
157 const char* appDataFile
= getenv("XUL_APP_FILE");
158 if ((!appDataFile
|| !*appDataFile
) && (argc
> 1 && IsArg(argv
[1], "app"))) {
160 Output("Incorrect number of arguments passed to -app");
163 appDataFile
= argv
[2];
165 char appEnv
[MAXPATHLEN
];
166 SprintfLiteral(appEnv
, "XUL_APP_FILE=%s", argv
[2]);
167 if (putenv(strdup(appEnv
))) {
168 Output("Couldn't set %s.\n", appEnv
);
174 } else if (argc
> 1 && IsArg(argv
[1], "xpcshell")) {
175 for (int i
= 1; i
< argc
; i
++) {
176 argv
[i
] = argv
[i
+ 1];
179 XREShellData shellData
;
180 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
181 shellData
.sandboxBrokerServices
=
182 sandboxing::GetInitializedBrokerServices();
186 shellData
.fuzzerDriver
= fuzzer::FuzzerDriver
;
189 return gBootstrap
->XRE_XPCShellMain(--argc
, argv
, envp
, &shellData
);
192 BootstrapConfig config
;
194 if (appDataFile
&& *appDataFile
) {
195 config
.appData
= nullptr;
196 config
.appDataPath
= appDataFile
;
198 // no -app flag so we use the compiled-in app data
199 config
.appData
= &sAppData
;
200 config
.appDataPath
= kDesktopFolder
;
203 #if defined(XP_WIN) && defined(MOZ_SANDBOX)
204 sandbox::BrokerServices
* brokerServices
=
205 sandboxing::GetInitializedBrokerServices();
206 sandboxing::PermissionsService
* permissionsService
=
207 sandboxing::GetPermissionsService();
208 if (!brokerServices
) {
209 Output("Couldn't initialize the broker services.\n");
212 config
.sandboxBrokerServices
= brokerServices
;
213 config
.sandboxPermissionsService
= permissionsService
;
217 if (getenv("FUZZER"))
218 gBootstrap
->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver
);
221 // Note: keep in sync with LauncherProcessWin.
222 const char* acceptableParams
[] = {"url", nullptr};
223 EnsureCommandlineSafe(argc
, argv
, acceptableParams
);
225 return gBootstrap
->XRE_main(argc
, argv
, config
);
228 static nsresult
InitXPCOMGlue(LibLoadingStrategy aLibLoadingStrategy
) {
233 UniqueFreePtr
<char> exePath
= BinaryPath::Get();
235 Output("Couldn't find the application directory.\n");
236 return NS_ERROR_FAILURE
;
239 auto bootstrapResult
=
240 mozilla::GetBootstrap(exePath
.get(), aLibLoadingStrategy
);
241 if (bootstrapResult
.isErr()) {
242 Output("Couldn't load XPCOM.\n");
243 return NS_ERROR_FAILURE
;
246 gBootstrap
= bootstrapResult
.unwrap();
248 // This will set this thread as the main thread.
249 gBootstrap
->NS_LogInit();
254 #ifdef HAS_DLL_BLOCKLIST
255 // NB: This must be extern, as this value is checked elsewhere
256 uint32_t gBlocklistInitFlags
= eDllBlocklistInitFlagDefault
;
259 int main(int argc
, char* argv
[], char* envp
[]) {
260 #if defined(MOZ_ENABLE_FORKSERVER)
261 if (strcmp(argv
[argc
- 1], "forkserver") == 0) {
262 nsresult rv
= InitXPCOMGlue(LibLoadingStrategy::NoReadAhead
);
267 // Run a fork server in this process, single thread. When it
268 // returns, it means the fork server have been stopped or a new
269 // content process is created.
271 // For the later case, XRE_ForkServer() will return false, running
272 // in a content process just forked from the fork server process.
273 // argc & argv will be updated with the values passing from the
274 // chrome process. With the new values, this function
275 // continues the reset of the code acting as a content process.
276 if (gBootstrap
->XRE_ForkServer(&argc
, &argv
)) {
277 // Return from the fork server in the fork server process.
278 // Stop the fork server.
279 gBootstrap
->NS_LogTerm();
282 // In a content process forked from the fork server.
283 // Start acting as a content process.
287 mozilla::TimeStamp start
= mozilla::TimeStamp::Now();
289 AUTO_BASE_PROFILER_INIT
;
290 AUTO_BASE_PROFILER_LABEL("nsBrowserApp main", OTHER
);
292 #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
293 // We are launching as a content process, delegate to the appropriate
295 if (argc
> 1 && IsArg(argv
[1], "contentproc")) {
296 # ifdef HAS_DLL_BLOCKLIST
297 DllBlocklist_Initialize(gBlocklistInitFlags
|
298 eDllBlocklistInitFlagIsChildProcess
);
301 // Ideally, we would be able to set our DPI awareness in
302 // firefox.exe.manifest Unfortunately, that would cause Win32k calls when
303 // user32.dll gets loaded, which would be incompatible with Win32k Lockdown
305 // MSDN says that it's allowed-but-not-recommended to initialize DPI
306 // programatically, as long as it's done before any HWNDs are created.
307 // Thus, we do it almost as soon as we possibly can
309 auto result
= mozilla::WindowsDpiInitialization();
310 (void)result
; // Ignore errors since some tools block DPI calls
313 # if defined(XP_WIN) && defined(MOZ_SANDBOX)
314 // We need to initialize the sandbox TargetServices before InitXPCOMGlue
315 // because we might need the sandbox broker to give access to some files.
316 if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) {
317 Output("Failed to initialize the sandbox target services.");
322 nsresult rv
= InitXPCOMGlue(LibLoadingStrategy::NoReadAhead
);
327 int result
= content_process_main(gBootstrap
.get(), argc
, argv
);
329 # if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
330 DllBlocklist_Shutdown();
333 // InitXPCOMGlue calls NS_LogInit, so we need to balance it here.
334 gBootstrap
->NS_LogTerm();
340 #ifdef HAS_DLL_BLOCKLIST
341 DllBlocklist_Initialize(gBlocklistInitFlags
);
344 // We will likely only ever support this as a command line argument on Windows
345 // and OSX, so we're ifdefing here just to not create any expectations.
346 #if defined(XP_WIN) || defined(XP_MACOSX)
347 if (argc
> 1 && IsArg(argv
[1], "silentmode")) {
348 ::putenv(const_cast<char*>("MOZ_APP_SILENT_START=1"));
354 // Ideally, we would be able to set our DPI awareness in firefox.exe.manifest
355 // Unfortunately, that would cause Win32k calls when user32.dll gets loaded,
356 // which would be incompatible with Win32k Lockdown
358 // MSDN says that it's allowed-but-not-recommended to initialize DPI
359 // programatically, as long as it's done before any HWNDs are created.
360 // Thus, we do it almost as soon as we possibly can
362 auto result
= mozilla::WindowsDpiInitialization();
363 (void)result
; // Ignore errors since some tools block DPI calls
366 // Once the browser process hits the main function, we no longer need
367 // a writable section handle because all dependent modules have been
369 mozilla::freestanding::gSharedSection
.ConvertToReadOnly();
370 ::RtlRunOnceInitialize(&mozilla::freestanding::gK32ExportsResolveOnce
);
372 mozilla::CreateAndStorePreXULSkeletonUI(GetModuleHandle(nullptr), argc
, argv
);
375 nsresult rv
= InitXPCOMGlue(LibLoadingStrategy::ReadAhead
);
380 gBootstrap
->XRE_StartupTimelineRecord(mozilla::StartupTimeline::START
, start
);
382 #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
383 gBootstrap
->XRE_EnableSameExecutableForContentProc();
386 int result
= do_main(argc
, argv
, envp
);
389 CleanupProcessRuntime();
392 gBootstrap
->NS_LogTerm();
394 #if defined(DEBUG) && defined(HAS_DLL_BLOCKLIST)
395 DllBlocklist_Shutdown();
399 // Allow writes again. While we would like to catch writes from static
400 // destructors to allow early exits to use _exit, we know that there is
401 // at least one such write that we don't control (see bug 826029). For
402 // now we enable writes again and early exits will have to use exit instead
404 gBootstrap
->XRE_StopLateWriteChecks();