Unrevert 152017 - Add chrome.runtime.onStartup, which is fired on browser start.

I reused LazyBackgroundTaskQueue so that this works for regular background
pages, which may not be fully loaded by the time this event is dispatched.

BUG=132328
Review URL: https://chromiumcodereview.appspot.com/10828218


Reason for revert: introduced a frequent crash


Review URL: https://chromiumcodereview.appspot.com/10855237

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@152238 0039d316-1c4b-4281-b951-d872f2087c98
parent a72e39dc
...@@ -4,24 +4,71 @@ ...@@ -4,24 +4,71 @@
#include "chrome/browser/extensions/api/runtime/runtime_api.h" #include "chrome/browser/extensions/api/runtime/runtime_api.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/event_router.h" #include "chrome/browser/extensions/event_router.h"
#include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h" #include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/lazy_background_task_queue.h" #include "chrome/browser/extensions/lazy_background_task_queue.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension.h"
#include "googleurl/src/gurl.h" #include "googleurl/src/gurl.h"
namespace extensions {
namespace { namespace {
const char kOnStartupEvent[] = "runtime.onStartup";
const char kOnInstalledEvent[] = "runtime.onInstalled"; const char kOnInstalledEvent[] = "runtime.onInstalled";
const char kNoBackgroundPageError[] = "You do not have a background page."; const char kNoBackgroundPageError[] = "You do not have a background page.";
const char kPageLoadError[] = "Background page failed to load."; const char kPageLoadError[] = "Background page failed to load.";
static void DispatchOnStartupEventImpl(
Profile* profile,
const std::string& extension_id,
bool first_call,
ExtensionHost* host) {
// A NULL host from the LazyBackgroundTaskQueue means the page failed to
// load. Give up.
if (!host && !first_call)
return;
if (g_browser_process->IsShuttingDown() ||
!g_browser_process->profile_manager()->IsValidProfile(profile))
return;
ExtensionSystem* system = ExtensionSystem::Get(profile);
if (!system)
return;
// If this is a persistent background page, we want to wait for it to load
// (it might not be ready, since this is startup). But only enqueue once.
// If it fails to load the first time, don't bother trying again.
const Extension* extension =
system->extension_service()->extensions()->GetByID(extension_id);
if (extension && extension->has_persistent_background_page() && first_call &&
system->lazy_background_task_queue()->
ShouldEnqueueTask(profile, extension)) {
system->lazy_background_task_queue()->AddPendingTask(
profile, extension_id,
base::Bind(&DispatchOnStartupEventImpl,
profile, extension_id, false));
return;
}
scoped_ptr<ListValue> event_args(new ListValue());
system->event_router()->DispatchEventToExtension(
extension_id, kOnStartupEvent, event_args.Pass(), NULL, GURL());
} }
namespace extensions { } // namespace
// static
void RuntimeEventRouter::DispatchOnStartupEvent(
Profile* profile, const std::string& extension_id) {
DispatchOnStartupEventImpl(profile, extension_id, true, NULL);
}
// static // static
void RuntimeEventRouter::DispatchOnInstalledEvent( void RuntimeEventRouter::DispatchOnInstalledEvent(
......
...@@ -15,6 +15,10 @@ class ExtensionHost; ...@@ -15,6 +15,10 @@ class ExtensionHost;
class RuntimeEventRouter { class RuntimeEventRouter {
public: public:
// Dispatches the onStartup event to all currently-loaded extensions.
static void DispatchOnStartupEvent(Profile* profile,
const std::string& extension_id);
// Dispatches the onInstalled event to the given extension. // Dispatches the onInstalled event to the given extension.
static void DispatchOnInstalledEvent(Profile* profile, static void DispatchOnInstalledEvent(Profile* profile,
const std::string& extension_id); const std::string& extension_id);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/message_loop.h" #include "base/message_loop.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/runtime/runtime_api.h" #include "chrome/browser/extensions/api/runtime/runtime_api.h"
#include "chrome/browser/extensions/api/web_request/web_request_api.h" #include "chrome/browser/extensions/api/web_request/web_request_api.h"
#include "chrome/browser/extensions/extension_devtools_manager.h" #include "chrome/browser/extensions/extension_devtools_manager.h"
...@@ -20,6 +21,7 @@ ...@@ -20,6 +21,7 @@
#include "chrome/browser/extensions/lazy_background_task_queue.h" #include "chrome/browser/extensions/lazy_background_task_queue.h"
#include "chrome/browser/extensions/process_map.h" #include "chrome/browser/extensions/process_map.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension.h"
...@@ -32,6 +34,8 @@ ...@@ -32,6 +34,8 @@
using base::Value; using base::Value;
using content::BrowserThread; using content::BrowserThread;
namespace extensions {
namespace { namespace {
const char kDispatchEvent[] = "Event.dispatchEvent"; const char kDispatchEvent[] = "Event.dispatchEvent";
...@@ -44,9 +48,15 @@ void NotifyEventListenerRemovedOnIOThread( ...@@ -44,9 +48,15 @@ void NotifyEventListenerRemovedOnIOThread(
profile, extension_id, sub_event_name); profile, extension_id, sub_event_name);
} }
} // namespace void DispatchOnInstalledEvent(
Profile* profile, const std::string& extension_id) {
if (!g_browser_process->profile_manager()->IsValidProfile(profile))
return;
namespace extensions { RuntimeEventRouter::DispatchOnInstalledEvent(profile, extension_id);
}
} // namespace
struct EventRouter::ListenerProcess { struct EventRouter::ListenerProcess {
content::RenderProcessHost* process; content::RenderProcessHost* process;
...@@ -558,8 +568,7 @@ void EventRouter::Observe(int type, ...@@ -558,8 +568,7 @@ void EventRouter::Observe(int type,
const Extension* extension = const Extension* extension =
content::Details<const Extension>(details).ptr(); content::Details<const Extension>(details).ptr();
MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(&RuntimeEventRouter::DispatchOnInstalledEvent, base::Bind(&DispatchOnInstalledEvent, profile_, extension->id()));
profile_, extension->id()));
break; break;
} }
default: default:
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/metrics/histogram.h" #include "base/metrics/histogram.h"
#include "base/string_number_conversions.h" #include "base/string_number_conversions.h"
#include "base/time.h" #include "base/time.h"
#include "chrome/browser/extensions/api/runtime/runtime_api.h"
#include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_info_map.h" #include "chrome/browser/extensions/extension_info_map.h"
...@@ -89,16 +90,20 @@ class IncognitoExtensionProcessManager : public ExtensionProcessManager { ...@@ -89,16 +90,20 @@ class IncognitoExtensionProcessManager : public ExtensionProcessManager {
static void CreateBackgroundHostForExtensionLoad( static void CreateBackgroundHostForExtensionLoad(
ExtensionProcessManager* manager, const Extension* extension) { ExtensionProcessManager* manager, const Extension* extension) {
if (extension->has_persistent_background_page()) { if (extension->has_persistent_background_page())
manager->CreateBackgroundHost(extension, extension->GetBackgroundURL()); manager->CreateBackgroundHost(extension, extension->GetBackgroundURL());
}
} }
static void CreateBackgroundHostsForProfileStartup( static void CreateBackgroundHostsForProfileStartup(
ExtensionProcessManager* manager, const ExtensionSet* extensions) { Profile* profile,
ExtensionProcessManager* manager,
const ExtensionSet* extensions) {
for (ExtensionSet::const_iterator extension = extensions->begin(); for (ExtensionSet::const_iterator extension = extensions->begin();
extension != extensions->end(); ++extension) { extension != extensions->end(); ++extension) {
CreateBackgroundHostForExtensionLoad(manager, *extension); CreateBackgroundHostForExtensionLoad(manager, *extension);
extensions::RuntimeEventRouter::DispatchOnStartupEvent(
profile, (*extension)->id());
} }
} }
...@@ -557,19 +562,19 @@ void ExtensionProcessManager::Observe( ...@@ -557,19 +562,19 @@ void ExtensionProcessManager::Observe(
const content::NotificationDetails& details) { const content::NotificationDetails& details) {
switch (type) { switch (type) {
case chrome::NOTIFICATION_EXTENSIONS_READY: { case chrome::NOTIFICATION_EXTENSIONS_READY: {
CreateBackgroundHostsForProfileStartup(this, Profile* profile = content::Source<Profile>(source).ptr();
content::Source<Profile>(source).ptr()-> CreateBackgroundHostsForProfileStartup(profile, this,
GetExtensionService()->extensions()); profile->GetExtensionService()->extensions());
break; break;
} }
case chrome::NOTIFICATION_EXTENSION_LOADED: { case chrome::NOTIFICATION_EXTENSION_LOADED: {
ExtensionService* service = Profile* profile = content::Source<Profile>(source).ptr();
content::Source<Profile>(source).ptr()->GetExtensionService(); ExtensionService* service = profile->GetExtensionService();
if (service->is_ready()) { if (service->is_ready()) {
const Extension* extension = const Extension* extension =
content::Details<const Extension>(details).ptr(); content::Details<const Extension>(details).ptr();
::CreateBackgroundHostForExtensionLoad(this, extension); CreateBackgroundHostForExtensionLoad(this, extension);
} }
break; break;
} }
...@@ -805,7 +810,8 @@ void IncognitoExtensionProcessManager::Observe( ...@@ -805,7 +810,8 @@ void IncognitoExtensionProcessManager::Observe(
// service will be NULL. // service will be NULL.
ExtensionService* service = GetProfile()->GetExtensionService(); ExtensionService* service = GetProfile()->GetExtensionService();
if (service && service->is_ready()) if (service && service->is_ready())
CreateBackgroundHostsForProfileStartup(this, service->extensions()); CreateBackgroundHostsForProfileStartup(GetProfile(),
this, service->extensions());
} }
break; break;
} }
......
...@@ -42,7 +42,7 @@ LazyBackgroundTaskQueue::~LazyBackgroundTaskQueue() { ...@@ -42,7 +42,7 @@ LazyBackgroundTaskQueue::~LazyBackgroundTaskQueue() {
bool LazyBackgroundTaskQueue::ShouldEnqueueTask( bool LazyBackgroundTaskQueue::ShouldEnqueueTask(
Profile* profile, const Extension* extension) { Profile* profile, const Extension* extension) {
DCHECK(extension); DCHECK(extension);
if (extension->has_lazy_background_page()) { if (extension->has_background_page()) {
ExtensionProcessManager* pm = profile->GetExtensionProcessManager(); ExtensionProcessManager* pm = profile->GetExtensionProcessManager();
ExtensionHost* background_host = ExtensionHost* background_host =
pm->GetBackgroundHostForExtension(extension->id()); pm->GetBackgroundHostForExtension(extension->id());
...@@ -66,16 +66,17 @@ void LazyBackgroundTaskQueue::AddPendingTask( ...@@ -66,16 +66,17 @@ void LazyBackgroundTaskQueue::AddPendingTask(
tasks_list = new PendingTasksList(); tasks_list = new PendingTasksList();
pending_tasks_[key] = linked_ptr<PendingTasksList>(tasks_list); pending_tasks_[key] = linked_ptr<PendingTasksList>(tasks_list);
// If this is the first enqueued task, ensure the background page
// is loaded.
const Extension* extension = const Extension* extension =
ExtensionSystem::Get(profile)->extension_service()-> ExtensionSystem::Get(profile)->extension_service()->
extensions()->GetByID(extension_id); extensions()->GetByID(extension_id);
DCHECK(extension->has_lazy_background_page()); if (extension && extension->has_lazy_background_page()) {
// If this is the first enqueued task, and we're not waiting for the
// background page to unload, ensure the background page is loaded.
ExtensionProcessManager* pm = ExtensionProcessManager* pm =
ExtensionSystem::Get(profile)->process_manager(); ExtensionSystem::Get(profile)->process_manager();
pm->IncrementLazyKeepaliveCount(extension); pm->IncrementLazyKeepaliveCount(extension);
pm->CreateBackgroundHost(extension, extension->GetBackgroundURL()); pm->CreateBackgroundHost(extension, extension->GetBackgroundURL());
}
} else { } else {
tasks_list = it->second.get(); tasks_list = it->second.get();
} }
...@@ -87,13 +88,13 @@ void LazyBackgroundTaskQueue::ProcessPendingTasks( ...@@ -87,13 +88,13 @@ void LazyBackgroundTaskQueue::ProcessPendingTasks(
ExtensionHost* host, ExtensionHost* host,
Profile* profile, Profile* profile,
const Extension* extension) { const Extension* extension) {
if (!profile->IsSameProfile(profile_) || if (!profile->IsSameProfile(profile_))
!extension->has_lazy_background_page())
return; return;
PendingTasksKey key(profile, extension->id()); PendingTasksKey key(profile, extension->id());
PendingTasksMap::iterator map_it = pending_tasks_.find(key); PendingTasksMap::iterator map_it = pending_tasks_.find(key);
if (map_it == pending_tasks_.end()) { if (map_it == pending_tasks_.end()) {
if (extension->has_lazy_background_page())
CHECK(!host); // lazy page should not load without any pending tasks CHECK(!host); // lazy page should not load without any pending tasks
return; return;
} }
...@@ -111,7 +112,7 @@ void LazyBackgroundTaskQueue::ProcessPendingTasks( ...@@ -111,7 +112,7 @@ void LazyBackgroundTaskQueue::ProcessPendingTasks(
// Balance the keepalive in AddPendingTask. Note we don't do this on a // Balance the keepalive in AddPendingTask. Note we don't do this on a
// failure to load, because the keepalive count is reset in that case. // failure to load, because the keepalive count is reset in that case.
if (host) { if (host && extension->has_lazy_background_page()) {
ExtensionSystem::Get(profile)->process_manager()-> ExtensionSystem::Get(profile)->process_manager()->
DecrementLazyKeepaliveCount(extension); DecrementLazyKeepaliveCount(extension);
} }
......
...@@ -109,6 +109,11 @@ ...@@ -109,6 +109,11 @@
} }
], ],
"events": [ "events": [
{
"name": "onStartup",
"type": "function",
"description": "Fired when the browser first starts up."
},
{ {
"name": "onInstalled", "name": "onInstalled",
"type": "function", "type": "function",
......
...@@ -193,6 +193,8 @@ ...@@ -193,6 +193,8 @@
<ol> <ol>
<li> <li>
<a href="#event-onInstalled">onInstalled</a> <a href="#event-onInstalled">onInstalled</a>
</li><li>
<a href="#event-onStartup">onStartup</a>
</li><li> </li><li>
<a href="#event-onSuspend">onSuspend</a> <a href="#event-onSuspend">onSuspend</a>
</li><li> </li><li>
...@@ -497,6 +499,22 @@ ...@@ -497,6 +499,22 @@
</dl> </dl>
</div> <!-- /description --> </div> <!-- /description -->
<!-- /description --> <!-- /description -->
</div><div class="apiItem">
<a name="event-onStartup"></a>
<h4>onStartup</h4>
<div class="summary">
<!-- Note: intentionally longer 80 columns -->
<span class="subdued">chrome.runtime.</span><span>onStartup</span><span class="subdued">.addListener</span>(function(<span></span>) <span class="subdued">{...}</span><span></span>);
</div>
<div class="description">
<p>Fired when the browser first starts up.</p>
<!-- LISTENER PARAMETERS -->
<!-- EXTRA PARAMETERS -->
<!-- LISTENER RETURN VALUE -->
<dl>
</dl>
</div> <!-- /description -->
<!-- /description -->
</div><div class="apiItem"> </div><div class="apiItem">
<a name="event-onSuspend"></a> <a name="event-onSuspend"></a>
<h4>onSuspend</h4> <h4>onSuspend</h4>
......
...@@ -224,6 +224,8 @@ ...@@ -224,6 +224,8 @@
<ol> <ol>
<li> <li>
<a href="#event-onInstalled">onInstalled</a> <a href="#event-onInstalled">onInstalled</a>
</li><li>
<a href="#event-onStartup">onStartup</a>
</li><li> </li><li>
<a href="#event-onSuspend">onSuspend</a> <a href="#event-onSuspend">onSuspend</a>
</li><li> </li><li>
...@@ -566,6 +568,22 @@ ...@@ -566,6 +568,22 @@
</dl> </dl>
</div> <!-- /description --> </div> <!-- /description -->
<!-- /description --> <!-- /description -->
</div><div class="apiItem">
<a name="event-onStartup"></a>
<h4>onStartup</h4>
<div class="summary">
<!-- Note: intentionally longer 80 columns -->
<span class="subdued">chrome.runtime.</span><span>onStartup</span><span class="subdued">.addListener</span>(function(<span></span>) <span class="subdued">{...}</span><span></span>);
</div>
<div class="description">
<p>Fired when the browser first starts up.</p>
<!-- LISTENER PARAMETERS -->
<!-- EXTRA PARAMETERS -->
<!-- LISTENER RETURN VALUE -->
<dl>
</dl>
</div> <!-- /description -->
<!-- /description -->
</div><div class="apiItem"> </div><div class="apiItem">
<a name="event-onSuspend"></a> <a name="event-onSuspend"></a>
<h4>onSuspend</h4> <h4>onSuspend</h4>
......
...@@ -184,6 +184,7 @@ ...@@ -184,6 +184,7 @@
"chrome.experimental.speechInput.onSoundStart": "experimental.speechInput.html#event-onSoundStart", "chrome.experimental.speechInput.onSoundStart": "experimental.speechInput.html#event-onSoundStart",
"chrome.experimental.speechInput.start": "experimental.speechInput.html#method-start", "chrome.experimental.speechInput.start": "experimental.speechInput.html#method-start",
"chrome.experimental.speechInput.stop": "experimental.speechInput.html#method-stop", "chrome.experimental.speechInput.stop": "experimental.speechInput.html#method-stop",
"chrome.experimental.systemInfo.cpu.get": "experimental.systemInfo.cpu.html#method-get",
"chrome.experimental.usb.bulkTransfer": "experimental.usb.html#method-bulkTransfer", "chrome.experimental.usb.bulkTransfer": "experimental.usb.html#method-bulkTransfer",
"chrome.experimental.usb.closeDevice": "experimental.usb.html#method-closeDevice", "chrome.experimental.usb.closeDevice": "experimental.usb.html#method-closeDevice",
"chrome.experimental.usb.controlTransfer": "experimental.usb.html#method-controlTransfer", "chrome.experimental.usb.controlTransfer": "experimental.usb.html#method-controlTransfer",
...@@ -290,6 +291,7 @@ ...@@ -290,6 +291,7 @@
"chrome.runtime.getManifest": "runtime.html#method-getManifest", "chrome.runtime.getManifest": "runtime.html#method-getManifest",
"chrome.runtime.getURL": "runtime.html#method-getURL", "chrome.runtime.getURL": "runtime.html#method-getURL",
"chrome.runtime.onInstalled": "runtime.html#event-onInstalled", "chrome.runtime.onInstalled": "runtime.html#event-onInstalled",
"chrome.runtime.onStartup": "runtime.html#event-onStartup",
"chrome.runtime.onSuspend": "runtime.html#event-onSuspend", "chrome.runtime.onSuspend": "runtime.html#event-onSuspend",
"chrome.runtime.onSuspendCanceled": "runtime.html#event-onSuspendCanceled", "chrome.runtime.onSuspendCanceled": "runtime.html#event-onSuspendCanceled",
"chrome.scriptBadge.getAttention": "scriptBadge.html#method-getAttention", "chrome.scriptBadge.getAttention": "scriptBadge.html#method-getAttention",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment