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 "extensions.backgroundServiceWorkerEnabled.enabled",
139 "privacy.restrict3rdpartystorage.url_decorations",
142 function getPref(name) {
143 let type = Services.prefs.getPrefType(name);
144 if (!(type in PREFS_GETTERS)) {
145 throw new Error("Unknown preference type " + type + " for " + name);
147 return PREFS_GETTERS[type](Services.prefs, name);
150 // Return the preferences filtered by PREF_REGEXES_NOT_TO_DISPLAY and PREFS_FOR_DISPLAY
151 // and also by the custom 'filter'-ing function.
152 function getPrefList(filter, allowlist = PREFS_FOR_DISPLAY) {
153 return allowlist.reduce(function (prefs, branch) {
154 Services.prefs.getChildList(branch).forEach(function (name) {
157 !PREF_REGEXES_NOT_TO_DISPLAY.some(re => re.test(name))
159 prefs[name] = getPref(name);
166 export var Troubleshoot = {
168 * Captures a snapshot of data that may help troubleshooters troubleshoot
172 * A promise that is resolved with the snapshot data.
175 return new Promise(resolve => {
177 let numPending = Object.keys(dataProviders).length;
178 function providerDone(providerName, providerData) {
179 snapshot[providerName] = providerData;
180 if (--numPending == 0) {
181 // Ensure that done is always and truly called asynchronously.
182 Services.tm.dispatchToMainThread(() => resolve(snapshot));
185 for (let name in dataProviders) {
187 dataProviders[name](providerDone.bind(null, name));
189 let msg = "Troubleshoot data provider failed: " + name + "\n" + err;
191 providerDone(name, msg);
197 kMaxCrashAge: 3 * 24 * 60 * 60 * 1000, // 3 days
200 // Each data provider is a name => function mapping. When a snapshot is
201 // captured, each provider's function is called, and it's the function's job to
202 // generate the provider's data. The function is passed a "done" callback, and
203 // when done, it must pass its data to the callback. The resulting snapshot
204 // object will contain a name => data entry for each provider.
205 var dataProviders = {
206 application: async function application(done) {
208 name: Services.appinfo.name,
210 Services.sysinfo.getProperty("name") +
212 Services.sysinfo.getProperty("version") +
214 Services.sysinfo.getProperty("build"),
215 version: AppConstants.MOZ_APP_VERSION_DISPLAY,
216 buildID: Services.appinfo.appBuildID,
217 distributionID: Services.prefs
218 .getDefaultBranch("")
219 .getCharPref("distribution.id", ""),
220 userAgent: Cc["@mozilla.org/network/protocol;1?name=http"].getService(
221 Ci.nsIHttpProtocolHandler
223 safeMode: Services.appinfo.inSafeMode,
224 memorySizeBytes: Services.sysinfo.getProperty("memsize"),
225 diskAvailableBytes: Services.dirsvc.get("ProfD", Ci.nsIFile)
229 if (Services.sysinfo.getProperty("name") == "Windows_NT") {
230 if ((await Services.sysinfo.processInfo).isWindowsSMode) {
231 data.osVersion += " S";
235 if (AppConstants.MOZ_UPDATER) {
236 data.updateChannel = ChromeUtils.importESModule(
237 "resource://gre/modules/UpdateUtils.sys.mjs"
238 ).UpdateUtils.UpdateChannel;
241 // eslint-disable-next-line mozilla/use-default-preference-values
243 data.vendor = Services.prefs.getCharPref("app.support.vendor");
246 data.supportURL = Services.urlFormatter.formatURLPref(
247 "app.support.baseURL"
251 data.osTheme = Services.sysinfo.getProperty("osThemeInfo");
254 // MacOSX: Check for rosetta status, if it exists
255 data.rosetta = Services.sysinfo.getProperty("rosettaStatus");
259 // Windows - Get info about attached pointing devices
260 data.pointingDevices = Services.sysinfo
261 .getProperty("pointingDevices")
265 data.numTotalWindows = 0;
266 data.numFissionWindows = 0;
267 data.numRemoteWindows = 0;
268 for (let { docShell } of Services.wm.getEnumerator("navigator:browser")) {
269 docShell.QueryInterface(Ci.nsILoadContext);
270 data.numTotalWindows++;
271 if (docShell.useRemoteSubframes) {
272 data.numFissionWindows++;
274 if (docShell.useRemoteTabs) {
275 data.numRemoteWindows++;
280 data.launcherProcessState = Services.appinfo.launcherProcessState;
283 data.fissionAutoStart = Services.appinfo.fissionAutostart;
284 data.fissionDecisionStatus = Services.appinfo.fissionDecisionStatusString;
286 data.remoteAutoStart = Services.appinfo.browserTabsRemoteAutostart;
288 if (Services.policies) {
289 data.policiesStatus = Services.policies.status;
292 const keyLocationServiceGoogle = Services.urlFormatter
293 .formatURL("%GOOGLE_LOCATION_SERVICE_API_KEY%")
295 data.keyLocationServiceGoogleFound =
296 keyLocationServiceGoogle != "no-google-location-service-api-key" &&
297 !!keyLocationServiceGoogle.length;
299 const keySafebrowsingGoogle = Services.urlFormatter
300 .formatURL("%GOOGLE_SAFEBROWSING_API_KEY%")
302 data.keySafebrowsingGoogleFound =
303 keySafebrowsingGoogle != "no-google-safebrowsing-api-key" &&
304 !!keySafebrowsingGoogle.length;
306 const keyMozilla = Services.urlFormatter
307 .formatURL("%MOZILLA_API_KEY%")
309 data.keyMozillaFound =
310 keyMozilla != "no-mozilla-api-key" && !!keyMozilla.length;
315 addons: async function addons(done) {
316 let addons = await AddonManager.getAddonsByTypes([
323 addons = addons.filter(e => !e.isSystem);
324 addons.sort(function (a, b) {
325 if (a.isActive != b.isActive) {
326 return b.isActive ? 1 : -1;
329 if (a.type != b.type) {
330 return a.type.localeCompare(b.type);
333 // In some unfortunate cases add-on names can be null.
334 let aname = a.name || "";
335 let bname = b.name || "";
336 let lc = aname.localeCompare(bname);
340 if (a.version != b.version) {
341 return a.version > b.version ? 1 : -1;
345 let props = ["name", "type", "version", "isActive", "id"];
347 addons.map(function (ext) {
348 return props.reduce(function (extData, prop) {
349 extData[prop] = ext[prop];
356 securitySoftware: function securitySoftware(done) {
360 "registeredAntiVirus",
361 "registeredAntiSpyware",
362 "registeredFirewall",
364 for (let key of keys) {
367 prop = Services.sysinfo.getProperty(key);
376 features: async function features(done) {
377 let features = await AddonManager.getAddonsByTypes(["extension"]);
378 features = features.filter(f => f.isSystem);
379 features.sort(function (a, b) {
380 // In some unfortunate cases addon names can be null.
381 let aname = a.name || null;
382 let bname = b.name || null;
383 let lc = aname.localeCompare(bname);
387 if (a.version != b.version) {
388 return a.version > b.version ? 1 : -1;
392 let props = ["name", "version", "id"];
394 features.map(function (f) {
395 return props.reduce(function (fData, prop) {
396 fData[prop] = f[prop];
403 processes: async function processes(done) {
404 let remoteTypes = {};
405 const processInfo = await ChromeUtils.requestProcInfo();
406 for (let i = 0; i < processInfo.children.length; i++) {
409 remoteType = processInfo.children[i].type;
410 // Workaround for bug 1790070, since requestProcInfo refers to the preallocated content
411 // process as "preallocated", and the localization string mapping expects "prealloc".
412 remoteType = remoteType === "preallocated" ? "prealloc" : remoteType;
415 // The parent process is also managed by the ppmm (because
416 // of non-remote tabs), but it doesn't have a remoteType.
421 if (remoteTypes[remoteType]) {
422 remoteTypes[remoteType]++;
424 remoteTypes[remoteType] = 1;
429 let winUtils = Services.wm.getMostRecentWindow("").windowUtils;
430 if (winUtils.gpuProcessPid != -1) {
435 if (Services.io.socketProcessLaunched) {
436 remoteTypes.socket = 1;
441 maxWebContentProcesses: Services.appinfo.maxWebProcessCount,
447 async experimentalFeatures(done) {
448 if (AppConstants.platform == "android") {
452 let gates = await FeatureGate.all();
458 Services.prefs.getBoolPref(gate.preference),
464 async legacyUserStylesheets(done) {
465 if (AppConstants.platform == "android") {
466 done({ active: false, types: [] });
470 let active = Services.prefs.getBoolPref(
471 "toolkit.legacyUserProfileCustomizations.stylesheets"
474 for (let name of ["userChrome.css", "userContent.css"]) {
475 let path = PathUtils.join(PathUtils.profileDir, "chrome", name);
476 if (await IOUtils.exists(path)) {
480 done({ active, types });
483 async environmentVariables(done) {
486 // Subprocess is not available in all builds
487 Subprocess = ChromeUtils.importESModule(
488 "resource://gre/modules/Subprocess.sys.mjs"
495 let environment = Subprocess.getEnvironment();
496 let filteredEnvironment = {};
497 // Limit the environment variables to those that we
498 // know may affect Firefox to reduce leaking PII.
499 let filteredEnvironmentKeys = ["xre_", "moz_", "gdk", "display"];
500 for (let key of Object.keys(environment)) {
501 if (filteredEnvironmentKeys.some(k => key.toLowerCase().startsWith(k))) {
502 filteredEnvironment[key] = environment[key];
505 done(filteredEnvironment);
508 modifiedPreferences: function modifiedPreferences(done) {
509 done(getPrefList(name => Services.prefs.prefHasUserValue(name)));
512 lockedPreferences: function lockedPreferences(done) {
516 !PREFS_UNIMPORTANT_LOCKED.includes(name) &&
517 Services.prefs.prefIsLocked(name)
522 places: async function places(done) {
523 const data = AppConstants.MOZ_PLACES
524 ? await lazy.PlacesDBUtils.getEntitiesStatsAndCounts()
529 printingPreferences: function printingPreferences(done) {
530 let filter = name => Services.prefs.prefHasUserValue(name);
531 let prefs = getPrefList(filter, ["print."]);
533 // print_printer is special and is the only pref that is outside of the
534 // "print." branch... Maybe we should change it to print.printer or
536 if (filter("print_printer")) {
537 prefs.print_printer = getPref("print_printer");
543 graphics: function graphics(done) {
544 function statusMsgForFeature(feature) {
545 // We return an object because in the try-newer-driver case we need to
546 // include the suggested version, which the consumer likely needs to plug
547 // into a format string from a localization file. Rather than returning
548 // a string in some cases and an object in others, return an object always.
549 let msg = { key: "" };
551 var status = gfxInfo.getFeatureStatus(feature);
554 case Ci.nsIGfxInfo.FEATURE_BLOCKED_DEVICE:
555 case Ci.nsIGfxInfo.FEATURE_DISCOURAGED:
556 msg = { key: "blocked-gfx-card" };
558 case Ci.nsIGfxInfo.FEATURE_BLOCKED_OS_VERSION:
559 msg = { key: "blocked-os-version" };
561 case Ci.nsIGfxInfo.FEATURE_BLOCKED_DRIVER_VERSION:
564 gfxInfo.getFeatureSuggestedDriverVersion(feature);
567 ? { key: "try-newer-driver", args: { driverVersion } }
568 : { key: "blocked-driver" };
570 case Ci.nsIGfxInfo.FEATURE_BLOCKED_MISMATCHED_VERSION:
571 msg = { key: "blocked-mismatched-version" };
580 // nsIGfxInfo may not be implemented on some platforms.
581 var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
584 data.desktopEnvironment = Services.appinfo.desktopEnvironment;
585 data.numTotalWindows = 0;
586 data.numAcceleratedWindows = 0;
588 let devicePixelRatios = [];
590 for (let win of Services.ww.getWindowEnumerator()) {
591 let winUtils = win.windowUtils;
593 // NOTE: windowless browser's windows should not be reported in the graphics troubleshoot report
595 winUtils.layerManagerType == "None" ||
596 !winUtils.layerManagerRemote
600 devicePixelRatios.push(win.devicePixelRatio);
602 data.numTotalWindows++;
603 data.windowLayerManagerType = winUtils.layerManagerType;
604 data.windowLayerManagerRemote = winUtils.layerManagerRemote;
608 if (data.windowLayerManagerType != "Basic") {
609 data.numAcceleratedWindows++;
612 data.graphicsDevicePixelRatios = devicePixelRatios;
614 // If we had no OMTC windows, report back Basic Layers.
615 if (!data.windowLayerManagerType) {
616 data.windowLayerManagerType = "Basic";
617 data.windowLayerManagerRemote = false;
620 if (!data.numAcceleratedWindows && gfxInfo) {
621 let win = AppConstants.platform == "win";
623 ? gfxInfo.FEATURE_DIRECT3D_9_LAYERS
624 : gfxInfo.FEATURE_OPENGL_LAYERS;
625 data.numAcceleratedWindowsMessage = statusMsgForFeature(feature);
629 // keys are the names of attributes on nsIGfxInfo, values become the names
630 // of the corresponding properties in our data object. A null value means
631 // no change. This is needed so that the names of properties in the data
632 // object are the same as the names of keys in aboutSupport.properties.
634 adapterDescription: null,
635 adapterVendorID: null,
636 adapterDeviceID: null,
637 adapterSubsysID: null,
639 adapterDriver: "adapterDrivers",
640 adapterDriverVendor: "driverVendor",
641 adapterDriverVersion: "driverVersion",
642 adapterDriverDate: "driverDate",
644 adapterDescription2: null,
645 adapterVendorID2: null,
646 adapterDeviceID2: null,
647 adapterSubsysID2: null,
649 adapterDriver2: "adapterDrivers2",
650 adapterDriverVendor2: "driverVendor2",
651 adapterDriverVersion2: "driverVersion2",
652 adapterDriverDate2: "driverDate2",
655 D2DEnabled: "direct2DEnabled",
656 DWriteEnabled: "directWriteEnabled",
657 DWriteVersion: "directWriteVersion",
658 cleartypeParameters: "clearTypeParameters",
659 TargetFrameRate: "targetFrameRate",
660 windowProtocol: null,
663 for (let prop in gfxInfoProps) {
665 data[gfxInfoProps[prop] || prop] = gfxInfo[prop];
669 if ("direct2DEnabled" in data && !data.direct2DEnabled) {
670 data.direct2DEnabledMessage = statusMsgForFeature(
671 Ci.nsIGfxInfo.FEATURE_DIRECT2D
676 let doc = new DOMParser().parseFromString("<html/>", "text/html");
678 function GetWebGLInfo(data, keyPrefix, contextType) {
679 data[keyPrefix + "Renderer"] = "-";
680 data[keyPrefix + "Version"] = "-";
681 data[keyPrefix + "DriverExtensions"] = "-";
682 data[keyPrefix + "Extensions"] = "-";
683 data[keyPrefix + "WSIInfo"] = "-";
687 let canvas = doc.createElement("canvas");
693 let creationError = null;
695 canvas.addEventListener(
696 "webglcontextcreationerror",
699 creationError = e.statusMessage;
705 gl = canvas.getContext(contextType);
707 if (!creationError) {
708 creationError = e.toString();
712 data[keyPrefix + "Renderer"] =
713 creationError || "(no creation error info)";
719 data[keyPrefix + "Extensions"] = gl.getSupportedExtensions().join(" ");
723 let ext = gl.getExtension("MOZ_debug");
724 // This extension is unconditionally available to chrome. No need to check.
725 let vendor = ext.getParameter(gl.VENDOR);
726 let renderer = ext.getParameter(gl.RENDERER);
728 data[keyPrefix + "Renderer"] = vendor + " -- " + renderer;
729 data[keyPrefix + "Version"] = ext.getParameter(gl.VERSION);
730 data[keyPrefix + "DriverExtensions"] = ext.getParameter(ext.EXTENSIONS);
731 data[keyPrefix + "WSIInfo"] = ext.getParameter(ext.WSI_INFO);
735 // Eagerly free resources.
736 let loseExt = gl.getExtension("WEBGL_lose_context");
738 loseExt.loseContext();
742 GetWebGLInfo(data, "webgl1", "webgl");
743 GetWebGLInfo(data, "webgl2", "webgl2");
746 let infoInfo = gfxInfo.getInfo();
748 data.info = infoInfo;
751 let failureIndices = {};
753 let failures = gfxInfo.getFailures(failureIndices);
754 if (failures.length) {
755 data.failures = failures;
756 if (failureIndices.value.length == failures.length) {
757 data.indices = failureIndices.value;
761 data.featureLog = gfxInfo.getFeatureLog();
762 data.crashGuards = gfxInfo.getActiveCrashGuards();
765 function getNavigator() {
766 for (let win of Services.ww.getWindowEnumerator()) {
767 let winUtils = win.windowUtils;
769 // NOTE: windowless browser's windows should not be reported in the graphics troubleshoot report
771 winUtils.layerManagerType == "None" ||
772 !winUtils.layerManagerRemote
776 const nav = win.navigator;
784 throw new Error("No window had window.navigator.");
787 const navigator = getNavigator();
789 async function GetWebgpuInfo(adapterOpts) {
791 if (!navigator.gpu) {
792 ret["navigator.gpu"] = null;
796 const requestAdapterkey = `navigator.gpu.requestAdapter(${JSON.stringify(
802 adapter = await navigator.gpu.requestAdapter(adapterOpts);
804 // If WebGPU isn't supported or is blocked somehow, include
805 // that in the report. Anything else is an error which should
806 // have consequences (test failures, etc).
807 if (DOMException.isInstance(e) && e.name == "NotSupportedError") {
808 return { [requestAdapterkey]: { not_supported: e.message } };
814 ret[requestAdapterkey] = null;
817 const desc = (ret[requestAdapterkey] = {});
819 desc.isFallbackAdapter = adapter.isFallbackAdapter;
821 const adapterInfo = await adapter.requestAdapterInfo();
822 // We can't directly enumerate properties of instances of `GPUAdapterInfo`s, so use the prototype instead.
823 const adapterInfoObj = {};
824 for (const k of Object.keys(Object.getPrototypeOf(adapterInfo)).sort()) {
825 adapterInfoObj[k] = adapterInfo[k];
827 desc[`requestAdapterInfo()`] = adapterInfoObj;
829 desc.features = Array.from(adapter.features).sort();
832 const keys = Object.keys(Object.getPrototypeOf(adapter.limits)).sort(); // limits not directly enumerable?
833 for (const k of keys) {
834 desc.limits[k] = adapter.limits[k];
840 // Webgpu info is going to need awaits.
842 data.webgpuDefaultAdapter = await GetWebgpuInfo({});
843 data.webgpuFallbackAdapter = await GetWebgpuInfo({
844 forceFallbackAdapter: true,
851 media: function media(done) {
852 function convertDevices(devices) {
857 for (let i = 0; i < devices.length; ++i) {
858 let device = devices.queryElementAt(i, Ci.nsIAudioDeviceInfo);
861 groupId: device.groupId,
862 vendor: device.vendor,
865 preferred: device.preferred,
866 supportedFormat: device.supportedFormat,
867 defaultFormat: device.defaultFormat,
868 maxChannels: device.maxChannels,
869 defaultRate: device.defaultRate,
870 maxRate: device.maxRate,
871 minRate: device.minRate,
872 maxLatency: device.maxLatency,
873 minLatency: device.minLatency,
880 let winUtils = Services.wm.getMostRecentWindow("").windowUtils;
881 data.currentAudioBackend = winUtils.currentAudioBackend;
882 data.currentMaxAudioChannels = winUtils.currentMaxAudioChannels;
883 data.currentPreferredSampleRate = winUtils.currentPreferredSampleRate;
884 data.audioOutputDevices = convertDevices(
886 .audioDevices(Ci.nsIDOMWindowUtils.AUDIO_OUTPUT)
887 .QueryInterface(Ci.nsIArray)
889 data.audioInputDevices = convertDevices(
891 .audioDevices(Ci.nsIDOMWindowUtils.AUDIO_INPUT)
892 .QueryInterface(Ci.nsIArray)
895 data.codecSupportInfo = "Unknown";
897 // We initialize gfxInfo here in the same way as in the media
898 // section -- should we break this out into a separate function?
900 // nsIGfxInfo may not be implemented on some platforms.
901 var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
903 // Note: CodecSupportInfo is not populated until we have
904 // actually instantiated a PDM. We may want to add a button
905 // or some other means of allowing the user to manually
906 // instantiate a PDM to ensure that the data is available.
907 data.codecSupportInfo = gfxInfo.CodecSupportInfo;
913 accessibility: function accessibility(done) {
915 data.isActive = Services.appinfo.accessibilityEnabled;
916 // eslint-disable-next-line mozilla/use-default-preference-values
918 data.forceDisabled = Services.prefs.getIntPref(
919 "accessibility.force_disabled"
922 data.instantiator = Services.appinfo.accessibilityInstantiator;
926 startupCache: function startupCache(done) {
927 const startupInfo = Cc["@mozilla.org/startupcacheinfo;1"].getService(
928 Ci.nsIStartupCacheInfo
931 DiskCachePath: startupInfo.DiskCachePath,
932 IgnoreDiskCache: startupInfo.IgnoreDiskCache,
933 FoundDiskCacheOnInit: startupInfo.FoundDiskCacheOnInit,
934 WroteToDiskCache: startupInfo.WroteToDiskCache,
938 libraryVersions: function libraryVersions(done) {
940 let verInfo = Cc["@mozilla.org/security/nssversion;1"].getService(
943 for (let prop in verInfo) {
944 let match = /^([^_]+)_((Min)?Version)$/.exec(prop);
946 let verProp = match[2][0].toLowerCase() + match[2].substr(1);
947 data[match[1]] = data[match[1]] || {};
948 data[match[1]][verProp] = verInfo[prop];
954 userJS: function userJS(done) {
955 let userJSFile = Services.dirsvc.get("PrefD", Ci.nsIFile);
956 userJSFile.append("user.js");
958 exists: userJSFile.exists() && userJSFile.fileSize > 0,
962 intl: function intl(done) {
963 const osPrefs = Cc["@mozilla.org/intl/ospreferences;1"].getService(
968 requested: Services.locale.requestedLocales,
969 available: Services.locale.availableLocales,
970 supported: Services.locale.appLocalesAsBCP47,
971 regionalPrefs: Services.locale.regionalPrefsLocales,
972 defaultLocale: Services.locale.defaultLocale,
975 systemLocales: osPrefs.systemLocales,
976 regionalPrefsLocales: osPrefs.regionalPrefsLocales,
981 async normandy(done) {
982 if (!AppConstants.MOZ_NORMANDY) {
987 const { PreferenceExperiments: NormandyPreferenceStudies } =
988 ChromeUtils.importESModule(
989 "resource://normandy/lib/PreferenceExperiments.sys.mjs"
991 const { AddonStudies: NormandyAddonStudies } = ChromeUtils.importESModule(
992 "resource://normandy/lib/AddonStudies.sys.mjs"
994 const { PreferenceRollouts: NormandyPreferenceRollouts } =
995 ChromeUtils.importESModule(
996 "resource://normandy/lib/PreferenceRollouts.sys.mjs"
998 const { ExperimentManager } = ChromeUtils.importESModule(
999 "resource://nimbus/lib/ExperimentManager.sys.mjs"
1002 // Get Normandy data in parallel, and sort each group by slug.
1009 ] = await Promise.all(
1011 NormandyAddonStudies.getAllActive(),
1012 NormandyPreferenceRollouts.getAllActive(),
1013 NormandyPreferenceStudies.getAllActive(),
1014 ExperimentManager.store
1016 .then(() => ExperimentManager.store.getAllActiveExperiments()),
1017 ExperimentManager.store
1019 .then(() => ExperimentManager.store.getAllActiveRollouts()),
1023 console.error(error);
1026 .then(items => items.sort((a, b) => a.slug.localeCompare(b.slug)))
1040 if (AppConstants.MOZ_CRASHREPORTER) {
1041 dataProviders.crashes = function crashes(done) {
1042 const { CrashReports } = ChromeUtils.importESModule(
1043 "resource://gre/modules/CrashReports.sys.mjs"
1045 let reports = CrashReports.getReports();
1046 let now = new Date();
1047 let reportsNew = reports.filter(
1048 report => now - report.date < Troubleshoot.kMaxCrashAge
1050 let reportsSubmitted = reportsNew.filter(report => !report.pending);
1051 let reportsPendingCount = reportsNew.length - reportsSubmitted.length;
1052 let data = { submitted: reportsSubmitted, pending: reportsPendingCount };
1057 if (AppConstants.MOZ_SANDBOX) {
1058 dataProviders.sandbox = function sandbox(done) {
1060 if (AppConstants.unixstyle == "linux") {
1064 "hasPrivilegedUserNamespaces",
1065 "hasUserNamespaces",
1066 "canSandboxContent",
1070 for (let key of keys) {
1071 if (Services.sysinfo.hasKey(key)) {
1072 data[key] = Services.sysinfo.getPropertyAsBool(key);
1076 let reporter = Cc["@mozilla.org/sandbox/syscall-reporter;1"].getService(
1077 Ci.mozISandboxReporter
1079 const snapshot = reporter.snapshot();
1081 for (let index = snapshot.begin; index < snapshot.end; ++index) {
1082 let report = snapshot.getElement(index);
1083 let { msecAgo, pid, tid, procType, syscall } = report;
1085 for (let i = 0; i < report.numArgs; ++i) {
1086 args.push(report.getArg(i));
1088 syscalls.push({ index, msecAgo, pid, tid, procType, syscall, args });
1090 data.syscallLog = syscalls;
1093 if (AppConstants.MOZ_SANDBOX) {
1094 let sandboxSettings = Cc[
1095 "@mozilla.org/sandbox/sandbox-settings;1"
1096 ].getService(Ci.mozISandboxSettings);
1097 data.contentSandboxLevel = Services.prefs.getIntPref(
1098 "security.sandbox.content.level"
1100 data.effectiveContentSandboxLevel =
1101 sandboxSettings.effectiveContentSandboxLevel;
1103 if (AppConstants.platform == "win") {
1104 data.contentWin32kLockdownState =
1105 sandboxSettings.contentWin32kLockdownStateString;
1107 data.supportSandboxGpuLevel = Services.prefs.getIntPref(
1108 "security.sandbox.gpu.level"
1117 if (AppConstants.ENABLE_WEBDRIVER) {
1118 dataProviders.remoteAgent = function remoteAgent(done) {
1119 const { RemoteAgent } = ChromeUtils.importESModule(
1120 "chrome://remote/content/components/RemoteAgent.sys.mjs"
1122 const { running, scheme, host, port } = RemoteAgent;
1125 url = `${scheme}://${host}:${port}/`;
1127 done({ running, url });