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

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

Issue 22900005: Fixing race conditions in chrome.alarms (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 4 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/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
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
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
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
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
OLDNEW
« no previous file with comments | « chrome/browser/extensions/api/alarms/alarm_manager.h ('k') | chrome/browser/extensions/api/alarms/alarms_api.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698