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 |