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

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

Issue 10545104: Refactor chrome.alarms interface to support absolute alarm deadlines. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rename timeToFire to time Created 8 years, 6 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 14 matching lines...) Expand all
25 25
26 // The minimum period between polling for alarms to run. 26 // The minimum period between polling for alarms to run.
27 const base::TimeDelta kDefaultMinPollPeriod = base::TimeDelta::FromMinutes(5); 27 const base::TimeDelta kDefaultMinPollPeriod = base::TimeDelta::FromMinutes(5);
28 28
29 class DefaultAlarmDelegate : public AlarmManager::Delegate { 29 class DefaultAlarmDelegate : public AlarmManager::Delegate {
30 public: 30 public:
31 explicit DefaultAlarmDelegate(Profile* profile) : profile_(profile) {} 31 explicit DefaultAlarmDelegate(Profile* profile) : profile_(profile) {}
32 virtual ~DefaultAlarmDelegate() {} 32 virtual ~DefaultAlarmDelegate() {}
33 33
34 virtual void OnAlarm(const std::string& extension_id, 34 virtual void OnAlarm(const std::string& extension_id,
35 const AlarmManager::Alarm& alarm) { 35 const Alarm& alarm) {
36 ListValue args; 36 ListValue args;
37 std::string json_args; 37 std::string json_args;
38 args.Append(alarm.ToValue().release()); 38 args.Append(alarm.js_alarm->ToValue().release());
39 base::JSONWriter::Write(&args, &json_args); 39 base::JSONWriter::Write(&args, &json_args);
40 ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( 40 ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
41 extension_id, kOnAlarmEvent, json_args, NULL, GURL()); 41 extension_id, kOnAlarmEvent, json_args, NULL, GURL());
42 } 42 }
43 43
44 private: 44 private:
45 Profile* profile_; 45 Profile* profile_;
46 }; 46 };
47 47
48 // Creates a TimeDelta from a delay as specified in the API. 48 // Creates a TimeDelta from a delay as specified in the API.
49 base::TimeDelta TimeDeltaFromDelay(double delay_in_minutes) { 49 base::TimeDelta TimeDeltaFromDelay(double delay_in_minutes) {
50 return base::TimeDelta::FromMicroseconds( 50 return base::TimeDelta::FromMicroseconds(
51 delay_in_minutes * base::Time::kMicrosecondsPerMinute); 51 delay_in_minutes * base::Time::kMicrosecondsPerMinute);
52 } 52 }
53 53
54 } // namespace 54 } // namespace
55 55
56 // AlarmManager 56 // AlarmManager
57 57
58 AlarmManager::AlarmManager(Profile* profile) 58 AlarmManager::AlarmManager(Profile* profile, TimeProvider now)
59 : profile_(profile), 59 : profile_(profile),
60 now_(now),
60 delegate_(new DefaultAlarmDelegate(profile)), 61 delegate_(new DefaultAlarmDelegate(profile)),
61 last_poll_time_(base::Time()) { 62 last_poll_time_(base::Time()) {
62 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, 63 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
63 content::Source<Profile>(profile_)); 64 content::Source<Profile>(profile_));
64 } 65 }
65 66
66 AlarmManager::~AlarmManager() { 67 AlarmManager::~AlarmManager() {
67 } 68 }
68 69
69 void AlarmManager::AddAlarm(const std::string& extension_id, 70 void AlarmManager::AddAlarm(const std::string& extension_id,
70 const linked_ptr<Alarm>& alarm) { 71 const Alarm& alarm) {
71 base::TimeDelta alarm_time = TimeDeltaFromDelay(alarm->delay_in_minutes); 72 AddAlarmImpl(extension_id, alarm);
72 AddAlarmImpl(extension_id, alarm, alarm_time);
73 WriteToPrefs(extension_id); 73 WriteToPrefs(extension_id);
74 } 74 }
75 75
76 const AlarmManager::Alarm* AlarmManager::GetAlarm( 76 const Alarm* AlarmManager::GetAlarm(
77 const std::string& extension_id, const std::string& name) { 77 const std::string& extension_id, const std::string& name) {
78 AlarmIterator it = GetAlarmIterator(extension_id, name); 78 AlarmIterator it = GetAlarmIterator(extension_id, name);
79 if (it.first == alarms_.end()) 79 if (it.first == alarms_.end())
80 return NULL; 80 return NULL;
81 return it.second->get(); 81 return &*it.second;
82 } 82 }
83 83
84 const AlarmManager::AlarmList* AlarmManager::GetAllAlarms( 84 const AlarmManager::AlarmList* AlarmManager::GetAllAlarms(
85 const std::string& extension_id) { 85 const std::string& extension_id) {
86 AlarmMap::iterator list = alarms_.find(extension_id); 86 AlarmMap::iterator list = alarms_.find(extension_id);
87 if (list == alarms_.end()) 87 if (list == alarms_.end())
88 return NULL; 88 return NULL;
89 return &list->second; 89 return &list->second;
90 } 90 }
91 91
92 AlarmManager::AlarmIterator AlarmManager::GetAlarmIterator( 92 AlarmManager::AlarmIterator AlarmManager::GetAlarmIterator(
93 const std::string& extension_id, const std::string& name) { 93 const std::string& extension_id, const std::string& name) {
94 AlarmMap::iterator list = alarms_.find(extension_id); 94 AlarmMap::iterator list = alarms_.find(extension_id);
95 if (list == alarms_.end()) 95 if (list == alarms_.end())
96 return make_pair(alarms_.end(), AlarmList::iterator()); 96 return make_pair(alarms_.end(), AlarmList::iterator());
97 97
98 for (AlarmList::iterator it = list->second.begin(); 98 for (AlarmList::iterator it = list->second.begin();
99 it != list->second.end(); ++it) { 99 it != list->second.end(); ++it) {
100 if ((*it)->name == name) 100 if (it->js_alarm->name == name)
101 return make_pair(list, it); 101 return make_pair(list, it);
102 } 102 }
103 103
104 return make_pair(alarms_.end(), AlarmList::iterator()); 104 return make_pair(alarms_.end(), AlarmList::iterator());
105 } 105 }
106 106
107 bool AlarmManager::RemoveAlarm(const std::string& extension_id, 107 bool AlarmManager::RemoveAlarm(const std::string& extension_id,
108 const std::string& name) { 108 const std::string& name) {
109 AlarmIterator it = GetAlarmIterator(extension_id, name); 109 AlarmIterator it = GetAlarmIterator(extension_id, name);
110 if (it.first == alarms_.end()) 110 if (it.first == alarms_.end())
(...skipping 12 matching lines...) Expand all
123 // Note: I'm using indices rather than iterators here because 123 // Note: I'm using indices rather than iterators here because
124 // RemoveAlarmIterator will delete the list when it becomes empty. 124 // RemoveAlarmIterator will delete the list when it becomes empty.
125 for (size_t i = 0, size = list->second.size(); i < size; ++i) 125 for (size_t i = 0, size = list->second.size(); i < size; ++i)
126 RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); 126 RemoveAlarmIterator(AlarmIterator(list, list->second.begin()));
127 127
128 CHECK(alarms_.find(extension_id) == alarms_.end()); 128 CHECK(alarms_.find(extension_id) == alarms_.end());
129 WriteToPrefs(extension_id); 129 WriteToPrefs(extension_id);
130 } 130 }
131 131
132 void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) { 132 void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) {
133 // Cancel the timer if there are no more alarms.
134 // We don't need to reschedule the poll otherwise, because in
135 // the worst case we would just poll one extra time.
136 scheduled_times_.erase(iter.second->get());
137 if (scheduled_times_.empty())
138 timer_.Stop();
139
140 // Clean up our alarm list.
141 AlarmList& list = iter.first->second; 133 AlarmList& list = iter.first->second;
142 list.erase(iter.second); 134 list.erase(iter.second);
143 if (list.empty()) 135 if (list.empty())
144 alarms_.erase(iter.first); 136 alarms_.erase(iter.first);
137
138 // Cancel the timer if there are no more alarms.
139 // We don't need to reschedule the poll otherwise, because in
140 // the worst case we would just poll one extra time.
141 if (alarms_.empty())
142 timer_.Stop();
145 } 143 }
146 144
147 void AlarmManager::OnAlarm(const std::string& extension_id, 145 void AlarmManager::OnAlarm(AlarmIterator it) {
148 const std::string& name) {
149 AlarmIterator it = GetAlarmIterator(extension_id, name);
150 CHECK(it.first != alarms_.end()); 146 CHECK(it.first != alarms_.end());
151 const Alarm* alarm = it.second->get(); 147 Alarm& alarm = *it.second;
152 delegate_->OnAlarm(extension_id, *alarm); 148 std::string extension_id_copy(it.first->first);
149 delegate_->OnAlarm(extension_id_copy, alarm);
153 150
154 std::string extension_id_copy(extension_id); 151 // Update our scheduled time for the next alarm.
155 if (!alarm->repeating) { 152 if (double* period_in_minutes =
Matt Perry 2012/06/11 22:32:44 I always thought our style guide banned this, but
153 alarm.js_alarm->period_in_minutes.get()) {
154 alarm.js_alarm->scheduled_time =
155 (last_poll_time_ +
156 TimeDeltaFromDelay(*period_in_minutes)).ToJsTime();
157 } else {
156 RemoveAlarmIterator(it); 158 RemoveAlarmIterator(it);
157 } else {
158 // Update our scheduled time for the next alarm.
159 scheduled_times_[alarm].time =
160 last_poll_time_ + TimeDeltaFromDelay(alarm->delay_in_minutes);
161 } 159 }
162 WriteToPrefs(extension_id_copy); 160 WriteToPrefs(extension_id_copy);
163 } 161 }
164 162
165 void AlarmManager::AddAlarmImpl(const std::string& extension_id, 163 void AlarmManager::AddAlarmImpl(const std::string& extension_id,
166 const linked_ptr<Alarm>& alarm, 164 const Alarm& alarm) {
167 base::TimeDelta time_delay) {
168 // Override any old alarm with the same name. 165 // Override any old alarm with the same name.
169 AlarmIterator old_alarm = GetAlarmIterator(extension_id, alarm->name); 166 AlarmIterator old_alarm = GetAlarmIterator(extension_id,
167 alarm.js_alarm->name);
170 if (old_alarm.first != alarms_.end()) 168 if (old_alarm.first != alarms_.end())
171 RemoveAlarmIterator(old_alarm); 169 RemoveAlarmIterator(old_alarm);
172 170
173 alarms_[extension_id].push_back(alarm); 171 alarms_[extension_id].push_back(alarm);
174 AlarmRuntimeInfo info;
175 info.extension_id = extension_id;
176 info.time = base::Time::Now() + time_delay;
177 scheduled_times_[alarm.get()] = info;
178 172
179 // TODO(yoz): Is 0 really sane? There could be thrashing. 173 // TODO(yoz): Is 0 really sane? There could be thrashing.
180 ScheduleNextPoll(base::TimeDelta::FromMinutes(0)); 174 ScheduleNextPoll(base::TimeDelta::FromMinutes(0));
181 } 175 }
182 176
183 void AlarmManager::WriteToPrefs(const std::string& extension_id) { 177 void AlarmManager::WriteToPrefs(const std::string& extension_id) {
184 ExtensionService* service = 178 ExtensionService* service =
185 ExtensionSystem::Get(profile_)->extension_service(); 179 ExtensionSystem::Get(profile_)->extension_service();
186 if (!service || !service->extension_prefs()) 180 if (!service || !service->extension_prefs())
187 return; 181 return;
188 182
189 std::vector<AlarmPref> alarm_prefs; 183 std::vector<Alarm> alarm_prefs;
190 184
191 AlarmMap::iterator list = alarms_.find(extension_id); 185 AlarmMap::iterator list = alarms_.find(extension_id);
192 if (list != alarms_.end()) { 186 if (list != alarms_.end()) {
193 for (AlarmList::iterator it = list->second.begin(); 187 for (AlarmList::iterator it = list->second.begin();
194 it != list->second.end(); ++it) { 188 it != list->second.end(); ++it) {
195 AlarmPref pref; 189 alarm_prefs.push_back(*it);
196 pref.alarm = *it;
197 pref.scheduled_run_time = scheduled_times_[it->get()].time;
198 alarm_prefs.push_back(pref);
199 } 190 }
200 } 191 }
201 192
202 service->extension_prefs()->SetRegisteredAlarms(extension_id, alarm_prefs); 193 service->extension_prefs()->SetRegisteredAlarms(extension_id, alarm_prefs);
Matt Perry 2012/06/11 22:32:44 I have a CL that changes this a bit. The slower on
Jeffrey Yasskin 2012/06/12 19:12:31 I already don't need to copy it to a temp list. I
203 } 194 }
204 195
205 void AlarmManager::ReadFromPrefs(const std::string& extension_id) { 196 void AlarmManager::ReadFromPrefs(const std::string& extension_id) {
206 ExtensionService* service = 197 ExtensionService* service =
207 ExtensionSystem::Get(profile_)->extension_service(); 198 ExtensionSystem::Get(profile_)->extension_service();
208 if (!service || !service->extension_prefs()) 199 if (!service || !service->extension_prefs())
209 return; 200 return;
210 201
211 std::vector<AlarmPref> alarm_prefs = 202 std::vector<Alarm> alarm_prefs =
212 service->extension_prefs()->GetRegisteredAlarms(extension_id); 203 service->extension_prefs()->GetRegisteredAlarms(extension_id);
213 for (size_t i = 0; i < alarm_prefs.size(); ++i) { 204 for (size_t i = 0; i < alarm_prefs.size(); ++i) {
214 base::TimeDelta delay = 205 AddAlarmImpl(extension_id, alarm_prefs[i]);
215 alarm_prefs[i].scheduled_run_time - base::Time::Now();
216 if (delay < base::TimeDelta::FromSeconds(0))
217 delay = base::TimeDelta::FromSeconds(0);
218
219 AddAlarmImpl(extension_id, alarm_prefs[i].alarm, delay);
220 } 206 }
221 } 207 }
222 208
223 void AlarmManager::ScheduleNextPoll(base::TimeDelta min_period) { 209 void AlarmManager::ScheduleNextPoll(base::TimeDelta min_period) {
224 // 0. If there are no alarms, stop the timer. 210 // 0. If there are no alarms, stop the timer.
225 if (scheduled_times_.empty()) { 211 if (alarms_.empty()) {
226 timer_.Stop(); 212 timer_.Stop();
227 return; 213 return;
228 } 214 }
229 215
230 // TODO(yoz): Try not to reschedule every single time if we're adding 216 // TODO(yoz): Try not to reschedule every single time if we're adding
231 // a lot of alarms. 217 // a lot of alarms.
232 218
233 base::Time next_poll(last_poll_time_ + min_period); 219 base::Time next_poll(last_poll_time_ + min_period);
234 220
235 // Find the soonest alarm that is scheduled to run. 221 // Find the soonest alarm that is scheduled to run.
236 AlarmRuntimeInfoMap::iterator min_it = scheduled_times_.begin(); 222 // alarms_ guarantees that none of its contained lists are empty.
237 for (AlarmRuntimeInfoMap::iterator it = min_it; 223 base::Time soonest_alarm_time = base::Time::FromJsTime(
238 it != scheduled_times_.end(); ++it) { 224 alarms_.begin()->second.begin()->js_alarm->scheduled_time);
239 if (it->second.time < min_it->second.time) 225 for (AlarmMap::const_iterator m_it = alarms_.begin(), m_end = alarms_.end();
240 min_it = it; 226 m_it != m_end; ++m_it) {
227 for (AlarmList::const_iterator
228 l_it = m_it->second.begin(), l_end = m_it->second.end();
Matt Perry 2012/06/11 22:32:44 nit: getting rid of l_end would actually require l
Jeffrey Yasskin 2012/06/12 19:12:31 True. I got into this habit in LLVM, where they po
229 l_it != l_end; ++l_it) {
230 base::Time cur_alarm_time =
231 base::Time::FromJsTime(l_it->js_alarm->scheduled_time);
232 if (cur_alarm_time < soonest_alarm_time)
233 soonest_alarm_time = cur_alarm_time;
234 }
241 } 235 }
242 base::Time soonest_alarm_time(min_it->second.time);
243 236
244 // If the next alarm is more than min_period in the future, wait for it. 237 // If the next alarm is more than min_period in the future, wait for it.
245 // Otherwise, only poll as often as min_period. 238 // Otherwise, only poll as often as min_period.
246 if (last_poll_time_.is_null() || next_poll < soonest_alarm_time) { 239 if (last_poll_time_.is_null() || next_poll < soonest_alarm_time) {
247 next_poll = soonest_alarm_time; 240 next_poll = soonest_alarm_time;
248 } 241 }
249 242
250 // Schedule the poll. 243 // Schedule the poll.
251 next_poll_time_ = next_poll; 244 next_poll_time_ = next_poll;
252 base::TimeDelta delay = std::max(base::TimeDelta::FromSeconds(0), 245 base::TimeDelta delay = std::max(base::TimeDelta::FromSeconds(0),
253 next_poll - base::Time::Now()); 246 next_poll - now_());
254 timer_.Start(FROM_HERE, 247 timer_.Start(FROM_HERE,
255 delay, 248 delay,
256 this, 249 this,
257 &AlarmManager::PollAlarms); 250 &AlarmManager::PollAlarms);
258 } 251 }
259 252
260 void AlarmManager::PollAlarms() { 253 void AlarmManager::PollAlarms() {
261 last_poll_time_ = base::Time::Now(); 254 last_poll_time_ = now_();
262 255
263 // Run any alarms scheduled in the past. Note that we could remove alarms 256 // Run any alarms scheduled in the past. OnAlarm uses vector::erase to remove
264 // during iteration if they are non-repeating. 257 // elements from the AlarmList, and map::erase to remove AlarmLists from the
265 AlarmRuntimeInfoMap::iterator iter = scheduled_times_.begin(); 258 // AlarmMap, so we have to be careful in the iteration to avoid using
266 while (iter != scheduled_times_.end()) { 259 // iterators after it's invalidated them.
267 AlarmRuntimeInfoMap::iterator it = iter; 260 for (AlarmMap::iterator m_it = alarms_.begin(), m_end = alarms_.end();
268 ++iter; 261 m_it != m_end;) {
269 if (it->second.time <= next_poll_time_) { 262 AlarmMap::iterator cur_extension = m_it;
270 OnAlarm(it->second.extension_id, it->first->name); 263 // cur_extension may be invalidated by OnAlarm in the last iteration of the
264 // nested loop, so increment the iterator before that.
265 ++m_it;
Matt Perry 2012/06/11 22:32:44 nit: no need to explain iterator details here. Doi
Jeffrey Yasskin 2012/06/12 19:12:31 Sounds good. I left most of the other explanations
266
267 // Iterate with indices and backwards so that (a) removing elements doesn't
268 // affect upcoming iterations, and (b) if the last iteration destroys the
269 // AlarmList, I'm not about to use the end iterator that the destruction
270 // invalidates.
271 for (size_t i = cur_extension->second.size(); i > 0; --i) {
272 AlarmList::iterator cur_alarm = cur_extension->second.begin() + i - 1;
273 if (base::Time::FromJsTime(cur_alarm->js_alarm->scheduled_time) <=
274 next_poll_time_) {
275 OnAlarm(make_pair(cur_extension, cur_alarm));
276 }
271 } 277 }
272 } 278 }
273 279
274 // Schedule the next poll. The soonest it may happen is after 280 // Schedule the next poll. The soonest it may happen is after
275 // kDefaultMinPollPeriod or after the shortest scheduled delay of any alarm, 281 // kDefaultMinPollPeriod or after the shortest granularity of any alarm,
276 // whichever comes sooner. 282 // whichever comes sooner.
277 base::TimeDelta min_poll_period = kDefaultMinPollPeriod; 283 base::TimeDelta min_poll_period = kDefaultMinPollPeriod;
278 for (AlarmRuntimeInfoMap::iterator it = scheduled_times_.begin(); 284 for (AlarmMap::const_iterator m_it = alarms_.begin(), m_end = alarms_.end();
279 it != scheduled_times_.end(); ++it) { 285 m_it != m_end; ++m_it) {
280 min_poll_period = std::min(TimeDeltaFromDelay(it->first->delay_in_minutes), 286 for (AlarmList::const_iterator
281 min_poll_period); 287 l_it = m_it->second.begin(), l_end = m_it->second.end();
288 l_it != l_end; ++l_it) {
289 if (l_it->granularity < min_poll_period)
290 min_poll_period = l_it->granularity;
291 }
282 } 292 }
283 ScheduleNextPoll(min_poll_period); 293 ScheduleNextPoll(min_poll_period);
284 } 294 }
285 295
286 void AlarmManager::Observe( 296 void AlarmManager::Observe(
287 int type, 297 int type,
288 const content::NotificationSource& source, 298 const content::NotificationSource& source,
289 const content::NotificationDetails& details) { 299 const content::NotificationDetails& details) {
290 switch (type) { 300 switch (type) {
291 case chrome::NOTIFICATION_EXTENSION_LOADED: { 301 case chrome::NOTIFICATION_EXTENSION_LOADED: {
292 const Extension* extension = 302 const Extension* extension =
293 content::Details<const Extension>(details).ptr(); 303 content::Details<const Extension>(details).ptr();
294 ReadFromPrefs(extension->id()); 304 ReadFromPrefs(extension->id());
295 break; 305 break;
296 } 306 }
297 default: 307 default:
298 NOTREACHED(); 308 NOTREACHED();
299 break; 309 break;
300 } 310 }
301 } 311 }
302 312
303 AlarmPref::AlarmPref() { 313 // AlarmManager::Alarm
314
315 Alarm::Alarm()
316 : js_alarm(new extensions::api::alarms::Alarm()) {
304 } 317 }
305 318
306 AlarmPref::~AlarmPref() { 319 Alarm::Alarm(const std::string& name,
320 const extensions::api::alarms::AlarmOneShotCreateInfo& create_info,
321 base::TimeDelta min_granularity,
322 TimeProvider now)
323 : js_alarm(new extensions::api::alarms::Alarm()) {
324 js_alarm->name = name;
325 if (create_info.delay_in_minutes.get()) {
326 // Relative scheduling.
327 base::TimeDelta delay = TimeDeltaFromDelay(*create_info.delay_in_minutes);
328 js_alarm->scheduled_time = (now() + delay).ToJsTime();
329 granularity = std::max(min_granularity, delay);
330 } else {
331 // Absolute scheduling.
332 CHECK(create_info.time.get())
333 << "ValidateAlarmOneShotCreateInfo in alarms_api.cc should have "
334 << "prevented this call.";
335 js_alarm->scheduled_time = *create_info.time;
336 granularity =
337 std::max(min_granularity,
338 base::Time::FromJsTime(js_alarm->scheduled_time) - now());
339 }
340 }
341
342 Alarm::Alarm(
343 const std::string& name,
344 const extensions::api::alarms::AlarmRepeatingCreateInfo& create_info,
345 base::TimeDelta min_granularity,
346 TimeProvider now)
347 : js_alarm(new extensions::api::alarms::Alarm()) {
348 js_alarm->name = name;
349 base::TimeDelta delay = TimeDeltaFromDelay(create_info.period_in_minutes);
350 js_alarm->scheduled_time = (now() + delay).ToJsTime();
351 js_alarm->period_in_minutes.reset(
352 new double(create_info.period_in_minutes));
353 granularity = std::max(min_granularity, delay);
354 }
355
356 Alarm::~Alarm() {
307 } 357 }
308 358
309 } // namespace extensions 359 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698