summaryrefslogtreecommitdiffstats
path: root/chrome/browser/background_contents_service.cc
diff options
context:
space:
mode:
authorsadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-01 04:49:59 +0000
committersadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-01 04:49:59 +0000
commitc45c706a68a750f7a3aa1901232c6c8cc2c4a39b (patch)
tree0b7d71b86878a669d720b019dce6956ca0f0142b /chrome/browser/background_contents_service.cc
parentfb33ae02cb0325dd8941fbac246e27b520255f68 (diff)
downloadchromium_src-c45c706a68a750f7a3aa1901232c6c8cc2c4a39b.zip
chromium_src-c45c706a68a750f7a3aa1901232c6c8cc2c4a39b.tar.gz
chromium_src-c45c706a68a750f7a3aa1901232c6c8cc2c4a39b.tar.bz2
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=none TEST=existing ExtensionCrashRecoveryTest.* tests. Review URL: http://codereview.chromium.org/6731038 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@80128 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/background_contents_service.cc')
-rw-r--r--chrome/browser/background_contents_service.cc151
1 files changed, 138 insertions, 13 deletions
diff --git a/chrome/browser/background_contents_service.cc b/chrome/browser/background_contents_service.cc
index 4c63bdc..d3e028e 100644
--- a/chrome/browser/background_contents_service.cc
+++ b/chrome/browser/background_contents_service.cc
@@ -9,7 +9,12 @@
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/notifications/desktop_notification_service.h"
+#include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/browser/profiles/profile.h"
@@ -23,6 +28,67 @@
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/notification_service.h"
#include "content/common/notification_type.h"
+#include "grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+class CrashNotificationDelegate : public NotificationDelegate {
+ public:
+ CrashNotificationDelegate(Profile* profile, const Extension* extension)
+ : profile_(profile),
+ is_app_(extension->is_app()),
+ extension_id_(extension->id()) {
+ }
+
+ ~CrashNotificationDelegate() {
+ }
+
+ void Display() {}
+
+ void Error() {}
+
+ void Close(bool by_user) {}
+
+ void Click() {
+ if (is_app_) {
+ profile_->GetBackgroundContentsService()->
+ LoadBackgroundContentsForExtension(profile_, extension_id_);
+ } else {
+ profile_->GetExtensionService()->ReloadExtension(extension_id_);
+ }
+
+ g_browser_process->notification_ui_manager()->CancelById(id());
+ }
+
+ std::string id() const {
+ return "app.background.crashed." + extension_id_;
+ }
+
+ private:
+ Profile* profile_;
+ bool is_app_;
+ std::string extension_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(CrashNotificationDelegate);
+};
+
+void ShowBalloon(const Extension* extension, Profile* profile) {
+ string16 message = l10n_util::GetStringFUTF16(
+ extension->is_app() ? IDS_BACKGROUND_CRASHED_APP_BALLOON_MESSAGE :
+ IDS_BACKGROUND_CRASHED_EXTENSION_BALLOON_MESSAGE,
+ UTF8ToUTF16(extension->name()));
+ string16 content_url = DesktopNotificationService::CreateDataUrl(
+ extension->GetIconURL(Extension::EXTENSION_ICON_SMALLISH,
+ ExtensionIconSet::MATCH_BIGGER),
+ string16(), message, WebKit::WebTextDirectionDefault);
+ Notification notification(
+ extension->url(), GURL(content_url), string16(),
+ string16(), new CrashNotificationDelegate(profile, extension));
+ g_browser_process->notification_ui_manager()->Add(notification, profile);
+}
+
+}
// Keys for the information we store about individual BackgroundContents in
// prefs. There is one top-level DictionaryValue (stored at
@@ -85,11 +151,19 @@ void BackgroundContentsService::StartObserving(Profile* profile) {
// during shutdown or if the render process dies).
registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_DELETED,
Source<Profile>(profile));
+
// Track when the BackgroundContents navigates to a new URL so we can update
// our persisted information as appropriate.
registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_NAVIGATED,
Source<Profile>(profile));
+ // Track when the extensions crash so that the user can be notified
+ // about it, and the crashed contents can be restarted.
+ registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
+ Source<Profile>(profile));
+ registrar_.Add(this, NotificationType::BACKGROUND_CONTENTS_TERMINATED,
+ Source<Profile>(profile));
+
// Listen for extensions to be unloaded so we can shutdown associated
// BackgroundContents.
registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
@@ -114,7 +188,36 @@ void BackgroundContentsService::Observe(NotificationType type,
DCHECK(IsTracked(Details<BackgroundContents>(details).ptr()));
RegisterBackgroundContents(Details<BackgroundContents>(details).ptr());
break;
- case NotificationType::EXTENSION_UNLOADED:
+
+ case NotificationType::EXTENSION_PROCESS_TERMINATED:
+ case NotificationType::BACKGROUND_CONTENTS_TERMINATED: {
+ Profile* profile = Source<Profile>(source).ptr();
+ const Extension* extension = NULL;
+ if (type.value == NotificationType::BACKGROUND_CONTENTS_TERMINATED) {
+ BackgroundContents* bg =
+ Details<BackgroundContents>(details).ptr();
+ const std::string ext_id = UTF16ToASCII(profile->
+ GetBackgroundContentsService()->GetParentApplicationId(bg));
+ extension =
+ profile->GetExtensionService()->GetExtensionById(ext_id, false);
+ } else {
+ ExtensionHost* extension_host = Details<ExtensionHost>(details).ptr();
+ extension = extension_host->extension();
+ }
+
+ if (!extension)
+ break;
+
+ // When an extension crashes, EXTENSION_PROCESS_TERMINATED is followed by
+ // an EXTENSION_UNLOADED notification. This UNLOADED signal causes all the
+ // notifications for this extension to be cancelled by
+ // DesktopNotificationService. For this reason, instead of showing the
+ // balloon right now, we schedule it to show a little later.
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ NewRunnableFunction(&ShowBalloon, extension, profile));
+ break;
+ }
+ case NotificationType::EXTENSION_UNLOADED:
switch (Details<UnloadedExtensionInfo>(details)->reason) {
case UnloadedExtensionInfo::DISABLE: // Intentionally fall through.
case UnloadedExtensionInfo::UNINSTALL:
@@ -152,17 +255,9 @@ void BackgroundContentsService::LoadBackgroundContentsFromPrefs(
DCHECK(extensions_service);
for (DictionaryValue::key_iterator it = contents->begin_keys();
it != contents->end_keys(); ++it) {
- DictionaryValue* dict;
- contents->GetDictionaryWithoutPathExpansion(*it, &dict);
- string16 frame_name;
- std::string url;
- dict->GetString(kUrlKey, &url);
- dict->GetString(kFrameNameKey, &frame_name);
-
// Check to make sure that the parent extension is still enabled.
const Extension* extension = extensions_service->GetExtensionById(
*it, false);
-
if (!extension) {
// We should never reach here - it should not be possible for an app
// to become uninstalled without the associated BackgroundContents being
@@ -172,13 +267,43 @@ void BackgroundContentsService::LoadBackgroundContentsFromPrefs(
<< *it;
return;
}
- LoadBackgroundContents(profile,
- GURL(url),
- frame_name,
- UTF8ToUTF16(*it));
+ LoadBackgroundContentsFromDictionary(profile, *it, contents);
}
}
+void BackgroundContentsService::LoadBackgroundContentsForExtension(
+ Profile* profile,
+ const std::string& extension_id) {
+ if (!prefs_)
+ return;
+ const DictionaryValue* contents =
+ prefs_->GetDictionary(prefs::kRegisteredBackgroundContents);
+ if (!contents)
+ return;
+ LoadBackgroundContentsFromDictionary(profile, extension_id, contents);
+}
+
+void BackgroundContentsService::LoadBackgroundContentsFromDictionary(
+ Profile* profile,
+ const std::string& extension_id,
+ const DictionaryValue* contents) {
+ ExtensionService* extensions_service = profile->GetExtensionService();
+ DCHECK(extensions_service);
+
+ DictionaryValue* dict;
+ contents->GetDictionaryWithoutPathExpansion(extension_id, &dict);
+ if (dict == NULL)
+ return;
+ string16 frame_name;
+ std::string url;
+ dict->GetString(kUrlKey, &url);
+ dict->GetString(kFrameNameKey, &frame_name);
+ LoadBackgroundContents(profile,
+ GURL(url),
+ frame_name,
+ UTF8ToUTF16(extension_id));
+}
+
void BackgroundContentsService::LoadBackgroundContents(
Profile* profile,
const GURL& url,