[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors. All rights reserved. |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 5 | #include "extensions/browser/lazy_background_task_queue.h" |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 6 | |
| 7 | #include "base/callback.h" |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 8 | #include "content/public/browser/browser_context.h" |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 9 | #include "content/public/browser/notification_service.h" |
| 10 | #include "content/public/browser/render_process_host.h" |
| 11 | #include "content/public/browser/render_view_host.h" |
| 12 | #include "content/public/browser/site_instance.h" |
| 13 | #include "content/public/browser/web_contents.h" |
[email protected] | 22401dc | 2014-03-21 01:38:57 | [diff] [blame] | 14 | #include "extensions/browser/extension_host.h" |
[email protected] | 5fdfa56 | 2013-12-27 17:43:59 | [diff] [blame] | 15 | #include "extensions/browser/extension_registry.h" |
[email protected] | 59b0e60 | 2014-01-30 00:41:24 | [diff] [blame] | 16 | #include "extensions/browser/extension_system.h" |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 17 | #include "extensions/browser/extensions_browser_client.h" |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 18 | #include "extensions/browser/notification_types.h" |
[email protected] | 98b6d94 | 2013-11-10 00:34:07 | [diff] [blame] | 19 | #include "extensions/browser/process_manager.h" |
[email protected] | 50de9aa2 | 2013-11-14 06:30:34 | [diff] [blame] | 20 | #include "extensions/browser/process_map.h" |
[email protected] | e4452d3 | 2013-11-15 23:07:41 | [diff] [blame] | 21 | #include "extensions/common/extension.h" |
[email protected] | fb820c0 | 2014-03-13 15:07:08 | [diff] [blame] | 22 | #include "extensions/common/extension_messages.h" |
[email protected] | 558878cc8 | 2013-11-09 01:25:51 | [diff] [blame] | 23 | #include "extensions/common/manifest_handlers/background_info.h" |
[email protected] | cb2edf2 | 2013-04-01 20:25:23 | [diff] [blame] | 24 | #include "extensions/common/view_type.h" |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 25 | |
[email protected] | 83055ea7 | 2012-04-05 18:56:36 | [diff] [blame] | 26 | namespace extensions { |
| 27 | |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 28 | LazyBackgroundTaskQueue::LazyBackgroundTaskQueue( |
| 29 | content::BrowserContext* browser_context) |
[email protected] | c3bb718 | 2014-07-16 21:15:18 | [diff] [blame] | 30 | : browser_context_(browser_context), extension_registry_observer_(this) { |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 31 | registrar_.Add(this, |
| 32 | extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 33 | content::NotificationService::AllBrowserContextsAndSources()); |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 34 | registrar_.Add(this, |
| 35 | extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, |
[email protected] | 76a383e | 2012-04-13 18:46:01 | [diff] [blame] | 36 | content::NotificationService::AllBrowserContextsAndSources()); |
[email protected] | c3bb718 | 2014-07-16 21:15:18 | [diff] [blame] | 37 | |
| 38 | extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context)); |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 39 | } |
| 40 | |
| 41 | LazyBackgroundTaskQueue::~LazyBackgroundTaskQueue() { |
| 42 | } |
| 43 | |
[email protected] | d79e3ab | 2012-04-03 18:28:36 | [diff] [blame] | 44 | bool LazyBackgroundTaskQueue::ShouldEnqueueTask( |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 45 | content::BrowserContext* browser_context, |
| 46 | const Extension* extension) { |
[email protected] | 9fc5bdc8 | 2014-08-03 23:49:26 | [diff] [blame^] | 47 | // Note: browser_context may not be the same as browser_context_ for incognito |
| 48 | // extension tasks. |
[email protected] | d79e3ab | 2012-04-03 18:28:36 | [diff] [blame] | 49 | DCHECK(extension); |
[email protected] | 9367eabc | 2013-03-01 01:29:29 | [diff] [blame] | 50 | if (BackgroundInfo::HasBackgroundPage(extension)) { |
[email protected] | 59b0e60 | 2014-01-30 00:41:24 | [diff] [blame] | 51 | ProcessManager* pm = ExtensionSystem::Get( |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 52 | browser_context)->process_manager(); |
[email protected] | f724021 | 2013-10-27 03:39:12 | [diff] [blame] | 53 | DCHECK(pm); |
[email protected] | d79e3ab | 2012-04-03 18:28:36 | [diff] [blame] | 54 | ExtensionHost* background_host = |
| 55 | pm->GetBackgroundHostForExtension(extension->id()); |
[email protected] | 0d475e07 | 2012-07-26 02:30:42 | [diff] [blame] | 56 | if (!background_host || !background_host->did_stop_loading()) |
[email protected] | d79e3ab | 2012-04-03 18:28:36 | [diff] [blame] | 57 | return true; |
[email protected] | 0d475e07 | 2012-07-26 02:30:42 | [diff] [blame] | 58 | if (pm->IsBackgroundHostClosing(extension->id())) |
| 59 | pm->CancelSuspend(extension); |
[email protected] | d79e3ab | 2012-04-03 18:28:36 | [diff] [blame] | 60 | } |
| 61 | |
| 62 | return false; |
| 63 | } |
| 64 | |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 65 | void LazyBackgroundTaskQueue::AddPendingTask( |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 66 | content::BrowserContext* browser_context, |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 67 | const std::string& extension_id, |
| 68 | const PendingTask& task) { |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 69 | if (ExtensionsBrowserClient::Get()->IsShuttingDown()) { |
[email protected] | 0951077 | 2013-09-05 00:08:47 | [diff] [blame] | 70 | task.Run(NULL); |
| 71 | return; |
| 72 | } |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 73 | PendingTasksList* tasks_list = NULL; |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 74 | PendingTasksKey key(browser_context, extension_id); |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 75 | PendingTasksMap::iterator it = pending_tasks_.find(key); |
| 76 | if (it == pending_tasks_.end()) { |
| 77 | tasks_list = new PendingTasksList(); |
| 78 | pending_tasks_[key] = linked_ptr<PendingTasksList>(tasks_list); |
| 79 | |
[email protected] | ed78d3fd | 2012-08-09 03:59:57 | [diff] [blame] | 80 | const Extension* extension = |
[email protected] | 5fdfa56 | 2013-12-27 17:43:59 | [diff] [blame] | 81 | ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID( |
| 82 | extension_id); |
[email protected] | 9367eabc | 2013-03-01 01:29:29 | [diff] [blame] | 83 | if (extension && BackgroundInfo::HasLazyBackgroundPage(extension)) { |
[email protected] | 546fc9d | 2012-08-18 04:10:06 | [diff] [blame] | 84 | // If this is the first enqueued task, and we're not waiting for the |
| 85 | // background page to unload, ensure the background page is loaded. |
[email protected] | 59b0e60 | 2014-01-30 00:41:24 | [diff] [blame] | 86 | ProcessManager* pm = ExtensionSystem::Get( |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 87 | browser_context)->process_manager(); |
[email protected] | 546fc9d | 2012-08-18 04:10:06 | [diff] [blame] | 88 | pm->IncrementLazyKeepaliveCount(extension); |
[email protected] | 61aa8c6 | 2013-10-01 00:43:07 | [diff] [blame] | 89 | // Creating the background host may fail, e.g. if |profile| is incognito |
| 90 | // but the extension isn't enabled in incognito mode. |
| 91 | if (!pm->CreateBackgroundHost( |
| 92 | extension, BackgroundInfo::GetBackgroundURL(extension))) { |
| 93 | task.Run(NULL); |
| 94 | return; |
| 95 | } |
[email protected] | 546fc9d | 2012-08-18 04:10:06 | [diff] [blame] | 96 | } |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 97 | } else { |
| 98 | tasks_list = it->second.get(); |
| 99 | } |
| 100 | |
| 101 | tasks_list->push_back(task); |
| 102 | } |
| 103 | |
[email protected] | 1ad12ef | 2012-04-16 19:26:22 | [diff] [blame] | 104 | void LazyBackgroundTaskQueue::ProcessPendingTasks( |
| 105 | ExtensionHost* host, |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 106 | content::BrowserContext* browser_context, |
[email protected] | 1ad12ef | 2012-04-16 19:26:22 | [diff] [blame] | 107 | const Extension* extension) { |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 108 | if (!ExtensionsBrowserClient::Get()->IsSameContext(browser_context, |
| 109 | browser_context_)) |
[email protected] | 1ad12ef | 2012-04-16 19:26:22 | [diff] [blame] | 110 | return; |
| 111 | |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 112 | PendingTasksKey key(browser_context, extension->id()); |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 113 | PendingTasksMap::iterator map_it = pending_tasks_.find(key); |
| 114 | if (map_it == pending_tasks_.end()) { |
[email protected] | 9367eabc | 2013-03-01 01:29:29 | [diff] [blame] | 115 | if (BackgroundInfo::HasLazyBackgroundPage(extension)) |
[email protected] | 546fc9d | 2012-08-18 04:10:06 | [diff] [blame] | 116 | CHECK(!host); // lazy page should not load without any pending tasks |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 117 | return; |
| 118 | } |
| 119 | |
[email protected] | b49fd0bdb | 2012-07-25 20:30:56 | [diff] [blame] | 120 | // Swap the pending tasks to a temporary, to avoid problems if the task |
| 121 | // list is modified during processing. |
| 122 | PendingTasksList tasks; |
| 123 | tasks.swap(*map_it->second); |
| 124 | for (PendingTasksList::const_iterator it = tasks.begin(); |
| 125 | it != tasks.end(); ++it) { |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 126 | it->Run(host); |
| 127 | } |
| 128 | |
[email protected] | b49fd0bdb | 2012-07-25 20:30:56 | [diff] [blame] | 129 | pending_tasks_.erase(key); |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 130 | |
[email protected] | 1ad12ef | 2012-04-16 19:26:22 | [diff] [blame] | 131 | // Balance the keepalive in AddPendingTask. Note we don't do this on a |
| 132 | // failure to load, because the keepalive count is reset in that case. |
[email protected] | 9367eabc | 2013-03-01 01:29:29 | [diff] [blame] | 133 | if (host && BackgroundInfo::HasLazyBackgroundPage(extension)) { |
[email protected] | 59b0e60 | 2014-01-30 00:41:24 | [diff] [blame] | 134 | ExtensionSystem::Get(browser_context)->process_manager()-> |
[email protected] | 1ad12ef | 2012-04-16 19:26:22 | [diff] [blame] | 135 | DecrementLazyKeepaliveCount(extension); |
| 136 | } |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 137 | } |
| 138 | |
| 139 | void LazyBackgroundTaskQueue::Observe( |
| 140 | int type, |
| 141 | const content::NotificationSource& source, |
| 142 | const content::NotificationDetails& details) { |
| 143 | switch (type) { |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 144 | case extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: { |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 145 | // If an on-demand background page finished loading, dispatch queued up |
| 146 | // events for it. |
[email protected] | 3a1dc57 | 2012-07-31 22:25:13 | [diff] [blame] | 147 | ExtensionHost* host = |
| 148 | content::Details<ExtensionHost>(details).ptr(); |
[email protected] | cb2edf2 | 2013-04-01 20:25:23 | [diff] [blame] | 149 | if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 150 | CHECK(host->did_stop_loading()); |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 151 | ProcessPendingTasks(host, host->browser_context(), host->extension()); |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 152 | } |
| 153 | break; |
| 154 | } |
[email protected] | adf5a10 | 2014-07-31 12:44:06 | [diff] [blame] | 155 | case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: { |
[email protected] | ed78d3fd | 2012-08-09 03:59:57 | [diff] [blame] | 156 | // Notify consumers about the load failure when the background host dies. |
| 157 | // This can happen if the extension crashes. This is not strictly |
| 158 | // necessary, since we also unload the extension in that case (which |
| 159 | // dispatches the tasks below), but is a good extra precaution. |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 160 | content::BrowserContext* browser_context = |
| 161 | content::Source<content::BrowserContext>(source).ptr(); |
[email protected] | 3a1dc57 | 2012-07-31 22:25:13 | [diff] [blame] | 162 | ExtensionHost* host = |
| 163 | content::Details<ExtensionHost>(details).ptr(); |
[email protected] | cb2edf2 | 2013-04-01 20:25:23 | [diff] [blame] | 164 | if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
[email protected] | 9fe4204 | 2013-10-29 21:13:33 | [diff] [blame] | 165 | ProcessPendingTasks(NULL, browser_context, host->extension()); |
[email protected] | 76a383e | 2012-04-13 18:46:01 | [diff] [blame] | 166 | } |
| 167 | break; |
| 168 | } |
[email protected] | b6536df | 2012-03-16 18:55:23 | [diff] [blame] | 169 | default: |
| 170 | NOTREACHED(); |
| 171 | break; |
| 172 | } |
| 173 | } |
[email protected] | 83055ea7 | 2012-04-05 18:56:36 | [diff] [blame] | 174 | |
[email protected] | c3bb718 | 2014-07-16 21:15:18 | [diff] [blame] | 175 | void LazyBackgroundTaskQueue::OnExtensionUnloaded( |
| 176 | content::BrowserContext* browser_context, |
| 177 | const Extension* extension, |
| 178 | UnloadedExtensionInfo::Reason reason) { |
| 179 | // Notify consumers that the page failed to load. |
| 180 | ProcessPendingTasks(NULL, browser_context, extension); |
| 181 | // If this extension is also running in an off-the-record context, notify that |
| 182 | // task queue as well. |
| 183 | ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get(); |
| 184 | if (browser_client->HasOffTheRecordContext(browser_context)) { |
| 185 | ProcessPendingTasks(NULL, |
| 186 | browser_client->GetOffTheRecordContext(browser_context), |
| 187 | extension); |
| 188 | } |
| 189 | } |
| 190 | |
[email protected] | 83055ea7 | 2012-04-05 18:56:36 | [diff] [blame] | 191 | } // namespace extensions |