BrowserGlue.jsm 179 KB
Newer Older
1
2
3
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4

5
var EXPORTED_SYMBOLS = [
6
  "AboutHomeStartupCache",
7
8
9
10
  "BrowserGlue",
  "ContentPermissionPrompt",
  "DefaultBrowserCheck",
];
11

12
13
14
15
16
17
18
const { XPCOMUtils } = ChromeUtils.import(
  "resource://gre/modules/XPCOMUtils.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { AppConstants } = ChromeUtils.import(
  "resource://gre/modules/AppConstants.jsm"
);
19

20
21
22
23
24
25
26
27
28
29
30
XPCOMUtils.defineLazyModuleGetters(this, {
  ActorManagerParent: "resource://gre/modules/ActorManagerParent.jsm",
  AddonManager: "resource://gre/modules/AddonManager.jsm",
  AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.jsm",
  ASRouterDefaultConfig:
    "resource://activity-stream/lib/ASRouterDefaultConfig.jsm",
  ASRouterNewTabHook: "resource://activity-stream/lib/ASRouterNewTabHook.jsm",
  AsyncShutdown: "resource://gre/modules/AsyncShutdown.jsm",
  Blocklist: "resource://gre/modules/Blocklist.jsm",
  BookmarkHTMLUtils: "resource://gre/modules/BookmarkHTMLUtils.jsm",
  BookmarkJSONUtils: "resource://gre/modules/BookmarkJSONUtils.jsm",
31
  BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.jsm",
32
33
34
35
36
37
38
39
40
41
42
43
  BrowserUsageTelemetry: "resource:///modules/BrowserUsageTelemetry.jsm",
  BrowserUtils: "resource://gre/modules/BrowserUtils.jsm",
  BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
  ContextualIdentityService:
    "resource://gre/modules/ContextualIdentityService.jsm",
  Corroborate: "resource://gre/modules/Corroborate.jsm",
  DeferredTask: "resource://gre/modules/DeferredTask.jsm",
  Discovery: "resource:///modules/Discovery.jsm",
  DoHController: "resource:///modules/DoHController.jsm",
  DownloadsViewableInternally:
    "resource:///modules/DownloadsViewableInternally.jsm",
  E10SUtils: "resource://gre/modules/E10SUtils.jsm",
44
  ExtensionData: "resource://gre/modules/Extension.jsm",
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  ExtensionsUI: "resource:///modules/ExtensionsUI.jsm",
  FeatureGate: "resource://featuregates/FeatureGate.jsm",
  FirefoxMonitor: "resource:///modules/FirefoxMonitor.jsm",
  FxAccounts: "resource://gre/modules/FxAccounts.jsm",
  HomePage: "resource:///modules/HomePage.jsm",
  Integration: "resource://gre/modules/Integration.jsm",
  Log: "resource://gre/modules/Log.jsm",
  LoginBreaches: "resource:///modules/LoginBreaches.jsm",
  NetUtil: "resource://gre/modules/NetUtil.jsm",
  NewTabUtils: "resource://gre/modules/NewTabUtils.jsm",
  Normandy: "resource://normandy/Normandy.jsm",
  OS: "resource://gre/modules/osfile.jsm",
  OsEnvironment: "resource://gre/modules/OsEnvironment.jsm",
  PageActions: "resource:///modules/PageActions.jsm",
  PageThumbs: "resource://gre/modules/PageThumbs.jsm",
  PdfJs: "resource://pdf.js/PdfJs.jsm",
  PermissionUI: "resource:///modules/PermissionUI.jsm",
  PlacesBackups: "resource://gre/modules/PlacesBackups.jsm",
  PlacesDBUtils: "resource://gre/modules/PlacesDBUtils.jsm",
  PlacesUIUtils: "resource:///modules/PlacesUIUtils.jsm",
  PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
  PluralForm: "resource://gre/modules/PluralForm.jsm",
  PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
  ProcessHangMonitor: "resource:///modules/ProcessHangMonitor.jsm",
  RemoteSettings: "resource://services-settings/remote-settings.js",
  RemoteSecuritySettings:
    "resource://gre/modules/psm/RemoteSecuritySettings.jsm",
  RFPHelper: "resource://gre/modules/RFPHelper.jsm",
  SafeBrowsing: "resource://gre/modules/SafeBrowsing.jsm",
  Sanitizer: "resource:///modules/Sanitizer.jsm",
  SaveToPocket: "chrome://pocket/content/SaveToPocket.jsm",
76
  SearchSERPTelemetry: "resource:///modules/SearchSERPTelemetry.jsm",
77
78
79
80
81
82
  SessionStartup: "resource:///modules/sessionstore/SessionStartup.jsm",
  SessionStore: "resource:///modules/sessionstore/SessionStore.jsm",
  TabCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
  TabUnloader: "resource:///modules/TabUnloader.jsm",
  TelemetryUtils: "resource://gre/modules/TelemetryUtils.jsm",
  TRRRacer: "resource:///modules/TRRPerformance.jsm",
83
  OnionAliasStore: "resource:///modules/OnionAliasStore.jsm",
84
85
86
87
  UIState: "resource://services-sync/UIState.jsm",
  WebChannel: "resource://gre/modules/WebChannel.jsm",
  WindowsRegistry: "resource://gre/modules/WindowsRegistry.jsm",
});
88

89
90
91
92
93
// eslint-disable-next-line no-unused-vars
XPCOMUtils.defineLazyModuleGetters(this, {
  AboutLoginsParent: "resource:///modules/AboutLoginsParent.jsm",
  PluginManager: "resource:///actors/PluginParent.jsm",
});
94

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Modules requiring an initialization method call.
let initializedModules = {};
[
  [
    "ContentPrefServiceParent",
    "resource://gre/modules/ContentPrefServiceParent.jsm",
    "alwaysInit",
  ],
  ["UpdateListener", "resource://gre/modules/UpdateListener.jsm", "init"],
].forEach(([name, resource, init]) => {
  XPCOMUtils.defineLazyGetter(this, name, () => {
    ChromeUtils.import(resource, initializedModules);
    initializedModules[name][init]();
    return initializedModules[name];
  });
});
111

112
113
114
115
116
117
118
XPCOMUtils.defineLazyServiceGetter(
  this,
  "PushService",
  "@mozilla.org/push/Service;1",
  "nsIPushService"
);

119
120
121
122
123
124
125
XPCOMUtils.defineLazyServiceGetters(this, {
  resProto: [
    "@mozilla.org/network/protocol;1?name=resource",
    "nsISubstitutingProtocolHandler",
  ],
});

126
const PREF_PDFJS_ISDEFAULT_CACHE_STATE = "pdfjs.enabledCache.state";
127

128
129
130
131
132
133
/**
 * Fission-compatible JSProcess implementations.
 * Each actor options object takes the form of a ProcessActorOptions dictionary.
 * Detailed documentation of these options is in dom/docs/Fission.rst,
 * available at https://firefox-source-docs.mozilla.org/dom/Fission.html#jsprocessactor
 */
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
let JSPROCESSACTORS = {
  // Miscellaneous stuff that needs to be initialized per process.
  BrowserProcess: {
    child: {
      moduleURI: "resource:///actors/BrowserProcessChild.jsm",
      observers: [
        // WebRTC related notifications. They are here to avoid loading WebRTC
        // components when not needed.
        "getUserMedia:request",
        "recording-device-stopped",
        "PeerConnection:request",
        "recording-device-events",
        "recording-window-ended",
      ],
    },
  },
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

  RefreshBlockerObserver: {
    child: {
      moduleURI: "resource:///actors/RefreshBlockerChild.jsm",
      observers: [
        "webnavigation-create",
        "chrome-webnavigation-create",
        "webnavigation-destroy",
        "chrome-webnavigation-destroy",
      ],
    },

    enablePreference: "accessibility.blockautorefresh",
    onPreferenceChanged: (prefName, prevValue, isEnabled) => {
      BrowserWindowTracker.orderedWindows.forEach(win => {
        for (let browser of win.gBrowser.browsers) {
          try {
            browser.sendMessageToActor(
              "PreferenceChanged",
              { isEnabled },
              "RefreshBlocker",
              "all"
            );
          } catch (ex) {}
        }
      });
    },
  },
178
};
179

180
181
182
183
184
/**
 * Fission-compatible JSWindowActor implementations.
 * Detailed documentation of these is in dom/docs/Fission.rst,
 * available at https://firefox-source-docs.mozilla.org/dom/Fission.html#jswindowactor
 */
185
let JSWINDOWACTORS = {
186
187
188
189
190
191
192
193
194
195
196
  AboutLogins: {
    parent: {
      moduleURI: "resource:///actors/AboutLoginsParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/AboutLoginsChild.jsm",
      events: {
        AboutLoginsCopyLoginDetail: { wantUntrusted: true },
        AboutLoginsCreateLogin: { wantUntrusted: true },
        AboutLoginsDeleteLogin: { wantUntrusted: true },
        AboutLoginsDismissBreachAlert: { wantUntrusted: true },
197
198
        AboutLoginsImportFromBrowser: { wantUntrusted: true },
        AboutLoginsImportFromFile: { wantUntrusted: true },
199
200
201
202
203
        AboutLoginsInit: { wantUntrusted: true },
        AboutLoginsGetHelp: { wantUntrusted: true },
        AboutLoginsOpenPreferences: { wantUntrusted: true },
        AboutLoginsOpenSite: { wantUntrusted: true },
        AboutLoginsRecordTelemetryEvent: { wantUntrusted: true },
204
        AboutLoginsRemoveAllLogins: { wantUntrusted: true },
205
206
207
208
        AboutLoginsSortChanged: { wantUntrusted: true },
        AboutLoginsSyncEnable: { wantUntrusted: true },
        AboutLoginsSyncOptions: { wantUntrusted: true },
        AboutLoginsUpdateLogin: { wantUntrusted: true },
209
        AboutLoginsExportPasswords: { wantUntrusted: true },
210
211
212
213
214
      },
    },
    matches: ["about:logins", "about:logins?*"],
  },

215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  AboutNewInstall: {
    parent: {
      moduleURI: "resource:///actors/AboutNewInstallParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/AboutNewInstallChild.jsm",

      events: {
        DOMWindowCreated: { capture: true },
      },
    },

    matches: ["about:newinstall"],
  },

230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  AboutPlugins: {
    parent: {
      moduleURI: "resource:///actors/AboutPluginsParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/AboutPluginsChild.jsm",

      events: {
        DOMWindowCreated: { capture: true },
      },
    },

    matches: ["about:plugins"],
  },

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
  AboutPrivateBrowsing: {
    parent: {
      moduleURI: "resource:///actors/AboutPrivateBrowsingParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/AboutPrivateBrowsingChild.jsm",

      events: {
        DOMWindowCreated: { capture: true },
      },
    },

    matches: ["about:privatebrowsing"],
  },

260
261
262
263
264
265
266
267
268
269
270
271
  AboutProtections: {
    parent: {
      moduleURI: "resource:///actors/AboutProtectionsParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/AboutProtectionsChild.jsm",

      events: {
        DOMWindowCreated: { capture: true },
      },
    },

272
    matches: ["about:protections", "about:protections?*"],
273
274
  },

275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  AboutReader: {
    parent: {
      moduleURI: "resource:///actors/AboutReaderParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/AboutReaderChild.jsm",
      events: {
        DOMContentLoaded: {},
        pageshow: { mozSystemGroup: true },
        pagehide: { mozSystemGroup: true },
      },
    },
    messageManagerGroups: ["browsers"],
  },

290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  AboutTabCrashed: {
    parent: {
      moduleURI: "resource:///actors/AboutTabCrashedParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/AboutTabCrashedChild.jsm",

      events: {
        DOMWindowCreated: { capture: true },
      },
    },

    matches: ["about:tabcrashed*"],
  },

305
306
307
308
309
310
311
312
313
314
315
316
317
  AboutWelcome: {
    parent: {
      moduleURI: "resource:///actors/AboutWelcomeParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/AboutWelcomeChild.jsm",
      events: {
        // This is added so the actor instantiates immediately and makes
        // methods available to the page js on load.
        DOMWindowCreated: {},
      },
    },
    matches: ["about:welcome"],
318
    remoteTypes: ["privilegedabout"],
319
320
321
322
323
324

    // See Bug 1618306
    // Remove this preference check when we turn on separate about:welcome for all users.
    enablePreference: "browser.aboutwelcome.enabled",
  },

325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
  BlockedSite: {
    parent: {
      moduleURI: "resource:///actors/BlockedSiteParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/BlockedSiteChild.jsm",
      events: {
        AboutBlockedLoaded: { wantUntrusted: true },
        click: {},
      },
    },
    matches: ["about:blocked?*"],
    allFrames: true,
  },

340
341
342
343
344
345
346
347
  BrowserTab: {
    parent: {
      moduleURI: "resource:///actors/BrowserTabParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/BrowserTabChild.jsm",

      events: {
348
349
        DOMWindowCreated: {},
        MozAfterPaint: {},
350
351
      },
    },
352
353

    messageManagerGroups: ["browsers"],
354
355
  },

356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
  ClickHandler: {
    parent: {
      moduleURI: "resource:///actors/ClickHandlerParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/ClickHandlerChild.jsm",
      events: {
        click: { capture: true, mozSystemGroup: true },
        auxclick: { capture: true, mozSystemGroup: true },
      },
    },

    allFrames: true,
  },

371
372
373
374
375
376
377
378
379
380
381
382
383
384
  // Collects description and icon information from meta tags.
  ContentMeta: {
    parent: {
      moduleURI: "resource:///actors/ContentMetaParent.jsm",
    },

    child: {
      moduleURI: "resource:///actors/ContentMetaChild.jsm",
      events: {
        DOMMetaAdded: {},
      },
    },
  },

385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  ContentSearch: {
    parent: {
      moduleURI: "resource:///actors/ContentSearchParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/ContentSearchChild.jsm",
      matches: [
        "about:home",
        "about:newtab",
        "about:welcome",
        "about:privatebrowsing",
        "chrome://mochitests/content/*",
      ],
      events: {
        ContentSearchClient: { capture: true, wantUntrusted: true },
      },
    },
  },

404
405
406
407
408
409
410
411
  ContextMenu: {
    parent: {
      moduleURI: "resource:///actors/ContextMenuParent.jsm",
    },

    child: {
      moduleURI: "resource:///actors/ContextMenuChild.jsm",
      events: {
412
        contextmenu: { mozSystemGroup: true },
413
414
415
416
417
418
      },
    },

    allFrames: true,
  },

419
420
421
422
423
424
425
426
427
428
429
430
431
432
  DecoderDoctor: {
    parent: {
      moduleURI: "resource:///actors/DecoderDoctorParent.jsm",
    },

    child: {
      moduleURI: "resource:///actors/DecoderDoctorChild.jsm",
      observers: ["decoder-doctor-notification"],
    },

    messageManagerGroups: ["browsers"],
    allFrames: true,
  },

433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  DOMFullscreen: {
    parent: {
      moduleURI: "resource:///actors/DOMFullscreenParent.jsm",
    },

    child: {
      moduleURI: "resource:///actors/DOMFullscreenChild.jsm",
      group: "browsers",
      events: {
        "MozDOMFullscreen:Request": {},
        "MozDOMFullscreen:Entered": {},
        "MozDOMFullscreen:NewOrigin": {},
        "MozDOMFullscreen:Exit": {},
        "MozDOMFullscreen:Exited": {},
      },
    },

    allFrames: true,
  },

453
454
455
456
457
458
459
460
461
462
  EncryptedMedia: {
    parent: {
      moduleURI: "resource:///actors/EncryptedMediaParent.jsm",
    },

    child: {
      moduleURI: "resource:///actors/EncryptedMediaChild.jsm",
      observers: ["mediakeys-request"],
    },

463
    messageManagerGroups: ["browsers"],
464
465
466
    allFrames: true,
  },

467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
  FormValidation: {
    parent: {
      moduleURI: "resource:///actors/FormValidationParent.jsm",
    },

    child: {
      moduleURI: "resource:///actors/FormValidationChild.jsm",
      events: {
        MozInvalidForm: {},
      },
    },

    allFrames: true,
  },

482
483
484
485
486
487
488
489
490
491
492
493
494
495
  LightweightTheme: {
    child: {
      moduleURI: "resource:///actors/LightweightThemeChild.jsm",
      events: {
        pageshow: { mozSystemGroup: true },
      },
    },
    includeChrome: true,
    allFrames: true,
    matches: [
      "about:home",
      "about:newtab",
      "about:welcome",
      "chrome://browser/content/syncedtabs/sidebar.xhtml",
496
497
      "chrome://browser/content/places/historySidebar.xhtml",
      "chrome://browser/content/places/bookmarksSidebar.xhtml",
498
499
500
    ],
  },

501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
  LinkHandler: {
    parent: {
      moduleURI: "resource:///actors/LinkHandlerParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/LinkHandlerChild.jsm",
      events: {
        DOMHeadElementParsed: {},
        DOMLinkAdded: {},
        DOMLinkChanged: {},
        pageshow: {},
        pagehide: {},
      },
    },
  },

517
518
519
520
521
522
523
  NetError: {
    parent: {
      moduleURI: "resource:///actors/NetErrorParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/NetErrorChild.jsm",
      events: {
524
        DOMWindowCreated: {},
525
526
527
528
529
530
531
532
        click: {},
      },
    },

    matches: ["about:certerror?*", "about:neterror?*"],
    allFrames: true,
  },

533
534
535
536
537
538
539
540
541
542
543
544
545
  OnionLocation: {
    parent: {
      moduleURI: "resource:///modules/OnionLocationParent.jsm",
    },
    child: {
      moduleURI: "resource:///modules/OnionLocationChild.jsm",
      events: {
        pageshow: { mozSystemGroup: true },
      },
    },
    messageManagerGroups: ["browsers"],
  },

546
547
548
549
550
551
552
553
  PageInfo: {
    child: {
      moduleURI: "resource:///actors/PageInfoChild.jsm",
    },

    allFrames: true,
  },

554
555
556
557
558
559
560
561
562
563
564
565
566
  PageStyle: {
    parent: {
      moduleURI: "resource:///actors/PageStyleParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/PageStyleChild.jsm",
      events: {
        pageshow: {},
      },
    },

    // Only matching web pages, as opposed to internal about:, chrome: or
    // resource: pages. See https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Match_patterns
567
    matches: ["*://*/*", "file:///*"],
568
    messageManagerGroups: ["browsers"],
569
570
571
    allFrames: true,
  },

572
573
574
575
576
577
578
579
580
581
  Pdfjs: {
    parent: {
      moduleURI: "resource://pdf.js/PdfjsParent.jsm",
    },
    child: {
      moduleURI: "resource://pdf.js/PdfjsChild.jsm",
    },
    allFrames: true,
  },

582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
  Plugin: {
    parent: {
      moduleURI: "resource:///actors/PluginParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/PluginChild.jsm",
      events: {
        PluginBindingAttached: { capture: true, wantUntrusted: true },
        PluginCrashed: { capture: true },
        PluginOutdated: { capture: true },
        PluginInstantiated: { capture: true },
        PluginRemoved: { capture: true },
        HiddenPlugin: { capture: true },
      },

      observers: ["decoder-doctor-notification"],
    },

    allFrames: true,
  },

603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
  PointerLock: {
    parent: {
      moduleURI: "resource:///actors/PointerLockParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/PointerLockChild.jsm",
      events: {
        "MozDOMPointerLock:Entered": {},
        "MozDOMPointerLock:Exited": {},
      },
    },

    messageManagerGroups: ["browsers"],
    allFrames: true,
  },

619
620
621
622
  Prompt: {
    parent: {
      moduleURI: "resource:///actors/PromptParent.jsm",
    },
623
    includeChrome: true,
624
625
626
    allFrames: true,
  },

627
628
629
630
631
632
633
634
635
636
637
638
  RefreshBlocker: {
    parent: {
      moduleURI: "resource:///actors/RefreshBlockerParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/RefreshBlockerChild.jsm",
    },

    messageManagerGroups: ["browsers"],
    enablePreference: "accessibility.blockautorefresh",
  },

639
  SearchSERPTelemetry: {
640
    parent: {
641
      moduleURI: "resource:///actors/SearchSERPTelemetryParent.jsm",
642
643
    },
    child: {
644
      moduleURI: "resource:///actors/SearchSERPTelemetryChild.jsm",
645
646
647
648
649
650
651
652
      events: {
        DOMContentLoaded: {},
        pageshow: { mozSystemGroup: true },
        unload: {},
      },
    },
  },

653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  ShieldFrame: {
    parent: {
      moduleURI: "resource://normandy-content/ShieldFrameParent.jsm",
    },
    child: {
      moduleURI: "resource://normandy-content/ShieldFrameChild.jsm",
      events: {
        pageshow: {},
        pagehide: {},
        ShieldPageEvent: { wantUntrusted: true },
      },
    },
    matches: ["about:studies"],
  },

668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  ASRouter: {
    parent: {
      moduleURI: "resource:///actors/ASRouterParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/ASRouterChild.jsm",
      events: {
        // This is added so the actor instantiates immediately and makes
        // methods available to the page js on load.
        DOMWindowCreated: {},
      },
    },
    matches: ["about:home*", "about:newtab*", "about:welcome*"],
    remoteTypes: ["privilegedabout"],
  },

684
685
686
687
688
689
690
  SwitchDocumentDirection: {
    child: {
      moduleURI: "resource:///actors/SwitchDocumentDirectionChild.jsm",
    },

    allFrames: true,
  },
691

692
693
694
695
696
697
698
699
700
701
702
  SiteSpecificBrowser: {
    parent: {
      moduleURI: "resource:///actors/SiteSpecificBrowserParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/SiteSpecificBrowserChild.jsm",
    },

    allFrames: true,
  },

703
704
705
706
707
708
709
710
  Translation: {
    parent: {
      moduleURI: "resource:///modules/translation/TranslationParent.jsm",
    },
    child: {
      moduleURI: "resource:///modules/translation/TranslationChild.jsm",
      events: {
        pageshow: {},
711
        load: { mozSystemGroup: true, capture: true },
712
713
714
715
716
      },
    },
    enablePreference: "browser.translation.detectLanguage",
  },

717
718
719
720
721
722
723
724
725
726
727
  UITour: {
    parent: {
      moduleURI: "resource:///modules/UITourParent.jsm",
    },
    child: {
      moduleURI: "resource:///modules/UITourChild.jsm",
      events: {
        mozUITour: { wantUntrusted: true },
      },
    },
  },
728
729
730
731
732
733
734
735
736
737
738

  WebRTC: {
    parent: {
      moduleURI: "resource:///actors/WebRTCParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/WebRTCChild.jsm",
    },

    allFrames: true,
  },
739
740
};

741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
if (AppConstants.TOR_BROWSER_UPDATE) {
  JSWINDOWACTORS["AboutTBUpdate"] = {
    parent: {
      moduleURI: "resource:///actors/AboutTBUpdateParent.jsm",
    },
    child: {
      moduleURI: "resource:///actors/AboutTBUpdateChild.jsm",
      events: {
        DOMWindowCreated: { capture: true },
      },
    },
    matches: ["about:tbupdate"],
  };
}

756
(function earlyBlankFirstPaint() {
757
  let startTime = Cu.now();
758
759
760
761
  if (
    AppConstants.platform == "macosx" ||
    !Services.prefs.getBoolPref("browser.startup.blankWindow", false)
  ) {
762
    return;
763
  }
764

765
766
  // Until bug 1450626 and bug 1488384 are fixed, skip the blank window when
  // using a non-default theme.
767
768
769
770
771
772
  if (
    Services.prefs.getCharPref(
      "extensions.activeThemeID",
      "default-theme@mozilla.org"
    ) != "default-theme@mozilla.org"
  ) {
773
    return;
774
  }
775

776
  let store = Services.xulStore;
777
  let getValue = attr =>
778
    store.getValue(AppConstants.BROWSER_CHROME_URL, "main-window", attr);
779
780
781
782
  let width = getValue("width");
  let height = getValue("height");

  // The clean profile case isn't handled yet. Return early for now.
783
  if (!width || !height) {
784
    return;
785
  }
786
787
788

  let browserWindowFeatures =
    "chrome,all,dialog=no,extrachrome,menubar,resizable,scrollbars,status," +
789
    "location,toolbar,personalbar";
790
791
792
793
794
795
796
  let win = Services.ww.openWindow(
    null,
    "about:blank",
    null,
    browserWindowFeatures,
    null
  );
797
798

  // Hide the titlebar if the actual browser window will draw in it.
799
800
801
802
  let hiddenTitlebar = Services.prefs.getBoolPref(
    "browser.tabs.drawInTitlebar",
    win.matchMedia("(-moz-gtk-csd-hide-titlebar-by-default)").matches
  );
803
  if (hiddenTitlebar) {
804
    win.windowUtils.setChromeMargin(0, 2, 2, 2);
805
806
  }

807
808
809
  let docElt = win.document.documentElement;
  docElt.setAttribute("screenX", getValue("screenX"));
  docElt.setAttribute("screenY", getValue("screenY"));
810
811
812
813
814
815

  // The sizemode="maximized" attribute needs to be set before first paint.
  let sizemode = getValue("sizemode");
  if (sizemode == "maximized") {
    docElt.setAttribute("sizemode", sizemode);

816
817
818
    // Set the size to use when the user leaves the maximized mode.
    // The persisted size is the outer size, but the height/width
    // attributes set the inner size.
819
    let appWin = win.docShell.treeOwner
820
      .QueryInterface(Ci.nsIInterfaceRequestor)
821
822
823
      .getInterface(Ci.nsIAppWindow);
    height -= appWin.outerToInnerHeightDifferenceInCSSPixels;
    width -= appWin.outerToInnerWidthDifferenceInCSSPixels;
824
825
826
827
828
829
830
831
    docElt.setAttribute("height", height);
    docElt.setAttribute("width", width);
  } else {
    // Setting the size of the window in the features string instead of here
    // causes the window to grow by the size of the titlebar.
    win.resizeTo(width, height);
  }

832
833
834
835
  // Set this before showing the window so that graphics code can use it to
  // decide to skip some expensive code paths (eg. starting the GPU process).
  docElt.setAttribute("windowtype", "navigator:blank");

836
837
838
  // The window becomes visible after OnStopRequest, so make this happen now.
  win.stop();

839
840
841
  ChromeUtils.addProfilerMarker("earlyBlankFirstPaint", startTime);
  win.openTime = Cu.now();

842
843
844
  let { TelemetryTimestamps } = ChromeUtils.import(
    "resource://gre/modules/TelemetryTimestamps.jsm"
  );
845
  TelemetryTimestamps.add("blankWindowShown");
846
847
})();

848
849
850
851
XPCOMUtils.defineLazyGetter(
  this,
  "WeaveService",
  () => Cc["@mozilla.org/weave/service;1"].getService().wrappedJSObject
852
);
853

854
if (AppConstants.MOZ_CRASHREPORTER) {
855
856
857
  XPCOMUtils.defineLazyModuleGetters(this, {
    UnsubmittedCrashHandler: "resource:///modules/ContentCrashHandlers.jsm",
  });
858
}
859

860
XPCOMUtils.defineLazyGetter(this, "gBrandBundle", function() {
861
862
863
  return Services.strings.createBundle(
    "chrome://branding/locale/brand.properties"
  );
864
865
866
});

XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
867
868
869
  return Services.strings.createBundle(
    "chrome://browser/locale/browser.properties"
  );
870
871
});

872
XPCOMUtils.defineLazyGetter(this, "gTabbrowserBundle", function() {
873
874
875
  return Services.strings.createBundle(
    "chrome://browser/locale/tabbrowser.properties"
  );
876
877
});

878
879
880
const global = this;

const listeners = {
881
  observers: {
882
    "update-downloading": ["UpdateListener"],
883
884
885
886
    "update-staged": ["UpdateListener"],
    "update-downloaded": ["UpdateListener"],
    "update-available": ["UpdateListener"],
    "update-error": ["UpdateListener"],
887
888
    "gmp-plugin-crash": ["PluginManager"],
    "plugin-crashed": ["PluginManager"],
889
890
891
892
893
894
895
896
897
898
899
900
  },

  observe(subject, topic, data) {
    for (let module of this.observers[topic]) {
      try {
        global[module].observe(subject, topic, data);
      } catch (e) {
        Cu.reportError(e);
      }
    }
  },

901
  init() {
902
903
904
    for (let observer of Object.keys(this.observers)) {
      Services.obs.addObserver(this, observer);
    }
905
  },
906
907
};

908
// Seconds of idle before trying to create a bookmarks backup.
909
const BOOKMARKS_BACKUP_IDLE_TIME_SEC = 8 * 60;
910
911
912
913
914
// Minimum interval between backups.  We try to not create more than one backup
// per interval.
const BOOKMARKS_BACKUP_MIN_INTERVAL_DAYS = 1;
// Maximum interval between backups.  If the last backup is older than these
// days we will try to create a new one more aggressively.
915
const BOOKMARKS_BACKUP_MAX_INTERVAL_DAYS = 3;
916
917
// Seconds of idle time before the late idle tasks will be scheduled.
const LATE_TASKS_IDLE_TIME_SEC = 20;
918
919
// Time after we stop tracking startup crashes.
const STARTUP_CRASHES_END_DELAY_MS = 30 * 1000;
920

921
922
923
924
925
/*
 * OS X has the concept of zero-window sessions and therefore ignores the
 * browser-lastwindow-close-* topics.
 */
const OBSERVE_LASTWINDOW_CLOSE_TOPICS = AppConstants.platform != "macosx";
926
927

function BrowserGlue() {
928
929
  XPCOMUtils.defineLazyServiceGetter(
    this,
930
931
932
    "_userIdleService",
    "@mozilla.org/widget/useridleservice;1",
    "nsIUserIdleService"
933
  );
934

935
  XPCOMUtils.defineLazyGetter(this, "_distributionCustomizer", function() {
936
937
938
939
940
    const { DistributionCustomizer } = ChromeUtils.import(
      "resource:///modules/distribution.js"
    );
    return new DistributionCustomizer();
  });
941

942
943
944
945
946
947
  XPCOMUtils.defineLazyServiceGetter(
    this,
    "AlertsService",
    "@mozilla.org/alerts-service;1",
    "nsIAlertsService"
  );
948

949
950
951
952
  this._init();
}

BrowserGlue.prototype = {
953
  _saveSession: false,
954
  _migrationImportsDefaultBookmarks: false,
955
  _placesBrowserInitComplete: false,
956
  _isNewProfile: undefined,
957

958
  _setPrefToSaveSession: function BG__setPrefToSaveSession(aForce) {
959
    if (!this._saveSession && !aForce) {
960
      return;
961
    }
962

963
    if (!PrivateBrowsingUtils.permanentPrivateBrowsing) {
964
965
966
967
      Services.prefs.setBoolPref(
        "browser.sessionstore.resume_session_once",
        true
      );
968
    }
969
970
971
972

    // This method can be called via [NSApplication terminate:] on Mac, which
    // ends up causing prefs not to be flushed to disk, so we need to do that
    // explicitly here. See bug 497652.
973
    Services.prefs.savePrefFile(null);
974
975
  },

976
977
978
  _setSyncAutoconnectDelay: function BG__setSyncAutoconnectDelay() {
    // Assume that a non-zero value for services.sync.autoconnectDelay should override
    if (Services.prefs.prefHasUserValue("services.sync.autoconnectDelay")) {
979
980
981
      let prefDelay = Services.prefs.getIntPref(
        "services.sync.autoconnectDelay"
      );
982

983
      if (prefDelay > 0) {
984
        return;
985
      }
986
987
988
989
990
    }

    // delays are in seconds
    const MAX_DELAY = 300;
    let delay = 3;
991
    for (let win of Services.wm.getEnumerator("navigator:browser")) {
992
993
994
995
996
      // browser windows without a gBrowser almost certainly means we are
      // shutting down, so instead of just ignoring that window we abort.
      if (win.closed || !win.gBrowser) {
        return;
      }
997
      delay += win.gBrowser.tabs.length;
998
999
1000
    }
    delay = delay <= MAX_DELAY ? delay : MAX_DELAY;

1001
    const { Weave } = ChromeUtils.import("resource://services-sync/main.js");
1002
    Weave.Service.scheduler.delayedAutoConnect(delay);
1003
1004
  },

1005
  // nsIObserver implementation
1006
  observe: async function BG_observe(subject, topic, data) {
1007
    switch (topic) {
1008
      case "notifications-open-settings":
1009
        this._openPreferences("privacy-permissions");
1010
        break;
1011
      case "final-ui-startup":
1012
        this._beforeUIStartup();
1013
        break;
1014
      case "browser-delayed-startup-finished":
1015
        this._onFirstWindowLoaded(subject);
1016
1017
        Services.obs.removeObserver(this, "browser-delayed-startup-finished");
        break;
1018
      case "sessionstore-windows-restored":
1019
        this._onWindowsRestored();
1020
        break;
1021
1022
      case "browser:purge-session-history":
        // reset the console service's error buffer
1023
1024
        Services.console.logStringMessage(null); // clear the console (in case it's open)
        Services.console.reset();
1025
        break;
1026
1027
1028
      case "restart-in-safe-mode":
        this._onSafeModeRestart();
        break;
1029
      case "quit-application-requested":
1030
        this._onQuitRequest(subject, data);
1031
1032
        break;
      case "quit-application-granted":
1033
        this._onQuitApplicationGranted();
1034
        break;
1035
      case "browser-lastwindow-close-requested":
1036
1037
1038
1039
1040
        if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
          // The application is not actually quitting, but the last full browser
          // window is about to be closed.
          this._onQuitRequest(subject, "lastwindow");
        }
1041
1042
        break;
      case "browser-lastwindow-close-granted":
1043
1044
1045
        if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
          this._setPrefToSaveSession();
        }
1046
        break;
1047
1048
1049
      case "weave:service:ready":
        this._setSyncAutoconnectDelay();
        break;
1050
      case "fxaccounts:onverified":
1051
        this._onThisDeviceConnected();
1052
        break;
1053
1054
1055
      case "fxaccounts:device_connected":
        this._onDeviceConnected(data);
        break;
1056
1057
1058
      case "fxaccounts:verify_login":
        this._onVerifyLoginNotification(JSON.parse(data));
        break;
1059
      case "fxaccounts:device_disconnected":
1060
1061
1062
1063
        data = JSON.parse(data);
        if (data.isLocalDevice) {
          this._onDeviceDisconnected();
        }
1064
        break;
1065
      case "fxaccounts:commands:open-uri":
1066
1067
      case "weave:engine:clients:display-uris":
        this._onDisplaySyncURIs(subject);
1068
        break;
1069
      case "session-save":
1070
        this._setPrefToSaveSession(true);
1071
1072
1073
        subject.QueryInterface(Ci.nsISupportsPRBool);
        subject.data = true;
        break;
1074
      case "places-init-complete":
1075
        Services.obs.removeObserver(this, "places-init-complete");
1076
        if (!this._migrationImportsDefaultBookmarks) {
1077
          this._initPlaces(false);
1078
        }
1079
        break;
1080
      case "idle":
1081
        this._backupBookmarks();
1082
        break;
1083
      case "distribution-customization-complete":
1084
1085
1086
1087
        Services.obs.removeObserver(
          this,
          "distribution-customization-complete"
        );
1088
1089
1090
        // Customization has finished, we don't need the customizer anymore.
        delete this._distributionCustomizer;
        break;
1091
      case "browser-glue-test": // used by tests
1092
        if (data == "force-ui-migration") {
1093
          this._migrateUI();
1094
        } else if (data == "force-distribution-customization") {
1095
          this._distributionCustomizer.applyCustomizations();
1096
          // To apply distribution bookmarks use "places-init-complete".
1097
        } else if (data == "force-places-init") {
1098
          this._initPlaces(false);
1099
1100
        } else if (data == "mock-alerts-service") {
          Object.defineProperty(this, "AlertsService", {
1101
            value: subject.wrappedJSObject,
1102
          });
1103
1104
1105
1106
        } else if (data == "places-browser-init-complete") {
          if (this._placesBrowserInitComplete) {
            Services.obs.notifyObservers(null, "places-browser-init-complete");
          }
1107
1108
        } else if (data == "add-breaches-sync-handler") {
          this._addBreachesSyncHandler();
1109
        }
1110
        break;
1111
1112
1113
1114
1115
      case "initial-migration-will-import-default-bookmarks":
        this._migrationImportsDefaultBookmarks = true;
        break;
      case "initial-migration-did-import-default-bookmarks":
        this._initPlaces(true);
1116
        break;
1117
1118
1119
      case "handle-xul-text-link":
        let linkHandled = subject.QueryInterface(Ci.nsISupportsPRBool);
        if (!linkHandled.data) {
1120
          let win = BrowserWindowTracker.getTopWindow();
1121
          if (win) {
1122
1123
            data = JSON.parse(data);
            let where = win.whereToOpenLink(data);
1124
1125
1126
1127
1128
            // Preserve legacy behavior of non-modifier left-clicks
            // opening in a new selected tab.
            if (where == "current") {
              where = "tab";
            }
1129
            win.openTrustedLinkIn(data.href, where);
1130
1131
1132
1133
            linkHandled.data = true;
          }
        }
        break;
1134
      case "profile-before-change":
1135
1136
1137
        // Any component depending on Places should be finalized in
        // _onPlacesShutdown.  Any component that doesn't need to act after
        // the UI has gone should be finalized in _onQuitApplicationGranted.
1138
        this._dispose();
1139
        break;
1140
      case "keyword-search":
1141
1142
        // This notification is broadcast by the docshell when it "fixes up" a
        // URI that it's been asked to load into a keyword search.
1143
1144
1145
1146
1147
1148
        let engine = null;
        try {
          engine = subject.QueryInterface(Ci.nsISearchEngine);
        } catch (ex) {
          Cu.reportError(ex);
        }
1149
        let win = BrowserWindowTracker.getTopWindow();
1150
        BrowserSearchTelemetry.recordSearch(win.gBrowser, engine, "urlbar");
1151
        break;
1152
      case "browser-search-engine-modified":
1153
1154
1155
1156
        // Ensure we cleanup the hiddenOneOffs pref when removing
        // an engine, and that newly added engines are visible.
        if (data == "engine-added" || data == "engine-removed") {
          let engineName = subject.QueryInterface(Ci.nsISearchEngine).name;
1157
1158
1159
          let pref = Services.prefs.getStringPref(
            "browser.search.hiddenOneOffs"
          );
1160
1161
          let hiddenList = pref ? pref.split(",") : [];
          hiddenList = hiddenList.filter(x => x !== engineName);
1162
1163
1164
1165
          Services.prefs.setStringPref(
            "browser.search.hiddenOneOffs",
            hiddenList.join(",")
          );
1166
        }
1167
        break;
1168
1169
1170
      case "flash-plugin-hang":
        this._handleFlashHang();
        break;
1171
      case "xpi-signature-changed":
1172
        let disabledAddons = JSON.parse(data).disabled;
1173
1174
1175
1176
        let addons = await AddonManager.getAddonsByIDs(disabledAddons);
        if (addons.some(addon => addon)) {
          this._notifyUnsignedAddonsDisabled();
        }
1177
        break;
1178
1179
1180
      case "sync-ui-state:update":
        this._updateFxaBadges();
        break;
1181
1182
1183
1184
1185
1186
1187
1188
      case "handlersvc-store-initialized":
        // Initialize PdfJs when running in-process and remote. This only
        // happens once since PdfJs registers global hooks. If the PdfJs
        // extension is installed the init method below will be overridden
        // leaving initialization to the extension.
        // parent only: configure default prefs, set up pref observers, register
        // pdf content handler, and initializes parent side message manager
        // shim for privileged api access.
1189
        PdfJs.init(this._isNewProfile);
1190
1191
1192
1193

        // Allow certain viewable internally types to be opened from downloads.
        DownloadsViewableInternally.register();

1194
        break;
1195
1196
1197
    }
  },

1198
  // initialization (called on application startup)
1199
  _init: function BG__init() {
1200
    let os = Services.obs;
1201
1202
1203
1204
1205
1206
1207
    os.addObserver(this, "notifications-open-settings");
    os.addObserver(this, "final-ui-startup");
    os.addObserver(this, "browser-delayed-startup-finished");
    os.addObserver(this, "sessionstore-windows-restored");
    os.addObserver(this, "browser:purge-session-history");
    os.addObserver(this, "quit-application-requested");
    os.addObserver(this, "quit-application-granted");
1208
    if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
1209
1210
      os.addObserver(this, "browser-lastwindow-close-requested");
      os.addObserver(this, "browser-lastwindow-close-granted");
1211
    }
1212
1213
1214
    os.addObserver(this, "weave:service:ready");
    os.addObserver(this, "fxaccounts:onverified");
    os.addObserver(this, "fxaccounts:device_connected");
1215
    os.addObserver(this, "fxaccounts:verify_login");
1216
    os.addObserver(this, "fxaccounts:device_disconnected");
1217
    os.addObserver(this, "fxaccounts:commands:open-uri");
1218
1219
1220
1221
1222
1223
    os.addObserver(this, "weave:engine:clients:display-uris");
    os.addObserver(this, "session-save");
    os.addObserver(this, "places-init-complete");
    os.addObserver(this, "distribution-customization-complete");
    os.addObserver(this, "handle-xul-text-link");
    os.addObserver(this, "profile-before-change");
1224
    os.addObserver(this, "keyword-search");
1225
1226
1227
1228
    os.addObserver(this, "browser-search-engine-modified");
    os.addObserver(this, "restart-in-safe-mode");
    os.addObserver(this, "flash-plugin-hang");
    os.addObserver(this, "xpi-signature-changed");
1229
    os.addObserver(this, "sync-ui-state:update");
1230
    os.addObserver(this, "handlersvc-store-initialized");
1231

1232
1233
    ActorManagerParent.addJSProcessActors(JSPROCESSACTORS);
    ActorManagerParent.addJSWindowActors(JSWINDOWACTORS);
1234

1235
    this._flashHangCount = 0;
1236
1237
1238
    this._firstWindowReady = new Promise(
      resolve => (this._firstWindowLoaded = resolve)
    );
1239
1240
1241
    if (AppConstants.platform == "win") {
      JawsScreenReaderVersionCheck.init();
    }
1242
1243
1244

    // This value is to limit collecting Places telemetry once per session.
    this._placesTelemetryGathered = false;
1245
1246
1247
  },

  // cleanup (called on application shutdown)
1248
  _dispose: function BG__dispose() {
1249
1250
1251
1252
1253
    // AboutHomeStartupCache might write to the cache during
    // quit-application-granted, so we defer uninitialization
    // until here.
    AboutHomeStartupCache.uninit();

1254
    let os = Services.obs;
1255
    os.removeObserver(this, "notifications-open-settings");
1256
1257
1258
1259
1260
    os.removeObserver(this, "final-ui-startup");
    os.removeObserver(this, "sessionstore-windows-restored");
    os.removeObserver(this, "browser:purge-session-history");
    os.removeObserver(this, "quit-application-requested");
    os.removeObserver(this, "quit-application-granted");
1261
    os.removeObserver(this, "restart-in-safe-mode");
1262
1263
1264
1265
    if (OBSERVE_LASTWINDOW_CLOSE_TOPICS) {
      os.removeObserver(this, "browser-lastwindow-close-requested");
      os.removeObserver(this, "browser-lastwindow-close-granted");
    }
1266
    os.removeObserver(this, "weave:service:ready");
1267
    os.removeObserver(this, "fxaccounts:onverified");
1268
    os.removeObserver(this, "fxaccounts:device_connected");
1269
    os.removeObserver(this, "fxaccounts:verify_login");