Add a 'simulate browser restart' button for apps to chrome://extensions.
Currently to test how an app behaves when the browser restarts you have to
restart the browser (eg: for an upgrade). This button lets you simulate that.
Review URL: https://chromiumcodereview.appspot.com/11188054
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@163774 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 081827bdd..253810f 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -30,6 +30,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_plugin_service_filter.h"
#include "chrome/browser/debugger/devtools_window.h"
+#include "chrome/browser/extensions/api/app_runtime/app_runtime_api.h"
#include "chrome/browser/extensions/api/cookies/cookies_api.h"
#include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
#include "chrome/browser/extensions/api/extension_action/extension_actions_api.h"
@@ -686,6 +687,18 @@
}
void ExtensionService::ReloadExtension(const std::string& extension_id) {
+ int events = HasShellWindows(extension_id) ? EVENT_LAUNCHED : EVENT_NONE;
+ ReloadExtensionWithEvents(extension_id, events);
+}
+
+void ExtensionService::RestartExtension(const std::string& extension_id) {
+ int events = HasShellWindows(extension_id) ? EVENT_RESTARTED : EVENT_NONE;
+ ReloadExtensionWithEvents(extension_id, events);
+}
+
+void ExtensionService::ReloadExtensionWithEvents(
+ const std::string& extension_id,
+ int events) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
FilePath path;
const Extension* current_extension = GetExtensionById(extension_id, false);
@@ -711,11 +724,7 @@
orphaned_dev_tools_[extension_id] = devtools_cookie;
}
- if (current_extension->is_platform_app() &&
- !extensions::ShellWindowRegistry::Get(profile_)->
- GetShellWindowsForApp(extension_id).empty()) {
- relaunch_app_ids_.insert(extension_id);
- }
+ on_load_events_[extension_id] = events;
path = current_extension->path();
DisableExtension(extension_id, Extension::DISABLE_RELOAD);
@@ -2041,7 +2050,7 @@
extensions_.Insert(scoped_extension);
SyncExtensionChangeIfNeeded(*extension);
NotifyExtensionLoaded(extension);
- QueueRestoreAppWindow(extension);
+ DoPostLoadTasks(extension);
}
void ExtensionService::InitializePermissions(const Extension* extension) {
@@ -2741,19 +2750,25 @@
return nacl_module_list_.end();
}
-void ExtensionService::QueueRestoreAppWindow(const Extension* extension) {
- std::set<std::string>::iterator relaunch_iter =
- relaunch_app_ids_.find(extension->id());
- if (relaunch_iter != relaunch_app_ids_.end()) {
- extensions::LazyBackgroundTaskQueue* queue =
- system_->lazy_background_task_queue();
- if (queue->ShouldEnqueueTask(profile(), extension)) {
+void ExtensionService::DoPostLoadTasks(const Extension* extension) {
+ std::map<std::string, int>::iterator it =
+ on_load_events_.find(extension->id());
+ if (it == on_load_events_.end())
+ return;
+
+ int events_to_fire = it->second;
+ extensions::LazyBackgroundTaskQueue* queue =
+ system_->lazy_background_task_queue();
+ if (queue->ShouldEnqueueTask(profile(), extension)) {
+ if (events_to_fire & EVENT_LAUNCHED)
queue->AddPendingTask(profile(), extension->id(),
base::Bind(&ExtensionService::LaunchApplication));
- }
-
- relaunch_app_ids_.erase(relaunch_iter);
+ if (events_to_fire & EVENT_RESTARTED)
+ queue->AddPendingTask(profile(), extension->id(),
+ base::Bind(&ExtensionService::RestartApplication));
}
+
+ on_load_events_.erase(it);
}
// static
@@ -2769,6 +2784,25 @@
#endif
}
+// static
+void ExtensionService::RestartApplication(
+ extensions::ExtensionHost* extension_host) {
+ if (!extension_host)
+ return;
+
+#if !defined(OS_ANDROID)
+ extensions::AppEventRouter::DispatchOnRestartedEvent(
+ extension_host->profile(), extension_host->extension());
+#endif
+}
+
+bool ExtensionService::HasShellWindows(const std::string& extension_id) {
+ const Extension* current_extension = GetExtensionById(extension_id, false);
+ return current_extension && current_extension->is_platform_app() &&
+ !extensions::ShellWindowRegistry::Get(profile_)->
+ GetShellWindowsForApp(extension_id).empty();
+}
+
void ExtensionService::InspectExtensionHost(
extensions::ExtensionHost* host) {
if (host)
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index f18d5e01..49f029bd 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -321,6 +321,9 @@
// Reloads the specified extension.
void ReloadExtension(const std::string& extension_id);
+ // Restarts the specified extension.
+ void RestartExtension(const std::string& extension_id);
+
// Uninstalls the specified extension. Callers should only call this method
// with extensions that exist. |external_uninstall| is a magical parameter
// that is only used to send information to ExtensionPrefs, which external
@@ -706,6 +709,13 @@
INCLUDE_TERMINATED = 1 << 2
};
+ // Events to be fired after an extension is reloaded.
+ enum PostReloadEvents {
+ EVENT_NONE = 0,
+ EVENT_LAUNCHED = 1 << 0,
+ EVENT_RESTARTED = 1 << 1,
+ };
+
// Look up an extension by ID, optionally including either or both of enabled
// and disabled extensions.
const extensions::Extension* GetExtensionByIdInternal(
@@ -727,6 +737,14 @@
void NotifyExtensionUnloaded(const extensions::Extension* extension,
extension_misc::UnloadedExtensionReason reason);
+ // Reloads |extension_id| and then dispatches to it the PostReloadEvents
+ // indicated by |events|.
+ void ReloadExtensionWithEvents(const std::string& extension_id,
+ int events);
+
+ // Returns true if the app with id |extension_id| has any shell windows open.
+ bool HasShellWindows(const std::string& extension_id);
+
// Helper that updates the active extension list used for crash reporting.
void UpdateActiveExtensionsInCrashReporter();
@@ -745,11 +763,16 @@
NaClModuleInfoList::iterator FindNaClModule(const GURL& url);
- // Enqueues a launch task in the lazy background page queue.
- void QueueRestoreAppWindow(const extensions::Extension* extension);
+ // Performs tasks requested to occur after |extension| loads.
+ void DoPostLoadTasks(const extensions::Extension* extension);
+
// Launches the platform app associated with |extension_host|.
static void LaunchApplication(extensions::ExtensionHost* extension_host);
+ // Dispatches a restart event to the platform app associated with
+ // |extension_host|.
+ static void RestartApplication(extensions::ExtensionHost* extension_host);
+
// Helper to inspect an ExtensionHost after it has been loaded.
void InspectExtensionHost(extensions::ExtensionHost* host);
@@ -823,9 +846,9 @@
typedef std::map<std::string, int> OrphanedDevTools;
OrphanedDevTools orphaned_dev_tools_;
- // A set of apps that had an open window the last time they were reloaded.
- // A new window will be launched when the app is succesfully reloaded.
- std::set<std::string> relaunch_app_ids_;
+ // Maps extension ids to a bitmask that indicates which events should be
+ // dispatched to the extension when it is loaded.
+ std::map<std::string, int> on_load_events_;
content::NotificationRegistrar registrar_;
PrefChangeRegistrar pref_change_registrar_;
diff --git a/chrome/browser/tab_contents/render_view_context_menu.cc b/chrome/browser/tab_contents/render_view_context_menu.cc
index 6fa59e4..1bb5296b 100644
--- a/chrome/browser/tab_contents/render_view_context_menu.cc
+++ b/chrome/browser/tab_contents/render_view_context_menu.cc
@@ -541,6 +541,8 @@
IDS_CONTENT_CONTEXT_RELOAD_PAGE);
menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP,
IDS_CONTENT_CONTEXT_RELOAD_PACKAGED_APP);
+ menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP,
+ IDS_CONTENT_CONTEXT_RESTART_APP);
AppendDeveloperItems();
menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE,
IDS_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE);
@@ -997,6 +999,7 @@
case IDC_CONTENT_CONTEXT_INSPECTELEMENT:
case IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE:
case IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP:
+ case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP:
return IsDevCommandEnabled(id);
case IDC_CONTENT_CONTEXT_VIEWPAGEINFO:
@@ -1518,6 +1521,16 @@
break;
}
+ case IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP: {
+ const Extension* platform_app = GetExtension();
+ DCHECK(platform_app);
+ DCHECK(platform_app->is_platform_app());
+
+ extensions::ExtensionSystem::Get(profile_)->extension_service()->
+ RestartExtension(platform_app->id());
+ break;
+ }
+
case IDC_PRINT:
if (params_.media_type == WebContextMenuData::MediaTypeNone) {
printing::PrintViewManager* print_view_manager =