diff options
author | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-01 04:49:59 +0000 |
---|---|---|
committer | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-01 04:49:59 +0000 |
commit | c45c706a68a750f7a3aa1901232c6c8cc2c4a39b (patch) | |
tree | 0b7d71b86878a669d720b019dce6956ca0f0142b /chrome/browser/background_contents_service.cc | |
parent | fb33ae02cb0325dd8941fbac246e27b520255f68 (diff) | |
download | chromium_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.cc | 151 |
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, |