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 "chrome/browser/extensions/extension_host.h" | 8 #include "chrome/browser/extensions/extension_host.h" |
9 #include "chrome/browser/extensions/extension_process_manager.h" | 9 #include "chrome/browser/extensions/extension_process_manager.h" |
10 #include "chrome/browser/extensions/extension_service.h" | 10 #include "chrome/browser/extensions/extension_service.h" |
(...skipping 24 matching lines...) Expand all Loading... |
35 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, | 35 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
36 content::Source<Profile>(profile)); | 36 content::Source<Profile>(profile)); |
37 } | 37 } |
38 | 38 |
39 LazyBackgroundTaskQueue::~LazyBackgroundTaskQueue() { | 39 LazyBackgroundTaskQueue::~LazyBackgroundTaskQueue() { |
40 } | 40 } |
41 | 41 |
42 bool LazyBackgroundTaskQueue::ShouldEnqueueTask( | 42 bool LazyBackgroundTaskQueue::ShouldEnqueueTask( |
43 Profile* profile, const Extension* extension) { | 43 Profile* profile, const Extension* extension) { |
44 DCHECK(extension); | 44 DCHECK(extension); |
45 if (extension->has_lazy_background_page()) { | 45 if (extension->has_background_page()) { |
46 ExtensionProcessManager* pm = profile->GetExtensionProcessManager(); | 46 ExtensionProcessManager* pm = profile->GetExtensionProcessManager(); |
47 ExtensionHost* background_host = | 47 ExtensionHost* background_host = |
48 pm->GetBackgroundHostForExtension(extension->id()); | 48 pm->GetBackgroundHostForExtension(extension->id()); |
49 if (!background_host || !background_host->did_stop_loading()) | 49 if (!background_host || !background_host->did_stop_loading()) |
50 return true; | 50 return true; |
51 if (pm->IsBackgroundHostClosing(extension->id())) | 51 if (pm->IsBackgroundHostClosing(extension->id())) |
52 pm->CancelSuspend(extension); | 52 pm->CancelSuspend(extension); |
53 } | 53 } |
54 | 54 |
55 return false; | 55 return false; |
56 } | 56 } |
57 | 57 |
58 void LazyBackgroundTaskQueue::AddPendingTask( | 58 void LazyBackgroundTaskQueue::AddPendingTask( |
59 Profile* profile, | 59 Profile* profile, |
60 const std::string& extension_id, | 60 const std::string& extension_id, |
61 const PendingTask& task) { | 61 const PendingTask& task) { |
| 62 LOG(ERROR) << "AddPendingTask: " << extension_id; |
62 PendingTasksList* tasks_list = NULL; | 63 PendingTasksList* tasks_list = NULL; |
63 PendingTasksKey key(profile, extension_id); | 64 PendingTasksKey key(profile, extension_id); |
64 PendingTasksMap::iterator it = pending_tasks_.find(key); | 65 PendingTasksMap::iterator it = pending_tasks_.find(key); |
65 if (it == pending_tasks_.end()) { | 66 if (it == pending_tasks_.end()) { |
66 tasks_list = new PendingTasksList(); | 67 tasks_list = new PendingTasksList(); |
67 pending_tasks_[key] = linked_ptr<PendingTasksList>(tasks_list); | 68 pending_tasks_[key] = linked_ptr<PendingTasksList>(tasks_list); |
68 | 69 |
69 // If this is the first enqueued task, ensure the background page | |
70 // is loaded. | |
71 const Extension* extension = | 70 const Extension* extension = |
72 ExtensionSystem::Get(profile)->extension_service()-> | 71 ExtensionSystem::Get(profile)->extension_service()-> |
73 extensions()->GetByID(extension_id); | 72 extensions()->GetByID(extension_id); |
74 DCHECK(extension->has_lazy_background_page()); | 73 if (extension && extension->has_lazy_background_page()) { |
75 ExtensionProcessManager* pm = | 74 // If this is the first enqueued task, and we're not waiting for the |
76 ExtensionSystem::Get(profile)->process_manager(); | 75 // background page to unload, ensure the background page is loaded. |
77 pm->IncrementLazyKeepaliveCount(extension); | 76 LOG(ERROR) << "AddPendingTask NEWHOST: " << extension_id; |
78 pm->CreateBackgroundHost(extension, extension->GetBackgroundURL()); | 77 ExtensionProcessManager* pm = |
| 78 ExtensionSystem::Get(profile)->process_manager(); |
| 79 pm->IncrementLazyKeepaliveCount(extension); |
| 80 pm->CreateBackgroundHost(extension, extension->GetBackgroundURL()); |
| 81 } |
79 } else { | 82 } else { |
80 tasks_list = it->second.get(); | 83 tasks_list = it->second.get(); |
81 } | 84 } |
82 | 85 |
83 tasks_list->push_back(task); | 86 tasks_list->push_back(task); |
84 } | 87 } |
85 | 88 |
86 void LazyBackgroundTaskQueue::ProcessPendingTasks( | 89 void LazyBackgroundTaskQueue::ProcessPendingTasks( |
87 ExtensionHost* host, | 90 ExtensionHost* host, |
88 Profile* profile, | 91 Profile* profile, |
89 const Extension* extension) { | 92 const Extension* extension) { |
90 if (!profile->IsSameProfile(profile_) || | 93 if (!profile->IsSameProfile(profile_)) |
91 !extension->has_lazy_background_page()) | |
92 return; | 94 return; |
93 | 95 |
94 PendingTasksKey key(profile, extension->id()); | 96 PendingTasksKey key(profile, extension->id()); |
95 PendingTasksMap::iterator map_it = pending_tasks_.find(key); | 97 PendingTasksMap::iterator map_it = pending_tasks_.find(key); |
96 if (map_it == pending_tasks_.end()) { | 98 if (map_it == pending_tasks_.end()) { |
97 CHECK(!host); // lazy page should not load without any pending tasks | 99 if (extension->has_lazy_background_page()) |
| 100 CHECK(!host); // lazy page should not load without any pending tasks |
98 return; | 101 return; |
99 } | 102 } |
100 | 103 |
| 104 LOG(ERROR) << "ProcessPendingTasks: " << extension->id() << " " << host; |
101 // Swap the pending tasks to a temporary, to avoid problems if the task | 105 // Swap the pending tasks to a temporary, to avoid problems if the task |
102 // list is modified during processing. | 106 // list is modified during processing. |
103 PendingTasksList tasks; | 107 PendingTasksList tasks; |
104 tasks.swap(*map_it->second); | 108 tasks.swap(*map_it->second); |
105 for (PendingTasksList::const_iterator it = tasks.begin(); | 109 for (PendingTasksList::const_iterator it = tasks.begin(); |
106 it != tasks.end(); ++it) { | 110 it != tasks.end(); ++it) { |
107 it->Run(host); | 111 it->Run(host); |
108 } | 112 } |
109 | 113 |
110 pending_tasks_.erase(key); | 114 pending_tasks_.erase(key); |
111 | 115 |
112 // Balance the keepalive in AddPendingTask. Note we don't do this on a | 116 // Balance the keepalive in AddPendingTask. Note we don't do this on a |
113 // failure to load, because the keepalive count is reset in that case. | 117 // failure to load, because the keepalive count is reset in that case. |
114 if (host) { | 118 if (host && extension->has_lazy_background_page()) { |
115 ExtensionSystem::Get(profile)->process_manager()-> | 119 ExtensionSystem::Get(profile)->process_manager()-> |
116 DecrementLazyKeepaliveCount(extension); | 120 DecrementLazyKeepaliveCount(extension); |
117 } | 121 } |
118 } | 122 } |
119 | 123 |
120 void LazyBackgroundTaskQueue::Observe( | 124 void LazyBackgroundTaskQueue::Observe( |
121 int type, | 125 int type, |
122 const content::NotificationSource& source, | 126 const content::NotificationSource& source, |
123 const content::NotificationDetails& details) { | 127 const content::NotificationDetails& details) { |
124 switch (type) { | 128 switch (type) { |
125 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: { | 129 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: { |
126 // If an on-demand background page finished loading, dispatch queued up | 130 // If an on-demand background page finished loading, dispatch queued up |
127 // events for it. | 131 // events for it. |
128 ExtensionHost* host = | 132 ExtensionHost* host = |
129 content::Details<ExtensionHost>(details).ptr(); | 133 content::Details<ExtensionHost>(details).ptr(); |
| 134 LOG(ERROR) << "Host done loading: " << host->extension()->id(); |
130 if (host->extension_host_type() == | 135 if (host->extension_host_type() == |
131 chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { | 136 chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
132 CHECK(host->did_stop_loading()); | 137 CHECK(host->did_stop_loading()); |
133 ProcessPendingTasks(host, host->profile(), host->extension()); | 138 ProcessPendingTasks(host, host->profile(), host->extension()); |
134 } | 139 } |
135 break; | 140 break; |
136 } | 141 } |
137 case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: { | 142 case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: { |
138 // Notify consumers about the load failure when the background host dies. | 143 // Notify consumers about the load failure when the background host dies. |
139 // This can happen if the extension crashes. This is not strictly | 144 // This can happen if the extension crashes. This is not strictly |
140 // necessary, since we also unload the extension in that case (which | 145 // necessary, since we also unload the extension in that case (which |
141 // dispatches the tasks below), but is a good extra precaution. | 146 // dispatches the tasks below), but is a good extra precaution. |
142 Profile* profile = content::Source<Profile>(source).ptr(); | 147 Profile* profile = content::Source<Profile>(source).ptr(); |
143 ExtensionHost* host = | 148 ExtensionHost* host = |
144 content::Details<ExtensionHost>(details).ptr(); | 149 content::Details<ExtensionHost>(details).ptr(); |
| 150 LOG(ERROR) << "Host destroyed: " << host->extension()->id(); |
145 if (host->extension_host_type() == | 151 if (host->extension_host_type() == |
146 chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { | 152 chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { |
147 ProcessPendingTasks(NULL, profile, host->extension()); | 153 ProcessPendingTasks(NULL, profile, host->extension()); |
148 } | 154 } |
149 break; | 155 break; |
150 } | 156 } |
151 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { | 157 case chrome::NOTIFICATION_EXTENSION_UNLOADED: { |
152 // Notify consumers that the page failed to load. | 158 // Notify consumers that the page failed to load. |
153 Profile* profile = content::Source<Profile>(source).ptr(); | 159 Profile* profile = content::Source<Profile>(source).ptr(); |
154 UnloadedExtensionInfo* unloaded = | 160 UnloadedExtensionInfo* unloaded = |
155 content::Details<UnloadedExtensionInfo>(details).ptr(); | 161 content::Details<UnloadedExtensionInfo>(details).ptr(); |
156 ProcessPendingTasks(NULL, profile, unloaded->extension); | 162 ProcessPendingTasks(NULL, profile, unloaded->extension); |
157 if (profile->HasOffTheRecordProfile()) { | 163 if (profile->HasOffTheRecordProfile()) { |
158 ProcessPendingTasks(NULL, profile->GetOffTheRecordProfile(), | 164 ProcessPendingTasks(NULL, profile->GetOffTheRecordProfile(), |
159 unloaded->extension); | 165 unloaded->extension); |
160 } | 166 } |
161 break; | 167 break; |
162 } | 168 } |
163 default: | 169 default: |
164 NOTREACHED(); | 170 NOTREACHED(); |
165 break; | 171 break; |
166 } | 172 } |
167 } | 173 } |
168 | 174 |
169 } // namespace extensions | 175 } // namespace extensions |
OLD | NEW |