Bug 603903 - Part 4: don't restore tabs until session unlock draft
authorAdam Gashlin <agashlin@mozilla.com>
Wed, 25 Apr 2018 15:46:28 -0700
changeset 788104 cf5f6919e83a0e59f46ba1d4274a2711d6b7e453
parent 788103 9d2f02c36460df7595e572bfa3e4d332af34b7be
push id107905
push userbmo:agashlin@mozilla.com
push dateWed, 25 Apr 2018 22:47:28 +0000
bugs603903
milestone61.0a1
Bug 603903 - Part 4: don't restore tabs until session unlock MozReview-Commit-ID: 2NMEdbQnXsd
browser/components/sessionstore/SessionStore.jsm
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsIWinAppHelper.idl
widget/windows/nsWindow.cpp
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -42,17 +42,18 @@ const MAX_CONCURRENT_TAB_RESTORES = 3;
 const SCREEN_EDGE_SLOP = 8;
 
 // global notifications observed
 const OBSERVING = [
   "browser-window-before-show", "domwindowclosed",
   "quit-application-granted", "browser-lastwindow-close-granted",
   "quit-application", "browser:purge-session-history",
   "browser:purge-domain-data",
-  "idle-daily", "clear-origin-attributes-data"
+  "idle-daily", "clear-origin-attributes-data",
+  "windows-session-unlocked"
 ];
 
 // XUL Window properties to (re)store
 // Restored in restoreDimensions()
 const WINDOW_ATTRIBUTES = ["width", "height", "screenX", "screenY", "sizemode"];
 
 // Hideable window features to (re)store
 // Restored in restoreWindowFeatures()
@@ -623,16 +624,23 @@ var SessionStoreInternal = {
     TelemetryTimestamps.add("sessionRestoreInitialized");
     OBSERVING.forEach(function(aTopic) {
       Services.obs.addObserver(this, aTopic, true);
     }, this);
 
     this._initPrefs();
     this._initialized = true;
 
+    if (Services.appinfo.OS == "WINNT" &&
+        Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).waitingForUnlock) {
+      this._restoreWhenUnlocked = [];
+    } else {
+      this._restoreWhenUnlocked = null;
+    }
+
     Telemetry.getHistogramById("FX_SESSION_RESTORE_PRIVACY_LEVEL").add(
       Services.prefs.getIntPref("browser.sessionstore.privacy_level"));
   },
 
   /**
    * Initialize the session using the state provided by SessionStartup
    */
   initSession() {
@@ -802,16 +810,32 @@ var SessionStoreInternal = {
         break;
       case "clear-origin-attributes-data":
         let userContextId = 0;
         try {
           userContextId = JSON.parse(aData).userContextId;
         } catch (e) {}
         if (userContextId)
           this._forgetTabsWithUserContextId(userContextId);
+        break;
+      case "windows-session-unlocked":
+      {
+        if (this._restoreWhenUnlocked === null) {
+          break;
+        }
+        for (let i = 0; i < this._restoreWhenUnlocked.length; i++) {
+          this._restoreWhenUnlocked[i].msg.requestTime =
+            Services.telemetry.msSystemNow();
+          this._restoreWhenUnlocked[i].browser.messageManager.sendAsyncMessage(
+            "SessionStore:restoreTabContent",
+            this._restoreWhenUnlocked[i].msg);
+        }
+        this._restoreWhenUnlocked = null;
+        break;
+      }
     }
   },
 
   /**
    * This method handles incoming messages sent by the session store content
    * script via the Frame Message Manager or Parent Process Message Manager,
    * and thus enables communication with OOP tabs.
    */
@@ -3429,33 +3453,41 @@ var SessionStoreInternal = {
 
     for (var t = 0; t < newTabCount; t++) {
       let tabData = winData.tabs[t];
 
       let userContextId = tabData.userContextId;
       let select = t == selectTab - 1;
       let tab;
 
+      let delayRestoreContent = this._restoreWhenUnlocked !== null &&
+        Services.appinfo.QueryInterface(Ci.nsIWinAppHelper).waitingForUnlock;
+
       // Re-use existing selected tab if possible to avoid the overhead of
       // selecting a new tab.
-      if (select &&
+      if (select && !delayRestoreContent &&
           tabbrowser.selectedTab.userContextId == userContextId) {
         tab = tabbrowser.selectedTab;
         if (!tabData.pinned) {
           tabbrowser.unpinTab(tab);
         }
         tabbrowser.moveTabToEnd();
         if (aWindow.gMultiProcessBrowser && !tab.linkedBrowser.isRemoteBrowser) {
           tabbrowser.updateBrowserRemoteness(tab.linkedBrowser, true);
         }
       }
 
       // Add a new tab if needed.
       if (!tab) {
         let createLazyBrowser = restoreTabsLazily && !select && !tabData.pinned;
+        let noInitialRestoreContent = false;
+        if (restoreTabsLazily && !createLazyBrowser && delayRestoreContent) {
+          createLazyBrowser = true;
+          noInitialRestoreContent = true;
+        }
 
         let url = "about:blank";
         if (createLazyBrowser && tabData.entries && tabData.entries.length) {
           // Let tabbrowser know the future URI because progress listeners won't
           // get onLocationChange notification before the browser is inserted.
           let activeIndex = (tabData.index || tabData.entries.length) - 1;
           // Ensure the index is in bounds.
           activeIndex = Math.min(activeIndex, tabData.entries.length - 1);
@@ -3468,16 +3500,17 @@ var SessionStoreInternal = {
         // Each tab will get its initial label set in restoreTab.
         tab = tabbrowser.addTab(url,
                                 { createLazyBrowser,
                                   skipAnimation: true,
                                   noInitialLabel: true,
                                   userContextId,
                                   skipBackgroundNotify: true,
                                   bulkOrderedOpen: true });
+        tab.noInitialRestoreContent = noInitialRestoreContent;
 
         if (select) {
           let leftoverTab = tabbrowser.selectedTab;
           tabbrowser.selectedTab = tab;
           tabbrowser.removeTab(leftoverTab);
         }
       }
 
@@ -4006,21 +4039,26 @@ var SessionStoreInternal = {
     }
 
     // If the restored browser wants to show view source content, start up a
     // view source browser that will load the required frame script.
     if (uri && ViewSourceBrowser.isViewSource(uri)) {
       new ViewSourceBrowser(browser);
     }
 
-    browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent",
-      {loadArguments, isRemotenessUpdate,
+    let restoreMessage = {loadArguments, isRemotenessUpdate,
        reason: aOptions.restoreContentReason ||
                RESTORE_TAB_CONTENT_REASON.SET_STATE,
-       requestTime: Services.telemetry.msSystemNow()});
+       requestTime: Services.telemetry.msSystemNow()};
+
+    if (aTab.noInitialRestoreContent && this._restoreWhenUnlocked !== null) {
+      this._restoreWhenUnlocked.push({browser, msg: restoreMessage});
+    } else {
+      browser.messageManager.sendAsyncMessage("SessionStore:restoreTabContent", restoreMessage);
+    }
 
     // Focus the tab's content area.
     if (aTab.selected) {
       browser.focus();
     }
   },
 
   /**
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1437,16 +1437,36 @@ nsXULAppInfo::Callback(nsISupports* aDat
 {
   nsCOMPtr<nsIFile> file = do_QueryInterface(aData);
   MOZ_ASSERT(file);
 
   CrashReporter::SetMemoryReportFile(file);
   return NS_OK;
 }
 
+#ifdef XP_WIN
+NS_IMETHODIMP
+nsXULAppInfo::GetWaitingForUnlock(bool *aWaiting) {
+  if (!gRARRestarted) {
+    *aWaiting = false;
+    return NS_OK;
+  }
+
+  HDESK hDesk = ::OpenInputDesktop(0, false, 0);
+  if (!hDesk) {
+    *aWaiting = true;
+    return NS_OK;
+  }
+  CloseDesktop(hDesk);
+
+  *aWaiting = false;
+  return NS_OK;
+}
+#endif
+
 static const nsXULAppInfo kAppInfo;
 static nsresult AppInfoConstructor(nsISupports* aOuter,
                                    REFNSIID aIID, void **aResult)
 {
   NS_ENSURE_NO_AGGREGATION(aOuter);
 
   return const_cast<nsXULAppInfo*>(&kAppInfo)->
     QueryInterface(aIID, aResult);
--- a/toolkit/xre/nsIWinAppHelper.idl
+++ b/toolkit/xre/nsIWinAppHelper.idl
@@ -11,9 +11,11 @@
  * @status UNSTABLE - This interface is not frozen and will probably change in
  *                    future releases.
  */
 
 [scriptable, uuid(dc263ca8-b257-47eb-b5b7-339d9e0b90f7)]
 interface nsIWinAppHelper : nsISupports
 {
   readonly attribute boolean userCanElevate;
+
+  readonly attribute boolean waitingForUnlock;
 };
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -5292,19 +5292,25 @@ nsWindow::ProcessMessage(UINT msg, WPARA
     break;
 
     case WM_WTSSESSION_CHANGE:
     {
       switch (wParam) {
         case WTS_CONSOLE_CONNECT:
         case WTS_REMOTE_CONNECT:
         case WTS_SESSION_UNLOCK:
+        {
+          nsCOMPtr<nsIObserverService> obsServ =
+            mozilla::services::GetObserverService();
+          obsServ->NotifyObservers(nullptr, "windows-session-unlocked", nullptr);
+
           // When a session becomes visible, we should invalidate.
           Invalidate(true, true, true);
-          break;
+        }
+        break;
         default:
           break;
       }
     }
     break;
 
     case WM_FONTCHANGE:
     {