Wed, 31 Dec 2014 06:09:35 +0100
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 };