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/values.h" | 10 #include "base/values.h" |
11 #include "chrome/browser/extensions/extension_event_router.h" | 11 #include "chrome/browser/extensions/extension_event_router.h" |
12 #include "chrome/browser/extensions/extension_prefs.h" | |
13 #include "chrome/browser/extensions/extension_service.h" | |
12 #include "chrome/browser/extensions/extension_system.h" | 14 #include "chrome/browser/extensions/extension_system.h" |
13 #include "chrome/browser/profiles/profile.h" | 15 #include "chrome/browser/profiles/profile.h" |
16 #include "chrome/common/chrome_notification_types.h" | |
17 #include "content/public/browser/notification_service.h" | |
14 | 18 |
15 namespace extensions { | 19 namespace extensions { |
16 | 20 |
17 namespace { | 21 namespace { |
18 | 22 |
19 const char kOnAlarmEvent[] = "experimental.alarms.onAlarm"; | 23 const char kOnAlarmEvent[] = "experimental.alarms.onAlarm"; |
20 | 24 |
21 class DefaultAlarmDelegate : public AlarmManager::Delegate { | 25 class DefaultAlarmDelegate : public AlarmManager::Delegate { |
22 public: | 26 public: |
23 explicit DefaultAlarmDelegate(Profile* profile) : profile_(profile) {} | 27 explicit DefaultAlarmDelegate(Profile* profile) : profile_(profile) {} |
24 virtual ~DefaultAlarmDelegate() {} | 28 virtual ~DefaultAlarmDelegate() {} |
25 | 29 |
26 virtual void OnAlarm(const std::string& extension_id, | 30 virtual void OnAlarm(const std::string& extension_id, |
27 const AlarmManager::Alarm& alarm) { | 31 const AlarmManager::Alarm& alarm) { |
28 ListValue args; | 32 ListValue args; |
29 std::string json_args; | 33 std::string json_args; |
30 args.Append(alarm.ToValue().release()); | 34 args.Append(alarm.ToValue().release()); |
31 base::JSONWriter::Write(&args, &json_args); | 35 base::JSONWriter::Write(&args, &json_args); |
32 ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( | 36 ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension( |
33 extension_id, kOnAlarmEvent, json_args, NULL, GURL()); | 37 extension_id, kOnAlarmEvent, json_args, NULL, GURL()); |
34 } | 38 } |
35 | 39 |
36 private: | 40 private: |
37 Profile* profile_; | 41 Profile* profile_; |
38 }; | 42 }; |
39 | 43 |
40 } | 44 } |
41 | 45 |
46 struct AlarmManager::TimerInfo { | |
47 base::Timer timer; | |
48 base::Time scheduled_run_time; | |
Aaron Boodman
2012/04/20 17:58:22
I don't understand why you introduced this struct.
Matt Perry
2012/04/20 19:38:49
It's used when persisting to prefs. Each time we p
Aaron Boodman
2012/04/20 23:15:24
I see.
| |
49 | |
50 explicit TimerInfo(bool repeating) : timer(true, repeating) {} | |
51 | |
52 void UpdateScheduledRunTime() { | |
53 scheduled_run_time = base::Time::Now() + timer.GetCurrentDelay(); | |
54 } | |
55 }; | |
56 | |
42 AlarmManager::AlarmManager(Profile* profile) | 57 AlarmManager::AlarmManager(Profile* profile) |
43 : profile_(profile), | 58 : profile_(profile), |
44 delegate_(new DefaultAlarmDelegate(profile)) { | 59 delegate_(new DefaultAlarmDelegate(profile)) { |
60 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, | |
61 content::Source<Profile>(profile_)); | |
45 } | 62 } |
46 | 63 |
47 AlarmManager::~AlarmManager() { | 64 AlarmManager::~AlarmManager() { |
48 } | 65 } |
49 | 66 |
50 void AlarmManager::AddAlarm(const std::string& extension_id, | 67 void AlarmManager::AddAlarm(const std::string& extension_id, |
51 const linked_ptr<Alarm>& alarm) { | 68 const linked_ptr<Alarm>& alarm) { |
52 // TODO(mpcomplete): Better handling of granularity. | 69 AddAlarmImpl(extension_id, alarm, |
53 // http://crbug.com/122683 | 70 base::TimeDelta::FromSeconds(alarm->delay_in_seconds)); |
54 | 71 WriteToPrefs(extension_id); |
55 // Override any old alarm with the same name. | |
56 AlarmIterator old_alarm = GetAlarmIterator(extension_id, alarm->name); | |
57 if (old_alarm.first != alarms_.end()) | |
58 RemoveAlarmIterator(old_alarm); | |
59 | |
60 alarms_[extension_id].push_back(alarm); | |
61 base::Timer* timer = new base::Timer(true, alarm->repeating); | |
62 timers_[alarm.get()] = make_linked_ptr(timer); | |
63 timer->Start(FROM_HERE, | |
64 base::TimeDelta::FromSeconds(alarm->delay_in_seconds), | |
65 base::Bind(&AlarmManager::OnAlarm, base::Unretained(this), | |
66 extension_id, alarm->name)); | |
67 } | 72 } |
68 | 73 |
69 const AlarmManager::Alarm* AlarmManager::GetAlarm( | 74 const AlarmManager::Alarm* AlarmManager::GetAlarm( |
70 const std::string& extension_id, const std::string& name) { | 75 const std::string& extension_id, const std::string& name) { |
71 AlarmIterator it = GetAlarmIterator(extension_id, name); | 76 AlarmIterator it = GetAlarmIterator(extension_id, name); |
72 if (it.first == alarms_.end()) | 77 if (it.first == alarms_.end()) |
73 return NULL; | 78 return NULL; |
74 return it.second->get(); | 79 return it.second->get(); |
75 } | 80 } |
76 | 81 |
(...skipping 18 matching lines...) Expand all Loading... | |
95 } | 100 } |
96 | 101 |
97 return make_pair(alarms_.end(), AlarmList::iterator()); | 102 return make_pair(alarms_.end(), AlarmList::iterator()); |
98 } | 103 } |
99 | 104 |
100 bool AlarmManager::RemoveAlarm(const std::string& extension_id, | 105 bool AlarmManager::RemoveAlarm(const std::string& extension_id, |
101 const std::string& name) { | 106 const std::string& name) { |
102 AlarmIterator it = GetAlarmIterator(extension_id, name); | 107 AlarmIterator it = GetAlarmIterator(extension_id, name); |
103 if (it.first == alarms_.end()) | 108 if (it.first == alarms_.end()) |
104 return false; | 109 return false; |
110 | |
105 RemoveAlarmIterator(it); | 111 RemoveAlarmIterator(it); |
112 WriteToPrefs(extension_id); | |
106 return true; | 113 return true; |
107 } | 114 } |
108 | 115 |
109 void AlarmManager::RemoveAllAlarms(const std::string& extension_id) { | 116 void AlarmManager::RemoveAllAlarms(const std::string& extension_id) { |
110 AlarmMap::iterator list = alarms_.find(extension_id); | 117 AlarmMap::iterator list = alarms_.find(extension_id); |
111 if (list == alarms_.end()) | 118 if (list == alarms_.end()) |
112 return; | 119 return; |
113 | 120 |
114 // Note: I'm using indices rather than iterators here because | 121 // Note: I'm using indices rather than iterators here because |
115 // RemoveAlarmIterator will delete the list when it becomes empty. | 122 // RemoveAlarmIterator will delete the list when it becomes empty. |
116 for (size_t i = 0, size = list->second.size(); i < size; ++i) | 123 for (size_t i = 0, size = list->second.size(); i < size; ++i) |
117 RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); | 124 RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); |
118 | 125 |
119 CHECK(alarms_.find(extension_id) == alarms_.end()); | 126 CHECK(alarms_.find(extension_id) == alarms_.end()); |
127 WriteToPrefs(extension_id); | |
120 } | 128 } |
121 | 129 |
122 void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) { | 130 void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) { |
123 // Cancel the timer first. | 131 // Cancel the timer first. |
124 timers_[iter.second->get()]->Stop(); | 132 timers_[iter.second->get()]->timer.Stop(); |
125 timers_.erase(iter.second->get()); | 133 timers_.erase(iter.second->get()); |
126 | 134 |
127 // Clean up our alarm list. | 135 // Clean up our alarm list. |
128 AlarmList& list = iter.first->second; | 136 AlarmList& list = iter.first->second; |
129 list.erase(iter.second); | 137 list.erase(iter.second); |
130 if (list.empty()) | 138 if (list.empty()) |
131 alarms_.erase(iter.first); | 139 alarms_.erase(iter.first); |
132 } | 140 } |
133 | 141 |
134 void AlarmManager::OnAlarm(const std::string& extension_id, | 142 void AlarmManager::OnAlarm(const std::string& extension_id, |
135 const std::string& name) { | 143 const std::string& name) { |
136 AlarmIterator it = GetAlarmIterator(extension_id, name); | 144 AlarmIterator it = GetAlarmIterator(extension_id, name); |
137 CHECK(it.first != alarms_.end()); | 145 CHECK(it.first != alarms_.end()); |
138 delegate_->OnAlarm(extension_id, *it.second->get()); | 146 const Alarm* alarm = it.second->get(); |
147 delegate_->OnAlarm(extension_id, *alarm); | |
139 | 148 |
140 if (!(*it.second)->repeating) | 149 if (!alarm->repeating) { |
141 RemoveAlarmIterator(it); | 150 RemoveAlarmIterator(it); |
151 } else { | |
152 // Restart the timer, since it may have been set with a shorter delay. | |
153 TimerInfo* timer = timers_[alarm].get(); | |
154 timer->timer.Start(FROM_HERE, | |
155 base::TimeDelta::FromSeconds(alarm->delay_in_seconds), | |
156 base::Bind(&AlarmManager::OnAlarm, base::Unretained(this), | |
157 extension_id, alarm->name)); | |
158 timer->UpdateScheduledRunTime(); | |
159 } | |
160 | |
161 WriteToPrefs(extension_id); | |
162 } | |
163 | |
164 void AlarmManager::AddAlarmImpl(const std::string& extension_id, | |
165 const linked_ptr<Alarm>& alarm, | |
166 base::TimeDelta timer_delay) { | |
167 // Override any old alarm with the same name. | |
168 AlarmIterator old_alarm = GetAlarmIterator(extension_id, alarm->name); | |
169 if (old_alarm.first != alarms_.end()) | |
170 RemoveAlarmIterator(old_alarm); | |
171 | |
172 alarms_[extension_id].push_back(alarm); | |
173 | |
174 TimerInfo* timer = new TimerInfo(alarm->repeating); | |
Aaron Boodman
2012/04/20 17:58:22
Nit: Maybe name this timer_info so you don't have
| |
175 timers_[alarm.get()] = make_linked_ptr(timer); | |
176 timer->timer.Start(FROM_HERE, | |
177 timer_delay, | |
178 base::Bind(&AlarmManager::OnAlarm, base::Unretained(this), | |
179 extension_id, alarm->name)); | |
180 timer->UpdateScheduledRunTime(); | |
181 } | |
182 | |
183 void AlarmManager::WriteToPrefs(const std::string& extension_id) { | |
184 ExtensionService* service = | |
185 ExtensionSystem::Get(profile_)->extension_service(); | |
Aaron Boodman
2012/04/20 17:58:22
Consider passing in ExtensionPrefs to make this mo
Matt Perry
2012/04/20 19:38:49
I don't think that's necessary. TestExtensionSyste
Aaron Boodman
2012/04/20 23:15:24
It's not necessary, but it seems nice to keep the
Matt Perry
2012/04/20 23:39:42
Yeah, I see what you're saying, but I'm not a fan
Aaron Boodman
2012/04/20 23:50:12
That is really odd to me. Creating a mock profile
| |
186 if (!service || !service->extension_prefs()) | |
187 return; | |
188 | |
189 std::vector<AlarmPref> alarm_prefs; | |
190 | |
191 AlarmMap::iterator list = alarms_.find(extension_id); | |
Aaron Boodman
2012/04/20 17:58:22
This reminds me: We should limit extensions to som
Matt Perry
2012/04/20 19:38:49
Are you worried about malicious extensions carpet-
Aaron Boodman
2012/04/20 23:15:24
I'm was thinking about buggy extensions filling up
Matt Perry
2012/04/20 23:39:42
They would each have to have a different name. I s
Aaron Boodman
2012/04/20 23:50:12
Hm, ok. Let's talk about this more next week. Diff
| |
192 if (list != alarms_.end()) { | |
193 for (AlarmList::iterator it = list->second.begin(); | |
194 it != list->second.end(); ++it) { | |
195 TimerInfo* timer = timers_[it->get()].get(); | |
196 AlarmPref pref; | |
197 pref.alarm = *it; | |
198 pref.scheduled_run_time = timer->scheduled_run_time; | |
199 alarm_prefs.push_back(pref); | |
200 } | |
201 } | |
202 | |
203 service->extension_prefs()->SetRegisteredAlarms(extension_id, alarm_prefs); | |
204 } | |
205 | |
206 void AlarmManager::ReadFromPrefs(const std::string& extension_id) { | |
207 ExtensionService* service = | |
208 ExtensionSystem::Get(profile_)->extension_service(); | |
209 if (!service || !service->extension_prefs()) | |
210 return; | |
211 | |
212 std::vector<AlarmPref> alarm_prefs = | |
213 service->extension_prefs()->GetRegisteredAlarms(extension_id); | |
214 for (size_t i = 0; i < alarm_prefs.size(); ++i) { | |
215 base::TimeDelta delay = | |
216 alarm_prefs[i].scheduled_run_time - base::Time::Now(); | |
217 if (delay < base::TimeDelta::FromSeconds(0)) | |
218 delay = base::TimeDelta::FromSeconds(0); | |
219 | |
220 AddAlarmImpl(extension_id, alarm_prefs[i].alarm, delay); | |
221 } | |
222 } | |
223 | |
224 void AlarmManager::Observe( | |
225 int type, | |
226 const content::NotificationSource& source, | |
227 const content::NotificationDetails& details) { | |
228 switch (type) { | |
229 case chrome::NOTIFICATION_EXTENSION_LOADED: { | |
230 const Extension* extension = | |
231 content::Details<const Extension>(details).ptr(); | |
232 ReadFromPrefs(extension->id()); | |
233 break; | |
234 } | |
235 default: | |
236 NOTREACHED(); | |
237 break; | |
238 } | |
239 } | |
240 | |
241 AlarmPref::AlarmPref() { | |
242 } | |
243 | |
244 AlarmPref::~AlarmPref() { | |
142 } | 245 } |
143 | 246 |
144 } // namespace extensions | 247 } // namespace extensions |
OLD | NEW |