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/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/time.h" | 10 #include "base/time.h" |
11 #include "base/value_conversions.h" | 11 #include "base/value_conversions.h" |
12 #include "base/values.h" | 12 #include "base/values.h" |
13 #include "chrome/browser/extensions/extension_event_router.h" | 13 #include "chrome/browser/extensions/extension_event_router.h" |
14 #include "chrome/browser/extensions/extension_service.h" | 14 #include "chrome/browser/extensions/extension_service.h" |
15 #include "chrome/browser/extensions/extension_system.h" | 15 #include "chrome/browser/extensions/extension_system.h" |
16 #include "chrome/browser/extensions/state_store.h" | 16 #include "chrome/browser/extensions/state_store.h" |
17 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
18 #include "chrome/common/chrome_notification_types.h" | 18 #include "chrome/common/chrome_notification_types.h" |
19 #include "content/public/browser/notification_service.h" | 19 #include "content/public/browser/notification_service.h" |
20 | 20 |
21 namespace extensions { | 21 namespace extensions { |
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 kAlarmScheduledRunTime[] = "scheduled_run_time"; | 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(5); | 32 const base::TimeDelta kDefaultMinPollPeriod = base::TimeDelta::FromMinutes(5); |
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 AlarmManager::Alarm& alarm) { | 40 const Alarm& alarm) { |
41 ListValue args; | 41 ListValue args; |
42 std::string json_args; | 42 std::string json_args; |
43 args.Append(alarm.ToValue().release()); | 43 args.Append(alarm.js_alarm->ToValue().release()); |
44 base::JSONWriter::Write(&args, &json_args); | 44 base::JSONWriter::Write(&args, &json_args); |
45 ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( | 45 ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( |
46 extension_id, kOnAlarmEvent, json_args, NULL, GURL()); | 46 extension_id, kOnAlarmEvent, json_args, NULL, GURL()); |
47 } | 47 } |
48 | 48 |
49 private: | 49 private: |
50 Profile* profile_; | 50 Profile* profile_; |
51 }; | 51 }; |
52 | 52 |
53 // Contains the state we persist for each alarm. | |
54 struct AlarmState { | |
55 linked_ptr<AlarmManager::Alarm> alarm; | |
56 base::Time scheduled_run_time; | |
57 | |
58 AlarmState() {} | |
59 ~AlarmState() {} | |
60 }; | |
61 | |
62 // Creates a TimeDelta from a delay as specified in the API. | 53 // Creates a TimeDelta from a delay as specified in the API. |
63 base::TimeDelta TimeDeltaFromDelay(double delay_in_minutes) { | 54 base::TimeDelta TimeDeltaFromDelay(double delay_in_minutes) { |
64 return base::TimeDelta::FromMicroseconds( | 55 return base::TimeDelta::FromMicroseconds( |
65 delay_in_minutes * base::Time::kMicrosecondsPerMinute); | 56 delay_in_minutes * base::Time::kMicrosecondsPerMinute); |
66 } | 57 } |
67 | 58 |
68 std::vector<AlarmState> AlarmsFromValue(const base::ListValue* list) { | 59 std::vector<Alarm> AlarmsFromValue(const base::ListValue* list) { |
69 typedef AlarmManager::Alarm Alarm; | 60 std::vector<Alarm> alarms; |
70 std::vector<AlarmState> alarms; | |
71 for (size_t i = 0; i < list->GetSize(); ++i) { | 61 for (size_t i = 0; i < list->GetSize(); ++i) { |
72 base::DictionaryValue* alarm_dict = NULL; | 62 base::DictionaryValue* alarm_dict = NULL; |
73 AlarmState alarm; | 63 Alarm alarm; |
74 alarm.alarm.reset(new Alarm()); | |
75 if (list->GetDictionary(i, &alarm_dict) && | 64 if (list->GetDictionary(i, &alarm_dict) && |
76 Alarm::Populate(*alarm_dict, alarm.alarm.get())) { | 65 api::alarms::Alarm::Populate(*alarm_dict, alarm.js_alarm.get())) { |
77 base::Value* time_value = NULL; | 66 base::Value* time_value = NULL; |
78 if (alarm_dict->Get(kAlarmScheduledRunTime, &time_value)) | 67 if (alarm_dict->Get(kAlarmGranularity, &time_value)) |
79 base::GetValueAsTime(*time_value, &alarm.scheduled_run_time); | 68 base::GetValueAsTimeDelta(*time_value, &alarm.granularity); |
80 alarms.push_back(alarm); | 69 alarms.push_back(alarm); |
81 } | 70 } |
82 } | 71 } |
83 return alarms; | 72 return alarms; |
84 } | 73 } |
85 | 74 |
86 scoped_ptr<base::ListValue> AlarmsToValue( | 75 scoped_ptr<base::ListValue> AlarmsToValue( |
87 const std::vector<AlarmState>& alarms) { | 76 const std::vector<Alarm>& alarms) { |
88 scoped_ptr<base::ListValue> list(new ListValue()); | 77 scoped_ptr<base::ListValue> list(new ListValue()); |
89 for (size_t i = 0; i < alarms.size(); ++i) { | 78 for (size_t i = 0; i < alarms.size(); ++i) { |
90 scoped_ptr<base::DictionaryValue> alarm = alarms[i].alarm->ToValue().Pass(); | 79 scoped_ptr<base::DictionaryValue> alarm = |
91 alarm->Set(kAlarmScheduledRunTime, | 80 alarms[i].js_alarm->ToValue().Pass(); |
92 base::CreateTimeValue(alarms[i].scheduled_run_time)); | 81 alarm->Set(kAlarmGranularity, |
| 82 base::CreateTimeDeltaValue(alarms[i].granularity)); |
93 list->Append(alarm.release()); | 83 list->Append(alarm.release()); |
94 } | 84 } |
95 return list.Pass(); | 85 return list.Pass(); |
96 } | 86 } |
97 | 87 |
98 | 88 |
99 } // namespace | 89 } // namespace |
100 | 90 |
101 // AlarmManager | 91 // AlarmManager |
102 | 92 |
103 AlarmManager::AlarmManager(Profile* profile) | 93 AlarmManager::AlarmManager(Profile* profile, TimeProvider now) |
104 : profile_(profile), | 94 : profile_(profile), |
| 95 now_(now), |
105 delegate_(new DefaultAlarmDelegate(profile)), | 96 delegate_(new DefaultAlarmDelegate(profile)), |
106 last_poll_time_(base::Time()) { | 97 last_poll_time_(base::Time()) { |
107 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, | 98 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
108 content::Source<Profile>(profile_)); | 99 content::Source<Profile>(profile_)); |
109 | 100 |
110 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); | 101 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); |
111 if (storage) | 102 if (storage) |
112 storage->RegisterKey(kRegisteredAlarms); | 103 storage->RegisterKey(kRegisteredAlarms); |
113 } | 104 } |
114 | 105 |
115 AlarmManager::~AlarmManager() { | 106 AlarmManager::~AlarmManager() { |
116 } | 107 } |
117 | 108 |
118 void AlarmManager::AddAlarm(const std::string& extension_id, | 109 void AlarmManager::AddAlarm(const std::string& extension_id, |
119 const linked_ptr<Alarm>& alarm) { | 110 const Alarm& alarm) { |
120 base::TimeDelta alarm_time = TimeDeltaFromDelay(alarm->delay_in_minutes); | 111 AddAlarmImpl(extension_id, alarm); |
121 AddAlarmImpl(extension_id, alarm, alarm_time); | |
122 WriteToStorage(extension_id); | 112 WriteToStorage(extension_id); |
123 } | 113 } |
124 | 114 |
125 const AlarmManager::Alarm* AlarmManager::GetAlarm( | 115 const Alarm* AlarmManager::GetAlarm( |
126 const std::string& extension_id, const std::string& name) { | 116 const std::string& extension_id, const std::string& name) { |
127 AlarmIterator it = GetAlarmIterator(extension_id, name); | 117 AlarmIterator it = GetAlarmIterator(extension_id, name); |
128 if (it.first == alarms_.end()) | 118 if (it.first == alarms_.end()) |
129 return NULL; | 119 return NULL; |
130 return it.second->get(); | 120 return &*it.second; |
131 } | 121 } |
132 | 122 |
133 const AlarmManager::AlarmList* AlarmManager::GetAllAlarms( | 123 const AlarmManager::AlarmList* AlarmManager::GetAllAlarms( |
134 const std::string& extension_id) { | 124 const std::string& extension_id) { |
135 AlarmMap::iterator list = alarms_.find(extension_id); | 125 AlarmMap::iterator list = alarms_.find(extension_id); |
136 if (list == alarms_.end()) | 126 if (list == alarms_.end()) |
137 return NULL; | 127 return NULL; |
138 return &list->second; | 128 return &list->second; |
139 } | 129 } |
140 | 130 |
141 AlarmManager::AlarmIterator AlarmManager::GetAlarmIterator( | 131 AlarmManager::AlarmIterator AlarmManager::GetAlarmIterator( |
142 const std::string& extension_id, const std::string& name) { | 132 const std::string& extension_id, const std::string& name) { |
143 AlarmMap::iterator list = alarms_.find(extension_id); | 133 AlarmMap::iterator list = alarms_.find(extension_id); |
144 if (list == alarms_.end()) | 134 if (list == alarms_.end()) |
145 return make_pair(alarms_.end(), AlarmList::iterator()); | 135 return make_pair(alarms_.end(), AlarmList::iterator()); |
146 | 136 |
147 for (AlarmList::iterator it = list->second.begin(); | 137 for (AlarmList::iterator it = list->second.begin(); |
148 it != list->second.end(); ++it) { | 138 it != list->second.end(); ++it) { |
149 if ((*it)->name == name) | 139 if (it->js_alarm->name == name) |
150 return make_pair(list, it); | 140 return make_pair(list, it); |
151 } | 141 } |
152 | 142 |
153 return make_pair(alarms_.end(), AlarmList::iterator()); | 143 return make_pair(alarms_.end(), AlarmList::iterator()); |
154 } | 144 } |
155 | 145 |
156 bool AlarmManager::RemoveAlarm(const std::string& extension_id, | 146 bool AlarmManager::RemoveAlarm(const std::string& extension_id, |
157 const std::string& name) { | 147 const std::string& name) { |
158 AlarmIterator it = GetAlarmIterator(extension_id, name); | 148 AlarmIterator it = GetAlarmIterator(extension_id, name); |
159 if (it.first == alarms_.end()) | 149 if (it.first == alarms_.end()) |
(...skipping 12 matching lines...) Expand all Loading... |
172 // Note: I'm using indices rather than iterators here because | 162 // Note: I'm using indices rather than iterators here because |
173 // RemoveAlarmIterator will delete the list when it becomes empty. | 163 // RemoveAlarmIterator will delete the list when it becomes empty. |
174 for (size_t i = 0, size = list->second.size(); i < size; ++i) | 164 for (size_t i = 0, size = list->second.size(); i < size; ++i) |
175 RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); | 165 RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); |
176 | 166 |
177 CHECK(alarms_.find(extension_id) == alarms_.end()); | 167 CHECK(alarms_.find(extension_id) == alarms_.end()); |
178 WriteToStorage(extension_id); | 168 WriteToStorage(extension_id); |
179 } | 169 } |
180 | 170 |
181 void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) { | 171 void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) { |
182 // Cancel the timer if there are no more alarms. | |
183 // We don't need to reschedule the poll otherwise, because in | |
184 // the worst case we would just poll one extra time. | |
185 scheduled_times_.erase(iter.second->get()); | |
186 if (scheduled_times_.empty()) | |
187 timer_.Stop(); | |
188 | |
189 // Clean up our alarm list. | |
190 AlarmList& list = iter.first->second; | 172 AlarmList& list = iter.first->second; |
191 list.erase(iter.second); | 173 list.erase(iter.second); |
192 if (list.empty()) | 174 if (list.empty()) |
193 alarms_.erase(iter.first); | 175 alarms_.erase(iter.first); |
| 176 |
| 177 // Cancel the timer if there are no more alarms. |
| 178 // We don't need to reschedule the poll otherwise, because in |
| 179 // the worst case we would just poll one extra time. |
| 180 if (alarms_.empty()) |
| 181 timer_.Stop(); |
194 } | 182 } |
195 | 183 |
196 void AlarmManager::OnAlarm(const std::string& extension_id, | 184 void AlarmManager::OnAlarm(AlarmIterator it) { |
197 const std::string& name) { | |
198 AlarmIterator it = GetAlarmIterator(extension_id, name); | |
199 CHECK(it.first != alarms_.end()); | 185 CHECK(it.first != alarms_.end()); |
200 const Alarm* alarm = it.second->get(); | 186 Alarm& alarm = *it.second; |
201 delegate_->OnAlarm(extension_id, *alarm); | 187 std::string extension_id_copy(it.first->first); |
| 188 delegate_->OnAlarm(extension_id_copy, alarm); |
202 | 189 |
203 std::string extension_id_copy(extension_id); | 190 // Update our scheduled time for the next alarm. |
204 if (!alarm->repeating) { | 191 if (double* period_in_minutes = |
| 192 alarm.js_alarm->period_in_minutes.get()) { |
| 193 alarm.js_alarm->scheduled_time = |
| 194 (last_poll_time_ + |
| 195 TimeDeltaFromDelay(*period_in_minutes)).ToJsTime(); |
| 196 } else { |
205 RemoveAlarmIterator(it); | 197 RemoveAlarmIterator(it); |
206 } else { | |
207 // Update our scheduled time for the next alarm. | |
208 scheduled_times_[alarm].time = | |
209 last_poll_time_ + TimeDeltaFromDelay(alarm->delay_in_minutes); | |
210 } | 198 } |
211 WriteToStorage(extension_id_copy); | 199 WriteToStorage(extension_id_copy); |
212 } | 200 } |
213 | 201 |
214 void AlarmManager::AddAlarmImpl(const std::string& extension_id, | 202 void AlarmManager::AddAlarmImpl(const std::string& extension_id, |
215 const linked_ptr<Alarm>& alarm, | 203 const Alarm& alarm) { |
216 base::TimeDelta time_delay) { | |
217 // Override any old alarm with the same name. | 204 // Override any old alarm with the same name. |
218 AlarmIterator old_alarm = GetAlarmIterator(extension_id, alarm->name); | 205 AlarmIterator old_alarm = GetAlarmIterator(extension_id, |
| 206 alarm.js_alarm->name); |
219 if (old_alarm.first != alarms_.end()) | 207 if (old_alarm.first != alarms_.end()) |
220 RemoveAlarmIterator(old_alarm); | 208 RemoveAlarmIterator(old_alarm); |
221 | 209 |
222 alarms_[extension_id].push_back(alarm); | 210 alarms_[extension_id].push_back(alarm); |
223 AlarmRuntimeInfo info; | |
224 info.extension_id = extension_id; | |
225 info.time = base::Time::Now() + time_delay; | |
226 scheduled_times_[alarm.get()] = info; | |
227 | 211 |
228 // TODO(yoz): Is 0 really sane? There could be thrashing. | 212 // TODO(yoz): Is 0 really sane? There could be thrashing. |
229 ScheduleNextPoll(base::TimeDelta::FromMinutes(0)); | 213 ScheduleNextPoll(base::TimeDelta::FromMinutes(0)); |
230 } | 214 } |
231 | 215 |
232 void AlarmManager::WriteToStorage(const std::string& extension_id) { | 216 void AlarmManager::WriteToStorage(const std::string& extension_id) { |
233 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); | 217 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); |
234 if (!storage) | 218 if (!storage) |
235 return; | 219 return; |
236 | 220 |
237 std::vector<AlarmState> alarm_states; | 221 scoped_ptr<Value> alarms; |
238 AlarmMap::iterator list = alarms_.find(extension_id); | 222 AlarmMap::iterator list = alarms_.find(extension_id); |
239 if (list != alarms_.end()) { | 223 if (list != alarms_.end()) |
240 for (AlarmList::iterator it = list->second.begin(); | 224 alarms.reset(AlarmsToValue(list->second).release()); |
241 it != list->second.end(); ++it) { | 225 else |
242 AlarmState pref; | 226 alarms.reset(AlarmsToValue(std::vector<Alarm>()).release()); |
243 pref.alarm = *it; | |
244 pref.scheduled_run_time = scheduled_times_[it->get()].time; | |
245 alarm_states.push_back(pref); | |
246 } | |
247 } | |
248 | |
249 scoped_ptr<Value> alarms(AlarmsToValue(alarm_states).release()); | |
250 storage->SetExtensionValue(extension_id, kRegisteredAlarms, alarms.Pass()); | 227 storage->SetExtensionValue(extension_id, kRegisteredAlarms, alarms.Pass()); |
251 } | 228 } |
252 | 229 |
253 void AlarmManager::ReadFromStorage(const std::string& extension_id, | 230 void AlarmManager::ReadFromStorage(const std::string& extension_id, |
254 scoped_ptr<base::Value> value) { | 231 scoped_ptr<base::Value> value) { |
255 base::ListValue* list = NULL; | 232 base::ListValue* list = NULL; |
256 if (!value.get() || !value->GetAsList(&list)) | 233 if (!value.get() || !value->GetAsList(&list)) |
257 return; | 234 return; |
258 | 235 |
259 std::vector<AlarmState> alarm_states = AlarmsFromValue(list); | 236 std::vector<Alarm> alarm_states = AlarmsFromValue(list); |
260 for (size_t i = 0; i < alarm_states.size(); ++i) { | 237 for (size_t i = 0; i < alarm_states.size(); ++i) { |
261 base::TimeDelta delay = | 238 AddAlarmImpl(extension_id, alarm_states[i]); |
262 alarm_states[i].scheduled_run_time - base::Time::Now(); | |
263 if (delay < base::TimeDelta::FromSeconds(0)) | |
264 delay = base::TimeDelta::FromSeconds(0); | |
265 | |
266 AddAlarmImpl(extension_id, alarm_states[i].alarm, delay); | |
267 } | 239 } |
268 } | 240 } |
269 | 241 |
270 void AlarmManager::ScheduleNextPoll(base::TimeDelta min_period) { | 242 void AlarmManager::ScheduleNextPoll(base::TimeDelta min_period) { |
271 // 0. If there are no alarms, stop the timer. | 243 // 0. If there are no alarms, stop the timer. |
272 if (scheduled_times_.empty()) { | 244 if (alarms_.empty()) { |
273 timer_.Stop(); | 245 timer_.Stop(); |
274 return; | 246 return; |
275 } | 247 } |
276 | 248 |
277 // TODO(yoz): Try not to reschedule every single time if we're adding | 249 // TODO(yoz): Try not to reschedule every single time if we're adding |
278 // a lot of alarms. | 250 // a lot of alarms. |
279 | 251 |
280 base::Time next_poll(last_poll_time_ + min_period); | 252 base::Time next_poll(last_poll_time_ + min_period); |
281 | 253 |
282 // Find the soonest alarm that is scheduled to run. | 254 // Find the soonest alarm that is scheduled to run. |
283 AlarmRuntimeInfoMap::iterator min_it = scheduled_times_.begin(); | 255 // alarms_ guarantees that none of its contained lists are empty. |
284 for (AlarmRuntimeInfoMap::iterator it = min_it; | 256 base::Time soonest_alarm_time = base::Time::FromJsTime( |
285 it != scheduled_times_.end(); ++it) { | 257 alarms_.begin()->second.begin()->js_alarm->scheduled_time); |
286 if (it->second.time < min_it->second.time) | 258 for (AlarmMap::const_iterator m_it = alarms_.begin(), m_end = alarms_.end(); |
287 min_it = it; | 259 m_it != m_end; ++m_it) { |
| 260 for (AlarmList::const_iterator l_it = m_it->second.begin(); |
| 261 l_it != m_it->second.end(); ++l_it) { |
| 262 base::Time cur_alarm_time = |
| 263 base::Time::FromJsTime(l_it->js_alarm->scheduled_time); |
| 264 if (cur_alarm_time < soonest_alarm_time) |
| 265 soonest_alarm_time = cur_alarm_time; |
| 266 } |
288 } | 267 } |
289 base::Time soonest_alarm_time(min_it->second.time); | |
290 | 268 |
291 // If the next alarm is more than min_period in the future, wait for it. | 269 // If the next alarm is more than min_period in the future, wait for it. |
292 // Otherwise, only poll as often as min_period. | 270 // Otherwise, only poll as often as min_period. |
293 if (last_poll_time_.is_null() || next_poll < soonest_alarm_time) { | 271 if (last_poll_time_.is_null() || next_poll < soonest_alarm_time) { |
294 next_poll = soonest_alarm_time; | 272 next_poll = soonest_alarm_time; |
295 } | 273 } |
296 | 274 |
297 // Schedule the poll. | 275 // Schedule the poll. |
298 next_poll_time_ = next_poll; | 276 next_poll_time_ = next_poll; |
299 base::TimeDelta delay = std::max(base::TimeDelta::FromSeconds(0), | 277 base::TimeDelta delay = std::max(base::TimeDelta::FromSeconds(0), |
300 next_poll - base::Time::Now()); | 278 next_poll - now_()); |
301 timer_.Start(FROM_HERE, | 279 timer_.Start(FROM_HERE, |
302 delay, | 280 delay, |
303 this, | 281 this, |
304 &AlarmManager::PollAlarms); | 282 &AlarmManager::PollAlarms); |
305 } | 283 } |
306 | 284 |
307 void AlarmManager::PollAlarms() { | 285 void AlarmManager::PollAlarms() { |
308 last_poll_time_ = base::Time::Now(); | 286 last_poll_time_ = now_(); |
309 | 287 |
310 // Run any alarms scheduled in the past. Note that we could remove alarms | 288 // Run any alarms scheduled in the past. OnAlarm uses vector::erase to remove |
311 // during iteration if they are non-repeating. | 289 // elements from the AlarmList, and map::erase to remove AlarmLists from the |
312 AlarmRuntimeInfoMap::iterator iter = scheduled_times_.begin(); | 290 // AlarmMap. |
313 while (iter != scheduled_times_.end()) { | 291 for (AlarmMap::iterator m_it = alarms_.begin(), m_end = alarms_.end(); |
314 AlarmRuntimeInfoMap::iterator it = iter; | 292 m_it != m_end;) { |
315 ++iter; | 293 AlarmMap::iterator cur_extension = m_it++; |
316 if (it->second.time <= next_poll_time_) { | 294 |
317 OnAlarm(it->second.extension_id, it->first->name); | 295 // Iterate (a) backwards so that removing elements doesn't affect |
| 296 // upcoming iterations, and (b) with indices so that if the last |
| 297 // iteration destroys the AlarmList, I'm not about to use the end |
| 298 // iterator that the destruction invalidates. |
| 299 for (size_t i = cur_extension->second.size(); i > 0; --i) { |
| 300 AlarmList::iterator cur_alarm = cur_extension->second.begin() + i - 1; |
| 301 if (base::Time::FromJsTime(cur_alarm->js_alarm->scheduled_time) <= |
| 302 next_poll_time_) { |
| 303 OnAlarm(make_pair(cur_extension, cur_alarm)); |
| 304 } |
318 } | 305 } |
319 } | 306 } |
320 | 307 |
321 // Schedule the next poll. The soonest it may happen is after | 308 // Schedule the next poll. The soonest it may happen is after |
322 // kDefaultMinPollPeriod or after the shortest scheduled delay of any alarm, | 309 // kDefaultMinPollPeriod or after the shortest granularity of any alarm, |
323 // whichever comes sooner. | 310 // whichever comes sooner. |
324 base::TimeDelta min_poll_period = kDefaultMinPollPeriod; | 311 base::TimeDelta min_poll_period = kDefaultMinPollPeriod; |
325 for (AlarmRuntimeInfoMap::iterator it = scheduled_times_.begin(); | 312 for (AlarmMap::const_iterator m_it = alarms_.begin(), m_end = alarms_.end(); |
326 it != scheduled_times_.end(); ++it) { | 313 m_it != m_end; ++m_it) { |
327 min_poll_period = std::min(TimeDeltaFromDelay(it->first->delay_in_minutes), | 314 for (AlarmList::const_iterator l_it = m_it->second.begin(); |
328 min_poll_period); | 315 l_it != m_it->second.end(); ++l_it) { |
| 316 if (l_it->granularity < min_poll_period) |
| 317 min_poll_period = l_it->granularity; |
| 318 } |
329 } | 319 } |
330 ScheduleNextPoll(min_poll_period); | 320 ScheduleNextPoll(min_poll_period); |
331 } | 321 } |
332 | 322 |
333 void AlarmManager::Observe( | 323 void AlarmManager::Observe( |
334 int type, | 324 int type, |
335 const content::NotificationSource& source, | 325 const content::NotificationSource& source, |
336 const content::NotificationDetails& details) { | 326 const content::NotificationDetails& details) { |
337 switch (type) { | 327 switch (type) { |
338 case chrome::NOTIFICATION_EXTENSION_LOADED: { | 328 case chrome::NOTIFICATION_EXTENSION_LOADED: { |
339 const Extension* extension = | 329 const Extension* extension = |
340 content::Details<const Extension>(details).ptr(); | 330 content::Details<const Extension>(details).ptr(); |
341 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); | 331 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); |
342 if (storage) { | 332 if (storage) { |
343 storage->GetExtensionValue(extension->id(), kRegisteredAlarms, | 333 storage->GetExtensionValue(extension->id(), kRegisteredAlarms, |
344 base::Bind(&AlarmManager::ReadFromStorage, | 334 base::Bind(&AlarmManager::ReadFromStorage, |
345 AsWeakPtr(), extension->id())); | 335 AsWeakPtr(), extension->id())); |
346 } | 336 } |
347 break; | 337 break; |
348 } | 338 } |
349 default: | 339 default: |
350 NOTREACHED(); | 340 NOTREACHED(); |
351 break; | 341 break; |
352 } | 342 } |
353 } | 343 } |
354 | 344 |
| 345 // AlarmManager::Alarm |
| 346 |
| 347 Alarm::Alarm() |
| 348 : js_alarm(new api::alarms::Alarm()) { |
| 349 } |
| 350 |
| 351 Alarm::Alarm(const std::string& name, |
| 352 const api::alarms::AlarmCreateInfo& create_info, |
| 353 base::TimeDelta min_granularity, |
| 354 TimeProvider now) |
| 355 : js_alarm(new api::alarms::Alarm()) { |
| 356 js_alarm->name = name; |
| 357 |
| 358 if (create_info.when.get()) { |
| 359 // Absolute scheduling. |
| 360 js_alarm->scheduled_time = *create_info.when; |
| 361 granularity = base::Time::FromJsTime(js_alarm->scheduled_time) - now(); |
| 362 } else { |
| 363 // Relative scheduling. |
| 364 double* delay_in_minutes = create_info.delay_in_minutes.get(); |
| 365 if (delay_in_minutes == NULL) |
| 366 delay_in_minutes = create_info.period_in_minutes.get(); |
| 367 CHECK(delay_in_minutes != NULL) |
| 368 << "ValidateAlarmCreateInfo in alarms_api.cc should have " |
| 369 << "prevented this call."; |
| 370 base::TimeDelta delay = TimeDeltaFromDelay(*delay_in_minutes); |
| 371 js_alarm->scheduled_time = (now() + delay).ToJsTime(); |
| 372 granularity = delay; |
| 373 } |
| 374 |
| 375 if (granularity < min_granularity) |
| 376 granularity = min_granularity; |
| 377 |
| 378 // Check for repetition. |
| 379 if (create_info.period_in_minutes.get()) { |
| 380 js_alarm->period_in_minutes.reset( |
| 381 new double(*create_info.period_in_minutes)); |
| 382 } |
| 383 } |
| 384 |
| 385 Alarm::~Alarm() { |
| 386 } |
| 387 |
355 } // namespace extensions | 388 } // namespace extensions |
OLD | NEW |