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",
25 "browser.contentanalysis.",
27 "browser.download.always_ask_before_handling_new_types",
28 "browser.download.enable_spam_prevention",
29 "browser.download.folderList",
30 "browser.download.improvements_to_download_panel",
31 "browser.download.lastDir.savePerSite",
32 "browser.download.manager.addToRecentDocs",
33 "browser.download.manager.resumeOnWakeDelay",
34 "browser.download.open_pdf_attachments_inline",
35 "browser.download.preferred.",
36 "browser.download.skipConfirmLaunchExecutable",
37 "browser.download.start_downloads_in_tmp_dir",
38 "browser.download.useDownloadDir",
40 "browser.history_expire_",
41 "browser.link.open_newwindow",
43 "browser.privatebrowsing.",
44 "browser.search.context.loadInBackground",
46 "browser.search.openintab",
47 "browser.search.param",
48 "browser.search.region",
49 "browser.search.searchEnginesURL",
50 "browser.search.suggest.enabled",
51 "browser.search.update",
52 "browser.sessionstore.",
53 "browser.startup.homepage",
54 "browser.startup.page",
61 "extensions.checkCompatibility",
62 "extensions.eventPages.enabled",
63 "extensions.formautofill.",
64 "extensions.lastAppVersion",
65 "extensions.manifestV3.enabled",
66 "extensions.quarantinedDomains.enabled",
67 "extensions.InstallTrigger.enabled",
68 "extensions.InstallTriggerImpl.enabled",
75 "identity.fxaccounts.enabled",
82 "layout.display-list.",
87 "permissions.default.image",
93 "services.sync.declinedEngines",
94 "services.sync.lastPing",
95 "services.sync.lastSync",
96 "services.sync.numClients",
97 "services.sync.engine.",
99 "storage.vacuum.last.",
101 "toolkit.startup.recent_crashes",
103 "ui.osk.detect_physical_keyboard",
104 "ui.osk.require_tablet_mode",
105 "ui.osk.debug.keyboardDisplayReason",
108 "widget.use-xdg-desktop-portal",
109 "widget.use-xdg-desktop-portal.file-picker",
110 "widget.use-xdg-desktop-portal.mime-handler",
111 "widget.gtk.overlay-scrollbars.enabled",
115 // The list of prefs we don't display, unlike the list of prefs for display,
116 // is a list of regular expressions.
117 const PREF_REGEXES_NOT_TO_DISPLAY = [
118 /^browser[.]fixup[.]domainwhitelist[.]/,
119 /^dom[.]push[.]userAgentID/,
120 /^media[.]webrtc[.]debug[.]aec_log_dir/,
121 /^media[.]webrtc[.]debug[.]log_file/,
122 /^print[.].*print_to_filename$/,
123 /^network[.]proxy[.]/,
126 // Table of getters for various preference types.
127 const PREFS_GETTERS = {};
129 PREFS_GETTERS[Ci.nsIPrefBranch.PREF_STRING] = (prefs, name) =>
130 prefs.getStringPref(name);
131 PREFS_GETTERS[Ci.nsIPrefBranch.PREF_INT] = (prefs, name) =>
132 prefs.getIntPref(name);
133 PREFS_GETTERS[Ci.nsIPrefBranch.PREF_BOOL] = (prefs, name) =>
134 prefs.getBoolPref(name);
136 // List of unimportant locked prefs (won't be shown on the troubleshooting
138 const PREFS_UNIMPORTANT_LOCKED = [
139 "dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabled",
140 "extensions.backgroundServiceWorkerEnabled.enabled",
141 "privacy.restrict3rdpartystorage.url_decorations",
144 function getPref(name) {
145 let type = Services.prefs.getPrefType(name);
146 if (!(type in PREFS_GETTERS)) {
147 throw new Error("Unknown preference type " + type + " for " + name);
149 return PREFS_GETTERS[type](Services.prefs, name);
152 // Return the preferences filtered by PREF_REGEXES_NOT_TO_DISPLAY and PREFS_FOR_DISPLAY
153 // and also by the custom 'filter'-ing function.
154 function getPrefList(filter, allowlist = PREFS_FOR_DISPLAY) {
155 return allowlist.reduce(function (prefs, branch) {
156 Services.prefs.getChildList(branch).forEach(function (name) {
159 !PREF_REGEXES_NOT_TO_DISPLAY.some(re => re.test(name))
161 prefs[name] = getPref(name);
168 export var Troubleshoot = {
170 * Captures a snapshot of data that may help troubleshooters troubleshoot
174 * A promise that is resolved with the snapshot data.
177 return new Promise(resolve => {
179 let numPending = Object.keys(dataProviders).length;
180 function providerDone(providerName, providerData) {
181 snapshot[providerName] = providerData;
182 if (--numPending == 0) {
183 // Ensure that done is always and truly called asynchronously.
184 Services.tm.dispatchToMainThread(() => resolve(snapshot));
187 for (let name in dataProviders) {
189 dataProviders[name](providerDone.bind(null, name));
191 let msg = "Troubleshoot data provider failed: " + name + "\n" + err;
193 providerDone(name, msg);
199 kMaxCrashAge: 3 * 24 * 60 * 60 * 1000, // 3 days
202 // Each data provider is a name => function mapping. When a snapshot is
203 // captured, each provider's function is called, and it's the function's job to
204 // generate the provider's data. The function is passed a "done" callback, and
205 // when done, it must pass its data to the callback. The resulting snapshot
206 // object will contain a name => data entry for each provider.
207 var dataProviders = {
208 application: async function application(done) {
210 name: Services.appinfo.name,
212 Services.sysinfo.getProperty("name") +
214 Services.sysinfo.getProperty("version") +
216 Services.sysinfo.getProperty("build"),
217 version: AppConstants.MOZ_APP_VERSION_DISPLAY,
218 buildID: Services.appinfo.appBuildID,
219 distributionID: Services.prefs
220 .getDefaultBranch("")
221 .getCharPref("distribution.id", ""),
222 userAgent: Cc["@mozilla.org/network/protocol;1?name=http"].getService(
223 Ci.nsIHttpProtocolHandler
225 safeMode: Services.appinfo.inSafeMode,
226 memorySizeBytes: Services.sysinfo.getProperty("memsize"),
227 diskAvailableBytes: Services.dirsvc.get("ProfD", Ci.nsIFile)
231 if (Services.sysinfo.getProperty("name") == "Windows_NT") {
232 if ((await Services.sysinfo.processInfo).isWindowsSMode) {
233 data.osVersion += " S";
237 if (AppConstants.MOZ_UPDATER) {
238 data.updateChannel = ChromeUtils.importESModule(
239 "resource://gre/modules/UpdateUtils.sys.mjs"
240 ).UpdateUtils.UpdateChannel;
243 // eslint-disable-next-line mozilla/use-default-preference-values
245 data.vendor = Services.prefs.getCharPref("app.support.vendor");
248 data.supportURL = Services.urlFormatter.formatURLPref(
249 "app.support.baseURL"
253 data.osTheme = Services.sysinfo.getProperty("osThemeInfo");
256 // MacOSX: Check for rosetta status, if it exists
257 data.rosetta = Services.sysinfo.getProperty("rosettaStatus");
261 // Windows - Get info about attached pointing devices
262 data.pointingDevices = Services.sysinfo
263 .getProperty("pointingDevices")
267 data.numTotalWindows = 0;
268 data.numFissionWindows = 0;
269 data.numRemoteWindows = 0;
270 for (let { docShell } of Services.wm.getEnumerator("navigator:browser")) {
271 docShell.QueryInterface(Ci.nsILoadContext);
272 data.numTotalWindows++;
273 if (docShell.useRemoteSubframes) {
274 data.numFissionWindows++;
276 if (docShell.useRemoteTabs) {
277 data.numRemoteWindows++;
282 data.launcherProcessState = Services.appinfo.launcherProcessState;
285 data.fissionAutoStart = Services.appinfo.fissionAutostart;
286 data.fissionDecisionStatus = Services.appinfo.fissionDecisionStatusString;
288 data.remoteAutoStart = Services.appinfo.browserTabsRemoteAutostart;
290 if (Services.policies) {
291 data.policiesStatus = Services.policies.status;
294 const keyLocationServiceGoogle = Services.urlFormatter
295 .formatURL("%GOOGLE_LOCATION_SERVICE_API_KEY%")
297 data.keyLocationServiceGoogleFound =
298 keyLocationServiceGoogle != "no-google-location-service-api-key" &&
299 !!keyLocationServiceGoogle.length;
301 const keySafebrowsingGoogle = Services.urlFormatter
302 .formatURL("%GOOGLE_SAFEBROWSING_API_KEY%")
304 data.keySafebrowsingGoogleFound =
305 keySafebrowsingGoogle != "no-google-safebrowsing-api-key" &&
306 !!keySafebrowsingGoogle.length;
308 const keyMozilla = Services.urlFormatter
309 .formatURL("%MOZILLA_API_KEY%")
311 data.keyMozillaFound =
312 keyMozilla != "no-mozilla-api-key" && !!keyMozilla.length;
317 addons: async function addons(done) {
318 let addons = await AddonManager.getAddonsByTypes([
325 addons = addons.filter(e => !e.isSystem);
326 addons.sort(function (a, b) {
327 if (a.isActive != b.isActive) {
328 return b.isActive ? 1 : -1;
331 if (a.type != b.type) {
332 return a.type.localeCompare(b.type);
335 // In some unfortunate cases add-on names can be null.
336 let aname = a.name || "";
337 let bname = b.name || "";
338 let lc = aname.localeCompare(bname);
342 if (a.version != b.version) {
343 return a.version > b.version ? 1 : -1;
347 let props = ["name", "type", "version", "isActive", "id"];
349 addons.map(function (ext) {
350 return props.reduce(function (extData, prop) {
351 extData[prop] = ext[prop];
358 securitySoftware: function securitySoftware(done) {
362 "registeredAntiVirus",
363 "registeredAntiSpyware",
364 "registeredFirewall",
366 for (let key of keys) {
369 prop = Services.sysinfo.getProperty(key);
378 features: async function features(done) {
379 let features = await AddonManager.getAddonsByTypes(["extension"]);
380 features = features.filter(f => f.isSystem);
381 features.sort(function (a, b) {
382 // In some unfortunate cases addon names can be null.
383 let aname = a.name || null;
384 let bname = b.name || null;
385 let lc = aname.localeCompare(bname);
389 if (a.version != b.version) {
390 return a.version > b.version ? 1 : -1;
394 let props = ["name", "version", "id"];
396 features.map(function (f) {
397 return props.reduce(function (fData, prop) {
398 fData[prop] = f[prop];
405 processes: async function processes(done) {
406 let remoteTypes = {};
407 const processInfo = await ChromeUtils.requestProcInfo();
408 for (let i = 0; i < processInfo.children.length; i++) {
411 remoteType = processInfo.children[i].type;
412 // Workaround for bug 1790070, since requestProcInfo refers to the preallocated content
413 // process as "preallocated", and the localization string mapping expects "prealloc".
414 remoteType = remoteType === "preallocated" ? "prealloc" : remoteType;
417 // We will split Utility by actor name, so do not do it now
418 if (remoteType === "utility") {
422 // The parent process is also managed by the ppmm (because
423 // of non-remote tabs), but it doesn't have a remoteType.
428 if (remoteTypes[remoteType]) {
429 remoteTypes[remoteType]++;
431 remoteTypes[remoteType] = 1;
435 for (let i = 0; i < processInfo.children.length; i++) {
436 if (processInfo.children[i].type === "utility") {
437 for (let utilityWithActor of processInfo.children[i].utilityActors.map(
438 e => `utility_${e.actorName}`
440 if (remoteTypes[utilityWithActor]) {
441 remoteTypes[utilityWithActor]++;
443 remoteTypes[utilityWithActor] = 1;
450 let winUtils = Services.wm.getMostRecentWindow("").windowUtils;
451 if (winUtils.gpuProcessPid != -1) {
456 if (Services.io.socketProcessLaunched) {
457 remoteTypes.socket = 1;
462 maxWebContentProcesses: Services.appinfo.maxWebProcessCount,
468 async experimentalFeatures(done) {
469 if (AppConstants.platform == "android") {
473 let gates = await FeatureGate.all();
479 Services.prefs.getBoolPref(gate.preference),
485 async legacyUserStylesheets(done) {
486 if (AppConstants.platform == "android") {
487 done({ active: false, types: [] });
491 let active = Services.prefs.getBoolPref(
492 "toolkit.legacyUserProfileCustomizations.stylesheets"
495 for (let name of ["userChrome.css", "userContent.css"]) {
496 let path = PathUtils.join(PathUtils.profileDir, "chrome", name);
497 if (await IOUtils.exists(path)) {
501 done({ active, types });
504 async environmentVariables(done) {
507 // Subprocess is not available in all builds
508 Subprocess = ChromeUtils.importESModule(
509 "resource://gre/modules/Subprocess.sys.mjs"
516 let environment = Subprocess.getEnvironment();
517 let filteredEnvironment = {};
518 // Limit the environment variables to those that we
519 // know may affect Firefox to reduce leaking PII.
520 let filteredEnvironmentKeys = ["xre_", "moz_", "gdk", "display"];
521 for (let key of Object.keys(environment)) {
522 if (filteredEnvironmentKeys.some(k => key.toLowerCase().startsWith(k))) {
523 filteredEnvironment[key] = environment[key];
526 done(filteredEnvironment);
529 modifiedPreferences: function modifiedPreferences(done) {
530 done(getPrefList(name => Services.prefs.prefHasUserValue(name)));
533 lockedPreferences: function lockedPreferences(done) {
537 !PREFS_UNIMPORTANT_LOCKED.includes(name) &&
538 Services.prefs.prefIsLocked(name)
543 places: async function places(done) {
544 const data = AppConstants.MOZ_PLACES
545 ? await lazy.PlacesDBUtils.getEntitiesStatsAndCounts()
550 printingPreferences: function printingPreferences(done) {
551 let filter = name => Services.prefs.prefHasUserValue(name);
552 let prefs = getPrefList(filter, ["print."]);
554 // print_printer is special and is the only pref that is outside of the
555 // "print." branch... Maybe we should change it to print.printer or
557 if (filter("print_printer")) {
558 prefs.print_printer = getPref("print_printer");
564 graphics: function graphics(done) {
565 function statusMsgForFeature(feature) {
566 // We return an object because in the try-newer-driver case we need to
567 // include the suggested version, which the consumer likely needs to plug
568 // into a format string from a localization file. Rather than returning
569 // a string in some cases and an object in others, return an object always.
570 let msg = { key: "" };
572 var status = gfxInfo.getFeatureStatus(feature);
575 case Ci.nsIGfxInfo.FEATURE_BLOCKED_DEVICE:
576 case Ci.nsIGfxInfo.FEATURE_DISCOURAGED:
577 msg = { key: "blocked-gfx-card" };
579 case Ci.nsIGfxInfo.FEATURE_BLOCKED_OS_VERSION:
580 msg = { key: "blocked-os-version" };
582 case Ci.nsIGfxInfo.FEATURE_BLOCKED_DRIVER_VERSION:
585 gfxInfo.getFeatureSuggestedDriverVersion(feature);
588 ? { key: "try-newer-driver", args: { driverVersion } }
589 : { key: "blocked-driver" };
591 case Ci.nsIGfxInfo.FEATURE_BLOCKED_MISMATCHED_VERSION:
592 msg = { key: "blocked-mismatched-version" };
601 // nsIGfxInfo may not be implemented on some platforms.
602 var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
605 data.desktopEnvironment = Services.appinfo.desktopEnvironment;
606 data.numTotalWindows = 0;
607 data.numAcceleratedWindows = 0;
609 let devicePixelRatios = [];
611 for (let win of Services.ww.getWindowEnumerator()) {
612 let winUtils = win.windowUtils;
614 // NOTE: windowless browser's windows should not be reported in the graphics troubleshoot report
616 winUtils.layerManagerType == "None" ||
617 !winUtils.layerManagerRemote
621 devicePixelRatios.push(win.devicePixelRatio);
623 data.numTotalWindows++;
624 data.windowLayerManagerType = winUtils.layerManagerType;
625 data.windowLayerManagerRemote = winUtils.layerManagerRemote;
629 if (data.windowLayerManagerType != "Basic") {
630 data.numAcceleratedWindows++;
633 data.graphicsDevicePixelRatios = devicePixelRatios;
635 // If we had no OMTC windows, report back Basic Layers.
636 if (!data.windowLayerManagerType) {
637 data.windowLayerManagerType = "Basic";
638 data.windowLayerManagerRemote = false;
641 if (!data.numAcceleratedWindows && gfxInfo) {
642 let win = AppConstants.platform == "win";
644 ? gfxInfo.FEATURE_DIRECT3D_9_LAYERS
645 : gfxInfo.FEATURE_OPENGL_LAYERS;
646 data.numAcceleratedWindowsMessage = statusMsgForFeature(feature);
650 // keys are the names of attributes on nsIGfxInfo, values become the names
651 // of the corresponding properties in our data object. A null value means
652 // no change. This is needed so that the names of properties in the data
653 // object are the same as the names of keys in aboutSupport.properties.
655 adapterDescription: null,
656 adapterVendorID: null,
657 adapterDeviceID: null,
658 adapterSubsysID: null,
660 adapterDriver: "adapterDrivers",
661 adapterDriverVendor: "driverVendor",
662 adapterDriverVersion: "driverVersion",
663 adapterDriverDate: "driverDate",
665 adapterDescription2: null,
666 adapterVendorID2: null,
667 adapterDeviceID2: null,
668 adapterSubsysID2: null,
670 adapterDriver2: "adapterDrivers2",
671 adapterDriverVendor2: "driverVendor2",
672 adapterDriverVersion2: "driverVersion2",
673 adapterDriverDate2: "driverDate2",
676 D2DEnabled: "direct2DEnabled",
677 DWriteEnabled: "directWriteEnabled",
678 DWriteVersion: "directWriteVersion",
679 cleartypeParameters: "clearTypeParameters",
680 TargetFrameRate: "targetFrameRate",
681 windowProtocol: null,
682 fontVisibilityDeterminationStr: "supportFontDetermination",
685 for (let prop in gfxInfoProps) {
687 data[gfxInfoProps[prop] || prop] = gfxInfo[prop];
691 if ("direct2DEnabled" in data && !data.direct2DEnabled) {
692 data.direct2DEnabledMessage = statusMsgForFeature(
693 Ci.nsIGfxInfo.FEATURE_DIRECT2D
698 let doc = new DOMParser().parseFromString("<html/>", "text/html");
700 function GetWebGLInfo(data, keyPrefix, contextType) {
701 data[keyPrefix + "Renderer"] = "-";
702 data[keyPrefix + "Version"] = "-";
703 data[keyPrefix + "DriverExtensions"] = "-";
704 data[keyPrefix + "Extensions"] = "-";
705 data[keyPrefix + "WSIInfo"] = "-";
709 let canvas = doc.createElement("canvas");
715 let creationError = null;
717 canvas.addEventListener(
718 "webglcontextcreationerror",
721 creationError = e.statusMessage;
727 gl = canvas.getContext(contextType);
729 if (!creationError) {
730 creationError = e.toString();
734 data[keyPrefix + "Renderer"] =
735 creationError || "(no creation error info)";
741 data[keyPrefix + "Extensions"] = gl.getSupportedExtensions().join(" ");
745 let ext = gl.getExtension("MOZ_debug");
746 // This extension is unconditionally available to chrome. No need to check.
747 let vendor = ext.getParameter(gl.VENDOR);
748 let renderer = ext.getParameter(gl.RENDERER);
750 data[keyPrefix + "Renderer"] = vendor + " -- " + renderer;
751 data[keyPrefix + "Version"] = ext.getParameter(gl.VERSION);
752 data[keyPrefix + "DriverExtensions"] = ext.getParameter(ext.EXTENSIONS);
753 data[keyPrefix + "WSIInfo"] = ext.getParameter(ext.WSI_INFO);
757 // Eagerly free resources.
758 let loseExt = gl.getExtension("WEBGL_lose_context");
760 loseExt.loseContext();
764 GetWebGLInfo(data, "webgl1", "webgl");
765 GetWebGLInfo(data, "webgl2", "webgl2");
768 let infoInfo = gfxInfo.getInfo();
770 data.info = infoInfo;
773 let failureIndices = {};
775 let failures = gfxInfo.getFailures(failureIndices);
776 if (failures.length) {
777 data.failures = failures;
778 if (failureIndices.value.length == failures.length) {
779 data.indices = failureIndices.value;
783 data.featureLog = gfxInfo.getFeatureLog();
784 data.crashGuards = gfxInfo.getActiveCrashGuards();
787 function getNavigator() {
788 for (let win of Services.ww.getWindowEnumerator()) {
789 let winUtils = win.windowUtils;
791 // NOTE: windowless browser's windows should not be reported in the graphics troubleshoot report
793 winUtils.layerManagerType == "None" ||
794 !winUtils.layerManagerRemote
798 const nav = win.navigator;
806 throw new Error("No window had window.navigator.");
809 const navigator = getNavigator();
811 async function GetWebgpuInfo(adapterOpts) {
813 if (!navigator.gpu) {
814 ret["navigator.gpu"] = null;
818 const requestAdapterkey = `navigator.gpu.requestAdapter(${JSON.stringify(
824 adapter = await navigator.gpu.requestAdapter(adapterOpts);
826 // If WebGPU isn't supported or is blocked somehow, include
827 // that in the report. Anything else is an error which should
828 // have consequences (test failures, etc).
829 if (DOMException.isInstance(e) && e.name == "NotSupportedError") {
830 return { [requestAdapterkey]: { not_supported: e.message } };
836 ret[requestAdapterkey] = null;
839 const desc = (ret[requestAdapterkey] = {});
841 desc.isFallbackAdapter = adapter.isFallbackAdapter;
843 const adapterInfo = await adapter.requestAdapterInfo();
844 // We can't directly enumerate properties of instances of `GPUAdapterInfo`s, so use the prototype instead.
845 const adapterInfoObj = {};
846 for (const k of Object.keys(Object.getPrototypeOf(adapterInfo)).sort()) {
847 adapterInfoObj[k] = adapterInfo[k];
849 desc[`requestAdapterInfo()`] = adapterInfoObj;
851 desc.features = Array.from(adapter.features).sort();
854 const keys = Object.keys(Object.getPrototypeOf(adapter.limits)).sort(); // limits not directly enumerable?
855 for (const k of keys) {
856 desc.limits[k] = adapter.limits[k];
862 // Webgpu info is going to need awaits.
864 data.webgpuDefaultAdapter = await GetWebgpuInfo({});
865 data.webgpuFallbackAdapter = await GetWebgpuInfo({
866 forceFallbackAdapter: true,
873 media: function media(done) {
874 function convertDevices(devices) {
879 for (let i = 0; i < devices.length; ++i) {
880 let device = devices.queryElementAt(i, Ci.nsIAudioDeviceInfo);
883 groupId: device.groupId,
884 vendor: device.vendor,
887 preferred: device.preferred,
888 supportedFormat: device.supportedFormat,
889 defaultFormat: device.defaultFormat,
890 maxChannels: device.maxChannels,
891 defaultRate: device.defaultRate,
892 maxRate: device.maxRate,
893 minRate: device.minRate,
894 maxLatency: device.maxLatency,
895 minLatency: device.minLatency,
902 let winUtils = Services.wm.getMostRecentWindow("").windowUtils;
903 data.currentAudioBackend = winUtils.currentAudioBackend;
904 data.currentMaxAudioChannels = winUtils.currentMaxAudioChannels;
905 data.currentPreferredSampleRate = winUtils.currentPreferredSampleRate;
906 data.audioOutputDevices = convertDevices(
908 .audioDevices(Ci.nsIDOMWindowUtils.AUDIO_OUTPUT)
909 .QueryInterface(Ci.nsIArray)
911 data.audioInputDevices = convertDevices(
913 .audioDevices(Ci.nsIDOMWindowUtils.AUDIO_INPUT)
914 .QueryInterface(Ci.nsIArray)
917 data.codecSupportInfo = "Unknown";
919 // We initialize gfxInfo here in the same way as in the media
920 // section -- should we break this out into a separate function?
922 // nsIGfxInfo may not be implemented on some platforms.
923 var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
925 // Note: CodecSupportInfo is not populated until we have
926 // actually instantiated a PDM. We may want to add a button
927 // or some other means of allowing the user to manually
928 // instantiate a PDM to ensure that the data is available.
929 data.codecSupportInfo = gfxInfo.CodecSupportInfo;
935 accessibility: function accessibility(done) {
937 data.isActive = Services.appinfo.accessibilityEnabled;
938 // eslint-disable-next-line mozilla/use-default-preference-values
940 data.forceDisabled = Services.prefs.getIntPref(
941 "accessibility.force_disabled"
944 data.instantiator = Services.appinfo.accessibilityInstantiator;
948 startupCache: function startupCache(done) {
949 const startupInfo = Cc["@mozilla.org/startupcacheinfo;1"].getService(
950 Ci.nsIStartupCacheInfo
953 DiskCachePath: startupInfo.DiskCachePath,
954 IgnoreDiskCache: startupInfo.IgnoreDiskCache,
955 FoundDiskCacheOnInit: startupInfo.FoundDiskCacheOnInit,
956 WroteToDiskCache: startupInfo.WroteToDiskCache,
960 libraryVersions: function libraryVersions(done) {
962 let verInfo = Cc["@mozilla.org/security/nssversion;1"].getService(
965 for (let prop in verInfo) {
966 let match = /^([^_]+)_((Min)?Version)$/.exec(prop);
968 let verProp = match[2][0].toLowerCase() + match[2].substr(1);
969 data[match[1]] = data[match[1]] || {};
970 data[match[1]][verProp] = verInfo[prop];
976 userJS: function userJS(done) {
977 let userJSFile = Services.dirsvc.get("PrefD", Ci.nsIFile);
978 userJSFile.append("user.js");
980 exists: userJSFile.exists() && userJSFile.fileSize > 0,
984 intl: function intl(done) {
985 const osPrefs = Cc["@mozilla.org/intl/ospreferences;1"].getService(
990 requested: Services.locale.requestedLocales,
991 available: Services.locale.availableLocales,
992 supported: Services.locale.appLocalesAsBCP47,
993 regionalPrefs: Services.locale.regionalPrefsLocales,
994 defaultLocale: Services.locale.defaultLocale,
997 systemLocales: osPrefs.systemLocales,
998 regionalPrefsLocales: osPrefs.regionalPrefsLocales,
1003 contentAnalysis: async function contentAnalysis(done) {
1004 const contentAnalysis = Cc["@mozilla.org/contentanalysis;1"].getService(
1005 Ci.nsIContentAnalysis
1007 if (!contentAnalysis.isActive) {
1008 done({ active: false });
1011 let info = await contentAnalysis.getDiagnosticInfo();
1014 connected: info.connectedToAgent,
1015 agentPath: info.agentPath,
1016 failedSignatureVerification: info.failedSignatureVerification,
1017 requestCount: info.requestCount,
1021 async normandy(done) {
1022 if (!AppConstants.MOZ_NORMANDY) {
1027 const { PreferenceExperiments: NormandyPreferenceStudies } =
1028 ChromeUtils.importESModule(
1029 "resource://normandy/lib/PreferenceExperiments.sys.mjs"
1031 const { AddonStudies: NormandyAddonStudies } = ChromeUtils.importESModule(
1032 "resource://normandy/lib/AddonStudies.sys.mjs"
1034 const { PreferenceRollouts: NormandyPreferenceRollouts } =
1035 ChromeUtils.importESModule(
1036 "resource://normandy/lib/PreferenceRollouts.sys.mjs"
1038 const { ExperimentManager } = ChromeUtils.importESModule(
1039 "resource://nimbus/lib/ExperimentManager.sys.mjs"
1042 // Get Normandy data in parallel, and sort each group by slug.
1049 ] = await Promise.all(
1051 NormandyAddonStudies.getAllActive(),
1052 NormandyPreferenceRollouts.getAllActive(),
1053 NormandyPreferenceStudies.getAllActive(),
1054 ExperimentManager.store
1056 .then(() => ExperimentManager.store.getAllActiveExperiments()),
1057 ExperimentManager.store
1059 .then(() => ExperimentManager.store.getAllActiveRollouts()),
1063 console.error(error);
1066 .then(items => items.sort((a, b) => a.slug.localeCompare(b.slug)))
1080 if (AppConstants.MOZ_CRASHREPORTER) {
1081 dataProviders.crashes = function crashes(done) {
1082 const { CrashReports } = ChromeUtils.importESModule(
1083 "resource://gre/modules/CrashReports.sys.mjs"
1085 let reports = CrashReports.getReports();
1086 let now = new Date();
1087 let reportsNew = reports.filter(
1088 report => now - report.date < Troubleshoot.kMaxCrashAge
1090 let reportsSubmitted = reportsNew.filter(report => !report.pending);
1091 let reportsPendingCount = reportsNew.length - reportsSubmitted.length;
1092 let data = { submitted: reportsSubmitted, pending: reportsPendingCount };
1097 if (AppConstants.MOZ_SANDBOX) {
1098 dataProviders.sandbox = function sandbox(done) {
1100 if (AppConstants.unixstyle == "linux") {
1104 "hasPrivilegedUserNamespaces",
1105 "hasUserNamespaces",
1106 "canSandboxContent",
1110 for (let key of keys) {
1111 if (Services.sysinfo.hasKey(key)) {
1112 data[key] = Services.sysinfo.getPropertyAsBool(key);
1116 let reporter = Cc["@mozilla.org/sandbox/syscall-reporter;1"].getService(
1117 Ci.mozISandboxReporter
1119 const snapshot = reporter.snapshot();
1121 for (let index = snapshot.begin; index < snapshot.end; ++index) {
1122 let report = snapshot.getElement(index);
1123 let { msecAgo, pid, tid, procType, syscall } = report;
1125 for (let i = 0; i < report.numArgs; ++i) {
1126 args.push(report.getArg(i));
1128 syscalls.push({ index, msecAgo, pid, tid, procType, syscall, args });
1130 data.syscallLog = syscalls;
1133 if (AppConstants.MOZ_SANDBOX) {
1134 let sandboxSettings = Cc[
1135 "@mozilla.org/sandbox/sandbox-settings;1"
1136 ].getService(Ci.mozISandboxSettings);
1137 data.contentSandboxLevel = Services.prefs.getIntPref(
1138 "security.sandbox.content.level"
1140 data.effectiveContentSandboxLevel =
1141 sandboxSettings.effectiveContentSandboxLevel;
1143 if (AppConstants.platform == "win") {
1144 data.contentWin32kLockdownState =
1145 sandboxSettings.contentWin32kLockdownStateString;
1147 data.supportSandboxGpuLevel = Services.prefs.getIntPref(
1148 "security.sandbox.gpu.level"
1157 if (AppConstants.ENABLE_WEBDRIVER) {
1158 dataProviders.remoteAgent = function remoteAgent(done) {
1159 const { RemoteAgent } = ChromeUtils.importESModule(
1160 "chrome://remote/content/components/RemoteAgent.sys.mjs"
1162 const { running, scheme, host, port } = RemoteAgent;
1165 url = `${scheme}://${host}:${port}/`;
1167 done({ running, url });