| 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/values.h" | 12 #include "base/values.h" |
| 12 #include "chrome/browser/extensions/extension_event_router.h" | 13 #include "chrome/browser/extensions/extension_event_router.h" |
| 13 #include "chrome/browser/extensions/extension_prefs.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/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
| 17 #include "chrome/common/chrome_notification_types.h" | 18 #include "chrome/common/chrome_notification_types.h" |
| 18 #include "content/public/browser/notification_service.h" | 19 #include "content/public/browser/notification_service.h" |
| 19 | 20 |
| 20 namespace extensions { | 21 namespace extensions { |
| 21 | 22 |
| 22 namespace { | 23 namespace { |
| 23 | 24 |
| 24 const char kOnAlarmEvent[] = "alarms.onAlarm"; | 25 const char kOnAlarmEvent[] = "alarms.onAlarm"; |
| 25 | 26 |
| 27 // A list of alarms that this extension has set. |
| 28 const char kRegisteredAlarms[] = "alarms"; |
| 29 const char kAlarmScheduledRunTime[] = "scheduled_run_time"; |
| 30 |
| 26 // The minimum period between polling for alarms to run. | 31 // The minimum period between polling for alarms to run. |
| 27 const base::TimeDelta kDefaultMinPollPeriod = base::TimeDelta::FromMinutes(5); | 32 const base::TimeDelta kDefaultMinPollPeriod = base::TimeDelta::FromMinutes(5); |
| 28 | 33 |
| 29 class DefaultAlarmDelegate : public AlarmManager::Delegate { | 34 class DefaultAlarmDelegate : public AlarmManager::Delegate { |
| 30 public: | 35 public: |
| 31 explicit DefaultAlarmDelegate(Profile* profile) : profile_(profile) {} | 36 explicit DefaultAlarmDelegate(Profile* profile) : profile_(profile) {} |
| 32 virtual ~DefaultAlarmDelegate() {} | 37 virtual ~DefaultAlarmDelegate() {} |
| 33 | 38 |
| 34 virtual void OnAlarm(const std::string& extension_id, | 39 virtual void OnAlarm(const std::string& extension_id, |
| 35 const AlarmManager::Alarm& alarm) { | 40 const AlarmManager::Alarm& alarm) { |
| 36 ListValue args; | 41 ListValue args; |
| 37 std::string json_args; | 42 std::string json_args; |
| 38 args.Append(alarm.ToValue().release()); | 43 args.Append(alarm.ToValue().release()); |
| 39 base::JSONWriter::Write(&args, &json_args); | 44 base::JSONWriter::Write(&args, &json_args); |
| 40 ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( | 45 ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( |
| 41 extension_id, kOnAlarmEvent, json_args, NULL, GURL()); | 46 extension_id, kOnAlarmEvent, json_args, NULL, GURL()); |
| 42 } | 47 } |
| 43 | 48 |
| 44 private: | 49 private: |
| 45 Profile* profile_; | 50 Profile* profile_; |
| 46 }; | 51 }; |
| 47 | 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 |
| 48 // Creates a TimeDelta from a delay as specified in the API. | 62 // Creates a TimeDelta from a delay as specified in the API. |
| 49 base::TimeDelta TimeDeltaFromDelay(double delay_in_minutes) { | 63 base::TimeDelta TimeDeltaFromDelay(double delay_in_minutes) { |
| 50 return base::TimeDelta::FromMicroseconds( | 64 return base::TimeDelta::FromMicroseconds( |
| 51 delay_in_minutes * base::Time::kMicrosecondsPerMinute); | 65 delay_in_minutes * base::Time::kMicrosecondsPerMinute); |
| 52 } | 66 } |
| 53 | 67 |
| 68 std::vector<AlarmState> AlarmsFromValue(const base::ListValue* list) { |
| 69 typedef AlarmManager::Alarm Alarm; |
| 70 std::vector<AlarmState> alarms; |
| 71 for (size_t i = 0; i < list->GetSize(); ++i) { |
| 72 base::DictionaryValue* alarm_dict = NULL; |
| 73 AlarmState alarm; |
| 74 alarm.alarm.reset(new Alarm()); |
| 75 if (list->GetDictionary(i, &alarm_dict) && |
| 76 Alarm::Populate(*alarm_dict, alarm.alarm.get())) { |
| 77 base::Value* time_value = NULL; |
| 78 if (alarm_dict->Get(kAlarmScheduledRunTime, &time_value)) |
| 79 base::GetValueAsTime(*time_value, &alarm.scheduled_run_time); |
| 80 alarms.push_back(alarm); |
| 81 } |
| 82 } |
| 83 return alarms; |
| 84 } |
| 85 |
| 86 scoped_ptr<base::ListValue> AlarmsToValue( |
| 87 const std::vector<AlarmState>& alarms) { |
| 88 scoped_ptr<base::ListValue> list(new ListValue()); |
| 89 for (size_t i = 0; i < alarms.size(); ++i) { |
| 90 scoped_ptr<base::DictionaryValue> alarm = alarms[i].alarm->ToValue().Pass(); |
| 91 alarm->Set(kAlarmScheduledRunTime, |
| 92 base::CreateTimeValue(alarms[i].scheduled_run_time)); |
| 93 list->Append(alarm.release()); |
| 94 } |
| 95 return list.Pass(); |
| 96 } |
| 97 |
| 98 |
| 54 } // namespace | 99 } // namespace |
| 55 | 100 |
| 56 // AlarmManager | 101 // AlarmManager |
| 57 | 102 |
| 58 AlarmManager::AlarmManager(Profile* profile) | 103 AlarmManager::AlarmManager(Profile* profile) |
| 59 : profile_(profile), | 104 : profile_(profile), |
| 60 delegate_(new DefaultAlarmDelegate(profile)), | 105 delegate_(new DefaultAlarmDelegate(profile)), |
| 61 last_poll_time_(base::Time()) { | 106 last_poll_time_(base::Time()) { |
| 62 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, | 107 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
| 63 content::Source<Profile>(profile_)); | 108 content::Source<Profile>(profile_)); |
| 109 |
| 110 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); |
| 111 if (storage) |
| 112 storage->RegisterKey(kRegisteredAlarms); |
| 64 } | 113 } |
| 65 | 114 |
| 66 AlarmManager::~AlarmManager() { | 115 AlarmManager::~AlarmManager() { |
| 67 } | 116 } |
| 68 | 117 |
| 69 void AlarmManager::AddAlarm(const std::string& extension_id, | 118 void AlarmManager::AddAlarm(const std::string& extension_id, |
| 70 const linked_ptr<Alarm>& alarm) { | 119 const linked_ptr<Alarm>& alarm) { |
| 71 base::TimeDelta alarm_time = TimeDeltaFromDelay(alarm->delay_in_minutes); | 120 base::TimeDelta alarm_time = TimeDeltaFromDelay(alarm->delay_in_minutes); |
| 72 AddAlarmImpl(extension_id, alarm, alarm_time); | 121 AddAlarmImpl(extension_id, alarm, alarm_time); |
| 73 WriteToPrefs(extension_id); | 122 WriteToStorage(extension_id); |
| 74 } | 123 } |
| 75 | 124 |
| 76 const AlarmManager::Alarm* AlarmManager::GetAlarm( | 125 const AlarmManager::Alarm* AlarmManager::GetAlarm( |
| 77 const std::string& extension_id, const std::string& name) { | 126 const std::string& extension_id, const std::string& name) { |
| 78 AlarmIterator it = GetAlarmIterator(extension_id, name); | 127 AlarmIterator it = GetAlarmIterator(extension_id, name); |
| 79 if (it.first == alarms_.end()) | 128 if (it.first == alarms_.end()) |
| 80 return NULL; | 129 return NULL; |
| 81 return it.second->get(); | 130 return it.second->get(); |
| 82 } | 131 } |
| 83 | 132 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 104 return make_pair(alarms_.end(), AlarmList::iterator()); | 153 return make_pair(alarms_.end(), AlarmList::iterator()); |
| 105 } | 154 } |
| 106 | 155 |
| 107 bool AlarmManager::RemoveAlarm(const std::string& extension_id, | 156 bool AlarmManager::RemoveAlarm(const std::string& extension_id, |
| 108 const std::string& name) { | 157 const std::string& name) { |
| 109 AlarmIterator it = GetAlarmIterator(extension_id, name); | 158 AlarmIterator it = GetAlarmIterator(extension_id, name); |
| 110 if (it.first == alarms_.end()) | 159 if (it.first == alarms_.end()) |
| 111 return false; | 160 return false; |
| 112 | 161 |
| 113 RemoveAlarmIterator(it); | 162 RemoveAlarmIterator(it); |
| 114 WriteToPrefs(extension_id); | 163 WriteToStorage(extension_id); |
| 115 return true; | 164 return true; |
| 116 } | 165 } |
| 117 | 166 |
| 118 void AlarmManager::RemoveAllAlarms(const std::string& extension_id) { | 167 void AlarmManager::RemoveAllAlarms(const std::string& extension_id) { |
| 119 AlarmMap::iterator list = alarms_.find(extension_id); | 168 AlarmMap::iterator list = alarms_.find(extension_id); |
| 120 if (list == alarms_.end()) | 169 if (list == alarms_.end()) |
| 121 return; | 170 return; |
| 122 | 171 |
| 123 // Note: I'm using indices rather than iterators here because | 172 // Note: I'm using indices rather than iterators here because |
| 124 // RemoveAlarmIterator will delete the list when it becomes empty. | 173 // RemoveAlarmIterator will delete the list when it becomes empty. |
| 125 for (size_t i = 0, size = list->second.size(); i < size; ++i) | 174 for (size_t i = 0, size = list->second.size(); i < size; ++i) |
| 126 RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); | 175 RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); |
| 127 | 176 |
| 128 CHECK(alarms_.find(extension_id) == alarms_.end()); | 177 CHECK(alarms_.find(extension_id) == alarms_.end()); |
| 129 WriteToPrefs(extension_id); | 178 WriteToStorage(extension_id); |
| 130 } | 179 } |
| 131 | 180 |
| 132 void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) { | 181 void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) { |
| 133 // Cancel the timer if there are no more alarms. | 182 // Cancel the timer if there are no more alarms. |
| 134 // We don't need to reschedule the poll otherwise, because in | 183 // We don't need to reschedule the poll otherwise, because in |
| 135 // the worst case we would just poll one extra time. | 184 // the worst case we would just poll one extra time. |
| 136 scheduled_times_.erase(iter.second->get()); | 185 scheduled_times_.erase(iter.second->get()); |
| 137 if (scheduled_times_.empty()) | 186 if (scheduled_times_.empty()) |
| 138 timer_.Stop(); | 187 timer_.Stop(); |
| 139 | 188 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 152 delegate_->OnAlarm(extension_id, *alarm); | 201 delegate_->OnAlarm(extension_id, *alarm); |
| 153 | 202 |
| 154 std::string extension_id_copy(extension_id); | 203 std::string extension_id_copy(extension_id); |
| 155 if (!alarm->repeating) { | 204 if (!alarm->repeating) { |
| 156 RemoveAlarmIterator(it); | 205 RemoveAlarmIterator(it); |
| 157 } else { | 206 } else { |
| 158 // Update our scheduled time for the next alarm. | 207 // Update our scheduled time for the next alarm. |
| 159 scheduled_times_[alarm].time = | 208 scheduled_times_[alarm].time = |
| 160 last_poll_time_ + TimeDeltaFromDelay(alarm->delay_in_minutes); | 209 last_poll_time_ + TimeDeltaFromDelay(alarm->delay_in_minutes); |
| 161 } | 210 } |
| 162 WriteToPrefs(extension_id_copy); | 211 WriteToStorage(extension_id_copy); |
| 163 } | 212 } |
| 164 | 213 |
| 165 void AlarmManager::AddAlarmImpl(const std::string& extension_id, | 214 void AlarmManager::AddAlarmImpl(const std::string& extension_id, |
| 166 const linked_ptr<Alarm>& alarm, | 215 const linked_ptr<Alarm>& alarm, |
| 167 base::TimeDelta time_delay) { | 216 base::TimeDelta time_delay) { |
| 168 // Override any old alarm with the same name. | 217 // Override any old alarm with the same name. |
| 169 AlarmIterator old_alarm = GetAlarmIterator(extension_id, alarm->name); | 218 AlarmIterator old_alarm = GetAlarmIterator(extension_id, alarm->name); |
| 170 if (old_alarm.first != alarms_.end()) | 219 if (old_alarm.first != alarms_.end()) |
| 171 RemoveAlarmIterator(old_alarm); | 220 RemoveAlarmIterator(old_alarm); |
| 172 | 221 |
| 173 alarms_[extension_id].push_back(alarm); | 222 alarms_[extension_id].push_back(alarm); |
| 174 AlarmRuntimeInfo info; | 223 AlarmRuntimeInfo info; |
| 175 info.extension_id = extension_id; | 224 info.extension_id = extension_id; |
| 176 info.time = base::Time::Now() + time_delay; | 225 info.time = base::Time::Now() + time_delay; |
| 177 scheduled_times_[alarm.get()] = info; | 226 scheduled_times_[alarm.get()] = info; |
| 178 | 227 |
| 179 // TODO(yoz): Is 0 really sane? There could be thrashing. | 228 // TODO(yoz): Is 0 really sane? There could be thrashing. |
| 180 ScheduleNextPoll(base::TimeDelta::FromMinutes(0)); | 229 ScheduleNextPoll(base::TimeDelta::FromMinutes(0)); |
| 181 } | 230 } |
| 182 | 231 |
| 183 void AlarmManager::WriteToPrefs(const std::string& extension_id) { | 232 void AlarmManager::WriteToStorage(const std::string& extension_id) { |
| 184 ExtensionService* service = | 233 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); |
| 185 ExtensionSystem::Get(profile_)->extension_service(); | 234 if (!storage) |
| 186 if (!service || !service->extension_prefs()) | |
| 187 return; | 235 return; |
| 188 | 236 |
| 189 std::vector<AlarmPref> alarm_prefs; | 237 std::vector<AlarmState> alarm_states; |
| 190 | |
| 191 AlarmMap::iterator list = alarms_.find(extension_id); | 238 AlarmMap::iterator list = alarms_.find(extension_id); |
| 192 if (list != alarms_.end()) { | 239 if (list != alarms_.end()) { |
| 193 for (AlarmList::iterator it = list->second.begin(); | 240 for (AlarmList::iterator it = list->second.begin(); |
| 194 it != list->second.end(); ++it) { | 241 it != list->second.end(); ++it) { |
| 195 AlarmPref pref; | 242 AlarmState pref; |
| 196 pref.alarm = *it; | 243 pref.alarm = *it; |
| 197 pref.scheduled_run_time = scheduled_times_[it->get()].time; | 244 pref.scheduled_run_time = scheduled_times_[it->get()].time; |
| 198 alarm_prefs.push_back(pref); | 245 alarm_states.push_back(pref); |
| 199 } | 246 } |
| 200 } | 247 } |
| 201 | 248 |
| 202 service->extension_prefs()->SetRegisteredAlarms(extension_id, alarm_prefs); | 249 scoped_ptr<Value> alarms(AlarmsToValue(alarm_states).release()); |
| 250 storage->SetExtensionValue(extension_id, kRegisteredAlarms, alarms.Pass()); |
| 203 } | 251 } |
| 204 | 252 |
| 205 void AlarmManager::ReadFromPrefs(const std::string& extension_id) { | 253 void AlarmManager::ReadFromStorage(const std::string& extension_id, |
| 206 ExtensionService* service = | 254 scoped_ptr<base::Value> value) { |
| 207 ExtensionSystem::Get(profile_)->extension_service(); | 255 base::ListValue* list = NULL; |
| 208 if (!service || !service->extension_prefs()) | 256 if (!value.get() || !value->GetAsList(&list)) |
| 209 return; | 257 return; |
| 210 | 258 |
| 211 std::vector<AlarmPref> alarm_prefs = | 259 std::vector<AlarmState> alarm_states = AlarmsFromValue(list); |
| 212 service->extension_prefs()->GetRegisteredAlarms(extension_id); | 260 for (size_t i = 0; i < alarm_states.size(); ++i) { |
| 213 for (size_t i = 0; i < alarm_prefs.size(); ++i) { | |
| 214 base::TimeDelta delay = | 261 base::TimeDelta delay = |
| 215 alarm_prefs[i].scheduled_run_time - base::Time::Now(); | 262 alarm_states[i].scheduled_run_time - base::Time::Now(); |
| 216 if (delay < base::TimeDelta::FromSeconds(0)) | 263 if (delay < base::TimeDelta::FromSeconds(0)) |
| 217 delay = base::TimeDelta::FromSeconds(0); | 264 delay = base::TimeDelta::FromSeconds(0); |
| 218 | 265 |
| 219 AddAlarmImpl(extension_id, alarm_prefs[i].alarm, delay); | 266 AddAlarmImpl(extension_id, alarm_states[i].alarm, delay); |
| 220 } | 267 } |
| 221 } | 268 } |
| 222 | 269 |
| 223 void AlarmManager::ScheduleNextPoll(base::TimeDelta min_period) { | 270 void AlarmManager::ScheduleNextPoll(base::TimeDelta min_period) { |
| 224 // 0. If there are no alarms, stop the timer. | 271 // 0. If there are no alarms, stop the timer. |
| 225 if (scheduled_times_.empty()) { | 272 if (scheduled_times_.empty()) { |
| 226 timer_.Stop(); | 273 timer_.Stop(); |
| 227 return; | 274 return; |
| 228 } | 275 } |
| 229 | 276 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 } | 331 } |
| 285 | 332 |
| 286 void AlarmManager::Observe( | 333 void AlarmManager::Observe( |
| 287 int type, | 334 int type, |
| 288 const content::NotificationSource& source, | 335 const content::NotificationSource& source, |
| 289 const content::NotificationDetails& details) { | 336 const content::NotificationDetails& details) { |
| 290 switch (type) { | 337 switch (type) { |
| 291 case chrome::NOTIFICATION_EXTENSION_LOADED: { | 338 case chrome::NOTIFICATION_EXTENSION_LOADED: { |
| 292 const Extension* extension = | 339 const Extension* extension = |
| 293 content::Details<const Extension>(details).ptr(); | 340 content::Details<const Extension>(details).ptr(); |
| 294 ReadFromPrefs(extension->id()); | 341 StateStore* storage = ExtensionSystem::Get(profile_)->state_store(); |
| 342 if (storage) { |
| 343 storage->GetExtensionValue(extension->id(), kRegisteredAlarms, |
| 344 base::Bind(&AlarmManager::ReadFromStorage, |
| 345 AsWeakPtr(), extension->id())); |
| 346 } |
| 295 break; | 347 break; |
| 296 } | 348 } |
| 297 default: | 349 default: |
| 298 NOTREACHED(); | 350 NOTREACHED(); |
| 299 break; | 351 break; |
| 300 } | 352 } |
| 301 } | 353 } |
| 302 | 354 |
| 303 AlarmPref::AlarmPref() { | |
| 304 } | |
| 305 | |
| 306 AlarmPref::~AlarmPref() { | |
| 307 } | |
| 308 | |
| 309 } // namespace extensions | 355 } // namespace extensions |
| OLD | NEW |