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.

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

mercurial