| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/lazy_background_task_queue.h" | 5 #include "chrome/browser/extensions/lazy_background_task_queue.h" |
| 6 | 6 |
| 7 #include "base/callback.h" | 7 #include "base/callback.h" |
| 8 #include "base/message_loop.h" |
| 8 #include "chrome/browser/extensions/extension_host.h" | 9 #include "chrome/browser/extensions/extension_host.h" |
| 9 #include "chrome/browser/extensions/extension_process_manager.h" | 10 #include "chrome/browser/extensions/extension_process_manager.h" |
| 10 #include "chrome/browser/extensions/extension_service.h" | 11 #include "chrome/browser/extensions/extension_service.h" |
| 11 #include "chrome/browser/extensions/extension_system.h" | 12 #include "chrome/browser/extensions/extension_system.h" |
| 12 #include "chrome/browser/extensions/extension_tab_util.h" | 13 #include "chrome/browser/extensions/extension_tab_util.h" |
| 13 #include "chrome/browser/extensions/process_map.h" | 14 #include "chrome/browser/extensions/process_map.h" |
| 14 #include "chrome/browser/profiles/profile.h" | 15 #include "chrome/browser/profiles/profile.h" |
| 15 #include "chrome/browser/tab_contents/tab_util.h" | 16 #include "chrome/browser/tab_contents/tab_util.h" |
| 16 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 17 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| 17 #include "chrome/common/chrome_notification_types.h" | 18 #include "chrome/common/chrome_notification_types.h" |
| (...skipping 18 matching lines...) Expand all Loading... |
| 36 content::Source<Profile>(profile)); | 37 content::Source<Profile>(profile)); |
| 37 } | 38 } |
| 38 | 39 |
| 39 LazyBackgroundTaskQueue::~LazyBackgroundTaskQueue() { | 40 LazyBackgroundTaskQueue::~LazyBackgroundTaskQueue() { |
| 40 } | 41 } |
| 41 | 42 |
| 42 bool LazyBackgroundTaskQueue::ShouldEnqueueTask( | 43 bool LazyBackgroundTaskQueue::ShouldEnqueueTask( |
| 43 Profile* profile, const Extension* extension) { | 44 Profile* profile, const Extension* extension) { |
| 44 DCHECK(extension); | 45 DCHECK(extension); |
| 45 if (extension->has_lazy_background_page()) { | 46 if (extension->has_lazy_background_page()) { |
| 46 ExtensionProcessManager* pm = profile->GetExtensionProcessManager(); | 47 ExtensionProcessManager* pm = |
| 48 ExtensionSystem::Get(profile)->process_manager(); |
| 47 ExtensionHost* background_host = | 49 ExtensionHost* background_host = |
| 48 pm->GetBackgroundHostForExtension(extension->id()); | 50 pm->GetBackgroundHostForExtension(extension->id()); |
| 49 if (!background_host || !background_host->did_stop_loading()) | 51 if (!background_host || !background_host->did_stop_loading() || |
| 52 pm->IsBackgroundHostClosing(extension->id())) |
| 50 return true; | 53 return true; |
| 51 } | 54 } |
| 52 | 55 |
| 53 return false; | 56 return false; |
| 54 } | 57 } |
| 55 | 58 |
| 56 void LazyBackgroundTaskQueue::AddPendingTask( | 59 void LazyBackgroundTaskQueue::AddPendingTask( |
| 57 Profile* profile, | 60 Profile* profile, |
| 58 const std::string& extension_id, | 61 const std::string& extension_id, |
| 59 const PendingTask& task) { | 62 const PendingTask& task) { |
| 60 PendingTasksList* tasks_list = NULL; | 63 PendingTasksList* tasks_list = NULL; |
| 61 PendingTasksKey key(profile, extension_id); | 64 PendingTasksKey key(profile, extension_id); |
| 62 PendingTasksMap::iterator it = pending_tasks_.find(key); | 65 PendingTasksMap::iterator it = pending_tasks_.find(key); |
| 63 if (it == pending_tasks_.end()) { | 66 if (it == pending_tasks_.end()) { |
| 64 tasks_list = new PendingTasksList(); | 67 tasks_list = new PendingTasksList(); |
| 65 pending_tasks_[key] = linked_ptr<PendingTasksList>(tasks_list); | 68 pending_tasks_[key] = linked_ptr<PendingTasksList>(tasks_list); |
| 66 | 69 |
| 67 // If this is the first enqueued task, ensure the background page | 70 // If this is the first enqueued task, and we're not waiting for the |
| 68 // is loaded. | 71 // background page to unload, ensure the background page is loaded. |
| 69 const Extension* extension = | 72 if (pending_page_loads_.count(key) == 0) |
| 70 ExtensionSystem::Get(profile)->extension_service()-> | 73 StartLazyBackgroundPage(profile, extension_id); |
| 71 extensions()->GetByID(extension_id); | |
| 72 DCHECK(extension->has_lazy_background_page()); | |
| 73 ExtensionProcessManager* pm = | |
| 74 ExtensionSystem::Get(profile)->process_manager(); | |
| 75 pm->IncrementLazyKeepaliveCount(extension); | |
| 76 pm->CreateBackgroundHost(extension, extension->GetBackgroundURL()); | |
| 77 } else { | 74 } else { |
| 78 tasks_list = it->second.get(); | 75 tasks_list = it->second.get(); |
| 79 } | 76 } |
| 80 | 77 |
| 81 tasks_list->push_back(task); | 78 tasks_list->push_back(task); |
| 82 } | 79 } |
| 83 | 80 |
| 81 void LazyBackgroundTaskQueue::StartLazyBackgroundPage( |
| 82 Profile* profile, const std::string& extension_id) { |
| 83 ExtensionProcessManager* pm = |
| 84 ExtensionSystem::Get(profile)->process_manager(); |
| 85 if (pm->IsBackgroundHostClosing(extension_id)) { |
| 86 // When the background host finishes closing, we will reload it. |
| 87 pending_page_loads_.insert(PendingTasksKey(profile, extension_id)); |
| 88 return; |
| 89 } |
| 90 |
| 91 const Extension* extension = |
| 92 ExtensionSystem::Get(profile)->extension_service()-> |
| 93 extensions()->GetByID(extension_id); |
| 94 DCHECK(extension->has_lazy_background_page()); |
| 95 pm->IncrementLazyKeepaliveCount(extension); |
| 96 pm->CreateBackgroundHost(extension, extension->GetBackgroundURL()); |
| 97 |
| 98 pending_page_loads_.erase(PendingTasksKey(profile, extension_id)); |
| 99 } |
| 100 |
| 84 void LazyBackgroundTaskQueue::ProcessPendingTasks( | 101 void LazyBackgroundTaskQueue::ProcessPendingTasks( |
| 85 ExtensionHost* host, | 102 ExtensionHost* host, |
| 86 Profile* profile, | 103 Profile* profile, |
| 87 const Extension* extension) { | 104 const Extension* extension) { |
| 88 if (!profile->IsSameProfile(profile_) || | 105 if (!profile->IsSameProfile(profile_) || |
| 89 !extension->has_lazy_background_page()) | 106 !extension->has_lazy_background_page()) |
| 90 return; | 107 return; |
| 91 | 108 |
| 92 PendingTasksKey key(profile, extension->id()); | 109 PendingTasksKey key(profile, extension->id()); |
| 93 PendingTasksMap::iterator map_it = pending_tasks_.find(key); | 110 PendingTasksMap::iterator map_it = pending_tasks_.find(key); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 123 // events for it. | 140 // events for it. |
| 124 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr(); | 141 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr(); |
| 125 if (host->extension_host_type() == | 142 if (host->extension_host_type() == |
| 126 chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { | 143 chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
| 127 CHECK(host->did_stop_loading()); | 144 CHECK(host->did_stop_loading()); |
| 128 ProcessPendingTasks(host, host->profile(), host->extension()); | 145 ProcessPendingTasks(host, host->profile(), host->extension()); |
| 129 } | 146 } |
| 130 break; | 147 break; |
| 131 } | 148 } |
| 132 case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: { | 149 case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: { |
| 133 // Notify consumers about the load failure when the background host dies. | |
| 134 // This can happen if the extension crashes. This is not strictly | |
| 135 // necessary, since we also unload the extension in that case (which | |
| 136 // dispatches the tasks below), but is a good extra precaution. | |
| 137 Profile* profile = content::Source<Profile>(source).ptr(); | 150 Profile* profile = content::Source<Profile>(source).ptr(); |
| 138 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr(); | 151 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr(); |
| 139 if (host->extension_host_type() == | 152 if (host->extension_host_type() == |
| 140 chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { | 153 chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
| 141 ProcessPendingTasks(NULL, profile, host->extension()); | 154 PendingTasksKey key(profile, host->extension()->id()); |
| 155 if (pending_page_loads_.count(key) > 0) { |
| 156 // We were waiting for the background page to unload. We can start it |
| 157 // up again and dispatch any queued events. |
| 158 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| 159 &LazyBackgroundTaskQueue::StartLazyBackgroundPage, |
| 160 AsWeakPtr(), profile, host->extension()->id())); |
| 161 } else { |
| 162 // This may be a load failure (e.g. a crash). In that case, notify |
| 163 // consumers about the load failure. This is not strictly necessary, |
| 164 // since we also unload the extension in that case (which dispatches |
| 165 // the tasks below), but is a good extra precaution. |
| 166 ProcessPendingTasks(NULL, profile, host->extension()); |
| 167 } |
| 142 } | 168 } |
| 143 break; | 169 break; |
| 144 } | 170 } |
| 145 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { | 171 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { |
| 146 // Notify consumers that the page failed to load. | 172 // Notify consumers that the page failed to load. |
| 147 Profile* profile = content::Source<Profile>(source).ptr(); | 173 Profile* profile = content::Source<Profile>(source).ptr(); |
| 148 UnloadedExtensionInfo* unloaded = | 174 UnloadedExtensionInfo* unloaded = |
| 149 content::Details<UnloadedExtensionInfo>(details).ptr(); | 175 content::Details<UnloadedExtensionInfo>(details).ptr(); |
| 150 ProcessPendingTasks(NULL, profile, unloaded->extension); | 176 ProcessPendingTasks(NULL, profile, unloaded->extension); |
| 151 if (profile->HasOffTheRecordProfile()) { | 177 if (profile->HasOffTheRecordProfile()) { |
| 152 ProcessPendingTasks(NULL, profile->GetOffTheRecordProfile(), | 178 ProcessPendingTasks(NULL, profile->GetOffTheRecordProfile(), |
| 153 unloaded->extension); | 179 unloaded->extension); |
| 154 } | 180 } |
| 155 break; | 181 break; |
| 156 } | 182 } |
| 157 default: | 183 default: |
| 158 NOTREACHED(); | 184 NOTREACHED(); |
| 159 break; | 185 break; |
| 160 } | 186 } |
| 161 } | 187 } |
| 162 | 188 |
| 163 } // namespace extensions | 189 } // namespace extensions |
| OLD | NEW |