Source code

Revision control

Other Tools

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/. */
4
5
var EXPORTED_SYMBOLS = ["BrowserGlue", "ContentPermissionPrompt"];
6
8
9
const { XPCOMUtils } = ChromeUtils.import(
11
);
12
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
13
const { AppConstants } = ChromeUtils.import(
15
);
16
17
ChromeUtils.defineModuleGetter(
18
this,
19
"ActorManagerParent",
21
);
22
23
ChromeUtils.defineModuleGetter(
24
this,
25
"CustomizableUI",
27
);
28
29
XPCOMUtils.defineLazyServiceGetter(
30
this,
31
"PushService",
32
"@mozilla.org/push/Service;1",
33
"nsIPushService"
34
);
35
36
const PREF_PDFJS_ENABLED_CACHE_STATE = "pdfjs.enabledCache.state";
37
38
/**
39
* Fission-compatible JSWindowActor implementations.
40
* Detailed documentation of these is in dom/docs/Fission.rst,
42
*/
43
let ACTORS = {
44
BrowserTab: {
45
parent: {
47
},
48
child: {
50
51
events: {
52
DOMWindowCreated: {},
53
MozAfterPaint: {},
54
"MozDOMPointerLock:Entered": {},
55
"MozDOMPointerLock:Exited": {},
56
},
57
},
58
},
59
60
// Collects description and icon information from meta tags.
61
ContentMeta: {
62
parent: {
64
},
65
66
child: {
68
events: {
69
DOMMetaAdded: {},
70
},
71
},
72
},
73
74
ContextMenu: {
75
parent: {
77
},
78
79
child: {
81
events: {
82
contextmenu: { mozSystemGroup: true },
83
},
84
},
85
86
allFrames: true,
87
},
88
89
DOMFullscreen: {
90
parent: {
92
},
93
94
child: {
96
group: "browsers",
97
events: {
98
"MozDOMFullscreen:Request": {},
99
"MozDOMFullscreen:Entered": {},
100
"MozDOMFullscreen:NewOrigin": {},
101
"MozDOMFullscreen:Exit": {},
102
"MozDOMFullscreen:Exited": {},
103
},
104
},
105
106
allFrames: true,
107
},
108
109
FormValidation: {
110
parent: {
112
},
113
114
child: {
116
events: {
117
MozInvalidForm: {},
118
},
119
},
120
121
allFrames: true,
122
},
123
124
LinkHandler: {
125
parent: {
127
},
128
child: {
130
events: {
131
DOMHeadElementParsed: {},
132
DOMLinkAdded: {},
133
DOMLinkChanged: {},
134
pageshow: {},
135
pagehide: {},
136
},
137
},
138
},
139
140
PageInfo: {
141
child: {
143
},
144
145
allFrames: true,
146
},
147
148
PageStyle: {
149
parent: {
151
},
152
child: {
154
events: {
155
pageshow: {},
156
},
157
},
158
159
// Only matching web pages, as opposed to internal about:, chrome: or
161
matches: ["*://*/*"],
162
allFrames: true,
163
},
164
165
Plugin: {
166
parent: {
168
},
169
child: {
171
events: {
172
PluginBindingAttached: { capture: true, wantUntrusted: true },
173
PluginCrashed: { capture: true },
174
PluginOutdated: { capture: true },
175
PluginInstantiated: { capture: true },
176
PluginRemoved: { capture: true },
177
HiddenPlugin: { capture: true },
178
},
179
180
observers: ["decoder-doctor-notification"],
181
},
182
183
allFrames: true,
184
},
185
186
Prompt: {
187
parent: {
189
},
190
191
allFrames: true,
192
},
193
194
RFPHelper: {
195
parent: {
197
},
198
child: {
200
events: {
201
resize: {},
202
},
203
},
204
205
allFrames: true,
206
},
207
208
ShieldFrame: {
209
parent: {
211
},
212
child: {
214
events: {
215
pageshow: {},
216
pagehide: {},
217
ShieldPageEvent: { wantUntrusted: true },
218
},
219
},
220
matches: ["about:studies"],
221
},
222
223
SwitchDocumentDirection: {
226
},
227
228
allFrames: true,
229
},
230
};
231
232
let LEGACY_ACTORS = {
233
AboutLogins: {
234
child: {
235
matches: ["about:logins", "about:logins?*"],
237
events: {
238
AboutLoginsCopyLoginDetail: { wantUntrusted: true },
239
AboutLoginsCreateLogin: { wantUntrusted: true },
240
AboutLoginsDeleteLogin: { wantUntrusted: true },
241
AboutLoginsDismissBreachAlert: { wantUntrusted: true },
242
AboutLoginsHideFooter: { wantUntrusted: true },
243
AboutLoginsImport: { wantUntrusted: true },
244
AboutLoginsInit: { wantUntrusted: true },
245
AboutLoginsGetHelp: { wantUntrusted: true },
246
AboutLoginsOpenMobileAndroid: { wantUntrusted: true },
247
AboutLoginsOpenMobileIos: { wantUntrusted: true },
248
AboutLoginsOpenPreferences: { wantUntrusted: true },
249
AboutLoginsOpenSite: { wantUntrusted: true },
250
AboutLoginsRecordTelemetryEvent: { wantUntrusted: true },
251
AboutLoginsSortChanged: { wantUntrusted: true },
252
AboutLoginsSyncEnable: { wantUntrusted: true },
253
AboutLoginsSyncOptions: { wantUntrusted: true },
254
AboutLoginsUpdateLogin: { wantUntrusted: true },
255
},
256
messages: [
257
"AboutLogins:AllLogins",
258
"AboutLogins:LoginAdded",
259
"AboutLogins:LoginModified",
260
"AboutLogins:LoginRemoved",
261
"AboutLogins:MasterPasswordAuthRequired",
262
"AboutLogins:MasterPasswordResponse",
263
"AboutLogins:SendFavicons",
264
"AboutLogins:SetBreaches",
265
"AboutLogins:Setup",
266
"AboutLogins:ShowLoginItemError",
267
"AboutLogins:SyncState",
268
"AboutLogins:UpdateBreaches",
269
],
270
},
271
},
272
273
AboutReader: {
274
child: {
276
group: "browsers",
277
events: {
278
AboutReaderContentLoaded: { wantUntrusted: true },
279
DOMContentLoaded: {},
280
pageshow: { mozSystemGroup: true },
281
pagehide: { mozSystemGroup: true },
282
},
283
messages: ["Reader:ToggleReaderMode", "Reader:PushState"],
284
},
285
},
286
287
BlockedSite: {
288
child: {
290
events: {
291
AboutBlockedLoaded: { wantUntrusted: true },
292
click: {},
293
},
294
matches: ["about:blocked?*"],
295
allFrames: true,
296
messages: ["DeceptiveBlockedDetails"],
297
},
298
},
299
300
ClickHandler: {
301
child: {
303
events: {
304
click: { capture: true, mozSystemGroup: true },
305
auxclick: { capture: true, mozSystemGroup: true },
306
},
307
},
308
},
309
310
ContentSearch: {
311
child: {
313
group: "browsers",
314
matches: [
315
"about:home",
316
"about:newtab",
317
"about:welcome",
318
"about:privatebrowsing",
320
],
321
events: {
322
ContentSearchClient: { capture: true, wantUntrusted: true },
323
},
324
messages: ["ContentSearch"],
325
},
326
},
327
328
LightweightTheme: {
329
child: {
331
matches: ["about:home", "about:newtab", "about:welcome"],
332
events: {
333
pageshow: { mozSystemGroup: true },
334
},
335
},
336
},
337
338
NetError: {
339
child: {
341
events: {
342
click: {},
343
},
344
matches: ["about:certerror?*", "about:neterror?*"],
345
allFrames: true,
346
},
347
},
348
349
OfflineApps: {
350
child: {
352
events: {
353
MozApplicationManifest: {},
354
},
355
messages: ["OfflineApps:StartFetching"],
356
},
357
},
358
359
SearchTelemetry: {
360
child: {
362
events: {
363
DOMContentLoaded: {},
364
pageshow: { mozSystemGroup: true },
365
},
366
},
367
},
368
369
UITour: {
370
child: {
372
events: {
373
mozUITour: { wantUntrusted: true },
374
},
375
permissions: ["uitour"],
376
},
377
},
378
379
URIFixup: {
380
child: {
382
group: "browsers",
383
observers: ["keyword-uri-fixup"],
384
},
385
},
386
387
WebRTC: {
388
child: {
390
messages: [
391
"rtcpeer:Allow",
392
"rtcpeer:Deny",
393
"webrtc:Allow",
394
"webrtc:Deny",
395
"webrtc:StopSharing",
396
],
397
},
398
},
399
};
400
401
(function earlyBlankFirstPaint() {
402
if (
403
AppConstants.platform == "macosx" ||
404
!Services.prefs.getBoolPref("browser.startup.blankWindow", false)
405
) {
406
return;
407
}
408
409
// Until bug 1450626 and bug 1488384 are fixed, skip the blank window when
410
// using a non-default theme.
411
if (
412
Services.prefs.getCharPref(
413
"extensions.activeThemeID",
414
"default-theme@mozilla.org"
415
) != "default-theme@mozilla.org"
416
) {
417
return;
418
}
419
420
let store = Services.xulStore;
421
let getValue = attr =>
422
store.getValue(AppConstants.BROWSER_CHROME_URL, "main-window", attr);
423
let width = getValue("width");
424
let height = getValue("height");
425
426
// The clean profile case isn't handled yet. Return early for now.
427
if (!width || !height) {
428
return;
429
}
430
431
let browserWindowFeatures =
432
"chrome,all,dialog=no,extrachrome,menubar,resizable,scrollbars,status," +
433
"location,toolbar,personalbar";
434
let win = Services.ww.openWindow(
435
null,
436
"about:blank",
437
null,
438
browserWindowFeatures,
439
null
440
);
441
442
// Hide the titlebar if the actual browser window will draw in it.
443
let hiddenTitlebar = Services.prefs.getBoolPref(
444
"browser.tabs.drawInTitlebar",
445
win.matchMedia("(-moz-gtk-csd-hide-titlebar-by-default)").matches
446
);
447
if (hiddenTitlebar) {
448
win.windowUtils.setChromeMargin(0, 2, 2, 2);
449
}
450
451
let docElt = win.document.documentElement;
452
docElt.setAttribute("screenX", getValue("screenX"));
453
docElt.setAttribute("screenY", getValue("screenY"));
454
455
// The sizemode="maximized" attribute needs to be set before first paint.
456
let sizemode = getValue("sizemode");
457
if (sizemode == "maximized") {
458
docElt.setAttribute("sizemode", sizemode);
459
460
// Set the size to use when the user leaves the maximized mode.
461
// The persisted size is the outer size, but the height/width
462
// attributes set the inner size.
463
let appWin = win.docShell.treeOwner
464
.QueryInterface(Ci.nsIInterfaceRequestor)
465
.getInterface(Ci.nsIAppWindow);
466
height -= appWin.outerToInnerHeightDifferenceInCSSPixels;
467
width -= appWin.outerToInnerWidthDifferenceInCSSPixels;
468
docElt.setAttribute("height", height);
469
docElt.setAttribute("width", width);
470
} else {
471
// Setting the size of the window in the features string instead of here
472
// causes the window to grow by the size of the titlebar.
473
win.resizeTo(width, height);
474
}
475
476
// Set this before showing the window so that graphics code can use it to
477
// decide to skip some expensive code paths (eg. starting the GPU process).
478
docElt.setAttribute("windowtype", "navigator:blank");
479
480
// The window becomes visible after OnStopRequest, so make this happen now.
481
win.stop();
482
483
let { TelemetryTimestamps } = ChromeUtils.import(
485
);
486
TelemetryTimestamps.add("blankWindowShown");
487
})();
488
489
XPCOMUtils.defineLazyServiceGetters(this, {
490
aboutNewTabService: [
491
"@mozilla.org/browser/aboutnewtab-service;1",
492
"nsIAboutNewTabService",
493
],
494
});
495
XPCOMUtils.defineLazyGetter(
496
this,
497
"WeaveService",
498
() => Cc["@mozilla.org/weave/service;1"].getService().wrappedJSObject
499
);
500
501
// lazy module getters
502
503
XPCOMUtils.defineLazyModuleGetters(this, {
504
AboutNetErrorHandler:
506
AboutPrivateBrowsingHandler:
508
AboutProtectionsHandler:
516
BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
517
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
518
ContextualIdentityService:
528
LiveBookmarkMigrator: "resource:///modules/LiveBookmarkMigrator.jsm",
542
ProcessHangMonitor: "resource:///modules/ProcessHangMonitor.jsm",
545
RemoteSecuritySettings:
551
SearchTelemetry: "resource:///modules/SearchTelemetry.jsm",
561
});
562
563
// eslint-disable-next-line no-unused-vars
564
XPCOMUtils.defineLazyModuleGetters(this, {
565
AboutLoginsParent: "resource:///modules/AboutLoginsParent.jsm",
568
PluginManager: "resource:///actors/PluginParent.jsm",
570
});
571
572
/**
573
* IF YOU ADD OR REMOVE FROM THIS LIST, PLEASE UPDATE THE LIST ABOVE AS WELL.
574
* XXX Bug 1325373 is for making eslint detect these automatically.
575
*/
576
577
let initializedModules = {};
578
579
[
580
[
581
"ContentPrefServiceParent",
583
"alwaysInit",
584
],
585
["ContentSearch", "resource:///modules/ContentSearch.jsm", "init"],
586
["UpdateListener", "resource://gre/modules/UpdateListener.jsm", "init"],
587
["webrtcUI", "resource:///modules/webrtcUI.jsm", "init"],
588
].forEach(([name, resource, init]) => {
589
XPCOMUtils.defineLazyGetter(this, name, () => {
590
ChromeUtils.import(resource, initializedModules);
591
initializedModules[name][init]();
592
return initializedModules[name];
593
});
594
});
595
596
if (AppConstants.MOZ_CRASHREPORTER) {
597
XPCOMUtils.defineLazyModuleGetters(this, {
598
UnsubmittedCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
599
});
600
}
601
602
XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
603
return Services.strings.createBundle(
605
);
606
});
607
608
XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
609
return Services.strings.createBundle(
611
);
612
});
613
614
XPCOMUtils.defineLazyGetter(this, "gTabbrowserBundle", function() {
615
return Services.strings.createBundle(
617
);
618
});
619
620
const global = this;
621
622
const listeners = {
623
observers: {
624
"update-staged": ["UpdateListener"],
625
"update-downloaded": ["UpdateListener"],
626
"update-available": ["UpdateListener"],
627
"update-error": ["UpdateListener"],
628
"gmp-plugin-crash": ["PluginManager"],
629
"plugin-crashed": ["PluginManager"],
630
},
631
632
ppmm: {
633
// PLEASE KEEP THIS LIST IN SYNC WITH THE LISTENERS ADDED IN ContentPrefServiceParent.init
634
"ContentPrefs:FunctionCall": ["ContentPrefServiceParent"],
635
"ContentPrefs:AddObserverForName": ["ContentPrefServiceParent"],
636
"ContentPrefs:RemoveObserverForName": ["ContentPrefServiceParent"],
637
// PLEASE KEEP THIS LIST IN SYNC WITH THE LISTENERS ADDED IN ContentPrefServiceParent.init
638
639
// PLEASE KEEP THIS LIST IN SYNC WITH THE LISTENERS ADDED IN AsyncPrefs.init
640
"AsyncPrefs:SetPref": ["AsyncPrefs"],
641
"AsyncPrefs:ResetPref": ["AsyncPrefs"],
642
// PLEASE KEEP THIS LIST IN SYNC WITH THE LISTENERS ADDED IN AsyncPrefs.init
643
644
"webrtc:UpdateGlobalIndicators": ["webrtcUI"],
645
"webrtc:UpdatingIndicators": ["webrtcUI"],
646
},
647
648
mm: {
649
"AboutLogins:CreateLogin": ["AboutLoginsParent"],
650
"AboutLogins:DeleteLogin": ["AboutLoginsParent"],
651
"AboutLogins:DismissBreachAlert": ["AboutLoginsParent"],
652
"AboutLogins:HideFooter": ["AboutLoginsParent"],
653
"AboutLogins:Import": ["AboutLoginsParent"],
654
"AboutLogins:MasterPasswordRequest": ["AboutLoginsParent"],
655
"AboutLogins:OpenFAQ": ["AboutLoginsParent"],
656
"AboutLogins:GetHelp": ["AboutLoginsParent"],
657
"AboutLogins:OpenPreferences": ["AboutLoginsParent"],
658
"AboutLogins:OpenMobileAndroid": ["AboutLoginsParent"],
659
"AboutLogins:OpenMobileIos": ["AboutLoginsParent"],
660
"AboutLogins:OpenSite": ["AboutLoginsParent"],
661
"AboutLogins:SortChanged": ["AboutLoginsParent"],
662
"AboutLogins:Subscribe": ["AboutLoginsParent"],
663
"AboutLogins:SyncEnable": ["AboutLoginsParent"],
664
"AboutLogins:SyncOptions": ["AboutLoginsParent"],
665
"AboutLogins:UpdateLogin": ["AboutLoginsParent"],
666
"Content:Click": ["ContentClick"],
667
ContentSearch: ["ContentSearch"],
668
"Reader:FaviconRequest": ["ReaderParent"],
669
"Reader:UpdateReaderButton": ["ReaderParent"],
670
"rtcpeer:CancelRequest": ["webrtcUI"],
671
"rtcpeer:Request": ["webrtcUI"],
672
"webrtc:CancelRequest": ["webrtcUI"],
673
"webrtc:Request": ["webrtcUI"],
674
"webrtc:StopRecording": ["webrtcUI"],
675
"webrtc:UpdateBrowserIndicators": ["webrtcUI"],
676
},
677
678
observe(subject, topic, data) {
679
for (let module of this.observers[topic]) {
680
try {
681
global[module].observe(subject, topic, data);
682
} catch (e) {
683
Cu.reportError(e);
684
}
685
}
686
},
687
688
receiveMessage(modules, data) {
689
let val;
690
for (let module of modules[data.name]) {
691
try {
692
val = global[module].receiveMessage(data) || val;
693
} catch (e) {
694
Cu.reportError(e);
695
}
696
}
697
return val;
698
},
699
700
init() {
701
for (let observer of Object.keys(this.observers)) {
702
Services.obs.addObserver(this, observer);
703
}
704
705
let receiveMessageMM = this.receiveMessage.bind(this, this.mm);
706
for (let message of Object.keys(this.mm)) {
707
Services.mm.addMessageListener(message, receiveMessageMM);
708
}
709
710
let receiveMessagePPMM = this.receiveMessage.bind(this, this.ppmm);
711
for (let message of Object.keys(this.ppmm)) {
712
Services.ppmm.addMessageListener(message, receiveMessagePPMM);
713
}
714
},
715
};
716
717
// Seconds of idle before trying to create a bookmarks backup.
718
const BOOKMARKS_BACKUP_IDLE_TIME_SEC = 8 * 60;
719
// Minimum interval between backups. We try to not create more than one backup
720
// per interval.
721
const BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS = 1;
722
// Maximum interval between backups. If the last backup is older than these
723
// days we will try to create a new one more aggressively.
724
const BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS = 3;
725
// Seconds of idle time before the late idle tasks will be scheduled.
726
const LATE_TASKS_IDLE_TIME_SEC = 20;
727
// Time after we stop tracking startup crashes.
728
const STARTUP_CRASHES_END_DELAY_MS = 30 * 1000;
729
730
/*
731
* OS X has the concept of zero-window sessions and therefore ignores the
732
* browser-lastwindow-close-* topics.
733
*/
734
const OBSERVE_LASTWINDOW_CLOSE_TOPICS = AppConstants.platform != "macosx";
735
736
function BrowserGlue() {
737
XPCOMUtils.defineLazyServiceGetter(
738
this,
739
"_idleService",
740
"@mozilla.org/widget/idleservice;1",
741
"nsIIdleService"
742
);
743
744
XPCOMUtils.defineLazyGetter(this, "_distributionCustomizer", function() {
745
const { DistributionCustomizer } = ChromeUtils.import(
747
);
748
return new DistributionCustomizer();
749
});
750
751
XPCOMUtils.defineLazyServiceGetter(
752
this,
753
"AlertsService",
754
"@mozilla.org/alerts-service;1",
755
"nsIAlertsService"
756
);
757
758
this._init();
759
}
760
761
BrowserGlue.prototype = {
762
_saveSession: false,
763
_migrationImportsDefaultBookmarks: false,
764
_placesBrowserInitComplete: false,
765
_isNewProfile: undefined,
766
767
_setPrefToSaveSession: function BG__setPrefToSaveSession(aForce) {
768
if (!this._saveSession && !aForce) {
769
return;
770
}
771
772
if (!PrivateBrowsingUtils.permanentPrivateBrowsing) {
773
Services.prefs.setBoolPref(
774
"browser.sessionstore.resume_session_once",
775
true
776
);
777
}
778
779
// This method can be called via [NSApplication terminate:] on Mac, which
780
// ends up causing prefs not to be flushed to disk, so we need to do that
781
// explicitly here. See bug 497652.
782
Services.prefs.savePrefFile(null);
783
},
784
785
_setSyncAutoconnectDelay: function BG__setSyncAutoconnectDelay() {
786
// Assume that a non-zero value for services.sync.autoconnectDelay should override
787
if (Services.prefs.prefHasUserValue("services.sync.autoconnectDelay")) {
788
let prefDelay = Services.prefs.getIntPref(
789
"services.sync.autoconnectDelay"
790
);
791
792
if (prefDelay > 0) {
793
return;
794
}
795
}
796
797
// delays are in seconds
798
const MAX_DELAY = 300;
799
let delay = 3;
800
for (let win of Services.wm.getEnumerator("navigator:browser")) {
801
// browser windows without a gBrowser almost certainly means we are
802
// shutting down, so instead of just ignoring that window we abort.
803
if (win.closed || !win.gBrowser) {
804
return;
805
}
806
delay += win.gBrowser.tabs.length;
807
}
808
delay = delay <= MAX_DELAY ? delay : MAX_DELAY;
809
810
const { Weave } = ChromeUtils.import("resource://services-sync/main.js");
811
Weave.Service.scheduler.delayedAutoConnect(delay);
812
},
813
814
/**
815
* Lazily initialize PingCentre
816
*/
817
get pingCentre() {
818
const MAIN_TOPIC_ID = "main";
819
Object.defineProperty(this, "pingCentre", {
820
value: new PingCentre({ topic: MAIN_TOPIC_ID }),
821
});
822
return this.pingCentre;
823
},
824
825
_sendMainPingCentrePing() {
826
let newTabSetting;
827
let homePageSetting;
828
829
// Check whether or not about:home and about:newtab have been overridden at this point.
830
// Different settings are encoded as follows:
831
// * Value 0: default
832
// * Value 1: about:blank
833
// * Value 2: web extension
834
// * Value 3: other custom URL(s)
835
// Settings for about:newtab and about:home are combined in a bitwise manner.
836
837
// Note that a user could use about:blank and web extension at the same time
838
// to overwrite the about:newtab, but the web extension takes priority, so the
839
// ordering matters in the following check.
840
if (
841
Services.prefs.getBoolPref("browser.newtabpage.enabled") &&
842
!aboutNewTabService.overridden
843
) {
844
newTabSetting = 0;
845
} else if (aboutNewTabService.newTabURL.startsWith("moz-extension://")) {
846
newTabSetting = 2;
847
} else if (!Services.prefs.getBoolPref("browser.newtabpage.enabled")) {
848
newTabSetting = 1;
849
} else {
850
newTabSetting = 3;
851
}
852
853
const homePageURL = HomePage.get();
854
if (homePageURL === "about:home") {
855
homePageSetting = 0;
856
} else if (homePageURL === "about:blank") {
857
homePageSetting = 1;
858
} else if (homePageURL.startsWith("moz-extension://")) {
859
homePageSetting = 2;
860
} else {
861
homePageSetting = 3;
862
}
863
864
const payload = {
865
event: "AS_ENABLED",
866
value: newTabSetting | (homePageSetting << 2),
867
};
868
const ACTIVITY_STREAM_ID = "activity-stream";
869
const options = { filter: ACTIVITY_STREAM_ID };
870
this.pingCentre.sendPing(payload, options);
871
},
872
873
// nsIObserver implementation
874
observe: async function BG_observe(subject, topic, data) {
875
switch (topic) {
876
case "notifications-open-settings":
877
this._openPreferences("privacy-permissions");
878
break;
879
case "final-ui-startup":
880
this._beforeUIStartup();
881
break;
882
case "browser-delayed-startup-finished":
883
this._onFirstWindowLoaded(subject);
884
Services.obs.removeObserver(this, "browser-delayed-startup-finished");
885
break;
886
case "sessionstore-windows-restored":
887
this._onWindowsRestored();
888
break;
889
case "browser:purge-session-history":
890
// reset the console service's error buffer
891
Services.console.logStringMessage(null); // clear the console (in case it's open)
892
Services.console.reset();
893
break;
894
case "restart-in-safe-mode":
895
this._onSafeModeRestart();
896
break;
897
case "quit-application-requested":
898
this._onQuitRequest(subject, data);
899
break;
900
case "quit-application-granted":
901
this._onQuitApplicationGranted();
902
break;
903
case "browser-lastwindow-close-requested":
904
if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
905
// The application is not actually quitting, but the last full browser
906
// window is about to be closed.
907
this._onQuitRequest(subject, "lastwindow");
908
}
909
break;
910
case "browser-lastwindow-close-granted":
911
if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
912
this._setPrefToSaveSession();
913
}
914
break;
915
case "weave:service:ready":
916
this._setSyncAutoconnectDelay();
917
break;
918
case "fxaccounts:onverified":
919
this._onThisDeviceConnected();
920
break;
921
case "fxaccounts:device_connected":
922
this._onDeviceConnected(data);
923
break;
924
case "fxaccounts:verify_login":
925
this._onVerifyLoginNotification(JSON.parse(data));
926
break;
927
case "fxaccounts:device_disconnected":
928
data = JSON.parse(data);
929
if (data.isLocalDevice) {
930
this._onDeviceDisconnected();
931
}
932
break;
933
case "fxaccounts:commands:open-uri":
934
case "weave:engine:clients:display-uris":
935
this._onDisplaySyncURIs(subject);
936
break;
937
case "session-save":
938
this._setPrefToSaveSession(true);
939
subject.QueryInterface(Ci.nsISupportsPRBool);
940
subject.data = true;
941
break;
942
case "places-init-complete":
943
Services.obs.removeObserver(this, "places-init-complete");
944
if (!this._migrationImportsDefaultBookmarks) {
945
this._initPlaces(false);
946
}
947
break;
948
case "idle":
949
this._backupBookmarks();
950
break;
951
case "distribution-customization-complete":
952
Services.obs.removeObserver(
953
this,
954
"distribution-customization-complete"
955
);
956
// Customization has finished, we don't need the customizer anymore.
957
delete this._distributionCustomizer;
958
break;
959
case "browser-glue-test": // used by tests
960
if (data == "force-ui-migration") {
961
this._migrateUI();
962
} else if (data == "force-distribution-customization") {
963
this._distributionCustomizer.applyCustomizations();
964
// To apply distribution bookmarks use "places-init-complete".
965
} else if (data == "force-places-init") {
966
this._initPlaces(false);
967
} else if (data == "mock-alerts-service") {
968
Object.defineProperty(this, "AlertsService", {
969
value: subject.wrappedJSObject,
970
});
971
} else if (data == "places-browser-init-complete") {
972
if (this._placesBrowserInitComplete) {
973
Services.obs.notifyObservers(null, "places-browser-init-complete");
974
}
975
} else if (data == "migrateMatchBucketsPrefForUI66") {
976
this._migrateMatchBucketsPrefForUI66().then(() => {
977
Services.obs.notifyObservers(
978
null,
979
"browser-glue-test",
980
"migrateMatchBucketsPrefForUI66-done"
981
);
982
});
983
} else if (data == "add-breaches-sync-handler") {
984
this._addBreachesSyncHandler();
985
}
986
break;
987
case "initial-migration-will-import-default-bookmarks":
988
this._migrationImportsDefaultBookmarks = true;
989
break;
990
case "initial-migration-did-import-default-bookmarks":
991
this._initPlaces(true);
992
break;
993
case "handle-xul-text-link":
994
let linkHandled = subject.QueryInterface(Ci.nsISupportsPRBool);
995
if (!linkHandled.data) {
996
let win = BrowserWindowTracker.getTopWindow();
997
if (win) {
998
data = JSON.parse(data);
999
let where = win.whereToOpenLink(data);
1000
// Preserve legacy behavior of non-modifier left-clicks
1001
// opening in a new selected tab.
1002
if (where == "current") {
1003
where = "tab";
1004
}
1005
win.openTrustedLinkIn(data.href, where);
1006
linkHandled.data = true;
1007
}
1008
}
1009
break;
1010
case "profile-before-change":
1011
// Any component depending on Places should be finalized in
1012
// _onPlacesShutdown. Any component that doesn't need to act after
1013
// the UI has gone should be finalized in _onQuitApplicationGranted.
1014
this._dispose();
1015
break;
1016
case "keyword-search":
1017
// This notification is broadcast by the docshell when it "fixes up" a
1018
// URI that it's been asked to load into a keyword search.
1019
let engine = null;
1020
try {
1021
engine = subject.QueryInterface(Ci.nsISearchEngine);
1022
} catch (ex) {
1023
Cu.reportError(ex);
1024
}
1025
let win = BrowserWindowTracker.getTopWindow();
1026
win.BrowserSearch.recordSearchInTelemetry(engine, "urlbar");
1027
break;
1028
case "browser-search-engine-modified":
1029
// Ensure we cleanup the hiddenOneOffs pref when removing
1030
// an engine, and that newly added engines are visible.
1031
if (data == "engine-added" || data == "engine-removed") {
1032
let engineName = subject.QueryInterface(Ci.nsISearchEngine).name;
1033
let pref = Services.prefs.getStringPref(
1034
"browser.search.hiddenOneOffs"
1035
);
1036
let hiddenList = pref ? pref.split(",") : [];
1037
hiddenList = hiddenList.filter(x => x !== engineName);
1038
Services.prefs.setStringPref(
1039
"browser.search.hiddenOneOffs",
1040
hiddenList.join(",")
1041
);
1042
}
1043
break;
1044
case "flash-plugin-hang":
1045
this._handleFlashHang();
1046
break;
1047
case "xpi-signature-changed":
1048
let disabledAddons = JSON.parse(data).disabled;
1049
let addons = await AddonManager.getAddonsByIDs(disabledAddons);
1050
if (addons.some(addon => addon)) {
1051
this._notifyUnsignedAddonsDisabled();
1052
}
1053
break;
1054
case "sync-ui-state:update":
1055
this._updateFxaBadges();
1056
break;
1057
case "handlersvc-store-initialized":
1058
// Initialize PdfJs when running in-process and remote. This only
1059
// happens once since PdfJs registers global hooks. If the PdfJs
1060
// extension is installed the init method below will be overridden
1061
// leaving initialization to the extension.
1062
// parent only: configure default prefs, set up pref observers, register
1063
// pdf content handler, and initializes parent side message manager
1064
// shim for privileged api access.
1065
PdfJs.init();
1066
break;
1067
case "shield-init-complete":
1068
this._shieldInitComplete = true;
1069
this._sendMainPingCentrePing();
1070
break;
1071
}
1072
},
1073
1074
// initialization (called on application startup)
1075
_init: function BG__init() {
1076
let os = Services.obs;
1077
os.addObserver(this, "notifications-open-settings");
1078
os.addObserver(this, "final-ui-startup");
1079
os.addObserver(this, "browser-delayed-startup-finished");
1080
os.addObserver(this, "sessionstore-windows-restored");
1081
os.addObserver(this, "browser:purge-session-history");
1082
os.addObserver(this, "quit-application-requested");
1083
os.addObserver(this, "quit-application-granted");
1084
if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
1085
os.addObserver(this, "browser-lastwindow-close-requested");
1086
os.addObserver(this, "browser-lastwindow-close-granted");
1087
}
1088
os.addObserver(this, "weave:service:ready");
1089
os.addObserver(this, "fxaccounts:onverified");
1090
os.addObserver(this, "fxaccounts:device_connected");
1091
os.addObserver(this, "fxaccounts:verify_login");
1092
os.addObserver(this, "fxaccounts:device_disconnected");
1093
os.addObserver(this, "fxaccounts:commands:open-uri");
1094
os.addObserver(this, "weave:engine:clients:display-uris");
1095
os.addObserver(this, "session-save");
1096
os.addObserver(this, "places-init-complete");
1097
os.addObserver(this, "distribution-customization-complete");
1098
os.addObserver(this, "handle-xul-text-link");
1099
os.addObserver(this, "profile-before-change");
1100
os.addObserver(this, "keyword-search");
1101
os.addObserver(this, "browser-search-engine-modified");
1102
os.addObserver(this, "restart-in-safe-mode");
1103
os.addObserver(this, "flash-plugin-hang");
1104
os.addObserver(this, "xpi-signature-changed");
1105
os.addObserver(this, "sync-ui-state:update");
1106
os.addObserver(this, "handlersvc-store-initialized");
1107
os.addObserver(this, "shield-init-complete");
1108
1109
ActorManagerParent.addActors(ACTORS);
1110
ActorManagerParent.addLegacyActors(LEGACY_ACTORS);
1111
ActorManagerParent.flush();
1112
1113
this._flashHangCount = 0;
1114
this._firstWindowReady = new Promise(
1115
resolve => (this._firstWindowLoaded = resolve)
1116
);
1117
if (AppConstants.platform == "win") {
1118
JawsScreenReaderVersionCheck.init();
1119
}
1120
},
1121
1122
// cleanup (called on application shutdown)
1123
_dispose: function BG__dispose() {
1124
let os = Services.obs;
1125
os.removeObserver(this, "notifications-open-settings");
1126
os.removeObserver(this, "final-ui-startup");
1127
os.removeObserver(this, "sessionstore-windows-restored");
1128
os.removeObserver(this, "browser:purge-session-history");
1129
os.removeObserver(this, "quit-application-requested");
1130
os.removeObserver(this, "quit-application-granted");
1131
os.removeObserver(this, "restart-in-safe-mode");
1132
if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
1133
os.removeObserver(this, "browser-lastwindow-close-requested");
1134
os.removeObserver(this, "browser-lastwindow-close-granted");
1135
}
1136
os.removeObserver(this, "weave:service:ready");
1137
os.removeObserver(this, "fxaccounts:onverified");
1138
os.removeObserver(this, "fxaccounts:device_connected");
1139
os.removeObserver(this, "fxaccounts:verify_login");
1140
os.removeObserver(this, "fxaccounts:device_disconnected");
1141
os.removeObserver(this, "fxaccounts:commands:open-uri");
1142
os.removeObserver(this, "weave:engine:clients:display-uris");
1143
os.removeObserver(this, "session-save");
1144
if (this._bookmarksBackupIdleTime) {
1145
this._idleService.removeIdleObserver(this, this._bookmarksBackupIdleTime);
1146
delete this._bookmarksBackupIdleTime;
1147
}
1148
if (this._lateTasksIdleObserver) {
1149
this._idleService.removeIdleObserver(
1150
this._lateTasksIdleObserver,
1151
LATE_TASKS_IDLE_TIME_SEC
1152
);
1153
delete this._lateTasksIdleObserver;
1154
}
1155
if (this._gmpInstallManager) {
1156
this._gmpInstallManager.uninit();
1157
delete this._gmpInstallManager;
1158
}
1159
try {
1160
os.removeObserver(this, "places-init-complete");
1161
} catch (ex) {
1162
/* Could have been removed already */
1163
}
1164
os.removeObserver(this, "handle-xul-text-link");
1165
os.removeObserver(this, "profile-before-change");
1166
os.removeObserver(this, "keyword-search");
1167
os.removeObserver(this, "browser-search-engine-modified");
1168
os.removeObserver(this, "flash-plugin-hang");
1169
os.removeObserver(this, "xpi-signature-changed");
1170
os.removeObserver(this, "sync-ui-state:update");
1171
os.removeObserver(this, "shield-init-complete");
1172
1173
Services.prefs.removeObserver(
1174
"permissions.eventTelemetry.enabled",
1175
this._togglePermissionPromptTelemetry
1176
);
1177
Services.prefs.removeObserver(
1178
"privacy.trackingprotection",
1179
this._matchCBCategory
1180
);
1181
Services.prefs.removeObserver(
1182
"network.cookie.cookieBehavior",
1183
this._matchCBCategory
1184
);
1185
Services.prefs.removeObserver(
1186
ContentBlockingCategoriesPrefs.PREF_CB_CATEGORY,
1187
this._updateCBCategory
1188
);
1189
Services.prefs.removeObserver(
1190
"privacy.trackingprotection",
1191
this._setPrefExpectations
1192
);
1193
Services.prefs.removeObserver(
1194
"browser.contentblocking.features.strict",
1195
this._setPrefExpectationsAndUpdate
1196
);
1197
},
1198
1199
// runs on startup, before the first command line handler is invoked
1200
// (i.e. before the first window is opened)
1201
_beforeUIStartup: function BG__beforeUIStartup() {
1202
SessionStartup.init();
1203
1204
if (Services.prefs.prefHasUserValue(PREF_PDFJS_ENABLED_CACHE_STATE)) {
1205
Services.ppmm.sharedData.set(
1206
"pdfjs.enabled",
1207
Services.prefs.getBoolPref(PREF_PDFJS_ENABLED_CACHE_STATE)
1208
);
1209
} else {
1210
PdfJs.earlyInit();
1211
}
1212
1213
// check if we're in safe mode
1214
if (Services.appinfo.inSafeMode) {
1215
Services.ww.openWindow(
1216
null,
1218
"_blank",
1219
"chrome,centerscreen,modal,resizable=no",
1220
null
1221
);
1222
}
1223
1224
// apply distribution customizations
1225
this._distributionCustomizer.applyCustomizations();
1226
1227
// handle any UI migration
1228
this._migrateUI();
1229
1230
listeners.init();
1231
1232
SessionStore.init();
1233
1234
AddonManager.maybeInstallBuiltinAddon(
1235
"firefox-compact-light@mozilla.org",
1236
"1.0",
1238
);
1239
AddonManager.maybeInstallBuiltinAddon(
1240
"firefox-compact-dark@mozilla.org",
1241
"1.0",
1243
);
1244
1245
if (AppConstants.MOZ_NORMANDY) {
1246
Normandy.init();
1247
}
1248
1249
SaveToPocket.init();
1250
Services.obs.notifyObservers(null, "browser-ui-startup-complete");
1251
},
1252
1253
_checkForOldBuildUpdates() {
1254
// check for update if our build is old
1255
if (
1256
AppConstants.MOZ_UPDATER &&
1257
Services.prefs.getBoolPref("app.update.checkInstallTime")
1258
) {
1259
let buildID = Services.appinfo.appBuildID;
1260
let today = new Date().getTime();
1261
/* eslint-disable no-multi-spaces */
1262
let buildDate = new Date(
1263
buildID.slice(0, 4), // year
1264
buildID.slice(4, 6) - 1, // months are zero-based.
1265
buildID.slice(6, 8), // day
1266
buildID.slice(8, 10), // hour
1267
buildID.slice(10, 12), // min
1268
buildID.slice(12, 14)
1269
) // ms
1270
.getTime();
1271
/* eslint-enable no-multi-spaces */
1272
1273
const millisecondsIn24Hours = 86400000;
1274
let acceptableAge =
1275
Services.prefs.getIntPref("app.update.checkInstallTime.days") *
1276
millisecondsIn24Hours;
1277
1278
if (buildDate + acceptableAge < today) {
1279
Cc["@mozilla.org/updates/update-service;1"]
1280
.getService(Ci.nsIApplicationUpdateService)
1281
.checkForBackgroundUpdates();
1282
}
1283
}
1284
},
1285
1286
_onSafeModeRestart: function BG_onSafeModeRestart() {
1287
// prompt the user to confirm
1288
let strings = gBrowserBundle;
1289
let promptTitle = strings.GetStringFromName("safeModeRestartPromptTitle");
1290
let promptMessage = strings.GetStringFromName(
1291
"safeModeRestartPromptMessage"
1292
);
1293
let restartText = strings.GetStringFromName("safeModeRestartButton");
1294
let buttonFlags =
1295
Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
1296
Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_CANCEL +
1297
Services.prompt.BUTTON_POS_0_DEFAULT;
1298
1299
let rv = Services.prompt.confirmEx(
1300
null,
1301
promptTitle,
1302
promptMessage,
1303
buttonFlags,
1304
restartText,
1305
null,
1306
null,
1307
null,
1308
{}
1309
);
1310
if (rv != 0) {
1311
return;
1312
}
1313
1314
let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(
1315
Ci.nsISupportsPRBool
1316
);
1317
Services.obs.notifyObservers(
1318
cancelQuit,
1319
"quit-application-requested",
1320
"restart"
1321
);
1322
1323
if (!cancelQuit.data) {
1324
Services.startup.restartInSafeMode(Ci.nsIAppStartup.eAttemptQuit);
1325
}
1326
},
1327
1328
_trackSlowStartup() {
1329
if (
1330
Services.startup.interrupted ||
1331
Services.prefs.getBoolPref("browser.slowStartup.notificationDisabled")
1332
) {
1333
return;
1334
}
1335
1336
let currentTime = Date.now() - Services.startup.getStartupInfo().process;
1337
let averageTime = 0;
1338
let samples = 0;
1339
try {
1340
averageTime = Services.prefs.getIntPref(
1341
"browser.slowStartup.averageTime"
1342
);
1343
samples = Services.prefs.getIntPref("browser.slowStartup.samples");
1344
} catch (e) {}
1345
1346
let totalTime = averageTime * samples + currentTime;
1347
samples++;
1348
averageTime = totalTime / samples;
1349
1350
if (
1351
samples >= Services.prefs.getIntPref("browser.slowStartup.maxSamples")
1352
) {
1353
if (
1354
averageTime >
1355
Services.prefs.getIntPref("browser.slowStartup.timeThreshold")
1356
) {
1357
this._calculateProfileAgeInDays().then(
1358
this._showSlowStartupNotification,
1359
null
1360
);
1361
}
1362
averageTime = 0;
1363
samples = 0;
1364
}
1365
1366
Services.prefs.setIntPref("browser.slowStartup.averageTime", averageTime);
1367
Services.prefs.setIntPref("browser.slowStartup.samples", samples);
1368
},
1369
1370
async _calculateProfileAgeInDays() {
1371
let ProfileAge = ChromeUtils.import(
1373
{}
1374
).ProfileAge;
1375
let profileAge = await ProfileAge();
1376
1377
let creationDate = await profileAge.created;
1378
let resetDate = await profileAge.reset;
1379
1380
// if the profile was reset, consider the
1381
// reset date for its age.
1382
let profileDate = resetDate || creationDate;
1383
1384
const ONE_DAY = 24 * 60 * 60 * 1000;
1385
return (Date.now() - profileDate) / ONE_DAY;
1386
},
1387
1388
_showSlowStartupNotification(profileAge) {
1389
if (profileAge < 90) {
1390
// 3 months
1391
return;
1392
}
1393
1394
let win = BrowserWindowTracker.getTopWindow();
1395
if (!win) {
1396
return;
1397
}
1398
1399
let productName = gBrandBundle.GetStringFromName("brandFullName");
1400
let message = win.gNavigatorBundle.getFormattedString(
1401
"slowStartup.message",
1402
[productName]
1403
);
1404
1405
let buttons = [
1406
{
1407
label: win.gNavigatorBundle.getString("slowStartup.helpButton.label"),
1408
accessKey: win.gNavigatorBundle.getString(
1409
"slowStartup.helpButton.accesskey"
1410
),
1411
callback() {
1412
win.openTrustedLinkIn(
1414
"tab"
1415
);
1416
},
1417
},
1418
{
1419
label: win.gNavigatorBundle.getString(
1420
"slowStartup.disableNotificationButton.label"
1421
),
1422
accessKey: win.gNavigatorBundle.getString(
1423
"slowStartup.disableNotificationButton.accesskey"
1424
),
1425
callback() {
1426
Services.prefs.setBoolPref(
1427
"browser.slowStartup.notificationDisabled",
1428
true
1429
);
1430
},
1431
},
1432
];
1433
1434
win.gNotificationBox.appendNotification(
1435
message,
1436
"slow-startup",
1438
win.gNotificationBox.PRIORITY_INFO_LOW,
1439
buttons
1440
);
1441
},
1442
1443
/**
1444
* Show a notification bar offering a reset.
1445
*
1446
* @param reason
1447
* String of either "unused" or "uninstall", specifying the reason
1448
* why a profile reset is offered.
1449
*/
1450
_resetProfileNotification(reason) {
1451
let win = BrowserWindowTracker.getTopWindow();
1452
if (!win) {
1453
return;
1454
}
1455
1456
const { ResetProfile } = ChromeUtils.import(
1458
);
1459
if (!ResetProfile.resetSupported()) {
1460
return;
1461
}
1462
1463
let productName = gBrandBundle.GetStringFromName("brandShortName");
1464
let resetBundle = Services.strings.createBundle(
1466
);
1467
1468
let message;
1469
if (reason == "unused") {
1470
message = resetBundle.formatStringFromName("resetUnusedProfile.message", [
1471
productName,
1472
]);
1473
} else if (reason == "uninstall") {
1474
message = resetBundle.formatStringFromName("resetUninstalled.message", [
1475
productName,
1476
]);
1477
} else {
1478
throw new Error(
1479
`Unknown reason (${reason}) given to _resetProfileNotification.`
1480
);
1481
}
1482
let buttons = [
1483
{
1484
label: resetBundle.formatStringFromName(
1485
"refreshProfile.resetButton.label",
1486
[productName]
1487
),
1488
accessKey: resetBundle.GetStringFromName(
1489
"refreshProfile.resetButton.accesskey"
1490
),
1491
callback() {
1492
ResetProfile.openConfirmationDialog(win);
1493
},
1494
},
1495
];
1496
1497
win.gNotificationBox.appendNotification(
1498
message,
1499
"reset-profile-notification",
1501
win.gNotificationBox.PRIORITY_INFO_LOW,
1502
buttons
1503
);
1504
},
1505
1506
_notifyUnsignedAddonsDisabled() {
1507
let win = BrowserWindowTracker.getTopWindow();
1508
if (!win) {
1509
return;
1510
}
1511
1512
let message = win.gNavigatorBundle.getString(
1513
"unsignedAddonsDisabled.message"
1514
);
1515
let buttons = [
1516
{
1517
label: win.gNavigatorBundle.getString(
1518
"unsignedAddonsDisabled.learnMore.label"
1519
),
1520
accessKey: win.gNavigatorBundle.getString(
1521
"unsignedAddonsDisabled.learnMore.accesskey"
1522
),
1523
callback() {
1524
win.BrowserOpenAddonsMgr("addons://list/extension?unsigned=true");
1525
},
1526
},
1527
];
1528
1529
win.gHighPriorityNotificationBox.appendNotification(
1530
message,
1531
"unsigned-addons-disabled",
1532
"",
1533
win.gHighPriorityNotificationBox.PRIORITY_WARNING_MEDIUM,
1534
buttons
1535
);
1536
},
1537
1538
_firstWindowTelemetry(aWindow) {
1539
let scaling = aWindow.devicePixelRatio * 100;
1540
try {
1541
Services.telemetry.getHistogramById("DISPLAY_SCALING").add(scaling);
1542
} catch (ex) {}
1543
},
1544
1545
_collectStartupConditionsTelemetry() {
1546
let nowSeconds = Math.round(Date.now() / 1000);
1547
// Don't include cases where we don't have the pref. This rules out the first install
1548
// as well as the first run of a build since this was introduced. These could by some
1549
// definitions be referred to as "cold" startups, but probably not since we likely
1550
// just wrote many of the files we use to disk. This way we should approximate a lower
1551
// bound to the number of cold startups rather than an upper bound.
1552
let lastCheckSeconds = Services.prefs.getIntPref(
1553
"browser.startup.lastColdStartupCheck",
1554
nowSeconds
1555
);
1556
Services.prefs.setIntPref(
1557
"browser.startup.lastColdStartupCheck",
1558
nowSeconds
1559
);
1560
try {
1561
let secondsSinceLastOSRestart =
1562
Services.startup.secondsSinceLastOSRestart;
1563
let isColdStartup =
1564
nowSeconds - secondsSinceLastOSRestart > lastCheckSeconds;
1565
Services.telemetry.scalarSet("startup.is_cold", isColdStartup);
1566
} catch (ex) {
1567
Cu.reportError(ex);
1568
}
1569
},
1570
1571
// the first browser window has finished initializing
1572
_onFirstWindowLoaded: function BG__onFirstWindowLoaded(aWindow) {
1573
TabCrashHandler.init();
1574
1575
ProcessHangMonitor.init();
1576
1577
// A channel for "remote troubleshooting" code...
1578
let channel = new WebChannel(
1579
"remote-troubleshooting",
1580
"remote-troubleshooting"
1581
);
1582
channel.listen((id, data, target) => {
1583
if (data.command == "request") {
1584
let { Troubleshoot } = ChromeUtils.import(
1586
);
1587
Troubleshoot.snapshot(snapshotData => {
1588
// for privacy we remove crash IDs and all preferences (but bug 1091944
1589
// exists to expose prefs once we are confident of privacy implications)
1590
delete snapshotData.crashes;
1591
delete snapshotData.modifiedPreferences;
1592
channel.send(snapshotData, target);
1593
});
1594
}
1595
});
1596
1597
this._trackSlowStartup();
1598
1599
// Offer to reset a user's profile if it hasn't been used for 60 days.
1600
const OFFER_PROFILE_RESET_INTERVAL_MS = 60 * 24 * 60 * 60 * 1000;
1601
let lastUse = Services.appinfo.replacedLockTime;
1602
let disableResetPrompt = Services.prefs.getBoolPref(
1603
"browser.disableResetPrompt",
1604
false
1605
);
1606
1607
if (
1608
!disableResetPrompt &&
1609
lastUse &&
1610
Date.now() - lastUse >= OFFER_PROFILE_RESET_INTERVAL_MS
1611
) {
1612
this._resetProfileNotification("unused");
1613
} else if (AppConstants.platform == "win" && !disableResetPrompt) {
1614
// Check if we were just re-installed and offer Firefox Reset
1615
let updateChannel;
1616
try {
1617
updateChannel = ChromeUtils.import(
1619
{}
1620
).UpdateUtils.UpdateChannel;
1621
} catch (ex) {}
1622
if (updateChannel) {
1623
let uninstalledValue = WindowsRegistry.readRegKey(
1624
Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
1625
"Software\\Mozilla\\Firefox",
1626
`Uninstalled-${updateChannel}`
1627
);
1628
let removalSuccessful = WindowsRegistry.removeRegKey(
1629
Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
1630
"Software\\Mozilla\\Firefox",
1631
`Uninstalled-${updateChannel}`
1632
);
1633
if (removalSuccessful && uninstalledValue == "True") {
1634
this._resetProfileNotification("uninstall");
1635
}
1636
}
1637
}
1638
1639
this._checkForOldBuildUpdates();
1640
1641
// Check if Sync is configured
1642
if (Services.prefs.prefHasUserValue("services.sync.username")) {
1643
WeaveService.init();
1644
}
1645
1646
PageThumbs.init();
1647
1648
NewTabUtils.init();
1649
1650
AboutNetErrorHandler.init();
1651
1652
AboutPrivateBrowsingHandler.init();
1653
1654
AboutProtectionsHandler.init();
1655
1656
PageActions.init();
1657
1658
this._firstWindowTelemetry(aWindow);
1659
this._firstWindowLoaded();
1660
1661
this._collectStartupConditionsTelemetry();
1662
1663
// Set the default favicon size for UI views that use the page-icon protocol.
1664
PlacesUtils.favicons.setDefaultIconURIPreferredSize(
1665
16 * aWindow.devicePixelRatio
1666
);
1667
this._setPrefExpectationsAndUpdate();
1668
this._matchCBCategory();
1669
1670
// This observes the entire privacy.trackingprotection.* pref tree.
1671
Services.prefs.addObserver(
1672
"privacy.trackingprotection",
1673
this._matchCBCategory
1674
);
1675
Services.prefs.addObserver(
1676
"network.cookie.cookieBehavior",
1677
this._matchCBCategory
1678
);
1679
Services.prefs.addObserver(
1680
ContentBlockingCategoriesPrefs.PREF_CB_CATEGORY,
1681
this._updateCBCategory
1682
);
1683
Services.prefs.addObserver(
1684
"media.autoplay.default",
1685
this._updateAutoplayPref
1686
);
1687
Services.prefs.addObserver(
1688
"privacy.trackingprotection",
1689
this._setPrefExpectations
1690
);
1691
Services.prefs.addObserver(
1692
"browser.contentblocking.features.strict",
1693
this._setPrefExpectationsAndUpdate
1694
);
1695
},
1696
1697
_updateAutoplayPref() {
1698
const blocked = Services.prefs.getIntPref("media.autoplay.default", 1);
1699
const telemetry = Services.telemetry.getHistogramById(
1700
"AUTOPLAY_DEFAULT_SETTING_CHANGE"
1701
);
1702
const labels = { 0: "allow", 1: "blockAudible", 5: "blockAll" };
1703
if (blocked in labels) {
1704
telemetry.add(labels[blocked]);
1705
}
1706
},
1707
1708
_setPrefExpectations() {
1709
ContentBlockingCategoriesPrefs.setPrefExpectations();
1710
},
1711
1712
_setPrefExpectationsAndUpdate() {
1713
ContentBlockingCategoriesPrefs.setPrefExpectations();
1714
ContentBlockingCategoriesPrefs.updateCBCategory();
1715
},
1716
1717
_matchCBCategory() {
1718
ContentBlockingCategoriesPrefs.matchCBCategory();
1719
},
1720
1721
_updateCBCategory() {
1722
ContentBlockingCategoriesPrefs.updateCBCategory();
1723
},
1724
1725
_togglePermissionPromptTelemetry() {
1726
let enablePermissionPromptTelemetry = Services.prefs.getBoolPref(
1727
"permissions.eventTelemetry.enabled",
1728
false
1729
);
1730
1731
Services.telemetry.setEventRecordingEnabled(
1732
"security.ui.permissionprompt",
1733
enablePermissionPromptTelemetry
1734
);
1735
1736
if (!enablePermissionPromptTelemetry) {
1737
// Remove the saved unique identifier to reduce the (remote) chance
1738
// of leaking it to our servers in the future.
1739
Services.prefs.clearUserPref("permissions.eventTelemetry.uuid");
1740
}
1741
},
1742
1743
_recordContentBlockingTelemetry() {
1744
Services.telemetry.setEventRecordingEnabled(
1745
"security.ui.protectionspopup",
1746
Services.prefs.getBoolPref(
1747
"security.protectionspopup.recordEventTelemetry"
1748
)
1749
);
1750
1751
let tpEnabled = Services.prefs.getBoolPref(
1752
"privacy.trackingprotection.enabled"
1753
);
1754
Services.telemetry
1755
.getHistogramById("TRACKING_PROTECTION_ENABLED")
1756
.add(tpEnabled);
1757
1758
let tpPBDisabled = Services.prefs.getBoolPref(
1759
"privacy.trackingprotection.pbmode.enabled"
1760
);
1761
Services.telemetry
1762
.getHistogramById("TRACKING_PROTECTION_PBM_DISABLED")
1763
.add(!tpPBDisabled);
1764
1765
let cookieBehavior = Services.prefs.getIntPref(
1766
"network.cookie.cookieBehavior"
1767
);
1768
Services.telemetry.getHistogramById("COOKIE_BEHAVIOR").add(cookieBehavior);
1769
1770
let exceptions = 0;
1771
for (let permission of Services.perms.all) {
1772
if (permission.type == "trackingprotection") {
1773
exceptions++;
1774
}
1775
}
1776
Services.telemetry.scalarSet("contentblocking.exceptions", exceptions);
1777
1778
let fpEnabled = Services.prefs.getBoolPref(
1779
"privacy.trackingprotection.fingerprinting.enabled"
1780
);
1781
let cmEnabled = Services.prefs.getBoolPref(
1782
"privacy.trackingprotection.cryptomining.enabled"
1783
);
1784
let categoryPref;
1785
switch (
1786
Services.prefs.getStringPref("browser.contentblocking.category", null)
1787
) {
1788
case "standard":
1789
categoryPref = 0;
1790
break;
1791
case "strict":
1792
categoryPref = 1;
1793
break;
1794
case "custom":
1795
categoryPref = 2;
1796
break;
1797
default:
1798
// Any other value is unsupported.
1799
categoryPref = 3;
1800
break;
1801
}
1802
1803
Services.telemetry.scalarSet(
1804
"contentblocking.fingerprinting_blocking_enabled",
1805
fpEnabled
1806
);
1807
Services.telemetry.scalarSet(
1808
"contentblocking.cryptomining_blocking_enabled",
1809
cmEnabled
1810
);
1811
Services.telemetry.scalarSet("contentblocking.category", categoryPref);
1812
},
1813
1814
_recordContentBlockerTelemetry() {
1815
[
1816
"other",
1817
"script",
1818
"image",
1819
"stylesheet",
1820
"object",
1821
"document",
1822
"subdocument",
1823
"refresh",
1824
"xbl",
1825
"ping",
1826
"xmlhttprequest",
1827
"objectsubrequest",
1828
"dtd",
1829
"font",
1830
"media",
1831
"websocket",
1832
"csp_report",
1833
"xslt",
1834
"beacon",
1835
"fetch",
1836
"image",
1837
"manifest",
1838
"saveas_download",
1839
"speculative",
1840
].forEach(type => {
1841
Services.telemetry.keyedScalarSet(
1842
"security.contentblocker_permissions",
1843
type,
1844
Services.perms.getAllWithTypePrefix(type).length
1845
);
1846
});
1847
},
1848
1849
_recordDataSanitizationPrefs() {
1850
Services.telemetry.scalarSet(
1851
"datasanitization.network_cookie_lifetimePolicy",
1852
Services.prefs.getIntPref("network.cookie.lifetimePolicy")
1853
);
1854
Services.telemetry.scalarSet(
1855
"datasanitization.privacy_sanitize_sanitizeOnShutdown",
1856
Services.prefs.getBoolPref("privacy.sanitize.sanitizeOnShutdown")
1857
);
1858
Services.telemetry.scalarSet(
1859
"datasanitization.privacy_clearOnShutdown_cookies",
1860
Services.prefs.getBoolPref("privacy.clearOnShutdown.cookies")
1861
);
1862
Services.telemetry.scalarSet(
1863
"datasanitization.privacy_clearOnShutdown_history",
1864
Services.prefs.getBoolPref("privacy.clearOnShutdown.history")
1865
);
1866
Services.telemetry.scalarSet(
1867
"datasanitization.privacy_clearOnShutdown_formdata",
1868
Services.prefs.getBoolPref("privacy.clearOnShutdown.formdata")
1869
);
1870
Services.telemetry.scalarSet(
1871
"datasanitization.privacy_clearOnShutdown_downloads",
1872
Services.prefs.getBoolPref("privacy.clearOnShutdown.downloads")
1873
);
1874
Services.telemetry.scalarSet(
1875
"datasanitization.privacy_clearOnShutdown_cache",
1876
Services.prefs.getBoolPref("privacy.clearOnShutdown.cache")
1877
);
1878
Services.telemetry.scalarSet(
1879
"datasanitization.privacy_clearOnShutdown_sessions",
1880
Services.prefs.getBoolPref("privacy.clearOnShutdown.sessions")
1881
);
1882
Services.telemetry.scalarSet(
1883
"datasanitization.privacy_clearOnShutdown_offlineApps",
1884
Services.prefs.getBoolPref("privacy.clearOnShutdown.offlineApps")
1885
);
1886
Services.telemetry.scalarSet(
1887
"datasanitization.privacy_clearOnShutdown_siteSettings",
1888
Services.prefs.getBoolPref("privacy.clearOnShutdown.siteSettings")
1889
);
1890
Services.telemetry.scalarSet(
1891
"datasanitization.privacy_clearOnShutdown_openWindows",
1892
Services.prefs.getBoolPref("privacy.clearOnShutdown.openWindows")
1893
);
1894
1895
let exceptions = 0;
1896
for (let permission of Services.perms.all) {
1897
let uri = permission.principal.URI;
1898
// We consider just permissions set for http, https and file URLs.
1899
if (
1900
permission.type == "cookie" &&
1901
permission.capability == Ci.nsICookiePermission.ACCESS_SESSION &&
1902
(uri.scheme == "http" || uri.scheme == "https" || uri.scheme == "file")
1903
) {
1904
exceptions++;
1905
}
1906
}
1907
Services.telemetry.scalarSet(
1908
"datasanitization.session_permission_exceptions",
1909
exceptions
1910
);
1911
},
1912
1913
_sendMediaTelemetry() {
1914
let win = Services.wm.getMostRecentWindow("navigator:browser");
1915
if (win) {
1916
let v = win.document.createElementNS(
1918
"video"
1919
);
1920
v.reportCanPlayTelemetry();
1921
}
1922
},
1923
1924
/**
1925
* Application shutdown handler.
1926
*/
1927
_onQuitApplicationGranted() {
1928
// This pref must be set here because SessionStore will use its value
1929
// on quit-application.
1930
this._setPrefToSaveSession();
1931
1932
// Call trackStartupCrashEnd here in case the delayed call on startup hasn't
1933
// yet occurred (see trackStartupCrashEnd caller in browser.js).
1934
try {
1935
Services.startup.trackStartupCrashEnd();
1936
} catch (e) {
1937
Cu.reportError(
1938
"Could not end startup crash tracking in quit-application-granted: " + e
1939
);
1940
}
1941
1942
if (this._bookmarksBackupIdleTime) {
1943
this._idleService.removeIdleObserver(this, this._bookmarksBackupIdleTime);
1944
delete this._bookmarksBackupIdleTime;
1945
}
1946
1947
for (let mod of Object.values(initializedModules)) {
1948
if (mod.uninit) {
1949
mod.uninit();
1950
}
1951
}
1952
1953