From 2ce85f90169d86463c156a76dc441d028e2108f2 Mon Sep 17 00:00:00 2001 From: Yury Semikhatsky Date: Tue, 31 Mar 2020 17:20:08 -0700 Subject: [PATCH] =?UTF-8?q?Revert=20"browser(firefox):=20instrument=20all?= =?UTF-8?q?=20windows,=20support=20silent=20mode=E2=80=A6=20(#1615)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser_patches/firefox/BUILD_NUMBER | 2 +- .../firefox/patches/bootstrap.diff | 210 +++++++----------- .../firefox/preferences/playwright.cfg | 2 +- 3 files changed, 85 insertions(+), 129 deletions(-) diff --git a/browser_patches/firefox/BUILD_NUMBER b/browser_patches/firefox/BUILD_NUMBER index f7b4fb992b..00146f256d 100644 --- a/browser_patches/firefox/BUILD_NUMBER +++ b/browser_patches/firefox/BUILD_NUMBER @@ -1 +1 @@ -1065 +1066 diff --git a/browser_patches/firefox/patches/bootstrap.diff b/browser_patches/firefox/patches/bootstrap.diff index 8b16affca9..87281ebbce 100644 --- a/browser_patches/firefox/patches/bootstrap.diff +++ b/browser_patches/firefox/patches/bootstrap.diff @@ -1996,10 +1996,10 @@ index 0000000000000000000000000000000000000000..ba34976ad05e7f5f1a99777f76ac08b1 +this.SimpleChannel = SimpleChannel; diff --git a/juggler/TargetRegistry.js b/juggler/TargetRegistry.js new file mode 100644 -index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e178eb98d5 +index 0000000000000000000000000000000000000000..dcf03385589acc29c7fe0f02f912d40ab7efb76f --- /dev/null +++ b/juggler/TargetRegistry.js -@@ -0,0 +1,559 @@ +@@ -0,0 +1,479 @@ +const {EventEmitter} = ChromeUtils.import('resource://gre/modules/EventEmitter.jsm'); +const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); +const {SimpleChannel} = ChromeUtils.import('chrome://juggler/content/SimpleChannel.js'); @@ -2010,7 +2010,6 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 +const {NetworkHandler} = ChromeUtils.import("chrome://juggler/content/protocol/NetworkHandler.js"); +const {RuntimeHandler} = ChromeUtils.import("chrome://juggler/content/protocol/RuntimeHandler.js"); +const {AccessibilityHandler} = ChromeUtils.import("chrome://juggler/content/protocol/AccessibilityHandler.js"); -+const {AppConstants} = ChromeUtils.import("resource://gre/modules/AppConstants.jsm"); + +const Cc = Components.classes; +const Ci = Components.interfaces; @@ -2027,7 +2026,7 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 +]; + +class TargetRegistry { -+ constructor() { ++ constructor(mainWindow) { + EventEmitter.decorate(this); + + this._browserContextIdToBrowserContext = new Map(); @@ -2043,20 +2042,22 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 + + this._defaultContext = new BrowserContext(this, undefined, undefined); + ++ this._mainWindow = mainWindow; + this._targets = new Map(); -+ this._tabToTarget = new Map(); -+ Services.obs.addObserver(this, 'oop-frameloader-crashed'); + -+ const onTabOpenListener = event => { ++ this._tabToTarget = new Map(); ++ ++ for (const tab of this._mainWindow.gBrowser.tabs) ++ this._createTargetForTab(tab); ++ this._mainWindow.gBrowser.tabContainer.addEventListener('TabOpen', event => { + const target = this._createTargetForTab(event.target); + // If we come here, content will have juggler script from the start, + // and we should wait for initial navigation. + target._waitForInitialNavigation = true; + // For pages created before we attach to them, we don't wait for initial + // navigation (target._waitForInitialNavigation is false by default). -+ }; -+ -+ const onTabCloseListener = event => { ++ }); ++ this._mainWindow.gBrowser.tabContainer.addEventListener('TabClose', event => { + const tab = event.target; + const target = this._tabToTarget.get(tab); + if (!target) @@ -2065,32 +2066,8 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 + this._tabToTarget.delete(tab); + target.dispose(); + this.emit(TargetRegistry.Events.TargetDestroyed, target); -+ }; -+ -+ const wmListener = { -+ onOpenWindow: async window => { -+ const domWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); -+ if (!(domWindow instanceof Ci.nsIDOMChromeWindow)) -+ return; -+ await this._waitForWindowLoad(domWindow); -+ for (const tab of domWindow.gBrowser.tabs) -+ this._createTargetForTab(tab); -+ domWindow.gBrowser.tabContainer.addEventListener('TabOpen', onTabOpenListener); -+ domWindow.gBrowser.tabContainer.addEventListener('TabClose', onTabCloseListener); -+ }, -+ onCloseWindow: window => { -+ const domWindow = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow); -+ if (!(domWindow instanceof Ci.nsIDOMChromeWindow)) -+ return; -+ if (!domWindow.gBrowser) -+ return; -+ domWindow.gBrowser.tabContainer.removeEventListener('TabOpen', onTabOpenListener); -+ domWindow.gBrowser.tabContainer.removeEventListener('TabClose', onTabCloseListener); -+ for (const tab of domWindow.gBrowser.tabs) -+ onTabCloseListener({ target: tab }); -+ }, -+ }; -+ Services.wm.addListener(wmListener); ++ }); ++ Services.obs.addObserver(this, 'oop-frameloader-crashed'); + } + + defaultContext() { @@ -2105,42 +2082,13 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 + return this._browserContextIdToBrowserContext.get(browserContextId); + } + -+ async _waitForWindowLoad(window) { -+ if (window.document.readyState === 'complete') -+ return; -+ await new Promise(fulfill => { -+ window.addEventListener('load', function listener() { -+ window.removeEventListener('load', listener); -+ fulfill(); -+ }); -+ }); -+ } -+ + async newPage({browserContextId}) { -+ let window; -+ let created = false; -+ const windowsIt = Services.wm.getEnumerator('navigator:browser'); -+ if (windowsIt.hasMoreElements()) { -+ window = windowsIt.getNext(); -+ } else { -+ const features = "chrome,dialog=no,all"; -+ const args = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString); -+ args.data = 'about:blank'; -+ window = Services.ww.openWindow(null, AppConstants.BROWSER_CHROME_URL, '_blank', features, args); -+ created = true; -+ } -+ await this._waitForWindowLoad(window); + const browserContext = this.browserContextForId(browserContextId); -+ const tab = window.gBrowser.addTab('about:blank', { ++ const tab = this._mainWindow.gBrowser.addTab('about:blank', { + userContextId: browserContext.userContextId, + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + }); -+ if (created) { -+ window.gBrowser.removeTab(window.gBrowser.getTabForBrowser(window.gBrowser.getBrowserAtIndex(0)), { -+ skipPermitUnload: true, -+ }); -+ } -+ window.gBrowser.selectedTab = tab; ++ this._mainWindow.gBrowser.selectedTab = tab; + const target = this._tabToTarget.get(tab); + await target._contentReadyPromise; + if (browserContext.options.timezoneId) { @@ -2181,25 +2129,14 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 + return this._targets.get(targetId); + } + -+ _tabForBrowser(browser) { -+ // TODO: replace all of this with browser -> target map. -+ const windowsIt = Services.wm.getEnumerator('navigator:browser'); -+ while (windowsIt.hasMoreElements()) { -+ const window = windowsIt.getNext(); -+ const tab = window.gBrowser.getTabForBrowser(browser); -+ if (tab) -+ return { tab, gBrowser: window.gBrowser }; -+ } -+ } -+ + _targetForBrowser(browser) { -+ const tab = this._tabForBrowser(browser); -+ return tab ? this._tabToTarget.get(tab.tab) : undefined; ++ const tab = this._mainWindow.gBrowser.getTabForBrowser(browser); ++ return tab ? this._tabToTarget.get(tab) : undefined; + } + + browserContextForBrowser(browser) { -+ const tab = this._tabForBrowser(browser); -+ return tab ? this._userContextIdToBrowserContext.get(tab.tab.userContextId) : undefined; ++ const tab = this._mainWindow.gBrowser.getTabForBrowser(browser); ++ return tab ? this._userContextIdToBrowserContext.get(tab.userContextId) : undefined; + } + + _createTargetForTab(tab) { @@ -2222,10 +2159,6 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 + if (!target) + return; + target.emit('crashed'); -+ this._targets.delete(target.id()); -+ this._tabToTarget.delete(target._tab); -+ target.dispose(); -+ this.emit(TargetRegistry.Events.TargetDestroyed, target); + return; + } + } @@ -2250,7 +2183,7 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 + this._eventListeners = [ + helper.addProgressListener(tab.linkedBrowser, navigationListener, Ci.nsIWebProgress.NOTIFY_LOCATION), + helper.addMessageListener(tab.linkedBrowser.messageManager, 'juggler:content-ready', { -+ receiveMessage: message => this._onContentReady(message.data) ++ receiveMessage: () => this._onContentReady() + }), + ]; + @@ -2296,8 +2229,7 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 + } + + async close(runBeforeUnload = false) { -+ const tab = this._registry._tabForBrowser(this._tab.linkedBrowser); -+ await tab.gBrowser.removeTab(this._tab, { ++ await this._registry._mainWindow.gBrowser.removeTab(this._tab, { + skipPermitUnload: !runBeforeUnload, + }); + } @@ -2313,9 +2245,7 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 + networkHandler.enable(); + } + -+ _onContentReady({ userContextId }) { -+ // TODO: this is the earliest when userContextId is available. -+ // We should create target here, while listening to onContentReady for every tab. ++ _onContentReady() { + const sessions = []; + const data = { sessions, target: this }; + this._registry.emit(TargetRegistry.Events.PageTargetReady, data); @@ -2399,20 +2329,10 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 + this.pages = new Set(); + } + -+ async destroy() { ++ destroy() { + if (this.userContextId !== 0) { + ContextualIdentityService.remove(this.userContextId); + ContextualIdentityService.closeContainerTabs(this.userContextId); -+ if (this.pages.size) { -+ await new Promise(f => { -+ const listener = helper.on(this._registry, TargetRegistry.Events.TargetDestroyed, () => { -+ if (!this.pages.size) { -+ helper.removeListeners([listener]); -+ f(); -+ } -+ }); -+ }); -+ } + } + this._registry._browserContextIdToBrowserContext.delete(this.browserContextId); + this._registry._userContextIdToBrowserContext.delete(this.userContextId); @@ -2561,10 +2481,10 @@ index 0000000000000000000000000000000000000000..13bce6f411d4b9f1f71f33526b4729e1 +this.TargetRegistry = TargetRegistry; diff --git a/juggler/components/juggler.js b/juggler/components/juggler.js new file mode 100644 -index 0000000000000000000000000000000000000000..858bb44e43fa3654dafaa9b7a35b2111237f4af0 +index 0000000000000000000000000000000000000000..50617b19845d32006873c15b446afc04651cb6b7 --- /dev/null +++ b/juggler/components/juggler.js -@@ -0,0 +1,76 @@ +@@ -0,0 +1,117 @@ +const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {Dispatcher} = ChromeUtils.import("chrome://juggler/content/protocol/Dispatcher.js"); @@ -2581,6 +2501,7 @@ index 0000000000000000000000000000000000000000..858bb44e43fa3654dafaa9b7a35b2111 + +// Command Line Handler +function CommandLineHandler() { ++ this._port = -1; +}; + +CommandLineHandler.prototype = { @@ -2597,30 +2518,31 @@ index 0000000000000000000000000000000000000000..858bb44e43fa3654dafaa9b7a35b2111 + const jugglerFlag = cmdLine.handleFlagWithParam("juggler", false); + if (!jugglerFlag || isNaN(jugglerFlag)) + return; -+ const port = parseInt(jugglerFlag, 10); -+ const silent = cmdLine.preventDefault; -+ if (silent) -+ Services.startup.enterLastWindowClosingSurvivalArea(); ++ this._port = parseInt(jugglerFlag, 10); ++ Services.obs.addObserver(this, 'sessionstore-windows-restored'); ++ }, + -+ const targetRegistry = new TargetRegistry(); ++ observe: async function(subject, topic) { ++ Services.obs.removeObserver(this, 'sessionstore-windows-restored'); ++ ++ const win = await waitForBrowserWindow(); ++ const targetRegistry = new TargetRegistry(win); + new NetworkObserver(targetRegistry); + + const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm"); + const WebSocketServer = require('devtools/server/socket/websocket-server'); + this._server = Cc["@mozilla.org/network/server-socket;1"].createInstance(Ci.nsIServerSocket); -+ this._server.initSpecialConnection(port, Ci.nsIServerSocket.KeepWhenOffline | Ci.nsIServerSocket.LoopbackOnly, 4); ++ this._server.initSpecialConnection(this._port, Ci.nsIServerSocket.KeepWhenOffline | Ci.nsIServerSocket.LoopbackOnly, 4); + + const token = helper.generateId(); ++ + this._server.asyncListen({ + onSocketAccepted: async(socket, transport) => { + const input = transport.openInputStream(0, 0, 0); + const output = transport.openOutputStream(0, 0, 0); + const webSocket = await WebSocketServer.accept(transport, input, output, "/" + token); + const dispatcher = new Dispatcher(webSocket); -+ const browserHandler = new BrowserHandler(dispatcher.rootSession(), dispatcher, targetRegistry, () => { -+ if (silent) -+ Services.startup.exitLastWindowClosingSurvivalArea(); -+ }); ++ const browserHandler = new BrowserHandler(dispatcher.rootSession(), dispatcher, targetRegistry); + dispatcher.rootSession().registerHandler('Browser', browserHandler); + } + }); @@ -2641,6 +2563,45 @@ index 0000000000000000000000000000000000000000..858bb44e43fa3654dafaa9b7a35b2111 +}; + +var NSGetFactory = XPCOMUtils.generateNSGetFactory([CommandLineHandler]); ++ ++/** ++ * @return {!Promise} ++ */ ++async function waitForBrowserWindow() { ++ const windowsIt = Services.wm.getEnumerator('navigator:browser'); ++ if (windowsIt.hasMoreElements()) ++ return waitForWindowLoaded(windowsIt.getNext()); ++ ++ let fulfill; ++ let promise = new Promise(x => fulfill = x); ++ ++ const listener = { ++ onOpenWindow: window => { ++ if (window instanceof Ci.nsIDOMChromeWindow) { ++ Services.wm.removeListener(listener); ++ fulfill(waitForWindowLoaded(window)); ++ } ++ }, ++ onCloseWindow: () => {} ++ }; ++ Services.wm.addListener(listener); ++ return promise; ++ ++ /** ++ * @param {!Ci.nsIDOMChromeWindow} window ++ * @return {!Promise} ++ */ ++ function waitForWindowLoaded(window) { ++ if (window.document.readyState === 'complete') ++ return window; ++ return new Promise(fulfill => { ++ window.addEventListener('load', function listener() { ++ window.removeEventListener('load', listener); ++ fulfill(window); ++ }); ++ }); ++ } ++} diff --git a/juggler/components/juggler.manifest b/juggler/components/juggler.manifest new file mode 100644 index 0000000000000000000000000000000000000000..50f8930207563e0d6b8a7878fc602dbca54d77fc @@ -4930,10 +4891,10 @@ index 0000000000000000000000000000000000000000..3a386425d3796d0a6786dea193b3402d + diff --git a/juggler/content/main.js b/juggler/content/main.js new file mode 100644 -index 0000000000000000000000000000000000000000..e2a8fc14afe9b851e2bf3893691ca98c69bd12ee +index 0000000000000000000000000000000000000000..1864328a47107621309c9b3726bb84535b780c2f --- /dev/null +++ b/juggler/content/main.js -@@ -0,0 +1,156 @@ +@@ -0,0 +1,153 @@ +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const {Helper} = ChromeUtils.import('chrome://juggler/content/Helper.js'); +const {FrameTree} = ChromeUtils.import('chrome://juggler/content/content/FrameTree.js'); @@ -4993,10 +4954,7 @@ index 0000000000000000000000000000000000000000..e2a8fc14afe9b851e2bf3893691ca98c +} + +function initialize() { -+ const loadContext = docShell.QueryInterface(Ci.nsILoadContext); -+ const userContextId = loadContext.originAttributes.userContextId; -+ -+ let response = sendSyncMessage('juggler:content-ready', { userContextId })[0]; ++ let response = sendSyncMessage('juggler:content-ready', {})[0]; + if (!response) + response = { sessionIds: [], browserContextOptions: {}, waitForInitialNavigation: false }; + @@ -5169,10 +5127,10 @@ index 0000000000000000000000000000000000000000..bf37558bccc48f4d90eadc971c1eb3e4 +this.AccessibilityHandler = AccessibilityHandler; diff --git a/juggler/protocol/BrowserHandler.js b/juggler/protocol/BrowserHandler.js new file mode 100644 -index 0000000000000000000000000000000000000000..5f2368224404c1a4497e1eb06d96f53e84d1453d +index 0000000000000000000000000000000000000000..b26325857d87f714f1250a52f233644806a61ebf --- /dev/null +++ b/juggler/protocol/BrowserHandler.js -@@ -0,0 +1,198 @@ +@@ -0,0 +1,196 @@ +"use strict"; + +const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); @@ -5185,7 +5143,7 @@ index 0000000000000000000000000000000000000000..5f2368224404c1a4497e1eb06d96f53e +const helper = new Helper(); + +class BrowserHandler { -+ constructor(session, dispatcher, targetRegistry, onclose) { ++ constructor(session, dispatcher, targetRegistry) { + this._session = session; + this._dispatcher = dispatcher; + this._targetRegistry = targetRegistry; @@ -5194,7 +5152,6 @@ index 0000000000000000000000000000000000000000..5f2368224404c1a4497e1eb06d96f53e + this._eventListeners = []; + this._createdBrowserContextIds = new Set(); + this._attachedSessions = new Map(); -+ this._onclose = onclose; + } + + async enable({attachToDefaultContext}) { @@ -5232,8 +5189,8 @@ index 0000000000000000000000000000000000000000..5f2368224404c1a4497e1eb06d96f53e + async removeBrowserContext({browserContextId}) { + if (!this._enabled) + throw new Error('Browser domain is not enabled'); -+ await this._targetRegistry.browserContextForId(browserContextId).destroy(); + this._createdBrowserContextIds.delete(browserContextId); ++ this._targetRegistry.browserContextForId(browserContextId).destroy(); + } + + dispose() { @@ -5289,7 +5246,6 @@ index 0000000000000000000000000000000000000000..5f2368224404c1a4497e1eb06d96f53e + } + + async close() { -+ this._onclose(); + let browserWindow = Services.wm.getMostRecentWindow( + "navigator:browser" + ); diff --git a/browser_patches/firefox/preferences/playwright.cfg b/browser_patches/firefox/preferences/playwright.cfg index e8b5149d73..a9d57d13d3 100644 --- a/browser_patches/firefox/preferences/playwright.cfg +++ b/browser_patches/firefox/preferences/playwright.cfg @@ -9,7 +9,7 @@ pref("browser.safebrowsing.provider.mozilla.updateURL", ""); pref("browser.library.activity-stream.enabled", false); pref("browser.search.geoSpecificDefaults", false); pref("browser.search.geoSpecificDefaults.url", ""); -pref("browser.startup.blankWindow", false); + // Make sure Shield doesn't hit the network. pref("app.normandy.api_url", "");