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 https://mozilla.org/MPL/2.0/. */
7 #include "ErrorHandler.h"
11 #include "mozilla/ArrayUtils.h"
12 #include "mozilla/CmdLineAndEnvUtils.h"
13 #include "mozilla/DebugOnly.h"
14 #include "mozilla/JSONWriter.h"
15 #include "mozilla/UniquePtr.h"
16 #include "mozilla/Unused.h"
17 #include "mozilla/WinTokenUtils.h"
18 #include "mozilla/XREAppData.h"
19 #include "mozilla/glue/WindowsDllServices.h"
20 #include "mozilla/mscom/ProcessRuntime.h"
21 #include "nsWindowsHelpers.h"
23 #if defined(MOZ_LAUNCHER_PROCESS)
24 # include "mozilla/LauncherRegistryInfo.h"
25 #endif // defined(MOZ_LAUNCHER_PROCESS)
37 #if !defined(__MINGW32__)
41 #endif // !defined(__MINGW32__)
44 #if !defined(RRF_SUBKEY_WOW6464KEY)
45 # define RRF_SUBKEY_WOW6464KEY 0x00010000
46 #endif // !defined(RRF_SUBKEY_WOW6464KEY)
48 #define QUOTE_ME2(x) #x
49 #define QUOTE_ME(x) QUOTE_ME2(x)
51 #define TELEMETRY_BASE_URL L"https://incoming.telemetry.mozilla.org/submit"
52 #define TELEMETRY_NAMESPACE L"/firefox-launcher-process"
53 #define TELEMETRY_LAUNCHER_PING_DOCTYPE L"/launcher-process-failure"
54 #define TELEMETRY_LAUNCHER_PING_VERSION L"/1"
56 static const wchar_t kUrl
[] = TELEMETRY_BASE_URL TELEMETRY_NAMESPACE
57 TELEMETRY_LAUNCHER_PING_DOCTYPE TELEMETRY_LAUNCHER_PING_VERSION L
"/";
58 static const uint32_t kGuidCharLenWithNul
= 39;
59 static const uint32_t kGuidCharLenNoBracesNoNul
= 36;
60 static const mozilla::StaticXREAppData
* gStaticAppData
;
62 // Ordinarily, errors are only reported to the Windows Event Log when they are
63 // not reported upstream via telemetry (usually due either to telemetry being
64 // disabled or to network failure).
66 // If `--log-launcher-error` is given at the command line, launcher errors will
67 // always be reported to the Windows Event Log, regardless of whether or not
68 // they're sent upstream.
69 static bool gForceEventLog
= false;
73 constexpr wchar_t kEventSourceName
[] = L
"" MOZ_APP_DISPLAYNAME
" Launcher";
75 struct EventSourceDeleter
{
76 using pointer
= HANDLE
;
78 void operator()(pointer aEvtSrc
) { ::DeregisterEventSource(aEvtSrc
); }
81 using EventLog
= mozilla::UniquePtr
<HANDLE
, EventSourceDeleter
>;
83 struct SerializedEventData
{
89 } // anonymous namespace
91 static void PostErrorToLog(const mozilla::LauncherError
& aError
) {
92 // This is very bare-bones; just enough to spit out an HRESULT to the
93 // Application event log.
94 EventLog
log(::RegisterEventSourceW(nullptr, kEventSourceName
));
100 size_t fileLen
= strlen(aError
.mFile
);
101 size_t dataLen
= sizeof(HRESULT
) + sizeof(uint32_t) + fileLen
;
102 auto evtDataBuf
= mozilla::MakeUnique
<char[]>(dataLen
);
103 SerializedEventData
& evtData
=
104 *reinterpret_cast<SerializedEventData
*>(evtDataBuf
.get());
105 evtData
.mHr
= aError
.mError
.AsHResult();
106 evtData
.mLine
= aError
.mLine
;
107 // Since this is binary data, we're not concerning ourselves with null
109 memcpy(evtData
.mFile
, aError
.mFile
, fileLen
);
111 ::ReportEventW(log
.get(), EVENTLOG_ERROR_TYPE
, 0, aError
.mError
.AsHResult(),
112 nullptr, 0, dataLen
, nullptr, evtDataBuf
.get());
115 #if defined(MOZ_TELEMETRY_REPORTING)
119 // This JSONWriteFunc writes directly to a temp file. By creating this file
120 // with the FILE_ATTRIBUTE_TEMPORARY attribute, we hint to the OS that this
121 // file is short-lived. The OS will try to avoid flushing it to disk if at
123 class TempFileWriter final
: public mozilla::JSONWriteFunc
{
125 TempFileWriter() : mFailed(false), mSuccessfulHandoff(false) {
126 wchar_t name
[MAX_PATH
+ 1] = {};
127 if (_wtmpnam_s(name
)) {
132 mTempFileName
= name
;
134 mTempFile
.own(::CreateFileW(name
, GENERIC_WRITE
, FILE_SHARE_READ
, nullptr,
135 CREATE_NEW
, FILE_ATTRIBUTE_TEMPORARY
, nullptr));
136 if (mTempFile
.get() == INVALID_HANDLE_VALUE
) {
142 if (mSuccessfulHandoff
) {
143 // It is no longer our responsibility to delete the temp file if we have
144 // successfully handed it off to pingsender.
149 ::DeleteFileW(mTempFileName
.c_str());
152 explicit operator bool() const { return !mFailed
; }
154 void Write(const mozilla::Span
<const char>& aStr
) final
{
159 DWORD bytesWritten
= 0;
160 if (!::WriteFile(mTempFile
, aStr
.data(), aStr
.size(), &bytesWritten
,
162 bytesWritten
!= aStr
.size()) {
167 const std::wstring
& GetFileName() const { return mTempFileName
; }
169 void SetSuccessfulHandoff() { mSuccessfulHandoff
= true; }
173 bool mSuccessfulHandoff
;
174 std::wstring mTempFileName
;
175 nsAutoHandle mTempFile
;
178 using SigMap
= mozilla::Vector
<std::wstring
, 0, InfallibleAllocPolicy
>;
180 } // anonymous namespace
182 // This is the guideline for maximum string length for telemetry intake
183 static const size_t kMaxStrLen
= 80;
185 static mozilla::UniquePtr
<char[]> WideToUTF8(const wchar_t* aStr
,
186 const size_t aStrLenExclNul
) {
187 // Yes, this might not handle surrogate pairs correctly. Let's just let
188 // WideCharToMultiByte fail in that unlikely case.
189 size_t cvtLen
= std::min(aStrLenExclNul
, kMaxStrLen
);
191 int numConv
= ::WideCharToMultiByte(CP_UTF8
, 0, aStr
, cvtLen
, nullptr, 0,
197 // Include room for the null terminator by adding one
198 auto buf
= mozilla::MakeUnique
<char[]>(numConv
+ 1);
200 numConv
= ::WideCharToMultiByte(CP_UTF8
, 0, aStr
, cvtLen
, buf
.get(), numConv
,
206 // Add null termination. numConv does not include the terminator, so we don't
207 // subtract 1 when indexing into buf.
213 static mozilla::UniquePtr
<char[]> WideToUTF8(const wchar_t* aStr
) {
214 return WideToUTF8(aStr
, wcslen(aStr
));
217 static mozilla::UniquePtr
<char[]> WideToUTF8(const std::wstring
& aStr
) {
218 return WideToUTF8(aStr
.c_str(), aStr
.length());
221 // MinGW does not support the Windows Security Center APIs.
222 # if !defined(__MINGW32__)
224 static mozilla::UniquePtr
<char[]> WideToUTF8(const _bstr_t
& aStr
) {
225 return WideToUTF8(static_cast<const wchar_t*>(aStr
), aStr
.length());
231 WSC_SECURITY_PROVIDER mProviderType
;
235 } // anonymous namespace
237 static bool EnumWSCProductList(RefPtr
<IWSCProductList
>& aProdList
,
238 mozilla::JSONWriter
& aJson
) {
240 HRESULT hr
= aProdList
->get_Count(&count
);
245 // Unlikely, but put a bound on the max length of the output array for the
246 // purposes of telemetry intake.
247 count
= std::min(count
, 1000L);
249 // Record the name(s) of each active registered product in this category
250 for (LONG index
= 0; index
< count
; ++index
) {
251 RefPtr
<IWscProduct
> product
;
252 hr
= aProdList
->get_Item(index
, getter_AddRefs(product
));
257 WSC_SECURITY_PRODUCT_STATE state
;
258 hr
= product
->get_ProductState(&state
);
263 // We only care about products that are active
264 if (state
== WSC_SECURITY_PRODUCT_STATE_OFF
||
265 state
== WSC_SECURITY_PRODUCT_STATE_SNOOZED
||
266 state
== WSC_SECURITY_PRODUCT_STATE_EXPIRED
) {
271 hr
= product
->get_ProductName(bName
.GetAddress());
276 auto buf
= WideToUTF8(bName
);
281 aJson
.StringElement(mozilla::MakeStringSpan(buf
.get()));
287 static const ProviderKey gProvKeys
[] = {
288 {WSC_SECURITY_PROVIDER_ANTIVIRUS
, "av"},
289 {WSC_SECURITY_PROVIDER_ANTISPYWARE
, "antispyware"},
290 {WSC_SECURITY_PROVIDER_FIREWALL
, "firewall"}};
292 static bool AddWscInfo(mozilla::JSONWriter
& aJson
) {
293 // We need COM for this. Using ProcessRuntime so that process-global COM
294 // configuration is done correctly
295 mozilla::mscom::ProcessRuntime
mscom(
296 mozilla::mscom::ProcessRuntime::ProcessCategory::Launcher
);
298 // We haven't written anything yet, so we can return true here and continue
303 aJson
.StartObjectProperty("security");
305 const CLSID clsid
= __uuidof(WSCProductList
);
306 const IID iid
= __uuidof(IWSCProductList
);
308 for (uint32_t index
= 0; index
< std::size(gProvKeys
); ++index
) {
309 // NB: A separate instance of IWSCProductList is needed for each distinct
310 // security provider type; MSDN says that we cannot reuse the same object
311 // and call Initialize() to pave over the previous data.
312 RefPtr
<IWSCProductList
> prodList
;
313 HRESULT hr
= ::CoCreateInstance(clsid
, nullptr, CLSCTX_INPROC_SERVER
, iid
,
314 getter_AddRefs(prodList
));
319 hr
= prodList
->Initialize(gProvKeys
[index
].mProviderType
);
324 aJson
.StartArrayProperty(mozilla::MakeStringSpan(gProvKeys
[index
].mKey
));
326 if (!EnumWSCProductList(prodList
, aJson
)) {
337 # endif // !defined(__MINGW32__)
339 // Max array length for telemetry intake.
340 static const size_t kMaxArrayLen
= 1000;
342 static bool AddModuleInfo(const nsAutoHandle
& aSnapshot
,
343 mozilla::JSONWriter
& aJson
) {
344 if (aSnapshot
.get() == INVALID_HANDLE_VALUE
) {
345 // We haven't written anything yet, so we can return true here and continue
351 size_t moduleCount
= 0;
353 MODULEENTRY32W module
= {sizeof(module
)};
354 if (!::Module32FirstW(aSnapshot
, &module
)) {
355 // We haven't written anything yet, so we can return true here and continue
360 mozilla::glue::BasicDllServices dllServices
;
362 aJson
.StartObjectProperty("modules");
364 // For each module, add its version number (or empty string if not present),
365 // followed by an optional index into the signatures array
369 wchar_t leaf
[_MAX_FNAME
] = {};
370 if (::_wsplitpath_s(module
.szExePath
, nullptr, 0, nullptr, 0, leaf
,
371 std::size(leaf
), nullptr, 0)) {
375 if (_wcslwr_s(leaf
, std::size(leaf
))) {
379 auto leafUtf8
= WideToUTF8(leaf
);
384 aJson
.StartArrayProperty(mozilla::MakeStringSpan(leafUtf8
.get()));
387 DWORD verInfoSize
= ::GetFileVersionInfoSizeW(module
.szExePath
, nullptr);
389 auto verInfoBuf
= mozilla::MakeUnique
<BYTE
[]>(verInfoSize
);
391 if (::GetFileVersionInfoW(module
.szExePath
, 0, verInfoSize
,
393 VS_FIXEDFILEINFO
* fixedInfo
= nullptr;
394 UINT fixedInfoLen
= 0;
396 if (::VerQueryValueW(verInfoBuf
.get(), L
"\\",
397 reinterpret_cast<LPVOID
*>(&fixedInfo
),
399 std::ostringstream oss
;
400 oss
<< HIWORD(fixedInfo
->dwFileVersionMS
) << '.'
401 << LOWORD(fixedInfo
->dwFileVersionMS
) << '.'
402 << HIWORD(fixedInfo
->dwFileVersionLS
) << '.'
403 << LOWORD(fixedInfo
->dwFileVersionLS
);
409 aJson
.StringElement(version
);
411 mozilla::Maybe
<ptrdiff_t> sigIndex
;
412 auto signedBy
= dllServices
.GetBinaryOrgName(module
.szExePath
);
414 std::wstring
strSignedBy(signedBy
.get());
415 auto entry
= std::find(signatures
.begin(), signatures
.end(), strSignedBy
);
416 if (entry
== signatures
.end()) {
417 mozilla::Unused
<< signatures
.append(std::move(strSignedBy
));
418 entry
= &signatures
.back();
421 sigIndex
= mozilla::Some(entry
- signatures
.begin());
425 aJson
.IntElement(sigIndex
.value());
429 } while (moduleCount
< kMaxArrayLen
&& ::Module32NextW(aSnapshot
, &module
));
433 aJson
.StartArrayProperty("signatures");
435 // Serialize each entry in the signatures array
436 for (auto&& itr
: signatures
) {
437 auto sigUtf8
= WideToUTF8(itr
);
442 aJson
.StringElement(mozilla::MakeStringSpan(sigUtf8
.get()));
452 struct PingThreadContext
{
453 explicit PingThreadContext(const mozilla::LauncherError
& aError
,
454 const char* aProcessType
)
455 : mLauncherError(aError
),
456 mModulesSnapshot(::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE
, 0)),
457 mProcessType(aProcessType
? aProcessType
: "") {}
458 mozilla::LauncherError mLauncherError
;
459 nsAutoHandle mModulesSnapshot
;
460 std::string mProcessType
;
463 } // anonymous namespace
465 static bool PrepPing(const PingThreadContext
& aContext
, const std::wstring
& aId
,
466 mozilla::JSONWriter
& aJson
) {
468 const mozilla::JSONWriter::CollectionStyle style
=
469 mozilla::JSONWriter::MultiLineStyle
;
471 const mozilla::JSONWriter::CollectionStyle style
=
472 mozilla::JSONWriter::SingleLineStyle
;
473 # endif // defined(DEBUG)
477 aJson
.StringProperty("type", "launcher-process-failure");
478 aJson
.IntProperty("version", 1);
480 auto idUtf8
= WideToUTF8(aId
);
482 aJson
.StringProperty("id", mozilla::MakeStringSpan(idUtf8
.get()));
488 if (!gmtime_s(&gmTm
, &now
)) {
489 char isoTimeBuf
[32] = {};
490 if (strftime(isoTimeBuf
, std::size(isoTimeBuf
), "%FT%T.000Z", &gmTm
)) {
491 aJson
.StringProperty("creationDate", isoTimeBuf
);
495 aJson
.StringProperty("update_channel", QUOTE_ME(MOZ_UPDATE_CHANNEL
));
497 if (gStaticAppData
) {
498 aJson
.StringProperty("build_id",
499 mozilla::MakeStringSpan(gStaticAppData
->buildID
));
500 aJson
.StringProperty("build_version",
501 mozilla::MakeStringSpan(gStaticAppData
->version
));
504 OSVERSIONINFOEXW osv
= {sizeof(osv
)};
505 if (::GetVersionExW(reinterpret_cast<OSVERSIONINFOW
*>(&osv
))) {
506 std::ostringstream oss
;
507 oss
<< osv
.dwMajorVersion
<< "." << osv
.dwMinorVersion
<< "."
508 << osv
.dwBuildNumber
;
510 if (osv
.dwMajorVersion
== 10 && osv
.dwMinorVersion
== 0) {
511 // Get the "Update Build Revision" (UBR) value
513 DWORD ubrValueLen
= sizeof(ubrValue
);
515 ::RegGetValueW(HKEY_LOCAL_MACHINE
,
516 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
517 L
"UBR", RRF_RT_DWORD
| RRF_SUBKEY_WOW6464KEY
, nullptr,
518 &ubrValue
, &ubrValueLen
);
519 if (ubrOk
== ERROR_SUCCESS
) {
520 oss
<< "." << ubrValue
;
525 aJson
.StringProperty("os_version", oss
.str());
528 bool isServer
= osv
.wProductType
== VER_NT_DOMAIN_CONTROLLER
||
529 osv
.wProductType
== VER_NT_SERVER
;
530 aJson
.BoolProperty("server_os", isServer
);
533 WCHAR localeName
[LOCALE_NAME_MAX_LENGTH
] = {};
535 ::GetUserDefaultLocaleName(localeName
, std::size(localeName
));
537 auto localeNameUtf8
= WideToUTF8(localeName
, localeNameLen
- 1);
538 if (localeNameUtf8
) {
539 aJson
.StringProperty("os_locale",
540 mozilla::MakeStringSpan(localeNameUtf8
.get()));
545 ::GetNativeSystemInfo(&sysInfo
);
546 aJson
.IntProperty("cpu_arch", sysInfo
.wProcessorArchitecture
);
547 aJson
.IntProperty("num_logical_cpus", sysInfo
.dwNumberOfProcessors
);
549 mozilla::LauncherResult
<bool> isAdminWithoutUac
=
550 mozilla::IsAdminWithoutUac();
551 if (isAdminWithoutUac
.isOk()) {
552 aJson
.BoolProperty("is_admin_without_uac", isAdminWithoutUac
.unwrap());
555 if (!aContext
.mProcessType
.empty()) {
556 aJson
.StringProperty("process_type", aContext
.mProcessType
);
559 MEMORYSTATUSEX memStatus
= {sizeof(memStatus
)};
560 if (::GlobalMemoryStatusEx(&memStatus
)) {
561 aJson
.StartObjectProperty("memory");
562 aJson
.IntProperty("total_phys", memStatus
.ullTotalPhys
);
563 aJson
.IntProperty("avail_phys", memStatus
.ullAvailPhys
);
564 aJson
.IntProperty("avail_page_file", memStatus
.ullAvailPageFile
);
565 aJson
.IntProperty("avail_virt", memStatus
.ullAvailVirtual
);
569 aJson
.StringProperty("xpcom_abi", TARGET_XPCOM_ABI
);
571 aJson
.StartObjectProperty("launcher_error", style
);
573 std::string
srcFileLeaf(aContext
.mLauncherError
.mFile
);
574 // Obtain the leaf name of the file for privacy reasons
575 // (In case this is somebody's local build)
576 auto pos
= srcFileLeaf
.find_last_of("/\\");
577 if (pos
!= std::string::npos
) {
578 srcFileLeaf
= srcFileLeaf
.substr(pos
+ 1);
581 aJson
.StringProperty("source_file", srcFileLeaf
);
583 aJson
.IntProperty("source_line", aContext
.mLauncherError
.mLine
);
584 aJson
.IntProperty("hresult", aContext
.mLauncherError
.mError
.AsHResult());
586 # if defined(NIGHTLY_BUILD)
587 if (aContext
.mLauncherError
.mDetourError
.isSome()) {
588 static const char* kHexMap
= "0123456789abcdef";
589 char hexStr
[sizeof(mozilla::DetourError::mOrigBytes
) * 2 + 1];
591 for (uint8_t byte
: aContext
.mLauncherError
.mDetourError
->mOrigBytes
) {
592 hexStr
[cnt
++] = kHexMap
[(byte
>> 4) & 0x0f];
593 hexStr
[cnt
++] = kHexMap
[byte
& 0x0f];
596 aJson
.StringProperty("detour_orig_bytes", hexStr
);
598 # endif // defined(NIGHTLY_BUILD)
602 # if !defined(__MINGW32__)
603 if (!AddWscInfo(aJson
)) {
606 # endif // !defined(__MINGW32__)
608 if (!AddModuleInfo(aContext
.mModulesSnapshot
, aJson
)) {
617 static bool DoSendPing(const PingThreadContext
& aContext
) {
618 TempFileWriter tempFile
;
619 mozilla::JSONWriter
json(tempFile
);
622 if (::UuidCreate(&uuid
) != RPC_S_OK
) {
626 wchar_t guidBuf
[kGuidCharLenWithNul
] = {};
627 if (::StringFromGUID2(uuid
, guidBuf
, kGuidCharLenWithNul
) !=
628 kGuidCharLenWithNul
) {
632 // Strip the curly braces off of the guid
633 std::wstring
guidNoBraces(guidBuf
+ 1, kGuidCharLenNoBracesNoNul
);
635 // Populate json with the ping information
636 if (!PrepPing(aContext
, guidNoBraces
, json
)) {
640 // Obtain the name of the temp file that we have written
641 const std::wstring
& fileName
= tempFile
.GetFileName();
643 // Using the path to our executable binary, construct the path to
645 mozilla::UniquePtr
<wchar_t[]> exePath(mozilla::GetFullBinaryPath());
647 wchar_t drive
[_MAX_DRIVE
] = {};
648 wchar_t dir
[_MAX_DIR
] = {};
649 if (_wsplitpath_s(exePath
.get(), drive
, std::size(drive
), dir
, std::size(dir
),
650 nullptr, 0, nullptr, 0)) {
654 wchar_t pingSenderPath
[MAX_PATH
+ 1] = {};
655 if (_wmakepath_s(pingSenderPath
, std::size(pingSenderPath
), drive
, dir
,
656 L
"pingsender", L
"exe")) {
660 // Construct the telemetry URL
661 wchar_t urlBuf
[std::size(kUrl
) + kGuidCharLenNoBracesNoNul
] = {};
662 if (wcscpy_s(urlBuf
, kUrl
)) {
666 if (wcscat_s(urlBuf
, guidNoBraces
.c_str())) {
670 // Now build the command line arguments to pingsender
671 wchar_t* pingSenderArgv
[] = {pingSenderPath
, urlBuf
,
672 const_cast<wchar_t*>(fileName
.c_str())};
674 mozilla::UniquePtr
<wchar_t[]> pingSenderCmdLine(
675 mozilla::MakeCommandLine(std::size(pingSenderArgv
), pingSenderArgv
));
677 // Now start pingsender to handle the rest
678 PROCESS_INFORMATION pi
;
680 STARTUPINFOW si
= {sizeof(si
)};
681 si
.dwFlags
= STARTF_USESHOWWINDOW
;
682 si
.wShowWindow
= SW_HIDE
;
684 if (!::CreateProcessW(pingSenderPath
, pingSenderCmdLine
.get(), nullptr,
685 nullptr, FALSE
, 0, nullptr, nullptr, &si
, &pi
)) {
689 tempFile
.SetSuccessfulHandoff();
691 nsAutoHandle
proc(pi
.hProcess
);
692 nsAutoHandle
thread(pi
.hThread
);
697 static unsigned __stdcall
SendPingThread(void* aContext
) {
698 mozilla::UniquePtr
<PingThreadContext
> context(
699 reinterpret_cast<PingThreadContext
*>(aContext
));
701 if (!DoSendPing(*context
) || gForceEventLog
) {
702 PostErrorToLog(context
->mLauncherError
);
708 #endif // defined(MOZ_TELEMETRY_REPORTING)
710 static bool SendPing(const mozilla::LauncherError
& aError
,
711 const char* aProcessType
) {
712 #if defined(MOZ_TELEMETRY_REPORTING)
713 # if defined(MOZ_LAUNCHER_PROCESS)
714 mozilla::LauncherRegistryInfo regInfo
;
715 mozilla::LauncherResult
<bool> telemetryEnabled
= regInfo
.IsTelemetryEnabled();
716 if (telemetryEnabled
.isErr() || !telemetryEnabled
.unwrap()) {
717 // Do not send anything if telemetry has been opted out
720 # endif // defined(MOZ_LAUNCHER_PROCESS)
722 // We send this ping when the launcher process fails. After we start the
723 // SendPingThread, this thread falls back from running as the launcher process
724 // to running as the browser main thread. Once this happens, it will be unsafe
725 // to set up PoisonIOInterposer (since we have already spun up a background
727 mozilla::SaveToEnv("MOZ_DISABLE_POISON_IO_INTERPOSER=1");
729 // Capture aError and our module list into context for processing on another
731 auto thdParam
= mozilla::MakeUnique
<PingThreadContext
>(aError
, aProcessType
);
733 // The ping does a lot of file I/O. Since we want this thread to continue
734 // executing browser startup, we should gather that information on a
735 // background thread.
736 uintptr_t thdHandle
=
737 _beginthreadex(nullptr, 0, &SendPingThread
, thdParam
.get(),
738 STACK_SIZE_PARAM_IS_A_RESERVATION
, nullptr);
743 // We have handed off thdParam to the background thread
744 mozilla::Unused
<< thdParam
.release();
746 ::CloseHandle(reinterpret_cast<HANDLE
>(thdHandle
));
755 void HandleLauncherError(const LauncherError
& aError
,
756 const char* aProcessType
) {
757 #if defined(MOZ_LAUNCHER_PROCESS)
758 LauncherRegistryInfo regInfo
;
759 Unused
<< regInfo
.DisableDueToFailure();
760 #endif // defined(MOZ_LAUNCHER_PROCESS)
762 if (!SendPing(aError
, aProcessType
)) {
763 // couldn't (or shouldn't) send telemetry; fall back to event log
764 PostErrorToLog(aError
);
768 void SetLauncherErrorAppData(const StaticXREAppData
& aAppData
) {
769 gStaticAppData
= &aAppData
;
772 void SetLauncherErrorForceEventLog() { gForceEventLog
= true; }
774 } // namespace mozilla