Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(632)

Side by Side Diff: chrome/browser/extensions/api/alarms/alarm_manager.cc

Issue 11818010: Make chrome.alarms API accept non-integers and too-short delays. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/time.h" 10 #include "base/time.h"
(...skipping 11 matching lines...) Expand all
22 22
23 namespace { 23 namespace {
24 24
25 const char kOnAlarmEvent[] = "alarms.onAlarm"; 25 const char kOnAlarmEvent[] = "alarms.onAlarm";
26 26
27 // A list of alarms that this extension has set. 27 // A list of alarms that this extension has set.
28 const char kRegisteredAlarms[] = "alarms"; 28 const char kRegisteredAlarms[] = "alarms";
29 const char kAlarmGranularity[] = "granularity"; 29 const char kAlarmGranularity[] = "granularity";
30 30
31 // The minimum period between polling for alarms to run. 31 // The minimum period between polling for alarms to run.
32 const base::TimeDelta kDefaultMinPollPeriod = base::TimeDelta::FromMinutes(1); 32 const base::TimeDelta kDefaultMinPollPeriod = base::TimeDelta::FromDays(1);
33 33
34 class DefaultAlarmDelegate : public AlarmManager::Delegate { 34 class DefaultAlarmDelegate : public AlarmManager::Delegate {
35 public: 35 public:
36 explicit DefaultAlarmDelegate(Profile* profile) : profile_(profile) {} 36 explicit DefaultAlarmDelegate(Profile* profile) : profile_(profile) {}
37 virtual ~DefaultAlarmDelegate() {} 37 virtual ~DefaultAlarmDelegate() {}
38 38
39 virtual void OnAlarm(const std::string& extension_id, 39 virtual void OnAlarm(const std::string& extension_id,
40 const Alarm& alarm) { 40 const Alarm& alarm) {
41 scoped_ptr<ListValue> args(new ListValue()); 41 scoped_ptr<ListValue> args(new ListValue());
42 args->Append(alarm.js_alarm->ToValue().release()); 42 args->Append(alarm.js_alarm->ToValue().release());
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 void AlarmManager::AddAlarmImpl(const std::string& extension_id, 200 void AlarmManager::AddAlarmImpl(const std::string& extension_id,
201 const Alarm& alarm) { 201 const Alarm& alarm) {
202 // Override any old alarm with the same name. 202 // Override any old alarm with the same name.
203 AlarmIterator old_alarm = GetAlarmIterator(extension_id, 203 AlarmIterator old_alarm = GetAlarmIterator(extension_id,
204 alarm.js_alarm->name); 204 alarm.js_alarm->name);
205 if (old_alarm.first != alarms_.end()) 205 if (old_alarm.first != alarms_.end())
206 RemoveAlarmIterator(old_alarm); 206 RemoveAlarmIterator(old_alarm);
207 207
208 alarms_[extension_id].push_back(alarm); 208 alarms_[extension_id].push_back(alarm);
209 209
210 // TODO(yoz): Is 0 really sane? There could be thrashing. 210 ScheduleNextPoll();
211 ScheduleNextPoll(base::TimeDelta::FromMinutes(0));
212 } 211 }
213 212
214 void AlarmManager::WriteToStorage(const std::string& extension_id) { 213 void AlarmManager::WriteToStorage(const std::string& extension_id) {
215 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); 214 StateStore* storage = ExtensionSystem::Get(profile_)->state_store();
216 if (!storage) 215 if (!storage)
217 return; 216 return;
218 217
219 scoped_ptr<Value> alarms; 218 scoped_ptr<Value> alarms;
220 AlarmMap::iterator list = alarms_.find(extension_id); 219 AlarmMap::iterator list = alarms_.find(extension_id);
221 if (list != alarms_.end()) 220 if (list != alarms_.end())
222 alarms.reset(AlarmsToValue(list->second).release()); 221 alarms.reset(AlarmsToValue(list->second).release());
223 else 222 else
224 alarms.reset(AlarmsToValue(std::vector<Alarm>()).release()); 223 alarms.reset(AlarmsToValue(std::vector<Alarm>()).release());
225 storage->SetExtensionValue(extension_id, kRegisteredAlarms, alarms.Pass()); 224 storage->SetExtensionValue(extension_id, kRegisteredAlarms, alarms.Pass());
226 } 225 }
227 226
228 void AlarmManager::ReadFromStorage(const std::string& extension_id, 227 void AlarmManager::ReadFromStorage(const std::string& extension_id,
229 scoped_ptr<base::Value> value) { 228 scoped_ptr<base::Value> value) {
230 base::ListValue* list = NULL; 229 base::ListValue* list = NULL;
231 if (!value.get() || !value->GetAsList(&list)) 230 if (!value.get() || !value->GetAsList(&list))
232 return; 231 return;
233 232
234 std::vector<Alarm> alarm_states = AlarmsFromValue(list); 233 std::vector<Alarm> alarm_states = AlarmsFromValue(list);
235 for (size_t i = 0; i < alarm_states.size(); ++i) { 234 for (size_t i = 0; i < alarm_states.size(); ++i) {
236 AddAlarmImpl(extension_id, alarm_states[i]); 235 AddAlarmImpl(extension_id, alarm_states[i]);
237 } 236 }
238 } 237 }
239 238
240 void AlarmManager::ScheduleNextPoll(base::TimeDelta min_period) { 239 void AlarmManager::ScheduleNextPoll() {
241 // 0. If there are no alarms, stop the timer. 240 // 0. If there are no alarms, stop the timer.
242 if (alarms_.empty()) { 241 if (alarms_.empty()) {
243 timer_.Stop(); 242 timer_.Stop();
244 return; 243 return;
245 } 244 }
246 245
247 // TODO(yoz): Try not to reschedule every single time if we're adding 246 // TODO(yoz): Try not to reschedule every single time if we're adding
248 // a lot of alarms. 247 // a lot of alarms.
249 248
250 base::Time next_poll(last_poll_time_ + min_period); 249 // Find the soonest alarm that is scheduled to run and the smallest
251 250 // granularity of any alarm.
252 // Find the soonest alarm that is scheduled to run.
253 // alarms_ guarantees that none of its contained lists are empty. 251 // alarms_ guarantees that none of its contained lists are empty.
254 base::Time soonest_alarm_time = base::Time::FromJsTime( 252 base::Time soonest_alarm_time = base::Time::FromJsTime(
255 alarms_.begin()->second.begin()->js_alarm->scheduled_time); 253 alarms_.begin()->second.begin()->js_alarm->scheduled_time);
254 base::TimeDelta min_granularity = kDefaultMinPollPeriod;
256 for (AlarmMap::const_iterator m_it = alarms_.begin(), m_end = alarms_.end(); 255 for (AlarmMap::const_iterator m_it = alarms_.begin(), m_end = alarms_.end();
257 m_it != m_end; ++m_it) { 256 m_it != m_end; ++m_it) {
258 for (AlarmList::const_iterator l_it = m_it->second.begin(); 257 for (AlarmList::const_iterator l_it = m_it->second.begin();
259 l_it != m_it->second.end(); ++l_it) { 258 l_it != m_it->second.end(); ++l_it) {
260 base::Time cur_alarm_time = 259 base::Time cur_alarm_time =
261 base::Time::FromJsTime(l_it->js_alarm->scheduled_time); 260 base::Time::FromJsTime(l_it->js_alarm->scheduled_time);
262 if (cur_alarm_time < soonest_alarm_time) 261 if (cur_alarm_time < soonest_alarm_time)
263 soonest_alarm_time = cur_alarm_time; 262 soonest_alarm_time = cur_alarm_time;
263 if (l_it->granularity < min_granularity)
264 min_granularity = l_it->granularity;
264 } 265 }
265 } 266 }
266 267
267 // If the next alarm is more than min_period in the future, wait for it. 268 base::Time next_poll(last_poll_time_ + min_granularity);
268 // Otherwise, only poll as often as min_period. 269 // If the next alarm is more than min_granularity in the future, wait for it.
269 if (last_poll_time_.is_null() || next_poll < soonest_alarm_time) { 270 // Otherwise, only poll as often as min_granularity.
271 // As a special case, if we've never checked for an alarm before
272 // (e.g. during startup), let alarms fire asap.
273 if (last_poll_time_.is_null() || next_poll < soonest_alarm_time)
270 next_poll = soonest_alarm_time; 274 next_poll = soonest_alarm_time;
271 }
272 275
273 // Schedule the poll. 276 // Schedule the poll.
274 next_poll_time_ = next_poll; 277 next_poll_time_ = next_poll;
275 base::TimeDelta delay = std::max(base::TimeDelta::FromSeconds(0), 278 base::TimeDelta delay = std::max(base::TimeDelta::FromSeconds(0),
276 next_poll - now_()); 279 next_poll - now_());
277 timer_.Start(FROM_HERE, 280 timer_.Start(FROM_HERE,
278 delay, 281 delay,
279 this, 282 this,
280 &AlarmManager::PollAlarms); 283 &AlarmManager::PollAlarms);
281 } 284 }
(...skipping 14 matching lines...) Expand all
296 // iterator that the destruction invalidates. 299 // iterator that the destruction invalidates.
297 for (size_t i = cur_extension->second.size(); i > 0; --i) { 300 for (size_t i = cur_extension->second.size(); i > 0; --i) {
298 AlarmList::iterator cur_alarm = cur_extension->second.begin() + i - 1; 301 AlarmList::iterator cur_alarm = cur_extension->second.begin() + i - 1;
299 if (base::Time::FromJsTime(cur_alarm->js_alarm->scheduled_time) <= 302 if (base::Time::FromJsTime(cur_alarm->js_alarm->scheduled_time) <=
300 next_poll_time_) { 303 next_poll_time_) {
301 OnAlarm(make_pair(cur_extension, cur_alarm)); 304 OnAlarm(make_pair(cur_extension, cur_alarm));
302 } 305 }
303 } 306 }
304 } 307 }
305 308
306 // Schedule the next poll. The soonest it may happen is after 309 ScheduleNextPoll();
307 // kDefaultMinPollPeriod or after the shortest granularity of any alarm,
308 // whichever comes sooner.
309 base::TimeDelta min_poll_period = kDefaultMinPollPeriod;
310 for (AlarmMap::const_iterator m_it = alarms_.begin(), m_end = alarms_.end();
311 m_it != m_end; ++m_it) {
312 for (AlarmList::const_iterator l_it = m_it->second.begin();
313 l_it != m_it->second.end(); ++l_it) {
314 if (l_it->granularity < min_poll_period)
315 min_poll_period = l_it->granularity;
316 }
317 }
318 ScheduleNextPoll(min_poll_period);
319 } 310 }
320 311
321 void AlarmManager::Observe( 312 void AlarmManager::Observe(
322 int type, 313 int type,
323 const content::NotificationSource& source, 314 const content::NotificationSource& source,
324 const content::NotificationDetails& details) { 315 const content::NotificationDetails& details) {
325 switch (type) { 316 switch (type) {
326 case chrome::NOTIFICATION_EXTENSION_LOADED: { 317 case chrome::NOTIFICATION_EXTENSION_LOADED: {
327 const Extension* extension = 318 const Extension* extension =
328 content::Details<const Extension>(details).ptr(); 319 content::Details<const Extension>(details).ptr();
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 if (create_info.period_in_minutes.get()) { 368 if (create_info.period_in_minutes.get()) {
378 js_alarm->period_in_minutes.reset( 369 js_alarm->period_in_minutes.reset(
379 new double(*create_info.period_in_minutes)); 370 new double(*create_info.period_in_minutes));
380 } 371 }
381 } 372 }
382 373
383 Alarm::~Alarm() { 374 Alarm::~Alarm() {
384 } 375 }
385 376
386 } // namespace extensions 377 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698