11e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 51e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "extensions/browser/lazy_background_task_queue.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/callback.h" 81e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "content/public/browser/browser_context.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_service.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_process_host.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/render_view_host.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/site_instance.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h" 1423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "extensions/browser/extension_host.h" 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_registry.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_system.h" 171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "extensions/browser/extensions_browser_client.h" 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "extensions/browser/notification_types.h" 19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/process_manager.h" 20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/browser/process_map.h" 21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h" 22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/manifest_handlers/background_info.h" 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "extensions/common/view_type.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions { 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 271e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)LazyBackgroundTaskQueue::LazyBackgroundTaskQueue( 281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) content::BrowserContext* browser_context) 29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch : browser_context_(browser_context), extension_registry_observer_(this) { 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) registrar_.Add(this, 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::AllBrowserContextsAndSources()); 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) registrar_.Add(this, 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::NotificationService::AllBrowserContextsAndSources()); 36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context)); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LazyBackgroundTaskQueue::~LazyBackgroundTaskQueue() { 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool LazyBackgroundTaskQueue::ShouldEnqueueTask( 441e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) content::BrowserContext* browser_context, 451e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) const Extension* extension) { 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Note: browser_context may not be the same as browser_context_ for incognito 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // extension tasks. 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(extension); 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (BackgroundInfo::HasBackgroundPage(extension)) { 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ProcessManager* pm = ExtensionSystem::Get( 511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) browser_context)->process_manager(); 521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DCHECK(pm); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionHost* background_host = 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pm->GetBackgroundHostForExtension(extension->id()); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!background_host || !background_host->did_stop_loading()) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pm->IsBackgroundHostClosing(extension->id())) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pm->CancelSuspend(extension); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LazyBackgroundTaskQueue::AddPendingTask( 651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) content::BrowserContext* browser_context, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& extension_id, 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const PendingTask& task) { 681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (ExtensionsBrowserClient::Get()->IsShuttingDown()) { 6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) task.Run(NULL); 7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PendingTasksList* tasks_list = NULL; 731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) PendingTasksKey key(browser_context, extension_id); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PendingTasksMap::iterator it = pending_tasks_.find(key); 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == pending_tasks_.end()) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tasks_list = new PendingTasksList(); 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_tasks_[key] = linked_ptr<PendingTasksList>(tasks_list); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Extension* extension = 805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ExtensionRegistry::Get(browser_context)->enabled_extensions().GetByID( 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) extension_id); 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (extension && BackgroundInfo::HasLazyBackgroundPage(extension)) { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If this is the first enqueued task, and we're not waiting for the 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // background page to unload, ensure the background page is loaded. 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ProcessManager* pm = ExtensionSystem::Get( 861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) browser_context)->process_manager(); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pm->IncrementLazyKeepaliveCount(extension); 884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Creating the background host may fail, e.g. if |profile| is incognito 894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // but the extension isn't enabled in incognito mode. 904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (!pm->CreateBackgroundHost( 914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) extension, BackgroundInfo::GetBackgroundURL(extension))) { 924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) task.Run(NULL); 934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return; 944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tasks_list = it->second.get(); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tasks_list->push_back(task); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LazyBackgroundTaskQueue::ProcessPendingTasks( 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionHost* host, 1051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) content::BrowserContext* browser_context, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Extension* extension) { 1071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!ExtensionsBrowserClient::Get()->IsSameContext(browser_context, 1081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) browser_context_)) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) PendingTasksKey key(browser_context, extension->id()); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PendingTasksMap::iterator map_it = pending_tasks_.find(key); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (map_it == pending_tasks_.end()) { 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (BackgroundInfo::HasLazyBackgroundPage(extension)) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(!host); // lazy page should not load without any pending tasks 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Swap the pending tasks to a temporary, to avoid problems if the task 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // list is modified during processing. 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PendingTasksList tasks; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tasks.swap(*map_it->second); 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (PendingTasksList::const_iterator it = tasks.begin(); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it != tasks.end(); ++it) { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) it->Run(host); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_tasks_.erase(key); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Balance the keepalive in AddPendingTask. Note we don't do this on a 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // failure to load, because the keepalive count is reset in that case. 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (host && BackgroundInfo::HasLazyBackgroundPage(extension)) { 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ExtensionSystem::Get(browser_context)->process_manager()-> 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DecrementLazyKeepaliveCount(extension); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LazyBackgroundTaskQueue::Observe( 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int type, 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationSource& source, 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const content::NotificationDetails& details) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (type) { 1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) case extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If an on-demand background page finished loading, dispatch queued up 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // events for it. 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionHost* host = 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Details<ExtensionHost>(details).ptr(); 148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK(host->did_stop_loading()); 1501e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ProcessPendingTasks(host, host->browser_context(), host->extension()); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: { 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Notify consumers about the load failure when the background host dies. 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This can happen if the extension crashes. This is not strictly 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // necessary, since we also unload the extension in that case (which 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // dispatches the tasks below), but is a good extra precaution. 1591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) content::BrowserContext* browser_context = 1601e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) content::Source<content::BrowserContext>(source).ptr(); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExtensionHost* host = 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content::Details<ExtensionHost>(details).ptr(); 163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (host->extension_host_type() == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { 1641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) ProcessPendingTasks(NULL, browser_context, host->extension()); 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 174116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid LazyBackgroundTaskQueue::OnExtensionUnloaded( 175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::BrowserContext* browser_context, 176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const Extension* extension, 177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch UnloadedExtensionInfo::Reason reason) { 178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Notify consumers that the page failed to load. 179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ProcessPendingTasks(NULL, browser_context, extension); 180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // If this extension is also running in an off-the-record context, notify that 181116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // task queue as well. 182116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ExtensionsBrowserClient* browser_client = ExtensionsBrowserClient::Get(); 183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (browser_client->HasOffTheRecordContext(browser_context)) { 184116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch ProcessPendingTasks(NULL, 185116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch browser_client->GetOffTheRecordContext(browser_context), 186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch extension); 187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace extensions 191