/* 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/. */ "use strict"; var EXPORTED_SYMBOLS = ["GeckoViewStartup"]; const { GeckoViewUtils } = ChromeUtils.importESModule( "resource://gre/modules/GeckoViewUtils.sys.mjs" ); const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { ActorManagerParent: "resource://gre/modules/ActorManagerParent.sys.mjs", EventDispatcher: "resource://gre/modules/Messaging.sys.mjs", PdfJs: "resource://pdf.js/PdfJs.sys.mjs", Preferences: "resource://gre/modules/Preferences.sys.mjs", }); const { XPCOMUtils } = ChromeUtils.importESModule( "resource://gre/modules/XPCOMUtils.sys.mjs" ); const { debug, warn } = GeckoViewUtils.initLogging("Startup"); var { DelayedInit } = ChromeUtils.import( "resource://gre/modules/DelayedInit.jsm" ); function InitLater(fn, object, name) { return DelayedInit.schedule(fn, object, name, 15000 /* 15s max wait */); } const JSPROCESSACTORS = { GeckoViewPermissionProcess: { parent: { esModuleURI: "resource:///actors/GeckoViewPermissionProcessParent.sys.mjs", }, child: { esModuleURI: "resource:///actors/GeckoViewPermissionProcessChild.sys.mjs", observers: [ "getUserMedia:ask-device-permission", "getUserMedia:request", "recording-device-events", "PeerConnection:request", ], }, }, }; const JSWINDOWACTORS = { LoadURIDelegate: { parent: { esModuleURI: "resource:///actors/LoadURIDelegateParent.sys.mjs", }, child: { esModuleURI: "resource:///actors/LoadURIDelegateChild.sys.mjs", }, messageManagerGroups: ["browsers"], }, GeckoViewPermission: { parent: { esModuleURI: "resource:///actors/GeckoViewPermissionParent.sys.mjs", }, child: { esModuleURI: "resource:///actors/GeckoViewPermissionChild.sys.mjs", }, allFrames: true, includeChrome: true, }, GeckoViewPrompt: { child: { esModuleURI: "resource:///actors/GeckoViewPromptChild.sys.mjs", events: { click: { capture: false, mozSystemGroup: true }, contextmenu: { capture: false, mozSystemGroup: true }, mozshowdropdown: {}, "mozshowdropdown-sourcetouch": {}, MozOpenDateTimePicker: {}, DOMPopupBlocked: { capture: false, mozSystemGroup: true }, }, }, allFrames: true, messageManagerGroups: ["browsers"], }, GeckoViewFormValidation: { child: { esModuleURI: "resource:///actors/GeckoViewFormValidationChild.sys.mjs", events: { MozInvalidForm: {}, }, }, allFrames: true, messageManagerGroups: ["browsers"], }, GeckoViewClipboardPermission: { parent: { esModuleURI: "resource:///actors/GeckoViewClipboardPermissionParent.sys.mjs", }, child: { esModuleURI: "resource:///actors/GeckoViewClipboardPermissionChild.sys.mjs", events: { MozClipboardReadPaste: {}, deactivate: { mozSystemGroup: true }, mousedown: { capture: true, mozSystemGroup: true }, mozvisualscroll: { mozSystemGroup: true }, pagehide: { capture: true, mozSystemGroup: true }, }, }, allFrames: true, }, GeckoViewPdfjs: { parent: { esModuleURI: "resource://pdf.js/GeckoViewPdfjsParent.sys.mjs", }, child: { esModuleURI: "resource://pdf.js/GeckoViewPdfjsChild.sys.mjs", }, allFrames: true, }, }; class GeckoViewStartup { /* ---------- nsIObserver ---------- */ observe(aSubject, aTopic, aData) { debug`observe: ${aTopic}`; switch (aTopic) { case "content-process-ready-for-script": case "app-startup": { GeckoViewUtils.addLazyGetter(this, "GeckoViewConsole", { module: "resource://gre/modules/GeckoViewConsole.sys.mjs", }); GeckoViewUtils.addLazyGetter(this, "GeckoViewStorageController", { module: "resource://gre/modules/GeckoViewStorageController.sys.mjs", ged: [ "GeckoView:ClearData", "GeckoView:ClearSessionContextData", "GeckoView:ClearHostData", "GeckoView:ClearBaseDomainData", "GeckoView:GetAllPermissions", "GeckoView:GetPermissionsByURI", "GeckoView:SetPermission", "GeckoView:SetPermissionByURI", "GeckoView:GetCookieBannerModeForDomain", "GeckoView:SetCookieBannerModeForDomain", "GeckoView:RemoveCookieBannerModeForDomain", ], }); GeckoViewUtils.addLazyGetter(this, "GeckoViewPushController", { module: "resource://gre/modules/GeckoViewPushController.sys.mjs", ged: ["GeckoView:PushEvent", "GeckoView:PushSubscriptionChanged"], }); GeckoViewUtils.addLazyPrefObserver( { name: "geckoview.console.enabled", default: false, }, { handler: _ => this.GeckoViewConsole, } ); // Parent process only if ( Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_DEFAULT ) { lazy.ActorManagerParent.addJSWindowActors(JSWINDOWACTORS); lazy.ActorManagerParent.addJSProcessActors(JSPROCESSACTORS); if (Services.appinfo.sessionHistoryInParent) { GeckoViewUtils.addLazyGetter(this, "GeckoViewSessionStore", { module: "resource://gre/modules/GeckoViewSessionStore.sys.mjs", observers: [ "browsing-context-did-set-embedder", "browsing-context-discarded", ], }); } GeckoViewUtils.addLazyGetter(this, "GeckoViewWebExtension", { module: "resource://gre/modules/GeckoViewWebExtension.sys.mjs", ged: [ "GeckoView:ActionDelegate:Attached", "GeckoView:BrowserAction:Click", "GeckoView:PageAction:Click", "GeckoView:RegisterWebExtension", "GeckoView:UnregisterWebExtension", "GeckoView:WebExtension:CancelInstall", "GeckoView:WebExtension:Disable", "GeckoView:WebExtension:Enable", "GeckoView:WebExtension:EnsureBuiltIn", "GeckoView:WebExtension:Get", "GeckoView:WebExtension:Install", "GeckoView:WebExtension:InstallBuiltIn", "GeckoView:WebExtension:List", "GeckoView:WebExtension:PortDisconnect", "GeckoView:WebExtension:PortMessageFromApp", "GeckoView:WebExtension:SetPBAllowed", "GeckoView:WebExtension:Uninstall", "GeckoView:WebExtension:Update", ], observers: [ "devtools-installed-addon", "testing-installed-addon", "testing-uninstalled-addon", ], }); GeckoViewUtils.addLazyGetter(this, "ChildCrashHandler", { module: "resource://gre/modules/ChildCrashHandler.sys.mjs", observers: ["ipc:content-shutdown", "compositor:process-aborted"], }); lazy.EventDispatcher.instance.registerListener(this, [ "GeckoView:StorageDelegate:Attached", ]); } break; } case "profile-after-change": { GeckoViewUtils.addLazyGetter(this, "GeckoViewRemoteDebugger", { module: "resource://gre/modules/GeckoViewRemoteDebugger.sys.mjs", init: gvrd => gvrd.onInit(), }); GeckoViewUtils.addLazyPrefObserver( { name: "devtools.debugger.remote-enabled", default: false, }, { handler: _ => this.GeckoViewRemoteDebugger, } ); GeckoViewUtils.addLazyGetter(this, "DownloadTracker", { module: "resource://gre/modules/GeckoViewWebExtension.sys.mjs", ged: ["GeckoView:WebExtension:DownloadChanged"], }); ChromeUtils.importESModule( "resource://gre/modules/NotificationDB.sys.mjs" ); // Listen for global EventDispatcher messages lazy.EventDispatcher.instance.registerListener(this, [ "GeckoView:ResetUserPrefs", "GeckoView:SetDefaultPrefs", "GeckoView:SetLocale", ]); Services.obs.addObserver(this, "browser-idle-startup-tasks-finished"); Services.obs.addObserver(this, "handlersvc-store-initialized"); Services.obs.notifyObservers(null, "geckoview-startup-complete"); break; } case "browser-idle-startup-tasks-finished": { // TODO bug 1730026: when an alternative is introduced that runs once, // replace this observer topic with that alternative. // This only needs to happen once during startup. Services.obs.removeObserver(this, aTopic); // Notify the start up crash tracker that the browser has successfully // started up so the startup cache isn't rebuilt on next startup. Services.startup.trackStartupCrashEnd(); break; } 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. try { lazy.PdfJs.init(this._isNewProfile); } catch {} break; } } } onEvent(aEvent, aData, aCallback) { debug`onEvent ${aEvent}`; switch (aEvent) { case "GeckoView:ResetUserPrefs": { const prefs = new lazy.Preferences(); prefs.reset(aData.names); break; } case "GeckoView:SetDefaultPrefs": { const prefs = new lazy.Preferences({ defaultBranch: true }); for (const name of Object.keys(aData)) { try { prefs.set(name, aData[name]); } catch (e) { warn`Failed to set preference ${name}: ${e}`; } } break; } case "GeckoView:SetLocale": if (aData.requestedLocales) { Services.locale.requestedLocales = aData.requestedLocales; } const pls = Cc["@mozilla.org/pref-localizedstring;1"].createInstance( Ci.nsIPrefLocalizedString ); pls.data = aData.acceptLanguages; Services.prefs.setComplexValue( "intl.accept_languages", Ci.nsIPrefLocalizedString, pls ); break; case "GeckoView:StorageDelegate:Attached": InitLater(() => { const loginDetection = Cc[ "@mozilla.org/login-detection-service;1" ].createInstance(Ci.nsILoginDetectionService); loginDetection.init(); }); break; } } } GeckoViewStartup.prototype.classID = Components.ID( "{8e993c34-fdd6-432c-967e-f995d888777f}" ); GeckoViewStartup.prototype.QueryInterface = ChromeUtils.generateQI([ "nsIObserver", ]);