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