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

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

Issue 10152008: Extension alarms now persist in Preferences. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: NULL check for unit tests Created 8 years, 8 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/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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698