Bug 1332343 - Fix browser_largeAllocation.js in multi-e10s, r=smaug
authorMichael Layzell <michael@thelayzells.com>
Thu, 26 Jan 2017 12:07:24 -0500
changeset 331910 5122878d77913ccd74420fb46340ef938cd18916
parent 331909 bb5ca84bd66091749a4a81a3eb82a5afd78ca0d8
child 331911 55309e5ab1bfbffefa7d0d879e1d63bb67723a3a
push id31291
push usercbook@mozilla.com
push dateWed, 01 Feb 2017 12:14:40 +0000
treeherdermozilla-central@9e7b1041929f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1332343
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1332343 - Fix browser_largeAllocation.js in multi-e10s, r=smaug MozReview-Commit-ID: EdNYf1saOI0
dom/interfaces/base/nsITabChild.idl
dom/ipc/TabChild.cpp
dom/tests/browser/browser.ini
dom/tests/browser/browser_largeAllocation.js
dom/tests/browser/test_largeAllocation.html
--- a/dom/interfaces/base/nsITabChild.idl
+++ b/dom/interfaces/base/nsITabChild.idl
@@ -29,10 +29,12 @@ interface nsITabChild : nsISupports
 
   [noscript] void remoteSizeShellTo(in int32_t width, in int32_t height,
                                     in int32_t shellItemWidth, in int32_t shellItemHeight);
 
   [noscript] void remoteDropLinks(in unsigned long linksCount,
                                   [array, size_is(linksCount)] in nsIDroppedLinkItem links);
 
   readonly attribute uint64_t tabId;
+
+  readonly attribute bool isInFreshProcess;
 };
 
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -3102,16 +3102,24 @@ TabChild::RecvThemeChanged(nsTArray<Look
 mozilla::ipc::IPCResult
 TabChild::RecvSetFreshProcess()
 {
   MOZ_ASSERT(!sWasFreshProcess, "Can only be a fresh process once!");
   mIsFreshProcess = true;
   return IPC_OK();
 }
 
+NS_IMETHODIMP
+TabChild::GetIsInFreshProcess(bool* aResult)
+{
+  MOZ_ASSERT(aResult);
+  *aResult = mIsFreshProcess || sWasFreshProcess;
+  return NS_OK;
+}
+
 mozilla::plugins::PPluginWidgetChild*
 TabChild::AllocPPluginWidgetChild()
 {
     return new mozilla::plugins::PluginWidgetChild();
 }
 
 bool
 TabChild::DeallocPPluginWidgetChild(mozilla::plugins::PPluginWidgetChild* aActor)
--- a/dom/tests/browser/browser.ini
+++ b/dom/tests/browser/browser.ini
@@ -31,17 +31,17 @@ skip-if = !e10s
 [browser_ConsoleAPITests.js]
 skip-if = e10s
 [browser_ConsoleStorageAPITests.js]
 [browser_ConsoleStoragePBTest_perwindowpb.js]
 [browser_focus_steal_from_chrome.js]
 [browser_focus_steal_from_chrome_during_mousedown.js]
 [browser_frame_elements.js]
 [browser_largeAllocation.js]
-skip-if = true || !e10s # Large-Allocation requires e10s, turned off for e10s-multi Bug 1315042
+skip-if = !e10s # Large-Allocation requires e10s
 [browser_localStorage_privatestorageevent.js]
 [browser_test__content.js]
 [browser_test_new_window_from_content.js]
 tags = openwindow
 skip-if = toolkit == 'android'  || (os == "linux" && debug) # see bug 1261495 for Linux debug time outs
 support-files =
   test_new_window_from_content_child.html
 [browser_test_toolbars_visibility.js]
--- a/dom/tests/browser/browser_largeAllocation.js
+++ b/dom/tests/browser/browser_largeAllocation.js
@@ -2,25 +2,33 @@
  * 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/. */
 
 const TEST_URI = "http://example.com/browser/dom/tests/browser/test_largeAllocation.html";
 const TEST_URI_2 = "http://example.com/browser/dom/tests/browser/test_largeAllocation2.html";
 
 function expectProcessCreated() {
   let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
-  return new Promise(resolve => {
+  let kill; // A kill function which will disable the promise.
+  let promise = new Promise((resolve, reject) => {
     let topic = "ipc:content-created";
     function observer() {
       os.removeObserver(observer, topic);
       ok(true, "Expect process created");
       resolve();
     }
     os.addObserver(observer, topic, /* weak = */ false);
+    kill = () => {
+      os.removeObserver(observer, topic);
+      ok(true, "Expect process created killed");
+      reject();
+    };
   });
+  promise.kill = kill;
+  return promise;
 }
 
 function expectNoProcess() {
   let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
   let topic = "ipc:content-created";
   function observer() {
     ok(false, "A process was created!");
     os.removeObserver(observer, topic);
@@ -33,16 +41,29 @@ function expectNoProcess() {
 function getPID(aBrowser) {
   return ContentTask.spawn(aBrowser, null, () => {
     const appinfo = Components.classes["@mozilla.org/xre/app-info;1"]
             .getService(Components.interfaces.nsIXULRuntime);
     return appinfo.processID;
   });
 }
 
+function getIsFreshProcess(aBrowser) {
+  return ContentTask.spawn(aBrowser, null, () => {
+    try {
+      return docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                     .getInterface(Ci.nsITabChild)
+                     .isInFreshProcess;
+    } catch (e) {
+      // This must be a non-remote browser, which means it is not fresh
+      return false;
+    }
+  });
+}
+
 add_task(function*() {
   // I'm terrible and put this set of tests into a single file, so I need a longer timeout
   requestLongerTimeout(2);
 
   yield SpecialPowers.pushPrefEnv({
     set: [
       ["dom.largeAllocationHeader.enabled", true],
       // Increase processCount.webLargeAllocation to avoid any races where
@@ -50,35 +71,38 @@ add_task(function*() {
       ["dom.ipc.processCount.webLargeAllocation", 20]
     ]
   });
 
   // A toplevel tab should be able to navigate cross process!
   yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
     info("Starting test 0");
     let pid1 = yield getPID(aBrowser);
+    is(false, yield getIsFreshProcess(aBrowser));
 
     let epc = expectProcessCreated();
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.location = TEST_URI;
     });
 
     // Wait for the new process to be created
     yield epc;
 
     let pid2 = yield getPID(aBrowser);
 
     isnot(pid1, pid2, "The pids should be different between the initial load and the new load");
+    is(true, yield getIsFreshProcess(aBrowser));
   });
 
   // When a Large-Allocation document is loaded in an iframe, the header should
   // be ignored, and the tab should stay in the current process.
   yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
     info("Starting test 1");
     let pid1 = yield getPID(aBrowser);
+    is(false, yield getIsFreshProcess(aBrowser));
 
     // Fail the test if we create a process
     let stopExpectNoProcess = expectNoProcess();
 
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.body.innerHTML = `<iframe src='${TEST_URI}'></iframe>`;
 
       return new Promise(resolve => {
@@ -87,24 +111,26 @@ add_task(function*() {
           resolve();
         };
       });
     });
 
     let pid2 = yield getPID(aBrowser);
 
     is(pid1, pid2, "The PID should not have changed");
+    is(false, yield getIsFreshProcess(aBrowser));
 
     stopExpectNoProcess();
   });
 
   // If you have an opener cross process navigation shouldn't work
   yield BrowserTestUtils.withNewTab("http://example.com", function*(aBrowser) {
     info("Starting test 2");
     let pid1 = yield getPID(aBrowser);
+    is(false, yield getIsFreshProcess(aBrowser));
 
     // Fail the test if we create a process
     let stopExpectNoProcess = expectNoProcess();
 
     let loaded = ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.body.innerHTML = '<button>CLICK ME</button>';
 
       return new Promise(resolve => {
@@ -121,180 +147,201 @@ add_task(function*() {
 
     yield BrowserTestUtils.synthesizeMouseAtCenter("button", {}, aBrowser);
 
     yield loaded;
 
     let pid2 = yield getPID(aBrowser);
 
     is(pid1, pid2, "The PID should not have changed");
+    is(false, yield getIsFreshProcess(aBrowser));
 
     stopExpectNoProcess();
   });
 
   // Load Large-Allocation twice with about:blank load in between
   yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
     info("Starting test 3");
     let pid1 = yield getPID(aBrowser);
+    is(false, yield getIsFreshProcess(aBrowser));
 
     let epc = expectProcessCreated();
 
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.location = TEST_URI;
     });
 
     yield epc;
 
     let pid2 = yield getPID(aBrowser);
 
     isnot(pid1, pid2);
-
-    epc = expectProcessCreated();
+    is(true, yield getIsFreshProcess(aBrowser));
 
     yield BrowserTestUtils.browserLoaded(aBrowser);
 
     yield ContentTask.spawn(aBrowser, null, () => content.document.location = "about:blank");
 
     yield BrowserTestUtils.browserLoaded(aBrowser);
 
     let pid3 = yield getPID(aBrowser);
 
     // We should have been kicked out of the large-allocation process by the
-    // load, meaning we're back in the first process.
-    is(pid1, pid3); // XXX: This may be flakey in multiple content process e10s?
+    // load, meaning we're back in a non-fresh process
+    is(false, yield getIsFreshProcess(aBrowser));
+
+    epc = expectProcessCreated();
 
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.location = TEST_URI;
     });
 
     yield epc;
 
     let pid4 = yield getPID(aBrowser);
 
     isnot(pid1, pid4);
     isnot(pid2, pid4);
+    is(true, yield getIsFreshProcess(aBrowser));
   });
 
   // Load Large-Allocation then about:blank load, then back button press should load from bfcache.
   yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
     info("Starting test 4");
     let pid1 = yield getPID(aBrowser);
+    is(false, yield getIsFreshProcess(aBrowser));
 
     let epc = expectProcessCreated();
 
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.location = TEST_URI;
     });
 
     yield epc;
 
     let pid2 = yield getPID(aBrowser);
 
     isnot(pid1, pid2, "PIDs 1 and 2 should not match");
-
-    let stopExpectNoProcess = expectNoProcess();
+    is(true, yield getIsFreshProcess(aBrowser));
 
     yield BrowserTestUtils.browserLoaded(aBrowser);
 
     // Switch to about:blank, so we can navigate back
     yield ContentTask.spawn(aBrowser, null, () => {
       content.document.location = "about:blank";
     });
 
     yield BrowserTestUtils.browserLoaded(aBrowser);
 
     let pid3 = yield getPID(aBrowser);
 
     // We should have been kicked out of the large-allocation process by the
-    // load, meaning we're back in the first process.
-    is(pid1, pid3, "PIDs 1 and 3 should match");
-
-    stopExpectNoProcess();
+    // load, meaning we're back in a non-large-allocation process.
+    is(false, yield getIsFreshProcess(aBrowser));
 
     epc = expectProcessCreated();
 
     // Navigate back to the previous page. As the large alloation process was
     // left, it won't be in bfcache and will have to be loaded fresh.
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.window.history.back();
     });
 
     yield epc;
 
     let pid4 = yield getPID(aBrowser);
 
     isnot(pid1, pid4, "PID 4 shouldn't match PID 1");
     isnot(pid2, pid4, "PID 4 shouldn't match PID 2");
-
+    isnot(pid3, pid4, "PID 4 shouldn't match PID 3");
+    is(true, yield getIsFreshProcess(aBrowser));
   });
 
   // Two consecutive large-allocation loads should create two processes.
   yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
     info("Starting test 5");
     let pid1 = yield getPID(aBrowser);
+    is(false, yield getIsFreshProcess(aBrowser));
 
     let ready = Promise.all([expectProcessCreated(),
                              BrowserTestUtils.browserLoaded(aBrowser)]);
 
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.location = TEST_URI;
     });
 
     yield ready;
 
     let pid2 = yield getPID(aBrowser);
 
     isnot(pid1, pid2, "PIDs 1 and 2 should not match");
+    is(true, yield getIsFreshProcess(aBrowser));
 
     let epc = expectProcessCreated();
 
     yield ContentTask.spawn(aBrowser, TEST_URI_2, TEST_URI_2 => {
       content.document.location = TEST_URI_2;
     });
 
     yield epc;
 
+    // We just saw the creation of a new process. This is either the process we
+    // are interested in, or, in a multi-e10s situation, the normal content
+    // process which was created for the normal content to be loaded into as the
+    // browsing context was booted out of the fresh process. If we discover that
+    // this was not a fresh process, we'll need to wait for another process.
+    // Start listening now.
+    epc = expectProcessCreated();
+    if (!(yield getIsFreshProcess(aBrowser))) {
+      yield epc;
+    } else {
+      epc.kill();
+    }
+
     let pid3 = yield getPID(aBrowser);
 
     isnot(pid1, pid3, "PIDs 1 and 3 should not match");
-    isnot(pid2, pid3, "PIDs 1 and 3 should not match");
+    isnot(pid2, pid3, "PIDs 2 and 3 should not match");
+    is(true, yield getIsFreshProcess(aBrowser));
   });
 
   // Opening a window from the large-allocation window should prevent the process switch.
   yield BrowserTestUtils.withNewTab("about:blank", function*(aBrowser) {
     info("Starting test 6");
     let pid1 = yield getPID(aBrowser);
+    is(false, yield getIsFreshProcess(aBrowser));
 
     let ready = Promise.all([expectProcessCreated(),
                              BrowserTestUtils.browserLoaded(aBrowser)]);
 
     yield ContentTask.spawn(aBrowser, TEST_URI, TEST_URI => {
       content.document.location = TEST_URI;
     });
 
     yield ready;
 
     let pid2 = yield getPID(aBrowser);
 
     isnot(pid1, pid2, "PIDs 1 and 2 should not match");
-
-    yield BrowserTestUtils.synthesizeMouse("a", 0, 0, {}, aBrowser);
+    is(true, yield getIsFreshProcess(aBrowser));
 
     let stopExpectNoProcess = expectNoProcess();
 
     yield ContentTask.spawn(aBrowser, null, () => {
+      this.__newWindow = content.window.open("about:blank");
       content.document.location = "about:blank";
     });
 
     yield BrowserTestUtils.browserLoaded(aBrowser);
 
     let pid3 = yield getPID(aBrowser);
 
     is(pid3, pid2, "PIDs 2 and 3 should match");
+    is(true, yield getIsFreshProcess(aBrowser));
 
     stopExpectNoProcess();
 
-    is(gBrowser.tabs.length, 3, "There should be 3 tabs");
-
-    // Get rid of that other tab. It should always be the last one.
-    gBrowser.removeTab(gBrowser.tabs[2]);
+    yield ContentTask.spawn(aBrowser, null, () => {
+      ok(this.__newWindow, "The window should have been stored");
+      this.__newWindow.close();
+    });
   });
 });
--- a/dom/tests/browser/test_largeAllocation.html
+++ b/dom/tests/browser/test_largeAllocation.html
@@ -1,9 +1,4 @@
 <!doctype html>
 <html>
-  <script>
-    function onClick() {
-      window.open("about:blank");
-    }
-  </script>
-  <body><a onclick="onClick()">clicky</a>Loaded in a new process!</body>
+  <body>Loaded in a new process!</body>
 </html>