summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/timer.h1
-rw-r--r--chrome/browser/extensions/api/alarms/alarm_manager.cc127
-rw-r--r--chrome/browser/extensions/api/alarms/alarm_manager.h28
-rw-r--r--chrome/browser/extensions/extension_prefs.cc45
-rw-r--r--chrome/browser/extensions/extension_prefs.h11
5 files changed, 193 insertions, 19 deletions
diff --git a/base/timer.h b/base/timer.h
index 24f2bb1..faa12da 100644
--- a/base/timer.h
+++ b/base/timer.h
@@ -108,6 +108,7 @@ class BASE_EXPORT Timer {
void Reset();
const base::Closure& user_task() const { return user_task_; }
+ const TimeTicks& desired_run_time() const { return desired_run_time_; }
protected:
// Used to initiate a new delayed task. This has the side-effect of disabling
diff --git a/chrome/browser/extensions/api/alarms/alarm_manager.cc b/chrome/browser/extensions/api/alarms/alarm_manager.cc
index 17a4889..f6c5080 100644
--- a/chrome/browser/extensions/api/alarms/alarm_manager.cc
+++ b/chrome/browser/extensions/api/alarms/alarm_manager.cc
@@ -9,8 +9,12 @@
#include "base/message_loop.h"
#include "base/values.h"
#include "chrome/browser/extensions/extension_event_router.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/notification_service.h"
namespace extensions {
@@ -42,6 +46,8 @@ class DefaultAlarmDelegate : public AlarmManager::Delegate {
AlarmManager::AlarmManager(Profile* profile)
: profile_(profile),
delegate_(new DefaultAlarmDelegate(profile)) {
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
+ content::Source<Profile>(profile_));
}
AlarmManager::~AlarmManager() {
@@ -49,21 +55,9 @@ AlarmManager::~AlarmManager() {
void AlarmManager::AddAlarm(const std::string& extension_id,
const linked_ptr<Alarm>& alarm) {
- // TODO(mpcomplete): Better handling of granularity.
- // http://crbug.com/122683
-
- // Override any old alarm with the same name.
- AlarmIterator old_alarm = GetAlarmIterator(extension_id, alarm->name);
- if (old_alarm.first != alarms_.end())
- RemoveAlarmIterator(old_alarm);
-
- alarms_[extension_id].push_back(alarm);
- base::Timer* timer = new base::Timer(true, alarm->repeating);
- timers_[alarm.get()] = make_linked_ptr(timer);
- timer->Start(FROM_HERE,
- base::TimeDelta::FromSeconds(alarm->delay_in_seconds),
- base::Bind(&AlarmManager::OnAlarm, base::Unretained(this),
- extension_id, alarm->name));
+ AddAlarmImpl(extension_id, alarm,
+ base::TimeDelta::FromSeconds(alarm->delay_in_seconds));
+ WriteToPrefs(extension_id);
}
const AlarmManager::Alarm* AlarmManager::GetAlarm(
@@ -102,7 +96,9 @@ bool AlarmManager::RemoveAlarm(const std::string& extension_id,
AlarmIterator it = GetAlarmIterator(extension_id, name);
if (it.first == alarms_.end())
return false;
+
RemoveAlarmIterator(it);
+ WriteToPrefs(extension_id);
return true;
}
@@ -117,6 +113,7 @@ void AlarmManager::RemoveAllAlarms(const std::string& extension_id) {
RemoveAlarmIterator(AlarmIterator(list, list->second.begin()));
CHECK(alarms_.find(extension_id) == alarms_.end());
+ WriteToPrefs(extension_id);
}
void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) {
@@ -135,10 +132,106 @@ void AlarmManager::OnAlarm(const std::string& extension_id,
const std::string& name) {
AlarmIterator it = GetAlarmIterator(extension_id, name);
CHECK(it.first != alarms_.end());
- delegate_->OnAlarm(extension_id, *it.second->get());
+ const Alarm* alarm = it.second->get();
+ delegate_->OnAlarm(extension_id, *alarm);
- if (!(*it.second)->repeating)
+ if (!alarm->repeating) {
RemoveAlarmIterator(it);
+ } else {
+ // Restart the timer, since it may have been set with a shorter delay
+ // initially.
+ base::Timer* timer = timers_[alarm].get();
+ timer->Start(FROM_HERE,
+ base::TimeDelta::FromSeconds(alarm->delay_in_seconds),
+ base::Bind(&AlarmManager::OnAlarm, base::Unretained(this),
+ extension_id, alarm->name));
+ }
+
+ WriteToPrefs(extension_id);
+}
+
+void AlarmManager::AddAlarmImpl(const std::string& extension_id,
+ const linked_ptr<Alarm>& alarm,
+ base::TimeDelta timer_delay) {
+ // Override any old alarm with the same name.
+ AlarmIterator old_alarm = GetAlarmIterator(extension_id, alarm->name);
+ if (old_alarm.first != alarms_.end())
+ RemoveAlarmIterator(old_alarm);
+
+ alarms_[extension_id].push_back(alarm);
+
+ base::Timer* timer = new base::Timer(true, alarm->repeating);
+ timers_[alarm.get()] = make_linked_ptr(timer);
+ timer->Start(FROM_HERE,
+ timer_delay,
+ base::Bind(&AlarmManager::OnAlarm, base::Unretained(this),
+ extension_id, alarm->name));
+}
+
+void AlarmManager::WriteToPrefs(const std::string& extension_id) {
+ ExtensionService* service =
+ ExtensionSystem::Get(profile_)->extension_service();
+ if (!service || !service->extension_prefs())
+ return;
+
+ std::vector<AlarmPref> alarm_prefs;
+
+ AlarmMap::iterator list = alarms_.find(extension_id);
+ if (list != alarms_.end()) {
+ for (AlarmList::iterator it = list->second.begin();
+ it != list->second.end(); ++it) {
+ base::Timer* timer = timers_[it->get()].get();
+ base::TimeDelta delay =
+ timer->desired_run_time() - base::TimeTicks::Now();
+ AlarmPref pref;
+ pref.alarm = *it;
+ pref.scheduled_run_time = base::Time::Now() + delay;
+ alarm_prefs.push_back(pref);
+ }
+ }
+
+ service->extension_prefs()->SetRegisteredAlarms(extension_id, alarm_prefs);
+}
+
+void AlarmManager::ReadFromPrefs(const std::string& extension_id) {
+ ExtensionService* service =
+ ExtensionSystem::Get(profile_)->extension_service();
+ if (!service || !service->extension_prefs())
+ return;
+
+ std::vector<AlarmPref> alarm_prefs =
+ service->extension_prefs()->GetRegisteredAlarms(extension_id);
+ for (size_t i = 0; i < alarm_prefs.size(); ++i) {
+ base::TimeDelta delay =
+ alarm_prefs[i].scheduled_run_time - base::Time::Now();
+ if (delay < base::TimeDelta::FromSeconds(0))
+ delay = base::TimeDelta::FromSeconds(0);
+
+ AddAlarmImpl(extension_id, alarm_prefs[i].alarm, delay);
+ }
+}
+
+void AlarmManager::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSION_LOADED: {
+ const Extension* extension =
+ content::Details<const Extension>(details).ptr();
+ ReadFromPrefs(extension->id());
+ break;
+ }
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+AlarmPref::AlarmPref() {
+}
+
+AlarmPref::~AlarmPref() {
}
} // namespace extensions
diff --git a/chrome/browser/extensions/api/alarms/alarm_manager.h b/chrome/browser/extensions/api/alarms/alarm_manager.h
index 775fd1e..6ca8dc07 100644
--- a/chrome/browser/extensions/api/alarms/alarm_manager.h
+++ b/chrome/browser/extensions/api/alarms/alarm_manager.h
@@ -13,6 +13,8 @@
#include "base/timer.h"
#include "chrome/browser/extensions/extension_function.h"
#include "chrome/common/extensions/api/experimental.alarms.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
class Profile;
@@ -20,7 +22,7 @@ namespace extensions {
// Manages the currently pending alarms for every extension in a profile.
// There is one manager per virtual Profile.
-class AlarmManager {
+class AlarmManager : public content::NotificationObserver {
public:
typedef extensions::api::experimental_alarms::Alarm Alarm;
typedef std::vector<linked_ptr<Alarm> > AlarmList;
@@ -79,7 +81,22 @@ class AlarmManager {
// Callback for when an alarm fires.
void OnAlarm(const std::string& extension_id, const std::string& name);
+ // Internal helper to add an alarm and start the timer with the given delay.
+ void AddAlarmImpl(const std::string& extension_id,
+ const linked_ptr<Alarm>& alarm,
+ base::TimeDelta timer_delay);
+
+ // Syncs our alarm data for the given extension to/from the prefs file.
+ void WriteToPrefs(const std::string& extension_id);
+ void ReadFromPrefs(const std::string& extension_id);
+
+ // NotificationObserver:
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
Profile* profile_;
+ content::NotificationRegistrar registrar_;
scoped_ptr<Delegate> delegate_;
// A map of our pending alarms, per extension.
@@ -89,6 +106,15 @@ class AlarmManager {
std::map<const Alarm*, linked_ptr<base::Timer> > timers_;
};
+// Contains the data we store in the extension prefs for each alarm.
+struct AlarmPref {
+ linked_ptr<AlarmManager::Alarm> alarm;
+ base::Time scheduled_run_time;
+
+ AlarmPref();
+ ~AlarmPref();
+};
+
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_ALARMS_ALARM_MANAGER_H__
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 7dc67c8..793a04e 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -7,6 +7,7 @@
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/extensions/api/alarms/alarm_manager.h"
#include "chrome/browser/extensions/extension_pref_store.h"
#include "chrome/browser/extensions/extension_sorting.h"
#include "chrome/browser/prefs/pref_notifier.h"
@@ -156,6 +157,10 @@ const char kPrefIncognitoContentSettings[] = "incognito_content_settings";
// background page.
const char kRegisteredEvents[] = "events";
+// A list of alarms that this extension has set.
+const char kRegisteredAlarms[] = "alarms";
+const char kAlarmScheduledRunTime[] = "scheduled_run_time";
+
// Provider of write access to a dictionary storing extension prefs.
class ScopedExtensionPrefUpdate : public DictionaryPrefUpdate {
public:
@@ -933,6 +938,43 @@ void ExtensionPrefs::SetRegisteredEvents(
UpdateExtensionPref(extension_id, kRegisteredEvents, value);
}
+std::vector<extensions::AlarmPref> ExtensionPrefs::GetRegisteredAlarms(
+ const std::string& extension_id) {
+ std::vector<extensions::AlarmPref> alarms;
+ const base::DictionaryValue* extension = GetExtensionPref(extension_id);
+ if (!extension)
+ return alarms;
+
+ base::ListValue* list = NULL;
+ if (!extension->GetList(kRegisteredAlarms, &list))
+ return alarms;
+
+ typedef extensions::AlarmManager::Alarm Alarm;
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ base::DictionaryValue* alarm_dict = NULL;
+ extensions::AlarmPref alarm;
+ alarm.alarm.reset(new Alarm());
+ if (list->GetDictionary(i, &alarm_dict) &&
+ Alarm::Populate(*alarm_dict, alarm.alarm.get())) {
+ alarm.scheduled_run_time = ReadTime(alarm_dict, kAlarmScheduledRunTime);
+ alarms.push_back(alarm);
+ }
+ }
+ return alarms;
+}
+
+void ExtensionPrefs::SetRegisteredAlarms(
+ const std::string& extension_id,
+ const std::vector<extensions::AlarmPref>& alarms) {
+ base::ListValue* list = new ListValue();
+ for (size_t i = 0; i < alarms.size(); ++i) {
+ scoped_ptr<base::DictionaryValue> alarm = alarms[i].alarm->ToValue().Pass();
+ SaveTime(alarm.get(), kAlarmScheduledRunTime, alarms[i].scheduled_run_time);
+ list->Append(alarm.release());
+ }
+ UpdateExtensionPref(extension_id, kRegisteredAlarms, list);
+}
+
bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) {
return ReadExtensionPrefBoolean(extension_id, kPrefIncognitoEnabled);
}
@@ -1130,8 +1172,9 @@ void ExtensionPrefs::OnExtensionInstalled(
extension->manifest()->value()->DeepCopy());
}
- // Clear any events that may be registered from a previous install.
+ // Clear any events and alarms that may be registered from a previous install.
extension_dict->Remove(kRegisteredEvents, NULL);
+ extension_dict->Remove(kRegisteredAlarms, NULL);
if (extension->is_app()) {
StringOrdinal new_page_ordinal = page_ordinal.IsValid() ?
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index ddebe41..c3791f9 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -24,6 +24,10 @@ class ExtensionSorting;
class PrefService;
class URLPatternSet;
+namespace extensions {
+struct AlarmPref;
+}
+
// Class for managing global and per-extension preferences.
//
// This class distinguishes the following kinds of preferences:
@@ -260,6 +264,13 @@ class ExtensionPrefs : public ExtensionContentSettingsStore::Observer,
void SetRegisteredEvents(const std::string& extension_id,
const std::set<std::string>& events);
+ // Controls a list of alarms for this extension, including the next time they
+ // should run.
+ std::vector<extensions::AlarmPref> GetRegisteredAlarms(
+ const std::string& extension_id);
+ void SetRegisteredAlarms(const std::string& extension_id,
+ const std::vector<extensions::AlarmPref>& alarms);
+
// Returns true if the user enabled this extension to be loaded in incognito
// mode.
bool IsIncognitoEnabled(const std::string& extension_id);