apps: Notify the user if an app's background page crashes.

Add a new notification for when an app's background page crashes, and use this
notification message to show a message to the user and allow to restart the app.
Extension-crashes also create balloon notifications instead of infobars.

BUG=78167,78126
TEST=existing ExtensionCrashRecoveryTest.* tests.

Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=80128

Review URL: http://codereview.chromium.org/6731038

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80259 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
index bc1b719b7..a71ec7f 100644
--- a/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
+++ b/chrome/browser/extensions/extension_crash_recovery_browsertest.cc
@@ -3,13 +3,16 @@
 // found in the LICENSE file.
 
 #include "base/process_util.h"
-#include "chrome/browser/extensions/crashed_extension_infobar.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_host.h"
 #include "chrome/browser/extensions/extension_process_manager.h"
 #include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/notifications/balloon_host.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_delegate.h"
+#include "chrome/browser/notifications/notification_ui_manager.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
 #include "chrome/browser/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/ui_test_utils.h"
@@ -28,23 +31,34 @@
     return browser()->profile()->GetExtensionProcessManager();
   }
 
-  ConfirmInfoBarDelegate* GetInfoBarDelegate(size_t index) {
-    TabContents* current_tab = browser()->GetSelectedTabContents();
-    EXPECT_LT(index, current_tab->infobar_count());
-    return current_tab->GetInfoBarDelegateAt(index)->AsConfirmInfoBarDelegate();
+  Balloon* GetNotificationDelegate(size_t index) {
+    NotificationUIManager* manager =
+        g_browser_process->notification_ui_manager();
+    BalloonCollection::Balloons balloons =
+        manager->balloon_collection()->GetActiveBalloons();
+    return balloons.at(index);
   }
 
-  void AcceptInfoBar(size_t index) {
-    ConfirmInfoBarDelegate* infobar = GetInfoBarDelegate(index);
-    ASSERT_TRUE(infobar);
-    infobar->Accept();
+  void AcceptNotification(size_t index) {
+    Balloon* balloon = GetNotificationDelegate(index);
+    ASSERT_TRUE(balloon);
+    balloon->OnClick();
     WaitForExtensionLoad();
   }
 
-  void CancelInfoBar(size_t index) {
-    ConfirmInfoBarDelegate* infobar = GetInfoBarDelegate(index);
-    ASSERT_TRUE(infobar);
-    infobar->Cancel();
+  void CancelNotification(size_t index) {
+    Balloon* balloon = GetNotificationDelegate(index);
+    NotificationUIManager* manager =
+        g_browser_process->notification_ui_manager();
+    manager->CancelById(balloon->notification().notification_id());
+  }
+
+  size_t CountBalloons() {
+    NotificationUIManager* manager =
+        g_browser_process->notification_ui_manager();
+    BalloonCollection::Balloons balloons =
+        manager->balloon_collection()->GetActiveBalloons();
+    return balloons.size();
   }
 
   void CrashExtension(size_t index) {
@@ -114,31 +128,26 @@
   ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
   ASSERT_EQ(crash_size_before + 1,
             GetExtensionService()->terminated_extensions()->size());
-  AcceptInfoBar(0);
+  AcceptNotification(0);
 
-  SCOPED_TRACE("after clicking the infobar");
+  SCOPED_TRACE("after clicking the balloon");
   CheckExtensionConsistency(size_before);
   ASSERT_EQ(crash_size_before,
             GetExtensionService()->terminated_extensions()->size());
 }
 
-// Crahes on windows. http://crbug.com/78126
-#if defined(OS_WIN)
-#define MAYBE_CloseAndReload DISABLED_CloseAndReload
-#else
-#define MAYBE_CloseAndReload CloseAndReload
-#endif
-IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, MAYBE_CloseAndReload) {
+IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, CloseAndReload) {
   const size_t size_before = GetExtensionService()->extensions()->size();
   const size_t crash_size_before =
       GetExtensionService()->terminated_extensions()->size();
   LoadTestExtension();
   CrashExtension(size_before);
+
   ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
   ASSERT_EQ(crash_size_before + 1,
             GetExtensionService()->terminated_extensions()->size());
 
-  CancelInfoBar(0);
+  CancelNotification(0);
   ReloadExtension(first_extension_id_);
 
   SCOPED_TRACE("after reloading");
@@ -161,9 +170,9 @@
   TabContents* current_tab = browser()->GetSelectedTabContents();
   ASSERT_TRUE(current_tab);
 
-  // The infobar should automatically hide after the extension is successfully
+  // The balloon should automatically hide after the extension is successfully
   // reloaded.
-  ASSERT_EQ(0U, current_tab->infobar_count());
+  ASSERT_EQ(0U, CountBalloons());
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
@@ -175,23 +184,23 @@
 
   TabContents* original_tab = browser()->GetSelectedTabContents();
   ASSERT_TRUE(original_tab);
-  ASSERT_EQ(1U, original_tab->infobar_count());
+  ASSERT_EQ(1U, CountBalloons());
 
-  // Open a new tab so the info bar will not be in the current tab.
+  // Open a new tab, but the balloon will still be there.
   browser()->NewTab();
   TabContents* new_current_tab = browser()->GetSelectedTabContents();
   ASSERT_TRUE(new_current_tab);
   ASSERT_NE(new_current_tab, original_tab);
-  ASSERT_EQ(0U, new_current_tab->infobar_count());
+  ASSERT_EQ(1U, CountBalloons());
 
   ReloadExtension(first_extension_id_);
 
   SCOPED_TRACE("after reloading");
   CheckExtensionConsistency(size_before);
 
-  // The infobar should automatically hide after the extension is successfully
+  // The balloon should automatically hide after the extension is successfully
   // reloaded.
-  ASSERT_EQ(0U, original_tab->infobar_count());
+  ASSERT_EQ(0U, CountBalloons());
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
@@ -203,13 +212,13 @@
 
   TabContents* current_tab = browser()->GetSelectedTabContents();
   ASSERT_TRUE(current_tab);
-  ASSERT_EQ(1U, current_tab->infobar_count());
+  ASSERT_EQ(1U, CountBalloons());
 
   // Navigate to another page.
   ui_test_utils::NavigateToURL(browser(),
       ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                 FilePath(FILE_PATH_LITERAL("title1.html"))));
-  ASSERT_EQ(1U, current_tab->infobar_count());
+  ASSERT_EQ(1U, CountBalloons());
 
   ReloadExtension(first_extension_id_);
 
@@ -218,7 +227,7 @@
 
   // The infobar should automatically hide after the extension is successfully
   // reloaded.
-  ASSERT_EQ(0U, current_tab->infobar_count());
+  ASSERT_EQ(0U, CountBalloons());
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
@@ -234,11 +243,11 @@
 
   TabContents* current_tab = browser()->GetSelectedTabContents();
   ASSERT_TRUE(current_tab);
-  ASSERT_EQ(1U, current_tab->infobar_count());
+  ASSERT_EQ(1U, CountBalloons());
 
   TabContents* current_tab2 = browser2->GetSelectedTabContents();
   ASSERT_TRUE(current_tab2);
-  ASSERT_EQ(1U, current_tab2->infobar_count());
+  ASSERT_EQ(1U, CountBalloons());
 
   ReloadExtension(first_extension_id_);
 
@@ -247,8 +256,8 @@
 
   // Both infobars should automatically hide after the extension is successfully
   // reloaded.
-  ASSERT_EQ(0U, current_tab->infobar_count());
-  ASSERT_EQ(0U, current_tab2->infobar_count());
+  ASSERT_EQ(0U, CountBalloons());
+  ASSERT_EQ(0U, CountBalloons());
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest,
@@ -264,11 +273,11 @@
 
   TabContents* current_tab = browser()->GetSelectedTabContents();
   ASSERT_TRUE(current_tab);
-  ASSERT_EQ(1U, current_tab->infobar_count());
+  ASSERT_EQ(1U, CountBalloons());
 
   TabContents* current_tab2 = browser2->GetSelectedTabContents();
   ASSERT_TRUE(current_tab2);
-  ASSERT_EQ(1U, current_tab2->infobar_count());
+  ASSERT_EQ(1U, CountBalloons());
 
   // Move second window into first browser so there will be multiple tabs
   // with the info bar for the same extension in one browser.
@@ -276,7 +285,7 @@
       browser2->tabstrip_model()->DetachTabContentsAt(0);
   browser()->tabstrip_model()->AppendTabContents(contents, true);
   current_tab2 = browser()->GetSelectedTabContents();
-  ASSERT_EQ(1U, current_tab2->infobar_count());
+  ASSERT_EQ(1U, CountBalloons());
   ASSERT_NE(current_tab2, current_tab);
 
   ReloadExtension(first_extension_id_);
@@ -286,10 +295,10 @@
 
   // Both infobars should automatically hide after the extension is successfully
   // reloaded.
-  ASSERT_EQ(0U, current_tab2->infobar_count());
+  ASSERT_EQ(0U, CountBalloons());
   browser()->SelectPreviousTab();
   ASSERT_EQ(current_tab, browser()->GetSelectedTabContents());
-  ASSERT_EQ(0U, current_tab->infobar_count());
+  ASSERT_EQ(0U, CountBalloons());
 }
 
 // Make sure that when we don't do anything about the crashed extension
@@ -308,9 +317,9 @@
   LoadSecondExtension();
   CrashExtension(size_before);
   ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
-  AcceptInfoBar(0);
+  AcceptNotification(0);
 
-  SCOPED_TRACE("after clicking the infobar");
+  SCOPED_TRACE("after clicking the balloon");
   CheckExtensionConsistency(size_before);
   CheckExtensionConsistency(size_before + 1);
 }
@@ -321,9 +330,9 @@
   LoadSecondExtension();
   CrashExtension(size_before + 1);
   ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
-  AcceptInfoBar(0);
+  AcceptNotification(0);
 
-  SCOPED_TRACE("after clicking the infobar");
+  SCOPED_TRACE("after clicking the balloon");
   CheckExtensionConsistency(size_before);
   CheckExtensionConsistency(size_before + 1);
 }
@@ -345,14 +354,14 @@
             GetExtensionService()->terminated_extensions()->size());
 
   {
-    SCOPED_TRACE("first infobar");
-    AcceptInfoBar(0);
+    SCOPED_TRACE("first balloon");
+    AcceptNotification(0);
     CheckExtensionConsistency(size_before);
   }
 
   {
-    SCOPED_TRACE("second infobar");
-    AcceptInfoBar(0);
+    SCOPED_TRACE("second balloon");
+    AcceptNotification(0);
     CheckExtensionConsistency(size_before);
     CheckExtensionConsistency(size_before + 1);
   }
@@ -370,14 +379,14 @@
   ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
 
   {
-    SCOPED_TRACE("first infobar");
-    AcceptInfoBar(0);
+    SCOPED_TRACE("first balloon");
+    AcceptNotification(0);
     CheckExtensionConsistency(size_before);
   }
 
   {
-    SCOPED_TRACE("second infobar");
-    AcceptInfoBar(0);
+    SCOPED_TRACE("second balloon");
+    AcceptNotification(0);
     CheckExtensionConsistency(size_before);
     CheckExtensionConsistency(size_before + 1);
   }
@@ -406,10 +415,12 @@
   CrashExtension(size_before);
   ASSERT_EQ(size_before, GetExtensionService()->extensions()->size());
 
-  CancelInfoBar(0);
-  AcceptInfoBar(1);
+  CancelNotification(0);
+  // Cancelling the balloon at 0 will close the balloon, and the balloon in
+  // index 1 will move into index 0.
+  AcceptNotification(0);
 
-  SCOPED_TRACE("infobars done");
+  SCOPED_TRACE("balloons done");
   ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
   CheckExtensionConsistency(size_before);
 }
@@ -429,16 +440,16 @@
     TabContents* current_tab = browser()->GetSelectedTabContents();
     ASSERT_TRUE(current_tab);
     // At the beginning we should have one infobar displayed for each extension.
-    ASSERT_EQ(2U, current_tab->infobar_count());
+    ASSERT_EQ(2U, CountBalloons());
     ReloadExtension(first_extension_id_);
     // One of the infobars should hide after the extension is reloaded.
-    ASSERT_EQ(1U, current_tab->infobar_count());
+    ASSERT_EQ(1U, CountBalloons());
     CheckExtensionConsistency(size_before);
   }
 
   {
-    SCOPED_TRACE("second: infobar");
-    AcceptInfoBar(0);
+    SCOPED_TRACE("second: balloon");
+    AcceptNotification(0);
     CheckExtensionConsistency(size_before);
     CheckExtensionConsistency(size_before + 1);
   }
@@ -455,13 +466,15 @@
   ASSERT_EQ(crash_size_before + 1,
             GetExtensionService()->terminated_extensions()->size());
 
+  ASSERT_EQ(1U, CountBalloons());
   UninstallExtension(first_extension_id_);
+  MessageLoop::current()->RunAllPending();
 
   SCOPED_TRACE("after uninstalling");
   ASSERT_EQ(size_before + 1, GetExtensionService()->extensions()->size());
   ASSERT_EQ(crash_size_before,
             GetExtensionService()->terminated_extensions()->size());
-  ASSERT_EQ(0U, browser()->GetSelectedTabContents()->infobar_count());
+  ASSERT_EQ(0U, CountBalloons());
 }
 
 IN_PROC_BROWSER_TEST_F(ExtensionCrashRecoveryTest, CrashAndUnloadAll) {