Extension alarms now persist in Preferences.

BUG=122815
TEST=no

Review URL: https://chromiumcodereview.appspot.com/10152008

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@133543 0039d316-1c4b-4281-b951-d872f2087c98
parent 7c4c5812
...@@ -108,6 +108,7 @@ class BASE_EXPORT Timer { ...@@ -108,6 +108,7 @@ class BASE_EXPORT Timer {
void Reset(); void Reset();
const base::Closure& user_task() const { return user_task_; } const base::Closure& user_task() const { return user_task_; }
const TimeTicks& desired_run_time() const { return desired_run_time_; }
protected: protected:
// Used to initiate a new delayed task. This has the side-effect of disabling // Used to initiate a new delayed task. This has the side-effect of disabling
......
...@@ -9,8 +9,12 @@ ...@@ -9,8 +9,12 @@
#include "base/message_loop.h" #include "base/message_loop.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/extensions/extension_event_router.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/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_service.h"
namespace extensions { namespace extensions {
...@@ -42,6 +46,8 @@ class DefaultAlarmDelegate : public AlarmManager::Delegate { ...@@ -42,6 +46,8 @@ class DefaultAlarmDelegate : public AlarmManager::Delegate {
AlarmManager::AlarmManager(Profile* profile) AlarmManager::AlarmManager(Profile* profile)
: profile_(profile), : profile_(profile),
delegate_(new DefaultAlarmDelegate(profile)) { delegate_(new DefaultAlarmDelegate(profile)) {
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
content::Source<Profile>(profile_));
} }
AlarmManager::~AlarmManager() { AlarmManager::~AlarmManager() {
...@@ -49,21 +55,9 @@ AlarmManager::~AlarmManager() { ...@@ -49,21 +55,9 @@ AlarmManager::~AlarmManager() {
void AlarmManager::AddAlarm(const std::string& extension_id, void AlarmManager::AddAlarm(const std::string& extension_id,
const linked_ptr<Alarm>& alarm) { const linked_ptr<Alarm>& alarm) {
// TODO(mpcomplete): Better handling of granularity. AddAlarmImpl(extension_id, alarm,
// http://crbug.com/122683 base::TimeDelta::FromSeconds(alarm->delay_in_seconds));
WriteToPrefs(extension_id);
// 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));
} }
const AlarmManager::Alarm* AlarmManager::GetAlarm( const AlarmManager::Alarm* AlarmManager::GetAlarm(
...@@ -102,7 +96,9 @@ bool AlarmManager::RemoveAlarm(const std::string& extension_id, ...@@ -102,7 +96,9 @@ bool AlarmManager::RemoveAlarm(const std::string& extension_id,
AlarmIterator it = GetAlarmIterator(extension_id, name); AlarmIterator it = GetAlarmIterator(extension_id, name);
if (it.first == alarms_.end()) if (it.first == alarms_.end())
return false; return false;
RemoveAlarmIterator(it); RemoveAlarmIterator(it);
WriteToPrefs(extension_id);
return true; return true;
} }
...@@ -117,6 +113,7 @@ void AlarmManager::RemoveAllAlarms(const std::string& extension_id) { ...@@ -117,6 +113,7 @@ void AlarmManager::RemoveAllAlarms(const std::string& extension_id) {
RemoveAlarmIterator(AlarmIterator(list, list->second.begin())); RemoveAlarmIterator(AlarmIterator(list, list->second.begin()));
CHECK(alarms_.find(extension_id) == alarms_.end()); CHECK(alarms_.find(extension_id) == alarms_.end());
WriteToPrefs(extension_id);
} }
void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) { void AlarmManager::RemoveAlarmIterator(const AlarmIterator& iter) {
...@@ -135,10 +132,106 @@ void AlarmManager::OnAlarm(const std::string& extension_id, ...@@ -135,10 +132,106 @@ void AlarmManager::OnAlarm(const std::string& extension_id,
const std::string& name) { const std::string& name) {
AlarmIterator it = GetAlarmIterator(extension_id, name); AlarmIterator it = GetAlarmIterator(extension_id, name);
CHECK(it.first != alarms_.end()); 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); 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 } // namespace extensions
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include "base/timer.h" #include "base/timer.h"
#include "chrome/browser/extensions/extension_function.h" #include "chrome/browser/extensions/extension_function.h"
#include "chrome/common/extensions/api/experimental.alarms.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; class Profile;
...@@ -20,7 +22,7 @@ namespace extensions { ...@@ -20,7 +22,7 @@ namespace extensions {
// Manages the currently pending alarms for every extension in a profile. // Manages the currently pending alarms for every extension in a profile.
// There is one manager per virtual Profile. // There is one manager per virtual Profile.
class AlarmManager { class AlarmManager : public content::NotificationObserver {
public: public:
typedef extensions::api::experimental_alarms::Alarm Alarm; typedef extensions::api::experimental_alarms::Alarm Alarm;
typedef std::vector<linked_ptr<Alarm> > AlarmList; typedef std::vector<linked_ptr<Alarm> > AlarmList;
...@@ -79,7 +81,22 @@ class AlarmManager { ...@@ -79,7 +81,22 @@ class AlarmManager {
// Callback for when an alarm fires. // Callback for when an alarm fires.
void OnAlarm(const std::string& extension_id, const std::string& name); 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_; Profile* profile_;
content::NotificationRegistrar registrar_;
scoped_ptr<Delegate> delegate_; scoped_ptr<Delegate> delegate_;
// A map of our pending alarms, per extension. // A map of our pending alarms, per extension.
...@@ -89,6 +106,15 @@ class AlarmManager { ...@@ -89,6 +106,15 @@ class AlarmManager {
std::map<const Alarm*, linked_ptr<base::Timer> > timers_; 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 } // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_API_ALARMS_ALARM_MANAGER_H__ #endif // CHROME_BROWSER_EXTENSIONS_API_ALARMS_ALARM_MANAGER_H__
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/string_number_conversions.h" #include "base/string_number_conversions.h"
#include "base/string_util.h" #include "base/string_util.h"
#include "base/utf_string_conversions.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_pref_store.h"
#include "chrome/browser/extensions/extension_sorting.h" #include "chrome/browser/extensions/extension_sorting.h"
#include "chrome/browser/prefs/pref_notifier.h" #include "chrome/browser/prefs/pref_notifier.h"
...@@ -156,6 +157,10 @@ const char kPrefIncognitoContentSettings[] = "incognito_content_settings"; ...@@ -156,6 +157,10 @@ const char kPrefIncognitoContentSettings[] = "incognito_content_settings";
// background page. // background page.
const char kRegisteredEvents[] = "events"; 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. // Provider of write access to a dictionary storing extension prefs.
class ScopedExtensionPrefUpdate : public DictionaryPrefUpdate { class ScopedExtensionPrefUpdate : public DictionaryPrefUpdate {
public: public:
...@@ -933,6 +938,43 @@ void ExtensionPrefs::SetRegisteredEvents( ...@@ -933,6 +938,43 @@ void ExtensionPrefs::SetRegisteredEvents(
UpdateExtensionPref(extension_id, kRegisteredEvents, value); 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) { bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) {
return ReadExtensionPrefBoolean(extension_id, kPrefIncognitoEnabled); return ReadExtensionPrefBoolean(extension_id, kPrefIncognitoEnabled);
} }
...@@ -1130,8 +1172,9 @@ void ExtensionPrefs::OnExtensionInstalled( ...@@ -1130,8 +1172,9 @@ void ExtensionPrefs::OnExtensionInstalled(
extension->manifest()->value()->DeepCopy()); 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(kRegisteredEvents, NULL);
extension_dict->Remove(kRegisteredAlarms, NULL);
if (extension->is_app()) { if (extension->is_app()) {
StringOrdinal new_page_ordinal = page_ordinal.IsValid() ? StringOrdinal new_page_ordinal = page_ordinal.IsValid() ?
......
...@@ -24,6 +24,10 @@ class ExtensionSorting; ...@@ -24,6 +24,10 @@ class ExtensionSorting;
class PrefService; class PrefService;
class URLPatternSet; class URLPatternSet;
namespace extensions {
struct AlarmPref;
}
// Class for managing global and per-extension preferences. // Class for managing global and per-extension preferences.
// //
// This class distinguishes the following kinds of preferences: // This class distinguishes the following kinds of preferences:
...@@ -260,6 +264,13 @@ class ExtensionPrefs : public ExtensionContentSettingsStore::Observer, ...@@ -260,6 +264,13 @@ class ExtensionPrefs : public ExtensionContentSettingsStore::Observer,
void SetRegisteredEvents(const std::string& extension_id, void SetRegisteredEvents(const std::string& extension_id,
const std::set<std::string>& events); 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 // Returns true if the user enabled this extension to be loaded in incognito
// mode. // mode.
bool IsIncognitoEnabled(const std::string& extension_id); bool IsIncognitoEnabled(const std::string& extension_id);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment