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/api/alarms/alarm_manager.h" | 5 #include "chrome/browser/extensions/api/alarms/alarm_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/json/json_writer.h" | 8 #include "base/json/json_writer.h" |
9 #include "base/lazy_instance.h" | 9 #include "base/lazy_instance.h" |
10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
102 | 102 |
103 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); | 103 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); |
104 if (storage) | 104 if (storage) |
105 storage->RegisterKey(kRegisteredAlarms); | 105 storage->RegisterKey(kRegisteredAlarms); |
106 } | 106 } |
107 | 107 |
108 AlarmManager::~AlarmManager() { | 108 AlarmManager::~AlarmManager() { |
109 } | 109 } |
110 | 110 |
111 void AlarmManager::AddAlarm(const std::string& extension_id, | 111 void AlarmManager::AddAlarm(const std::string& extension_id, |
112 const Alarm& alarm) { | 112 const Alarm& alarm, |
| 113 const AddAlarmCallback& callback) { |
| 114 RunWhenReady(extension_id, base::Bind( |
| 115 &AlarmManager::AddAlarmWhenReady, AsWeakPtr(), alarm, callback)); |
| 116 } |
| 117 |
| 118 void AlarmManager::GetAlarm(const std::string& extension_id, |
| 119 const std::string& name, |
| 120 const GetAlarmCallback& callback) { |
| 121 RunWhenReady(extension_id, base::Bind( |
| 122 &AlarmManager::GetAlarmWhenReady, AsWeakPtr(), name, callback)); |
| 123 } |
| 124 |
| 125 void AlarmManager::GetAllAlarms( |
| 126 const std::string& extension_id, const GetAllAlarmsCallback& callback) { |
| 127 RunWhenReady(extension_id, base::Bind( |
| 128 &AlarmManager::GetAllAlarmsWhenReady, AsWeakPtr(), callback)); |
| 129 } |
| 130 |
| 131 void AlarmManager::RemoveAlarm(const std::string& extension_id, |
| 132 const std::string& name, |
| 133 const RemoveAlarmCallback& callback) { |
| 134 RunWhenReady(extension_id, base::Bind( |
| 135 &AlarmManager::RemoveAlarmWhenReady, AsWeakPtr(), name, callback)); |
| 136 } |
| 137 |
| 138 void AlarmManager::RemoveAllAlarms(const std::string& extension_id, |
| 139 const RemoveAllAlarmsCallback& callback) { |
| 140 RunWhenReady(extension_id, base::Bind( |
| 141 &AlarmManager::RemoveAllAlarmsWhenReady, AsWeakPtr(), callback)); |
| 142 } |
| 143 |
| 144 void AlarmManager::AddAlarmWhenReady(const Alarm& alarm, |
| 145 const AddAlarmCallback& callback, |
| 146 const std::string& extension_id) { |
113 AddAlarmImpl(extension_id, alarm); | 147 AddAlarmImpl(extension_id, alarm); |
114 WriteToStorage(extension_id); | 148 WriteToStorage(extension_id); |
| 149 callback.Run(); |
115 } | 150 } |
116 | 151 |
117 const Alarm* AlarmManager::GetAlarm( | 152 void AlarmManager::GetAlarmWhenReady(const std::string& name, |
118 const std::string& extension_id, const std::string& name) { | 153 const GetAlarmCallback& callback, |
| 154 const std::string& extension_id) { |
119 AlarmIterator it = GetAlarmIterator(extension_id, name); | 155 AlarmIterator it = GetAlarmIterator(extension_id, name); |
120 if (it.first == alarms_.end()) | 156 callback.Run(it.first != alarms_.end() ? &*it.second : NULL); |
121 return NULL; | |
122 return &*it.second; | |
123 } | 157 } |
124 | 158 |
125 const AlarmManager::AlarmList* AlarmManager::GetAllAlarms( | 159 void AlarmManager::GetAllAlarmsWhenReady(const GetAllAlarmsCallback& callback, |
126 const std::string& extension_id) { | 160 const std::string& extension_id) { |
127 AlarmMap::iterator list = alarms_.find(extension_id); | 161 AlarmMap::iterator list = alarms_.find(extension_id); |
128 if (list == alarms_.end()) | 162 callback.Run(list != alarms_.end() ? &list->second : NULL); |
129 return NULL; | 163 } |
130 return &list->second; | 164 |
| 165 void AlarmManager::RemoveAlarmWhenReady(const std::string& name, |
| 166 const RemoveAlarmCallback& callback, |
| 167 const std::string& extension_id) { |
| 168 AlarmIterator it = GetAlarmIterator(extension_id, name); |
| 169 if (it.first == alarms_.end()) { |
| 170 callback.Run(false); |
| 171 return; |
| 172 } |
| 173 |
| 174 RemoveAlarmIterator(it); |
| 175 WriteToStorage(extension_id); |
| 176 callback.Run(true); |
| 177 } |
| 178 |
| 179 void AlarmManager::RemoveAllAlarmsWhenReady( |
| 180 const RemoveAllAlarmsCallback& callback, const std::string& extension_id) { |
| 181 AlarmMap::iterator list = alarms_.find(extension_id); |
| 182 if (list != alarms_.end()) { |
| 183 // Note: I'm using indices rather than iterators here because |
| 184 // RemoveAlarmIterator will delete the list when it becomes empty. |
| 185 for (size_t i = 0, size = list->second.size(); i < size; ++i) |
| 186 RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); |
| 187 |
| 188 CHECK(alarms_.find(extension_id) == alarms_.end()); |
| 189 WriteToStorage(extension_id); |
| 190 } |
| 191 callback.Run(); |
131 } | 192 } |
132 | 193 |
133 AlarmManager::AlarmIterator AlarmManager::GetAlarmIterator( | 194 AlarmManager::AlarmIterator AlarmManager::GetAlarmIterator( |
134 const std::string& extension_id, const std::string& name) { | 195 const std::string& extension_id, const std::string& name) { |
135 AlarmMap::iterator list = alarms_.find(extension_id); | 196 AlarmMap::iterator list = alarms_.find(extension_id); |
136 if (list == alarms_.end()) | 197 if (list == alarms_.end()) |
137 return make_pair(alarms_.end(), AlarmList::iterator()); | 198 return make_pair(alarms_.end(), AlarmList::iterator()); |
138 | 199 |
139 for (AlarmList::iterator it = list->second.begin(); | 200 for (AlarmList::iterator it = list->second.begin(); |
140 it != list->second.end(); ++it) { | 201 it != list->second.end(); ++it) { |
141 if (it->js_alarm->name == name) | 202 if (it->js_alarm->name == name) |
142 return make_pair(list, it); | 203 return make_pair(list, it); |
143 } | 204 } |
144 | 205 |
145 return make_pair(alarms_.end(), AlarmList::iterator()); | 206 return make_pair(alarms_.end(), AlarmList::iterator()); |
146 } | 207 } |
147 | 208 |
148 bool AlarmManager::RemoveAlarm(const std::string& extension_id, | |
149 const std::string& name) { | |
150 AlarmIterator it = GetAlarmIterator(extension_id, name); | |
151 if (it.first == alarms_.end()) | |
152 return false; | |
153 | |
154 RemoveAlarmIterator(it); | |
155 WriteToStorage(extension_id); | |
156 return true; | |
157 } | |
158 | |
159 void AlarmManager::RemoveAllAlarms(const std::string& extension_id) { | |
160 AlarmMap::iterator list = alarms_.find(extension_id); | |
161 if (list == alarms_.end()) | |
162 return; | |
163 | |
164 // Note: I'm using indices rather than iterators here because | |
165 // RemoveAlarmIterator will delete the list when it becomes empty. | |
166 for (size_t i = 0, size = list->second.size(); i < size; ++i) | |
167 RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); | |
168 | |
169 CHECK(alarms_.find(extension_id) == alarms_.end()); | |
170 WriteToStorage(extension_id); | |
171 } | |
172 | |
173 void AlarmManager::SetClockForTesting(base::Clock* clock) { | 209 void AlarmManager::SetClockForTesting(base::Clock* clock) { |
174 clock_.reset(clock); | 210 clock_.reset(clock); |
175 } | 211 } |
176 | 212 |
177 static base::LazyInstance<ProfileKeyedAPIFactory<AlarmManager> > | 213 static base::LazyInstance<ProfileKeyedAPIFactory<AlarmManager> > |
178 g_factory = LAZY_INSTANCE_INITIALIZER; | 214 g_factory = LAZY_INSTANCE_INITIALIZER; |
179 | 215 |
180 // static | 216 // static |
181 ProfileKeyedAPIFactory<AlarmManager>* AlarmManager::GetFactoryInstance() { | 217 ProfileKeyedAPIFactory<AlarmManager>* AlarmManager::GetFactoryInstance() { |
182 return &g_factory.Get(); | 218 return &g_factory.Get(); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 if (list != alarms_.end()) | 277 if (list != alarms_.end()) |
242 alarms.reset(AlarmsToValue(list->second).release()); | 278 alarms.reset(AlarmsToValue(list->second).release()); |
243 else | 279 else |
244 alarms.reset(AlarmsToValue(std::vector<Alarm>()).release()); | 280 alarms.reset(AlarmsToValue(std::vector<Alarm>()).release()); |
245 storage->SetExtensionValue(extension_id, kRegisteredAlarms, alarms.Pass()); | 281 storage->SetExtensionValue(extension_id, kRegisteredAlarms, alarms.Pass()); |
246 } | 282 } |
247 | 283 |
248 void AlarmManager::ReadFromStorage(const std::string& extension_id, | 284 void AlarmManager::ReadFromStorage(const std::string& extension_id, |
249 scoped_ptr<base::Value> value) { | 285 scoped_ptr<base::Value> value) { |
250 base::ListValue* list = NULL; | 286 base::ListValue* list = NULL; |
251 if (!value.get() || !value->GetAsList(&list)) | 287 if (value.get() && value->GetAsList(&list)) { |
252 return; | 288 std::vector<Alarm> alarm_states = AlarmsFromValue(list); |
| 289 for (size_t i = 0; i < alarm_states.size(); ++i) |
| 290 AddAlarmImpl(extension_id, alarm_states[i]); |
| 291 } |
253 | 292 |
254 std::vector<Alarm> alarm_states = AlarmsFromValue(list); | 293 ReadyQueue& extension_ready_queue = ready_actions_[extension_id]; |
255 for (size_t i = 0; i < alarm_states.size(); ++i) { | 294 while (!extension_ready_queue.empty()) { |
256 AddAlarmImpl(extension_id, alarm_states[i]); | 295 extension_ready_queue.front().Run(extension_id); |
| 296 extension_ready_queue.pop(); |
257 } | 297 } |
| 298 ready_actions_.erase(extension_id); |
258 } | 299 } |
259 | 300 |
260 void AlarmManager::ScheduleNextPoll() { | 301 void AlarmManager::ScheduleNextPoll() { |
261 // 0. If there are no alarms, stop the timer. | 302 // 0. If there are no alarms, stop the timer. |
262 if (alarms_.empty()) { | 303 if (alarms_.empty()) { |
263 timer_.Stop(); | 304 timer_.Stop(); |
264 return; | 305 return; |
265 } | 306 } |
266 | 307 |
267 // TODO(yoz): Try not to reschedule every single time if we're adding | 308 // TODO(yoz): Try not to reschedule every single time if we're adding |
(...skipping 20 matching lines...) Expand all Loading... |
288 | 329 |
289 base::Time next_poll(last_poll_time_ + min_granularity); | 330 base::Time next_poll(last_poll_time_ + min_granularity); |
290 // If the next alarm is more than min_granularity in the future, wait for it. | 331 // If the next alarm is more than min_granularity in the future, wait for it. |
291 // Otherwise, only poll as often as min_granularity. | 332 // Otherwise, only poll as often as min_granularity. |
292 // As a special case, if we've never checked for an alarm before | 333 // As a special case, if we've never checked for an alarm before |
293 // (e.g. during startup), let alarms fire asap. | 334 // (e.g. during startup), let alarms fire asap. |
294 if (last_poll_time_.is_null() || next_poll < soonest_alarm_time) | 335 if (last_poll_time_.is_null() || next_poll < soonest_alarm_time) |
295 next_poll = soonest_alarm_time; | 336 next_poll = soonest_alarm_time; |
296 | 337 |
297 // Schedule the poll. | 338 // Schedule the poll. |
298 next_poll_time_ = next_poll; | 339 test_next_poll_time_ = next_poll; |
299 base::TimeDelta delay = std::max(base::TimeDelta::FromSeconds(0), | 340 base::TimeDelta delay = std::max(base::TimeDelta::FromSeconds(0), |
300 next_poll - clock_->Now()); | 341 next_poll - clock_->Now()); |
301 timer_.Start(FROM_HERE, | 342 timer_.Start(FROM_HERE, |
302 delay, | 343 delay, |
303 this, | 344 this, |
304 &AlarmManager::PollAlarms); | 345 &AlarmManager::PollAlarms); |
305 } | 346 } |
306 | 347 |
307 void AlarmManager::PollAlarms() { | 348 void AlarmManager::PollAlarms() { |
308 last_poll_time_ = clock_->Now(); | 349 last_poll_time_ = clock_->Now(); |
309 | 350 |
310 // Run any alarms scheduled in the past. OnAlarm uses vector::erase to remove | 351 // Run any alarms scheduled in the past. OnAlarm uses vector::erase to remove |
311 // elements from the AlarmList, and map::erase to remove AlarmLists from the | 352 // elements from the AlarmList, and map::erase to remove AlarmLists from the |
312 // AlarmMap. | 353 // AlarmMap. |
313 for (AlarmMap::iterator m_it = alarms_.begin(), m_end = alarms_.end(); | 354 for (AlarmMap::iterator m_it = alarms_.begin(), m_end = alarms_.end(); |
314 m_it != m_end;) { | 355 m_it != m_end;) { |
315 AlarmMap::iterator cur_extension = m_it++; | 356 AlarmMap::iterator cur_extension = m_it++; |
316 | 357 |
317 // Iterate (a) backwards so that removing elements doesn't affect | 358 // Iterate (a) backwards so that removing elements doesn't affect |
318 // upcoming iterations, and (b) with indices so that if the last | 359 // upcoming iterations, and (b) with indices so that if the last |
319 // iteration destroys the AlarmList, I'm not about to use the end | 360 // iteration destroys the AlarmList, I'm not about to use the end |
320 // iterator that the destruction invalidates. | 361 // iterator that the destruction invalidates. |
321 for (size_t i = cur_extension->second.size(); i > 0; --i) { | 362 for (size_t i = cur_extension->second.size(); i > 0; --i) { |
322 AlarmList::iterator cur_alarm = cur_extension->second.begin() + i - 1; | 363 AlarmList::iterator cur_alarm = cur_extension->second.begin() + i - 1; |
323 if (base::Time::FromJsTime(cur_alarm->js_alarm->scheduled_time) <= | 364 if (base::Time::FromJsTime(cur_alarm->js_alarm->scheduled_time) <= |
324 next_poll_time_) { | 365 last_poll_time_) { |
325 OnAlarm(make_pair(cur_extension, cur_alarm)); | 366 OnAlarm(make_pair(cur_extension, cur_alarm)); |
326 } | 367 } |
327 } | 368 } |
328 } | 369 } |
329 | 370 |
330 ScheduleNextPoll(); | 371 ScheduleNextPoll(); |
331 } | 372 } |
332 | 373 |
| 374 static void RemoveAllOnUninstallCallback() {} |
| 375 |
| 376 void AlarmManager::RunWhenReady( |
| 377 const std::string& extension_id, const ReadyAction& action) { |
| 378 ReadyMap::iterator it = ready_actions_.find(extension_id); |
| 379 |
| 380 if (it == ready_actions_.end()) |
| 381 action.Run(extension_id); |
| 382 else |
| 383 it->second.push(action); |
| 384 } |
| 385 |
333 void AlarmManager::Observe( | 386 void AlarmManager::Observe( |
334 int type, | 387 int type, |
335 const content::NotificationSource& source, | 388 const content::NotificationSource& source, |
336 const content::NotificationDetails& details) { | 389 const content::NotificationDetails& details) { |
337 switch (type) { | 390 switch (type) { |
338 case chrome::NOTIFICATION_EXTENSION_LOADED: { | 391 case chrome::NOTIFICATION_EXTENSION_LOADED: { |
339 const Extension* extension = | 392 const Extension* extension = |
340 content::Details<const Extension>(details).ptr(); | 393 content::Details<const Extension>(details).ptr(); |
341 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); | 394 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); |
342 if (storage) { | 395 if (storage) { |
| 396 ready_actions_.insert( |
| 397 ReadyMap::value_type(extension->id(), ReadyQueue())); |
343 storage->GetExtensionValue(extension->id(), kRegisteredAlarms, | 398 storage->GetExtensionValue(extension->id(), kRegisteredAlarms, |
344 base::Bind(&AlarmManager::ReadFromStorage, | 399 base::Bind(&AlarmManager::ReadFromStorage, |
345 AsWeakPtr(), extension->id())); | 400 AsWeakPtr(), extension->id())); |
346 } | 401 } |
347 break; | 402 break; |
348 } | 403 } |
349 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: { | 404 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: { |
350 const Extension* extension = | 405 const Extension* extension = |
351 content::Details<const Extension>(details).ptr(); | 406 content::Details<const Extension>(details).ptr(); |
352 RemoveAllAlarms(extension->id()); | 407 RemoveAllAlarms( |
| 408 extension->id(), base::Bind(RemoveAllOnUninstallCallback)); |
353 break; | 409 break; |
354 } | 410 } |
355 default: | 411 default: |
356 NOTREACHED(); | 412 NOTREACHED(); |
357 break; | 413 break; |
358 } | 414 } |
359 } | 415 } |
360 | 416 |
361 // AlarmManager::Alarm | 417 // AlarmManager::Alarm |
362 | 418 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 if (create_info.period_in_minutes.get()) { | 451 if (create_info.period_in_minutes.get()) { |
396 js_alarm->period_in_minutes.reset( | 452 js_alarm->period_in_minutes.reset( |
397 new double(*create_info.period_in_minutes)); | 453 new double(*create_info.period_in_minutes)); |
398 } | 454 } |
399 } | 455 } |
400 | 456 |
401 Alarm::~Alarm() { | 457 Alarm::~Alarm() { |
402 } | 458 } |
403 | 459 |
404 } // namespace extensions | 460 } // namespace extensions |
OLD | NEW |