1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 import { AddonManager } from "resource://gre/modules/AddonManager.sys.mjs";
6 import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
8 import { FeatureGate } from "resource://featuregates/FeatureGate.sys.mjs";
12 ChromeUtils.defineESModuleGetters(lazy, {
13 PlacesDBUtils: "resource://gre/modules/PlacesDBUtils.sys.mjs",
16 // We use a list of prefs for display to make sure we only show prefs that
17 // are useful for support and won't compromise the user's privacy. Note that
18 // entries are *prefixes*: for example, "accessibility." applies to all prefs
19 // under the "accessibility.*" branch.
20 const PREFS_FOR_DISPLAY = [
24 "browser.contentblocking.category",
26 "browser.download.always_ask_before_handling_new_types",
27 "browser.download.enable_spam_prevention",
28 "browser.download.folderList",
29 "browser.download.improvements_to_download_panel",
30 "browser.download.lastDir.savePerSite",
31 "browser.download.manager.addToRecentDocs",
32 "browser.download.manager.resumeOnWakeDelay",
33 "browser.download.open_pdf_attachments_inline",
34 "browser.download.preferred.",
35 "browser.download.skipConfirmLaunchExecutable",
36 "browser.download.start_downloads_in_tmp_dir",
37 "browser.download.useDownloadDir",
39 "browser.history_expire_",
40 "browser.link.open_newwindow",
42 "browser.privatebrowsing.",
43 "browser.search.context.loadInBackground",
45 "browser.search.openintab",
46 "browser.search.param",
47 "browser.search.region",
48 "browser.search.searchEnginesURL",
49 "browser.search.suggest.enabled",
50 "browser.search.update",
51 "browser.sessionstore.",
52 "browser.startup.homepage",
53 "browser.startup.page",
59 "extensions.checkCompatibility",
60 "extensions.eventPages.enabled",
61 "extensions.formautofill.",
62 "extensions.lastAppVersion",
63 "extensions.manifestV3.enabled",
64 "extensions.quarantinedDomains.enabled",
65 "extensions.InstallTrigger.enabled",
66 "extensions.InstallTriggerImpl.enabled",
73 "identity.fxaccounts.enabled",
80 "layout.display-list.",
85 "permissions.default.image",
91 "services.sync.declinedEngines",
92 "services.sync.lastPing",
93 "services.sync.lastSync",
94 "services.sync.numClients",
95 "services.sync.engine.",
97 "storage.vacuum.last.",
99 "toolkit.startup.recent_crashes",
101 "ui.osk.detect_physical_keyboard",
102 "ui.osk.require_tablet_mode",
103 "ui.osk.debug.keyboardDisplayReason",
106 "widget.use-xdg-desktop-portal",
107 "widget.use-xdg-desktop-portal.file-picker",
108 "widget.use-xdg-desktop-portal.mime-handler",
109 "widget.gtk.overlay-scrollbars.enabled",
113 // The list of prefs we don't display, unlike the list of prefs for display,
114 // is a list of regular expressions.
115 const PREF_REGEXES_NOT_TO_DISPLAY = [
116 /^browser[.]fixup[.]domainwhitelist[.]/,
117 /^dom[.]push[.]userAgentID/,
118 /^media[.]webrtc[.]debug[.]aec_log_dir/,
119 /^media[.]webrtc[.]debug[.]log_file/,
120 /^print[.].*print_to_filename$/,
121 /^network[.]proxy[.]/,
124 // Table of getters for various preference types.
125 const PREFS_GETTERS = {};
127 PREFS_GETTERS[Ci.nsIPrefBranch.PREF_STRING] = (prefs, name) =>
128 prefs.getStringPref(name);
129 PREFS_GETTERS[Ci.nsIPrefBranch.PREF_INT] = (prefs, name) =>
130 prefs.getIntPref(name);
131 PREFS_GETTERS[Ci.nsIPrefBranch.PREF_BOOL] = (prefs, name) =>
132 prefs.getBoolPref(name);
134 // List of unimportant locked prefs (won't be shown on the troubleshooting
136 const PREFS_UNIMPORTANT_LOCKED = [
137 "dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled",
138 "privacy.restrict3rdpartystorage.url_decorations",
141 function getPref(name) {
142 let type = Services.prefs.getPrefType(name);
143 if (!(type in PREFS_GETTERS)) {
144 throw new Error("Unknown preference type " + type + " for " + name);
146 return PREFS_GETTERS[type](Services.prefs, name);
149 // Return the preferences filtered by PREF_REGEXES_NOT_TO_DISPLAY and PREFS_FOR_DISPLAY
150 // and also by the custom 'filter'-ing function.
151 function getPrefList(filter, allowlist = PREFS_FOR_DISPLAY) {
152 return allowlist.reduce(function (prefs, branch) {
153 Services.prefs.getChildList(branch).forEach(function (name) {
156 !PREF_REGEXES_NOT_TO_DISPLAY.some(re => re.test(name))
158 prefs[name] = getPref(name);
165 export var Troubleshoot = {
167 * Captures a snapshot of data that may help troubleshooters troubleshoot
171 * A promise that is resolved with the snapshot data.
174 return new Promise(resolve => {
176 let numPending = Object.keys(dataProviders).length;
177 function providerDone(providerName, providerData) {
178 snapshot[providerName] = providerData;
179 if (--numPending == 0) {
180 // Ensure that done is always and truly called asynchronously.
181 Services.tm.dispatchToMainThread(() => resolve(snapshot));
184 for (let name in dataProviders) {
186 dataProviders[name](providerDone.bind(null, name));
188 let msg = "Troubleshoot data provider failed: " + name + "\n" + err;
190 providerDone(name, msg);
196 kMaxCrashAge: 3 * 24 * 60 * 60 * 1000, // 3 days
199 // Each data provider is a name => function mapping. When a snapshot is
200 // captured, each provider's function is called, and it's the function's job to
201 // generate the provider's data. The function is passed a "done" callback, and
202 // when done, it must pass its data to the callback. The resulting snapshot
203 // object will contain a name => data entry for each provider.
204 var dataProviders = {
205 application: async function application(done) {
207 name: Services.appinfo.name,
209 Services.sysinfo.getProperty("name") +
211 Services.sysinfo.getProperty("version") +
213 Services.sysinfo.getProperty("build"),
214 version: AppConstants.MOZ_APP_VERSION_DISPLAY,
215 buildID: Services.appinfo.appBuildID,
216 distributionID: Services.prefs
217 .getDefaultBranch("")
218 .getCharPref("distribution.id", ""),
219 userAgent: Cc["@mozilla.org/network/protocol;1?name=http"].getService(
220 Ci.nsIHttpProtocolHandler
222 safeMode: Services.appinfo.inSafeMode,
223 memorySizeBytes: Services.sysinfo.getProperty("memsize"),
224 diskAvailableBytes: Services.dirsvc.get("ProfD", Ci.nsIFile)
228 if (Services.sysinfo.getProperty("name") == "Windows_NT") {
229 if ((await Services.sysinfo.processInfo).isWindowsSMode) {
230 data.osVersion += " S";
234 if (AppConstants.MOZ_UPDATER) {
235 data.updateChannel = ChromeUtils.importESModule(
236 "resource://gre/modules/UpdateUtils.sys.mjs"
237 ).UpdateUtils.UpdateChannel;
240 // eslint-disable-next-line mozilla/use-default-preference-values
242 data.vendor = Services.prefs.getCharPref("app.support.vendor");
245 data.supportURL = Services.urlFormatter.formatURLPref(
246 "app.support.baseURL"
250 data.osTheme = Services.sysinfo.getProperty("osThemeInfo");
253 // MacOSX: Check for rosetta status, if it exists
254 data.rosetta = Services.sysinfo.getProperty("rosettaStatus");
257 data.numTotalWindows = 0;
258 data.numFissionWindows = 0;
259 data.numRemoteWindows = 0;
260 for (let { docShell } of Services.wm.getEnumerator("navigator:browser")) {
261 docShell.QueryInterface(Ci.nsILoadContext);
262 data.numTotalWindows++;
263 if (docShell.useRemoteSubframes) {
264 data.numFissionWindows++;
266 if (docShell.useRemoteTabs) {
267 data.numRemoteWindows++;
272 data.launcherProcessState = Services.appinfo.launcherProcessState;
275 data.fissionAutoStart = Services.appinfo.fissionAutostart;
276 data.fissionDecisionStatus = Services.appinfo.fissionDecisionStatusString;
278 data.remoteAutoStart = Services.appinfo.browserTabsRemoteAutostart;
280 if (Services.policies) {
281 data.policiesStatus = Services.policies.status;
284 const keyLocationServiceGoogle = Services.urlFormatter
285 .formatURL("%GOOGLE_LOCATION_SERVICE_API_KEY%")
287 data.keyLocationServiceGoogleFound =
288 keyLocationServiceGoogle != "no-google-location-service-api-key" &&
289 !!keyLocationServiceGoogle.length;
291 const keySafebrowsingGoogle = Services.urlFormatter
292 .formatURL("%GOOGLE_SAFEBROWSING_API_KEY%")
294 data.keySafebrowsingGoogleFound =
295 keySafebrowsingGoogle != "no-google-safebrowsing-api-key" &&
296 !!keySafebrowsingGoogle.length;
298 const keyMozilla = Services.urlFormatter
299 .formatURL("%MOZILLA_API_KEY%")
301 data.keyMozillaFound =
302 keyMozilla != "no-mozilla-api-key" && !!keyMozilla.length;
307 addons: async function addons(done) {
308 let addons = await AddonManager.getAddonsByTypes([
315 addons = addons.filter(e => !e.isSystem);
316 addons.sort(function (a, b) {
317 if (a.isActive != b.isActive) {
318 return b.isActive ? 1 : -1;
321 if (a.type != b.type) {
322 return a.type.localeCompare(b.type);
325 // In some unfortunate cases add-on names can be null.
326 let aname = a.name || "";
327 let bname = b.name || "";
328 let lc = aname.localeCompare(bname);
332 if (a.version != b.version) {
333 return a.version > b.version ? 1 : -1;
337 let props = ["name", "type", "version", "isActive", "id"];
339 addons.map(function (ext) {
340 return props.reduce(function (extData, prop) {
341 extData[prop] = ext[prop];
348 securitySoftware: function securitySoftware(done) {
352 "registeredAntiVirus",
353 "registeredAntiSpyware",
354 "registeredFirewall",
356 for (let key of keys) {
359 prop = Services.sysinfo.getProperty(key);
368 features: async function features(done) {
369 let features = await AddonManager.getAddonsByTypes(["extension"]);
370 features = features.filter(f => f.isSystem);
371 features.sort(function (a, b) {
372 // In some unfortunate cases addon names can be null.
373 let aname = a.name || null;
374 let bname = b.name || null;
375 let lc = aname.localeCompare(bname);
379 if (a.version != b.version) {
380 return a.version > b.version ? 1 : -1;
384 let props = ["name", "version", "id"];
386 features.map(function (f) {
387 return props.reduce(function (fData, prop) {
388 fData[prop] = f[prop];
395 processes: async function processes(done) {
396 let remoteTypes = {};
397 const processInfo = await ChromeUtils.requestProcInfo();
398 for (let i = 0; i < processInfo.children.length; i++) {
401 remoteType = processInfo.children[i].type;
402 // Workaround for bug 1790070, since requestProcInfo refers to the preallocated content
403 // process as "preallocated", and the localization string mapping expects "prealloc".
404 remoteType = remoteType === "preallocated" ? "prealloc" : remoteType;
407 // The parent process is also managed by the ppmm (because
408 // of non-remote tabs), but it doesn't have a remoteType.
413 if (remoteTypes[remoteType]) {
414 remoteTypes[remoteType]++;
416 remoteTypes[remoteType] = 1;
421 let winUtils = Services.wm.getMostRecentWindow("").windowUtils;
422 if (winUtils.gpuProcessPid != -1) {
427 if (Services.io.socketProcessLaunched) {
428 remoteTypes.socket = 1;
433 maxWebContentProcesses: Services.appinfo.maxWebProcessCount,
439 async experimentalFeatures(done) {
440 if (AppConstants.platform == "android") {
444 let gates = await FeatureGate.all();
450 Services.prefs.getBoolPref(gate.preference),
456 async environmentVariables(done) {
459 // Subprocess is not available in all builds
460 Subprocess = ChromeUtils.importESModule(
461 "resource://gre/modules/Subprocess.sys.mjs"
468 let environment = Subprocess.getEnvironment();
469 let filteredEnvironment = {};
470 // Limit the environment variables to those that we
471 // know may affect Firefox to reduce leaking PII.
472 let filteredEnvironmentKeys = ["xre_", "moz_", "gdk", "display"];
473 for (let key of Object.keys(environment)) {
474 if (filteredEnvironmentKeys.some(k => key.toLowerCase().startsWith(k))) {
475 filteredEnvironment[key] = environment[key];
478 done(filteredEnvironment);
481 modifiedPreferences: function modifiedPreferences(done) {
482 done(getPrefList(name => Services.prefs.prefHasUserValue(name)));
485 lockedPreferences: function lockedPreferences(done) {
489 !PREFS_UNIMPORTANT_LOCKED.includes(name) &&
490 Services.prefs.prefIsLocked(name)
495 places: async function places(done) {
496 const data = AppConstants.MOZ_PLACES
497 ? await lazy.PlacesDBUtils.getEntitiesStatsAndCounts()
502 printingPreferences: function printingPreferences(done) {
503 let filter = name => Services.prefs.prefHasUserValue(name);
504 let prefs = getPrefList(filter, ["print."]);
506 // print_printer is special and is the only pref that is outside of the
507 // "print." branch... Maybe we should change it to print.printer or
509 if (filter("print_printer")) {
510 prefs.print_printer = getPref("print_printer");
516 graphics: function graphics(done) {
517 function statusMsgForFeature(feature) {
518 // We return an object because in the try-newer-driver case we need to
519 // include the suggested version, which the consumer likely needs to plug
520 // into a format string from a localization file. Rather than returning
521 // a string in some cases and an object in others, return an object always.
522 let msg = { key: "" };
524 var status = gfxInfo.getFeatureStatus(feature);
527 case Ci.nsIGfxInfo.FEATURE_BLOCKED_DEVICE:
528 case Ci.nsIGfxInfo.FEATURE_DISCOURAGED:
529 msg = { key: "blocked-gfx-card" };
531 case Ci.nsIGfxInfo.FEATURE_BLOCKED_OS_VERSION:
532 msg = { key: "blocked-os-version" };
534 case Ci.nsIGfxInfo.FEATURE_BLOCKED_DRIVER_VERSION:
537 gfxInfo.getFeatureSuggestedDriverVersion(feature);
540 ? { key: "try-newer-driver", args: { driverVersion } }
541 : { key: "blocked-driver" };
543 case Ci.nsIGfxInfo.FEATURE_BLOCKED_MISMATCHED_VERSION:
544 msg = { key: "blocked-mismatched-version" };
553 // nsIGfxInfo may not be implemented on some platforms.
554 var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
557 data.desktopEnvironment = Services.appinfo.desktopEnvironment;
558 data.numTotalWindows = 0;
559 data.numAcceleratedWindows = 0;
561 let devicePixelRatios = [];
563 for (let win of Services.ww.getWindowEnumerator()) {
564 let winUtils = win.windowUtils;
566 // NOTE: windowless browser's windows should not be reported in the graphics troubleshoot report
568 winUtils.layerManagerType == "None" ||
569 !winUtils.layerManagerRemote
573 devicePixelRatios.push(win.devicePixelRatio);
575 data.numTotalWindows++;
576 data.windowLayerManagerType = winUtils.layerManagerType;
577 data.windowLayerManagerRemote = winUtils.layerManagerRemote;
581 if (data.windowLayerManagerType != "Basic") {
582 data.numAcceleratedWindows++;
585 data.graphicsDevicePixelRatios = devicePixelRatios;
587 // If we had no OMTC windows, report back Basic Layers.
588 if (!data.windowLayerManagerType) {
589 data.windowLayerManagerType = "Basic";
590 data.windowLayerManagerRemote = false;
593 if (!data.numAcceleratedWindows && gfxInfo) {
594 let win = AppConstants.platform == "win";
596 ? gfxInfo.FEATURE_DIRECT3D_9_LAYERS
597 : gfxInfo.FEATURE_OPENGL_LAYERS;
598 data.numAcceleratedWindowsMessage = statusMsgForFeature(feature);
602 // keys are the names of attributes on nsIGfxInfo, values become the names
603 // of the corresponding properties in our data object. A null value means
604 // no change. This is needed so that the names of properties in the data
605 // object are the same as the names of keys in aboutSupport.properties.
607 adapterDescription: null,
608 adapterVendorID: null,
609 adapterDeviceID: null,
610 adapterSubsysID: null,
612 adapterDriver: "adapterDrivers",
613 adapterDriverVendor: "driverVendor",
614 adapterDriverVersion: "driverVersion",
615 adapterDriverDate: "driverDate",
617 adapterDescription2: null,
618 adapterVendorID2: null,
619 adapterDeviceID2: null,
620 adapterSubsysID2: null,
622 adapterDriver2: "adapterDrivers2",
623 adapterDriverVendor2: "driverVendor2",
624 adapterDriverVersion2: "driverVersion2",
625 adapterDriverDate2: "driverDate2",
628 D2DEnabled: "direct2DEnabled",
629 DWriteEnabled: "directWriteEnabled",
630 DWriteVersion: "directWriteVersion",
631 cleartypeParameters: "clearTypeParameters",
632 TargetFrameRate: "targetFrameRate",
633 windowProtocol: null,
636 for (let prop in gfxInfoProps) {
638 data[gfxInfoProps[prop] || prop] = gfxInfo[prop];
642 if ("direct2DEnabled" in data && !data.direct2DEnabled) {
643 data.direct2DEnabledMessage = statusMsgForFeature(
644 Ci.nsIGfxInfo.FEATURE_DIRECT2D
649 let doc = new DOMParser().parseFromString("<html/>", "text/html");
651 function GetWebGLInfo(data, keyPrefix, contextType) {
652 data[keyPrefix + "Renderer"] = "-";
653 data[keyPrefix + "Version"] = "-";
654 data[keyPrefix + "DriverExtensions"] = "-";
655 data[keyPrefix + "Extensions"] = "-";
656 data[keyPrefix + "WSIInfo"] = "-";
660 let canvas = doc.createElement("canvas");
666 let creationError = null;
668 canvas.addEventListener(
669 "webglcontextcreationerror",
672 creationError = e.statusMessage;
678 gl = canvas.getContext(contextType);
680 if (!creationError) {
681 creationError = e.toString();
685 data[keyPrefix + "Renderer"] =
686 creationError || "(no creation error info)";
692 data[keyPrefix + "Extensions"] = gl.getSupportedExtensions().join(" ");
696 let ext = gl.getExtension("MOZ_debug");
697 // This extension is unconditionally available to chrome. No need to check.
698 let vendor = ext.getParameter(gl.VENDOR);
699 let renderer = ext.getParameter(gl.RENDERER);
701 data[keyPrefix + "Renderer"] = vendor + " -- " + renderer;
702 data[keyPrefix + "Version"] = ext.getParameter(gl.VERSION);
703 data[keyPrefix + "DriverExtensions"] = ext.getParameter(ext.EXTENSIONS);
704 data[keyPrefix + "WSIInfo"] = ext.getParameter(ext.WSI_INFO);
708 // Eagerly free resources.
709 let loseExt = gl.getExtension("WEBGL_lose_context");
711 loseExt.loseContext();
715 GetWebGLInfo(data, "webgl1", "webgl");
716 GetWebGLInfo(data, "webgl2", "webgl2");
719 let infoInfo = gfxInfo.getInfo();
721 data.info = infoInfo;
724 let failureIndices = {};
726 let failures = gfxInfo.getFailures(failureIndices);
727 if (failures.length) {
728 data.failures = failures;
729 if (failureIndices.value.length == failures.length) {
730 data.indices = failureIndices.value;
734 data.featureLog = gfxInfo.getFeatureLog();
735 data.crashGuards = gfxInfo.getActiveCrashGuards();
738 function getNavigator() {
739 for (let win of Services.ww.getWindowEnumerator()) {
740 let winUtils = win.windowUtils;
742 // NOTE: windowless browser's windows should not be reported in the graphics troubleshoot report
744 winUtils.layerManagerType == "None" ||
745 !winUtils.layerManagerRemote
749 const nav = win.navigator;
757 throw new Error("No window had window.navigator.");
760 const navigator = getNavigator();
762 async function GetWebgpuInfo(adapterOpts) {
764 if (!navigator.gpu) {
765 ret["navigator.gpu"] = null;
769 const requestAdapterkey = `navigator.gpu.requestAdapter(${JSON.stringify(
775 adapter = await navigator.gpu.requestAdapter(adapterOpts);
777 // If WebGPU isn't supported or is blocked somehow, include
778 // that in the report. Anything else is an error which should
779 // have consequences (test failures, etc).
780 if (DOMException.isInstance(e) && e.name == "NotSupportedError") {
781 return { [requestAdapterkey]: { not_supported: e.message } };
787 ret[requestAdapterkey] = null;
790 const desc = (ret[requestAdapterkey] = {});
792 desc.isFallbackAdapter = adapter.isFallbackAdapter;
794 const adapterInfo = await adapter.requestAdapterInfo();
795 // We can't directly enumerate properties of instances of `GPUAdapterInfo`s, so use the prototype instead.
796 const adapterInfoObj = {};
797 for (const k of Object.keys(Object.getPrototypeOf(adapterInfo)).sort()) {
798 adapterInfoObj[k] = adapterInfo[k];
800 desc[`requestAdapterInfo()`] = adapterInfoObj;
802 desc.features = Array.from(adapter.features).sort();
805 const keys = Object.keys(Object.getPrototypeOf(adapter.limits)).sort(); // limits not directly enumerable?
806 for (const k of keys) {
807 desc.limits[k] = adapter.limits[k];
813 // Webgpu info is going to need awaits.
815 data.webgpuDefaultAdapter = await GetWebgpuInfo({});
816 data.webgpuFallbackAdapter = await GetWebgpuInfo({
817 forceFallbackAdapter: true,
824 media: function media(done) {
825 function convertDevices(devices) {
830 for (let i = 0; i < devices.length; ++i) {
831 let device = devices.queryElementAt(i, Ci.nsIAudioDeviceInfo);
834 groupId: device.groupId,
835 vendor: device.vendor,
838 preferred: device.preferred,
839 supportedFormat: device.supportedFormat,
840 defaultFormat: device.defaultFormat,
841 maxChannels: device.maxChannels,
842 defaultRate: device.defaultRate,
843 maxRate: device.maxRate,
844 minRate: device.minRate,
845 maxLatency: device.maxLatency,
846 minLatency: device.minLatency,
853 let winUtils = Services.wm.getMostRecentWindow("").windowUtils;
854 data.currentAudioBackend = winUtils.currentAudioBackend;
855 data.currentMaxAudioChannels = winUtils.currentMaxAudioChannels;
856 data.currentPreferredSampleRate = winUtils.currentPreferredSampleRate;
857 data.audioOutputDevices = convertDevices(
859 .audioDevices(Ci.nsIDOMWindowUtils.AUDIO_OUTPUT)
860 .QueryInterface(Ci.nsIArray)
862 data.audioInputDevices = convertDevices(
864 .audioDevices(Ci.nsIDOMWindowUtils.AUDIO_INPUT)
865 .QueryInterface(Ci.nsIArray)
868 data.codecSupportInfo = "Unknown";
870 // We initialize gfxInfo here in the same way as in the media
871 // section -- should we break this out into a separate function?
873 // nsIGfxInfo may not be implemented on some platforms.
874 var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
876 // Note: CodecSupportInfo is not populated until we have
877 // actually instantiated a PDM. We may want to add a button
878 // or some other means of allowing the user to manually
879 // instantiate a PDM to ensure that the data is available.
880 data.codecSupportInfo = gfxInfo.CodecSupportInfo;
886 accessibility: function accessibility(done) {
888 data.isActive = Services.appinfo.accessibilityEnabled;
889 // eslint-disable-next-line mozilla/use-default-preference-values
891 data.forceDisabled = Services.prefs.getIntPref(
892 "accessibility.force_disabled"
895 data.instantiator = Services.appinfo.accessibilityInstantiator;
899 startupCache: function startupCache(done) {
900 const startupInfo = Cc["@mozilla.org/startupcacheinfo;1"].getService(
901 Ci.nsIStartupCacheInfo
904 DiskCachePath: startupInfo.DiskCachePath,
905 IgnoreDiskCache: startupInfo.IgnoreDiskCache,
906 FoundDiskCacheOnInit: startupInfo.FoundDiskCacheOnInit,
907 WroteToDiskCache: startupInfo.WroteToDiskCache,
911 libraryVersions: function libraryVersions(done) {
913 let verInfo = Cc["@mozilla.org/security/nssversion;1"].getService(
916 for (let prop in verInfo) {
917 let match = /^([^_]+)_((Min)?Version)$/.exec(prop);
919 let verProp = match[2][0].toLowerCase() + match[2].substr(1);
920 data[match[1]] = data[match[1]] || {};
921 data[match[1]][verProp] = verInfo[prop];
927 userJS: function userJS(done) {
928 let userJSFile = Services.dirsvc.get("PrefD", Ci.nsIFile);
929 userJSFile.append("user.js");
931 exists: userJSFile.exists() && userJSFile.fileSize > 0,
935 intl: function intl(done) {
936 const osPrefs = Cc["@mozilla.org/intl/ospreferences;1"].getService(
941 requested: Services.locale.requestedLocales,
942 available: Services.locale.availableLocales,
943 supported: Services.locale.appLocalesAsBCP47,
944 regionalPrefs: Services.locale.regionalPrefsLocales,
945 defaultLocale: Services.locale.defaultLocale,
948 systemLocales: osPrefs.systemLocales,
949 regionalPrefsLocales: osPrefs.regionalPrefsLocales,
954 async normandy(done) {
955 if (!AppConstants.MOZ_NORMANDY) {
960 const { PreferenceExperiments: NormandyPreferenceStudies } =
961 ChromeUtils.importESModule(
962 "resource://normandy/lib/PreferenceExperiments.sys.mjs"
964 const { AddonStudies: NormandyAddonStudies } = ChromeUtils.importESModule(
965 "resource://normandy/lib/AddonStudies.sys.mjs"
967 const { PreferenceRollouts: NormandyPreferenceRollouts } =
968 ChromeUtils.importESModule(
969 "resource://normandy/lib/PreferenceRollouts.sys.mjs"
971 const { ExperimentManager } = ChromeUtils.importESModule(
972 "resource://nimbus/lib/ExperimentManager.sys.mjs"
975 // Get Normandy data in parallel, and sort each group by slug.
982 ] = await Promise.all(
984 NormandyAddonStudies.getAllActive(),
985 NormandyPreferenceRollouts.getAllActive(),
986 NormandyPreferenceStudies.getAllActive(),
987 ExperimentManager.store
989 .then(() => ExperimentManager.store.getAllActiveExperiments()),
990 ExperimentManager.store
992 .then(() => ExperimentManager.store.getAllActiveRollouts()),
996 console.error(error);
999 .then(items => items.sort((a, b) => a.slug.localeCompare(b.slug)))
1013 if (AppConstants.MOZ_CRASHREPORTER) {
1014 dataProviders.crashes = function crashes(done) {
1015 const { CrashReports } = ChromeUtils.importESModule(
1016 "resource://gre/modules/CrashReports.sys.mjs"
1018 let reports = CrashReports.getReports();
1019 let now = new Date();
1020 let reportsNew = reports.filter(
1021 report => now - report.date < Troubleshoot.kMaxCrashAge
1023 let reportsSubmitted = reportsNew.filter(report => !report.pending);
1024 let reportsPendingCount = reportsNew.length - reportsSubmitted.length;
1025 let data = { submitted: reportsSubmitted, pending: reportsPendingCount };
1030 if (AppConstants.MOZ_SANDBOX) {
1031 dataProviders.sandbox = function sandbox(done) {
1033 if (AppConstants.unixstyle == "linux") {
1037 "hasPrivilegedUserNamespaces",
1038 "hasUserNamespaces",
1039 "canSandboxContent",
1043 for (let key of keys) {
1044 if (Services.sysinfo.hasKey(key)) {
1045 data[key] = Services.sysinfo.getPropertyAsBool(key);
1049 let reporter = Cc["@mozilla.org/sandbox/syscall-reporter;1"].getService(
1050 Ci.mozISandboxReporter
1052 const snapshot = reporter.snapshot();
1054 for (let index = snapshot.begin; index < snapshot.end; ++index) {
1055 let report = snapshot.getElement(index);
1056 let { msecAgo, pid, tid, procType, syscall } = report;
1058 for (let i = 0; i < report.numArgs; ++i) {
1059 args.push(report.getArg(i));
1061 syscalls.push({ index, msecAgo, pid, tid, procType, syscall, args });
1063 data.syscallLog = syscalls;
1066 if (AppConstants.MOZ_SANDBOX) {
1067 let sandboxSettings = Cc[
1068 "@mozilla.org/sandbox/sandbox-settings;1"
1069 ].getService(Ci.mozISandboxSettings);
1070 data.contentSandboxLevel = Services.prefs.getIntPref(
1071 "security.sandbox.content.level"
1073 data.effectiveContentSandboxLevel =
1074 sandboxSettings.effectiveContentSandboxLevel;
1075 data.contentWin32kLockdownState =
1076 sandboxSettings.contentWin32kLockdownStateString;
1077 data.supportSandboxGpuLevel = Services.prefs.getIntPref(
1078 "security.sandbox.gpu.level"
1086 if (AppConstants.ENABLE_WEBDRIVER) {
1087 dataProviders.remoteAgent = function remoteAgent(done) {
1088 const { RemoteAgent } = ChromeUtils.importESModule(
1089 "chrome://remote/content/components/RemoteAgent.sys.mjs"
1091 const { running, scheme, host, port } = RemoteAgent;
1094 url = `${scheme}://${host}:${port}/`;
1096 done({ running, url });