Bug 913155 - Electrolysis: Add a submit crashreport box on the tab crashed page. r=felipe,smaug
authorTom Schuster <evilpies@gmail.com>
Thu, 12 Sep 2013 15:24:10 -0400
changeset 159828 394c53ce3e362b0cf6128686f0c8b87e7e48b29b
parent 159778 cc0af9e0a324f7e04762737005bcca7e8431e169
child 159829 966df39694c25507ef690c8e2570bca82d09363e
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipe, smaug
bugs913155
milestone26.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 913155 - Electrolysis: Add a submit crashreport box on the tab crashed page. r=felipe,smaug
browser/base/content/aboutTabCrashed.xhtml
browser/base/content/browser.js
browser/base/content/content.js
browser/locales/en-US/chrome/browser/browser.dtd
browser/modules/TabCrashReporter.jsm
browser/modules/moz.build
browser/themes/linux/aboutTabCrashed.css
browser/themes/osx/aboutTabCrashed.css
browser/themes/windows/aboutTabCrashed.css
content/base/public/nsIFrameLoader.idl
content/base/src/nsFrameLoader.cpp
content/base/src/nsFrameLoader.h
--- a/browser/base/content/aboutTabCrashed.xhtml
+++ b/browser/base/content/aboutTabCrashed.xhtml
@@ -10,31 +10,38 @@
     "DTD/xhtml1-strict.dtd">
   %htmlDTD;
   <!ENTITY % globalDTD
     SYSTEM "chrome://global/locale/global.dtd">
   %globalDTD;
   <!ENTITY % browserDTD
     SYSTEM "chrome://browser/locale/browser.dtd">
   %browserDTD;
+  <!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
+  %brandDTD;
 
 ]>
 
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <link rel="stylesheet" type="text/css" media="all"
           href="chrome://browser/skin/aboutTabCrashed.css"/>
   </head>
 
   <body dir="&locale.dir;">
     <div id="error-box">
       <p id="main-error-msg">&tabCrashed.header;</p>
       <p id="helper-error-msg">&tabCrashed.message;</p>
     </div>
 
+    <div id="report-box">
+      <input type="checkbox" id="checkSendReport" checked="checked"/>
+      <label for="checkSendReport">&tabCrashed.checkSendReport;</label>
+    </div>
+
     <div id="button-box">
       <button id="tryAgain">&tabCrashed.tryAgain;</button>
     </div>
   </body>
 
   <script type="text/javascript;version=1.8"><![CDATA[
     function parseQueryString() {
       let url = document.documentURI;
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -132,16 +132,21 @@ XPCOMUtils.defineLazyModuleGetter(this, 
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SitePermissions",
   "resource:///modules/SitePermissions.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
   "resource:///modules/sessionstore/SessionStore.jsm");
 
+#ifdef MOZ_CRASHREPORTER
+XPCOMUtils.defineLazyModuleGetter(this, "TabCrashReporter",
+  "resource:///modules/TabCrashReporter.jsm");
+#endif
+
 let gInitialPages = [
   "about:blank",
   "about:newtab",
   "about:home",
   "about:privatebrowsing",
   "about:welcomeback",
   "about:sessionrestore"
 ];
@@ -1037,16 +1042,21 @@ var gBrowserInit = {
     gFormSubmitObserver.init();
     SocialUI.init();
     AddonManager.addAddonListener(AddonsMgrListener);
     WebrtcIndicator.init();
 
     // Ensure login manager is up and running.
     Services.logins;
 
+#ifdef MOZ_CRASHREPORTER
+    if (gMultiProcessBrowser)
+      TabCrashReporter.init();
+#endif
+
     if (mustLoadSidebar) {
       let sidebar = document.getElementById("sidebar");
       let sidebarBox = document.getElementById("sidebar-box");
       sidebar.setAttribute("src", sidebarBox.getAttribute("src"));
     }
 
     UpdateUrlbarSearchSplitterState();
 
@@ -2492,16 +2502,22 @@ let BrowserOnClick = {
   onAboutTabCrashed: function(aEvent, aOwnerDoc) {
     let isTopFrame = (aOwnerDoc.defaultView.parent === aOwnerDoc.defaultView);
     if (!isTopFrame) {
       return;
     }
 
     let button = aEvent.originalTarget;
     if (button.id == "tryAgain") {
+#ifdef MOZ_CRASHREPORTER
+      if (aOwnerDoc.getElementById("checkSendReport").checked) {
+        let browser = gBrowser.getBrowserForDocument(aOwnerDoc);
+        TabCrashReporter.submitCrashReport(browser);
+      }
+#endif
       openUILinkIn(button.getAttribute("url"), "current");
     }
   },
 
   ignoreWarningButton: function BrowserOnClick_ignoreWarningButton(aIsMalware) {
     // Allow users to override and continue through to the site,
     // but add a notify bar as a reminder, so that they don't lose
     // track after, e.g., tab switching.
@@ -4262,16 +4278,21 @@ var TabsProgressListener = {
       aBrowser.addEventListener("pagehide", function onPageHide(event) {
         if (event.target.defaultView.frameElement)
           return;
         aBrowser.removeEventListener("click", BrowserOnClick, true);
         aBrowser.removeEventListener("pagehide", onPageHide, true);
         if (event.target.documentElement)
           event.target.documentElement.removeAttribute("hasBrowserHandlers");
       }, true);
+
+#ifdef MOZ_CRASHREPORTER
+      if (doc.documentURI.startsWith("about:tabcrashed"))
+        TabCrashReporter.onAboutTabCrashedLoad(aBrowser);
+#endif
     }
   },
 
   onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocationURI,
                               aFlags) {
     // Filter out location changes caused by anchor navigation
     // or history.push/pop/replaceState.
     if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -43,18 +43,17 @@ if (Services.prefs.getBoolPref("browser.
   });
   addEventListener("blur", function(event) {
     LoginManagerContent.onUsernameInput(event);
   });
 }
 
 let AboutHomeListener = {
   init: function(chromeGlobal) {
-    let self = this;
-    chromeGlobal.addEventListener('AboutHomeLoad', function(e) { self.onPageLoad(); }, false, true);
+    chromeGlobal.addEventListener('AboutHomeLoad', () => this.onPageLoad(), false, true);
   },
 
   handleEvent: function(aEvent) {
     switch (aEvent.type) {
       case "AboutHomeLoad":
         this.onPageLoad();
         break;
     }
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -668,16 +668,17 @@ just addresses the organization to follo
 
 <!-- LOCALIZATION NOTE (pluginActivateNow.label, pluginActivateAlways.label, pluginBlockNow.label): These should be the same as the matching strings in browser.properties -->
 <!ENTITY pluginActivateNow.label "Allow Now">
 <!ENTITY pluginActivateAlways.label "Allow and Remember">
 <!ENTITY pluginBlockNow.label "Block Plugin">
 
 <!ENTITY tabCrashed.header "Tab crashed">
 <!ENTITY tabCrashed.message "Well, this is embarrassing. We tried to display this Web page, but it's not responding.">
+<!ENTITY tabCrashed.checkSendReport "Tell &vendorShortName; about this crash so they can fix it.">
 <!ENTITY tabCrashed.tryAgain "Try Again">
 
 <!-- LOCALIZATION NOTE: the following strings are unused in Australis, they're
      kept here to avoid warnings from l10n tools like compare-locales on
      l10n-central. They will be definitely removed when Australis is ready
      for mozilla-aurora. -->
 
 <!ENTITY navbarCmd.accesskey           "N">
new file mode 100644
--- /dev/null
+++ b/browser/modules/TabCrashReporter.jsm
@@ -0,0 +1,73 @@
+/* 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";
+
+let Cc = Components.classes;
+let Ci = Components.interfaces;
+let Cu = Components.utils;
+
+this.EXPORTED_SYMBOLS = [ "TabCrashReporter" ];
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "CrashSubmit",
+  "resource://gre/modules/CrashSubmit.jsm");
+
+this.TabCrashReporter = {
+  init: function () {
+    if (this.initialized)
+      return;
+    this.initialized = true;
+
+    Services.obs.addObserver(this, "ipc:content-shutdown", false);
+    Services.obs.addObserver(this, "oop-frameloader-crashed", false);
+
+    this.childMap = new Map();
+    this.browserMap = new WeakMap();
+  },
+
+  observe: function (aSubject, aTopic, aData) {
+    switch (aTopic) {
+      case "ipc:content-shutdown":
+        aSubject.QueryInterface(Ci.nsIPropertyBag2);
+
+        if (!aSubject.get("abnormal"))
+          return;
+
+        this.childMap.set(aSubject.get("childID"), aSubject.get("dumpID"));
+        break;
+
+      case "oop-frameloader-crashed":
+        aSubject.QueryInterface(Ci.nsIFrameLoader);
+
+        let browser = aSubject.ownerElement;
+        if (!browser)
+          return;
+
+        this.browserMap.set(browser, aSubject.childID);
+        break;
+    }
+  },
+
+  submitCrashReport: function (aBrowser) {
+    let childID = this.browserMap.get(aBrowser);
+    let dumpID = this.childMap.get(childID);
+    if (!dumpID)
+      return
+
+    if (CrashSubmit.submit(dumpID)) {
+      this.childMap.set(childID, null); // Avoid resubmission.
+    }
+  },
+
+  onAboutTabCrashedLoad: function (aBrowser) {
+    let dumpID = this.childMap.get(this.browserMap.get(aBrowser));
+    if (!dumpID)
+      return;
+
+    aBrowser.contentDocument.documentElement.classList.add("crashDumpAvaible");
+  }
+}
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -9,16 +9,17 @@ TEST_DIRS += ['test']
 EXTRA_JS_MODULES += [
     'BrowserNewTabPreloader.jsm',
     'ContentClick.jsm',
     'NetworkPrioritizer.jsm',
     'SharedFrame.jsm',
     'SignInToWebsite.jsm',
     'SitePermissions.jsm',
     'Social.jsm',
+    'TabCrashReporter.jsm',
     'offlineAppCache.jsm',
     'openLocationLastURL.jsm',
     'webappsUI.jsm',
     'webrtcUI.jsm',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     EXTRA_JS_MODULES += [
--- a/browser/themes/linux/aboutTabCrashed.css
+++ b/browser/themes/linux/aboutTabCrashed.css
@@ -18,16 +18,26 @@ p {
   background-position: right 4px;
 }
 
 #main-error-msg {
   color: #4b4b4b;
   font-weight: bold;
 }
 
+#report-box {
+  text-align: center;
+  width: 75%;
+  margin: 0 auto;
+  display: none;
+}
+
+.crashDumpAvaible #report-box {
+  display: block
+}
 
 #button-box {
   text-align: center;
   width: 75%;
   margin: 0 auto;
 }
 
 @media all and (min-width: 300px) {
--- a/browser/themes/osx/aboutTabCrashed.css
+++ b/browser/themes/osx/aboutTabCrashed.css
@@ -18,16 +18,26 @@ p {
   background-position: right 4px;
 }
 
 #main-error-msg {
   color: #4b4b4b;
   font-weight: bold;
 }
 
+#report-box {
+  text-align: center;
+  width: 75%;
+  margin: 0 auto;
+  display: none;
+}
+
+.crashDumpAvaible #report-box {
+  display: block
+}
 
 #button-box {
   text-align: center;
   width: 75%;
   margin: 0 auto;
 }
 
 @media all and (min-width: 300px) {
--- a/browser/themes/windows/aboutTabCrashed.css
+++ b/browser/themes/windows/aboutTabCrashed.css
@@ -18,16 +18,26 @@ p {
   background-position: right 4px;
 }
 
 #main-error-msg {
   color: #4b4b4b;
   font-weight: bold;
 }
 
+#report-box {
+  text-align: center;
+  width: 75%;
+  margin: 0 auto;
+  display: none;
+}
+
+.crashDumpAvaible #report-box {
+  display: block
+}
 
 #button-box {
   text-align: center;
   width: 75%;
   margin: 0 auto;
 }
 
 @media all and (min-width: 300px) {
--- a/content/base/public/nsIFrameLoader.idl
+++ b/content/base/public/nsIFrameLoader.idl
@@ -106,17 +106,17 @@ interface nsIContentViewManager : nsISup
                          [retval, array, size_is(aLength)] out nsIContentView aResult);
 
   /**
    * The root content view.
    */
   readonly attribute nsIContentView rootContentView;
 };
 
-[scriptable, builtinclass, uuid(e4333e51-f2fa-4fdd-becd-75d000703355)]
+[scriptable, builtinclass, uuid(5b9949dc-56f1-47b6-b6d2-3785bb90ed6d)]
 interface nsIFrameLoader : nsISupports
 {
   /**
    * Get the docshell from the frame loader.
    */
   readonly attribute nsIDocShell docShell;
 
   /**
@@ -252,16 +252,23 @@ interface nsIFrameLoader : nsISupports
   /**
    * The element which owns this frame loader.
    *
    * For example, if this is a frame loader for an <iframe>, this attribute
    * returns the iframe element.
    */
   readonly attribute nsIDOMElement ownerElement;
 
+
+  /**
+   * Cached childID of the ContentParent owning the TabParent in this frame
+   * loader. This can be used to obtain the childID after the TabParent died.
+   */
+  readonly attribute unsigned long long childID;
+
   /**
    * Get or set this frame loader's visibility.
    *
    * The notion of "visibility" here is separate from the notion of a
    * window/docshell's visibility.  This field is mostly here so that we can
    * have a notion of visibility in the parent process when frames are OOP.
    */
   [infallible] attribute boolean visible;
--- a/content/base/src/nsFrameLoader.cpp
+++ b/content/base/src/nsFrameLoader.cpp
@@ -283,16 +283,17 @@ nsFrameLoader::nsFrameLoader(Element* aO
   , mRemoteFrame(false)
   , mClipSubdocument(true)
   , mClampScrollPosition(true)
   , mRemoteBrowserInitialized(false)
   , mObservingOwnerContent(false)
   , mVisible(true)
   , mCurrentRemoteFrame(nullptr)
   , mRemoteBrowser(nullptr)
+  , mChildID(0)
   , mRenderMode(RENDER_MODE_DEFAULT)
   , mEventMode(EVENT_MODE_NORMAL_DISPATCH)
 {
   ResetPermissionManagerStatus();
 }
 
 nsFrameLoader::~nsFrameLoader()
 {
@@ -2056,16 +2057,17 @@ nsFrameLoader::TryRemoteBrowser()
     // The |else| above is unnecessary; OwnerIsBrowserFrame() implies !ownApp.
     rv = context.SetTabContextForBrowserFrame(containingApp, scrollingBehavior);
   }
   NS_ENSURE_TRUE(rv, false);
 
   nsCOMPtr<Element> ownerElement = mOwnerContent;
   mRemoteBrowser = ContentParent::CreateBrowserOrApp(context, ownerElement);
   if (mRemoteBrowser) {
+    mChildID = mRemoteBrowser->Manager()->ChildID();
     nsCOMPtr<nsIDocShellTreeItem> rootItem;
     parentAsItem->GetRootTreeItem(getter_AddRefs(rootItem));
     nsCOMPtr<nsIDOMWindow> rootWin = do_GetInterface(rootItem);
     nsCOMPtr<nsIDOMChromeWindow> rootChromeWin = do_QueryInterface(rootWin);
     NS_ABORT_IF_FALSE(rootChromeWin, "How did we not get a chrome window here?");
 
     nsCOMPtr<nsIBrowserDOMWindow> browserDOMWin;
     rootChromeWin->GetBrowserDOMWindow(getter_AddRefs(browserDOMWin));
@@ -2439,24 +2441,31 @@ nsFrameLoader::GetTabChildGlobalAsEventT
 NS_IMETHODIMP
 nsFrameLoader::GetOwnerElement(nsIDOMElement **aElement)
 {
   nsCOMPtr<nsIDOMElement> ownerElement = do_QueryInterface(mOwnerContent);
   ownerElement.forget(aElement);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsFrameLoader::GetChildID(uint64_t* aChildID)
+{
+  *aChildID = mChildID;
+  return NS_OK;
+}
+
 void
 nsFrameLoader::SetRemoteBrowser(nsITabParent* aTabParent)
 {
   MOZ_ASSERT(!mRemoteBrowser);
   MOZ_ASSERT(!mCurrentRemoteFrame);
   mRemoteFrame = true;
   mRemoteBrowser = static_cast<TabParent*>(aTabParent);
-
+  mChildID = mRemoteBrowser ? mRemoteBrowser->Manager()->ChildID() : 0;
   ShowRemoteFrame(nsIntSize(0, 0));
 }
 
 void
 nsFrameLoader::SetDetachedSubdocView(nsView* aDetachedViews,
                                      nsIDocument* aContainerDoc)
 {
   mDetachedSubdocViews = aDetachedViews;
--- a/content/base/src/nsFrameLoader.h
+++ b/content/base/src/nsFrameLoader.h
@@ -437,16 +437,17 @@ private:
   // doesn't necessarily correlate with docshell/document visibility.
   bool mVisible : 1;
 
   // The ContentParent associated with mRemoteBrowser.  This was added as a
   // strong ref in bug 545237, and we're not sure if we can get rid of it.
   nsRefPtr<mozilla::dom::ContentParent> mContentParent;
   RenderFrameParent* mCurrentRemoteFrame;
   TabParent* mRemoteBrowser;
+  uint64_t mChildID;
 
   // See nsIFrameLoader.idl.  Short story, if !(mRenderMode &
   // RENDER_MODE_ASYNC_SCROLL), all the fields below are ignored in
   // favor of what content tells.
   uint32_t mRenderMode;
 
   // See nsIFrameLoader.idl. EVENT_MODE_NORMAL_DISPATCH automatically
   // forwards some input events to out-of-process content.