toolkit/modules/Troubleshoot.jsm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 this.EXPORTED_SYMBOLS = [
michael@0 6 "Troubleshoot",
michael@0 7 ];
michael@0 8
michael@0 9 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
michael@0 10
michael@0 11 Cu.import("resource://gre/modules/AddonManager.jsm");
michael@0 12 Cu.import("resource://gre/modules/Services.jsm");
michael@0 13
michael@0 14 #ifdef MOZ_CRASHREPORTER
michael@0 15 Cu.import("resource://gre/modules/CrashReports.jsm");
michael@0 16 #endif
michael@0 17
michael@0 18 let Experiments;
michael@0 19 try {
michael@0 20 Experiments = Cu.import("resource:///modules/experiments/Experiments.jsm").Experiments;
michael@0 21 }
michael@0 22 catch (e) {
michael@0 23 }
michael@0 24
michael@0 25 // We use a preferences whitelist to make sure we only show preferences that
michael@0 26 // are useful for support and won't compromise the user's privacy. Note that
michael@0 27 // entries are *prefixes*: for example, "accessibility." applies to all prefs
michael@0 28 // under the "accessibility.*" branch.
michael@0 29 const PREFS_WHITELIST = [
michael@0 30 "accessibility.",
michael@0 31 "browser.cache.",
michael@0 32 "browser.display.",
michael@0 33 "browser.fixup.",
michael@0 34 "browser.history_expire_",
michael@0 35 "browser.link.open_newwindow",
michael@0 36 "browser.newtab.url",
michael@0 37 "browser.places.",
michael@0 38 "browser.privatebrowsing.",
michael@0 39 "browser.search.context.loadInBackground",
michael@0 40 "browser.search.log",
michael@0 41 "browser.search.openintab",
michael@0 42 "browser.search.param",
michael@0 43 "browser.search.searchEnginesURL",
michael@0 44 "browser.search.suggest.enabled",
michael@0 45 "browser.search.update",
michael@0 46 "browser.search.useDBForOrder",
michael@0 47 "browser.sessionstore.",
michael@0 48 "browser.startup.homepage",
michael@0 49 "browser.tabs.",
michael@0 50 "browser.urlbar.",
michael@0 51 "browser.zoom.",
michael@0 52 "dom.",
michael@0 53 "extensions.checkCompatibility",
michael@0 54 "extensions.lastAppVersion",
michael@0 55 "font.",
michael@0 56 "general.autoScroll",
michael@0 57 "general.useragent.",
michael@0 58 "gfx.",
michael@0 59 "html5.",
michael@0 60 "image.",
michael@0 61 "javascript.",
michael@0 62 "keyword.",
michael@0 63 "layers.",
michael@0 64 "layout.css.dpi",
michael@0 65 "media.",
michael@0 66 "mousewheel.",
michael@0 67 "network.",
michael@0 68 "permissions.default.image",
michael@0 69 "places.",
michael@0 70 "plugin.",
michael@0 71 "plugins.",
michael@0 72 "print.",
michael@0 73 "privacy.",
michael@0 74 "security.",
michael@0 75 "social.enabled",
michael@0 76 "storage.vacuum.last.",
michael@0 77 "svg.",
michael@0 78 "toolkit.startup.recent_crashes",
michael@0 79 "webgl.",
michael@0 80 ];
michael@0 81
michael@0 82 // The blacklist, unlike the whitelist, is a list of regular expressions.
michael@0 83 const PREFS_BLACKLIST = [
michael@0 84 /^network[.]proxy[.]/,
michael@0 85 /[.]print_to_filename$/,
michael@0 86 ];
michael@0 87
michael@0 88 this.Troubleshoot = {
michael@0 89
michael@0 90 /**
michael@0 91 * Captures a snapshot of data that may help troubleshooters troubleshoot
michael@0 92 * trouble.
michael@0 93 *
michael@0 94 * @param done A function that will be asynchronously called when the
michael@0 95 * snapshot completes. It will be passed the snapshot object.
michael@0 96 */
michael@0 97 snapshot: function snapshot(done) {
michael@0 98 let snapshot = {};
michael@0 99 let numPending = Object.keys(dataProviders).length;
michael@0 100 function providerDone(providerName, providerData) {
michael@0 101 snapshot[providerName] = providerData;
michael@0 102 if (--numPending == 0)
michael@0 103 // Ensure that done is always and truly called asynchronously.
michael@0 104 Services.tm.mainThread.dispatch(done.bind(null, snapshot),
michael@0 105 Ci.nsIThread.DISPATCH_NORMAL);
michael@0 106 }
michael@0 107 for (let name in dataProviders) {
michael@0 108 try {
michael@0 109 dataProviders[name](providerDone.bind(null, name));
michael@0 110 }
michael@0 111 catch (err) {
michael@0 112 let msg = "Troubleshoot data provider failed: " + name + "\n" + err;
michael@0 113 Cu.reportError(msg);
michael@0 114 providerDone(name, msg);
michael@0 115 }
michael@0 116 }
michael@0 117 },
michael@0 118
michael@0 119 kMaxCrashAge: 3 * 24 * 60 * 60 * 1000, // 3 days
michael@0 120 };
michael@0 121
michael@0 122 // Each data provider is a name => function mapping. When a snapshot is
michael@0 123 // captured, each provider's function is called, and it's the function's job to
michael@0 124 // generate the provider's data. The function is passed a "done" callback, and
michael@0 125 // when done, it must pass its data to the callback. The resulting snapshot
michael@0 126 // object will contain a name => data entry for each provider.
michael@0 127 let dataProviders = {
michael@0 128
michael@0 129 application: function application(done) {
michael@0 130 let data = {
michael@0 131 name: Services.appinfo.name,
michael@0 132 version: Services.appinfo.version,
michael@0 133 userAgent: Cc["@mozilla.org/network/protocol;1?name=http"].
michael@0 134 getService(Ci.nsIHttpProtocolHandler).
michael@0 135 userAgent,
michael@0 136 };
michael@0 137 try {
michael@0 138 data.vendor = Services.prefs.getCharPref("app.support.vendor");
michael@0 139 }
michael@0 140 catch (e) {}
michael@0 141 let urlFormatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
michael@0 142 getService(Ci.nsIURLFormatter);
michael@0 143 try {
michael@0 144 data.supportURL = urlFormatter.formatURLPref("app.support.baseURL");
michael@0 145 }
michael@0 146 catch (e) {}
michael@0 147 done(data);
michael@0 148 },
michael@0 149
michael@0 150 #ifdef MOZ_CRASHREPORTER
michael@0 151 crashes: function crashes(done) {
michael@0 152 let reports = CrashReports.getReports();
michael@0 153 let now = new Date();
michael@0 154 let reportsNew = reports.filter(report => (now - report.date < Troubleshoot.kMaxCrashAge));
michael@0 155 let reportsSubmitted = reportsNew.filter(report => (!report.pending));
michael@0 156 let reportsPendingCount = reportsNew.length - reportsSubmitted.length;
michael@0 157 let data = {submitted : reportsSubmitted, pending : reportsPendingCount};
michael@0 158 done(data);
michael@0 159 },
michael@0 160 #endif
michael@0 161
michael@0 162 extensions: function extensions(done) {
michael@0 163 AddonManager.getAddonsByTypes(["extension"], function (extensions) {
michael@0 164 extensions.sort(function (a, b) {
michael@0 165 if (a.isActive != b.isActive)
michael@0 166 return b.isActive ? 1 : -1;
michael@0 167 let lc = a.name.localeCompare(b.name);
michael@0 168 if (lc != 0)
michael@0 169 return lc;
michael@0 170 if (a.version != b.version)
michael@0 171 return a.version > b.version ? 1 : -1;
michael@0 172 return 0;
michael@0 173 });
michael@0 174 let props = ["name", "version", "isActive", "id"];
michael@0 175 done(extensions.map(function (ext) {
michael@0 176 return props.reduce(function (extData, prop) {
michael@0 177 extData[prop] = ext[prop];
michael@0 178 return extData;
michael@0 179 }, {});
michael@0 180 }));
michael@0 181 });
michael@0 182 },
michael@0 183
michael@0 184 experiments: function experiments(done) {
michael@0 185 if (Experiments === undefined) {
michael@0 186 done([]);
michael@0 187 return;
michael@0 188 }
michael@0 189
michael@0 190 // getExperiments promises experiment history
michael@0 191 Experiments.instance().getExperiments().then(
michael@0 192 experiments => done(experiments)
michael@0 193 );
michael@0 194 },
michael@0 195
michael@0 196 modifiedPreferences: function modifiedPreferences(done) {
michael@0 197 function getPref(name) {
michael@0 198 let table = {};
michael@0 199 table[Ci.nsIPrefBranch.PREF_STRING] = "getCharPref";
michael@0 200 table[Ci.nsIPrefBranch.PREF_INT] = "getIntPref";
michael@0 201 table[Ci.nsIPrefBranch.PREF_BOOL] = "getBoolPref";
michael@0 202 let type = Services.prefs.getPrefType(name);
michael@0 203 if (!(type in table))
michael@0 204 throw new Error("Unknown preference type " + type + " for " + name);
michael@0 205 return Services.prefs[table[type]](name);
michael@0 206 }
michael@0 207 done(PREFS_WHITELIST.reduce(function (prefs, branch) {
michael@0 208 Services.prefs.getChildList(branch).forEach(function (name) {
michael@0 209 if (Services.prefs.prefHasUserValue(name) &&
michael@0 210 !PREFS_BLACKLIST.some(function (re) re.test(name)))
michael@0 211 prefs[name] = getPref(name);
michael@0 212 });
michael@0 213 return prefs;
michael@0 214 }, {}));
michael@0 215 },
michael@0 216
michael@0 217 graphics: function graphics(done) {
michael@0 218 function statusMsgForFeature(feature) {
michael@0 219 // We return an array because in the tryNewerDriver case we need to
michael@0 220 // include the suggested version, which the consumer likely needs to plug
michael@0 221 // into a format string from a localization file. Rather than returning
michael@0 222 // a string in some cases and an array in others, return an array always.
michael@0 223 let msg = [""];
michael@0 224 try {
michael@0 225 var status = gfxInfo.getFeatureStatus(feature);
michael@0 226 }
michael@0 227 catch (e) {}
michael@0 228 switch (status) {
michael@0 229 case Ci.nsIGfxInfo.FEATURE_BLOCKED_DEVICE:
michael@0 230 case Ci.nsIGfxInfo.FEATURE_DISCOURAGED:
michael@0 231 msg = ["blockedGfxCard"];
michael@0 232 break;
michael@0 233 case Ci.nsIGfxInfo.FEATURE_BLOCKED_OS_VERSION:
michael@0 234 msg = ["blockedOSVersion"];
michael@0 235 break;
michael@0 236 case Ci.nsIGfxInfo.FEATURE_BLOCKED_DRIVER_VERSION:
michael@0 237 try {
michael@0 238 var suggestedDriverVersion =
michael@0 239 gfxInfo.getFeatureSuggestedDriverVersion(feature);
michael@0 240 }
michael@0 241 catch (e) {}
michael@0 242 msg = suggestedDriverVersion ?
michael@0 243 ["tryNewerDriver", suggestedDriverVersion] :
michael@0 244 ["blockedDriver"];
michael@0 245 break;
michael@0 246 }
michael@0 247 return msg;
michael@0 248 }
michael@0 249
michael@0 250 let data = {};
michael@0 251
michael@0 252 try {
michael@0 253 // nsIGfxInfo may not be implemented on some platforms.
michael@0 254 var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfo);
michael@0 255 }
michael@0 256 catch (e) {}
michael@0 257
michael@0 258 data.numTotalWindows = 0;
michael@0 259 data.numAcceleratedWindows = 0;
michael@0 260 let winEnumer = Services.ww.getWindowEnumerator();
michael@0 261 while (winEnumer.hasMoreElements()) {
michael@0 262 data.numTotalWindows++;
michael@0 263 let winUtils = winEnumer.getNext().
michael@0 264 QueryInterface(Ci.nsIInterfaceRequestor).
michael@0 265 getInterface(Ci.nsIDOMWindowUtils);
michael@0 266 try {
michael@0 267 data.windowLayerManagerType = winUtils.layerManagerType;
michael@0 268 data.windowLayerManagerRemote = winUtils.layerManagerRemote;
michael@0 269 }
michael@0 270 catch (e) {
michael@0 271 continue;
michael@0 272 }
michael@0 273 if (data.windowLayerManagerType != "Basic")
michael@0 274 data.numAcceleratedWindows++;
michael@0 275 }
michael@0 276
michael@0 277 if (!data.numAcceleratedWindows && gfxInfo) {
michael@0 278 let feature =
michael@0 279 #ifdef XP_WIN
michael@0 280 gfxInfo.FEATURE_DIRECT3D_9_LAYERS;
michael@0 281 #else
michael@0 282 gfxInfo.FEATURE_OPENGL_LAYERS;
michael@0 283 #endif
michael@0 284 data.numAcceleratedWindowsMessage = statusMsgForFeature(feature);
michael@0 285 }
michael@0 286
michael@0 287 if (!gfxInfo) {
michael@0 288 done(data);
michael@0 289 return;
michael@0 290 }
michael@0 291
michael@0 292 // keys are the names of attributes on nsIGfxInfo, values become the names
michael@0 293 // of the corresponding properties in our data object. A null value means
michael@0 294 // no change. This is needed so that the names of properties in the data
michael@0 295 // object are the same as the names of keys in aboutSupport.properties.
michael@0 296 let gfxInfoProps = {
michael@0 297 adapterDescription: null,
michael@0 298 adapterVendorID: null,
michael@0 299 adapterDeviceID: null,
michael@0 300 adapterRAM: null,
michael@0 301 adapterDriver: "adapterDrivers",
michael@0 302 adapterDriverVersion: "driverVersion",
michael@0 303 adapterDriverDate: "driverDate",
michael@0 304
michael@0 305 adapterDescription2: null,
michael@0 306 adapterVendorID2: null,
michael@0 307 adapterDeviceID2: null,
michael@0 308 adapterRAM2: null,
michael@0 309 adapterDriver2: "adapterDrivers2",
michael@0 310 adapterDriverVersion2: "driverVersion2",
michael@0 311 adapterDriverDate2: "driverDate2",
michael@0 312 isGPU2Active: null,
michael@0 313
michael@0 314 D2DEnabled: "direct2DEnabled",
michael@0 315 DWriteEnabled: "directWriteEnabled",
michael@0 316 DWriteVersion: "directWriteVersion",
michael@0 317 cleartypeParameters: "clearTypeParameters",
michael@0 318 };
michael@0 319
michael@0 320 for (let prop in gfxInfoProps) {
michael@0 321 try {
michael@0 322 data[gfxInfoProps[prop] || prop] = gfxInfo[prop];
michael@0 323 }
michael@0 324 catch (e) {}
michael@0 325 }
michael@0 326
michael@0 327 if (("direct2DEnabled" in data) && !data.direct2DEnabled)
michael@0 328 data.direct2DEnabledMessage =
michael@0 329 statusMsgForFeature(Ci.nsIGfxInfo.FEATURE_DIRECT2D);
michael@0 330
michael@0 331 let doc =
michael@0 332 Cc["@mozilla.org/xmlextras/domparser;1"]
michael@0 333 .createInstance(Ci.nsIDOMParser)
michael@0 334 .parseFromString("<html/>", "text/html");
michael@0 335
michael@0 336 let canvas = doc.createElement("canvas");
michael@0 337 canvas.width = 1;
michael@0 338 canvas.height = 1;
michael@0 339
michael@0 340 let gl;
michael@0 341 try {
michael@0 342 gl = canvas.getContext("experimental-webgl");
michael@0 343 } catch(e) {}
michael@0 344
michael@0 345 if (gl) {
michael@0 346 let ext = gl.getExtension("WEBGL_debug_renderer_info");
michael@0 347 // this extension is unconditionally available to chrome. No need to check.
michael@0 348 data.webglRenderer = gl.getParameter(ext.UNMASKED_VENDOR_WEBGL)
michael@0 349 + " -- "
michael@0 350 + gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);
michael@0 351 } else {
michael@0 352 let feature =
michael@0 353 #ifdef XP_WIN
michael@0 354 // If ANGLE is not available but OpenGL is, we want to report on the
michael@0 355 // OpenGL feature, because that's what's going to get used. In all
michael@0 356 // other cases we want to report on the ANGLE feature.
michael@0 357 gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_WEBGL_ANGLE) !=
michael@0 358 Ci.nsIGfxInfo.FEATURE_NO_INFO &&
michael@0 359 gfxInfo.getFeatureStatus(Ci.nsIGfxInfo.FEATURE_WEBGL_OPENGL) ==
michael@0 360 Ci.nsIGfxInfo.FEATURE_NO_INFO ?
michael@0 361 Ci.nsIGfxInfo.FEATURE_WEBGL_OPENGL :
michael@0 362 Ci.nsIGfxInfo.FEATURE_WEBGL_ANGLE;
michael@0 363 #else
michael@0 364 Ci.nsIGfxInfo.FEATURE_WEBGL_OPENGL;
michael@0 365 #endif
michael@0 366 data.webglRendererMessage = statusMsgForFeature(feature);
michael@0 367 }
michael@0 368
michael@0 369 let infoInfo = gfxInfo.getInfo();
michael@0 370 if (infoInfo)
michael@0 371 data.info = infoInfo;
michael@0 372
michael@0 373 let failures = gfxInfo.getFailures();
michael@0 374 if (failures.length)
michael@0 375 data.failures = failures;
michael@0 376
michael@0 377 done(data);
michael@0 378 },
michael@0 379
michael@0 380 javaScript: function javaScript(done) {
michael@0 381 let data = {};
michael@0 382 let winEnumer = Services.ww.getWindowEnumerator();
michael@0 383 if (winEnumer.hasMoreElements())
michael@0 384 data.incrementalGCEnabled = winEnumer.getNext().
michael@0 385 QueryInterface(Ci.nsIInterfaceRequestor).
michael@0 386 getInterface(Ci.nsIDOMWindowUtils).
michael@0 387 isIncrementalGCEnabled();
michael@0 388 done(data);
michael@0 389 },
michael@0 390
michael@0 391 accessibility: function accessibility(done) {
michael@0 392 let data = {};
michael@0 393 try {
michael@0 394 data.isActive = Components.manager.QueryInterface(Ci.nsIServiceManager).
michael@0 395 isServiceInstantiatedByContractID(
michael@0 396 "@mozilla.org/accessibilityService;1",
michael@0 397 Ci.nsISupports);
michael@0 398 }
michael@0 399 catch (e) {
michael@0 400 data.isActive = false;
michael@0 401 }
michael@0 402 try {
michael@0 403 data.forceDisabled =
michael@0 404 Services.prefs.getIntPref("accessibility.force_disabled");
michael@0 405 }
michael@0 406 catch (e) {}
michael@0 407 done(data);
michael@0 408 },
michael@0 409
michael@0 410 libraryVersions: function libraryVersions(done) {
michael@0 411 let data = {};
michael@0 412 let verInfo = Cc["@mozilla.org/security/nssversion;1"].
michael@0 413 getService(Ci.nsINSSVersion);
michael@0 414 for (let prop in verInfo) {
michael@0 415 let match = /^([^_]+)_((Min)?Version)$/.exec(prop);
michael@0 416 if (match) {
michael@0 417 let verProp = match[2][0].toLowerCase() + match[2].substr(1);
michael@0 418 data[match[1]] = data[match[1]] || {};
michael@0 419 data[match[1]][verProp] = verInfo[prop];
michael@0 420 }
michael@0 421 }
michael@0 422 done(data);
michael@0 423 },
michael@0 424
michael@0 425 userJS: function userJS(done) {
michael@0 426 let userJSFile = Services.dirsvc.get("PrefD", Ci.nsIFile);
michael@0 427 userJSFile.append("user.js");
michael@0 428 done({
michael@0 429 exists: userJSFile.exists() && userJSFile.fileSize > 0,
michael@0 430 });
michael@0 431 },
michael@0 432 };

mercurial