Chromium Code Reviews| 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 |