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