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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/api/alarms/alarms_api.h" 6 7 #include "base/strings/string_number_conversions.h" 8 #include "base/time/clock.h" 9 #include "base/time/default_clock.h" 10 #include "base/values.h" 11 #include "chrome/browser/extensions/api/alarms/alarm_manager.h" 12 #include "chrome/common/extensions/api/alarms.h" 13 #include "extensions/common/error_utils.h" 14 15 namespace alarms = extensions::api::alarms; 16 17 namespace extensions { 18 19 namespace { 20 21 const char kDefaultAlarmName[] = ""; 22 const char kAlarmNotFound[] = "No alarm named '*' exists."; 23 const char kBothRelativeAndAbsoluteTime[] = 24 "Cannot set both when and delayInMinutes."; 25 const char kNoScheduledTime[] = 26 "Must set at least one of when, delayInMinutes, or periodInMinutes."; 27 const int kReleaseDelayMinimum = 1; 28 const int kDevDelayMinimum = 0; 29 30 bool ValidateAlarmCreateInfo(const std::string& alarm_name, 31 const alarms::AlarmCreateInfo& create_info, 32 const Extension* extension, 33 std::string* error, 34 std::vector<std::string>* warnings) { 35 if (create_info.delay_in_minutes.get() && 36 create_info.when.get()) { 37 *error = kBothRelativeAndAbsoluteTime; 38 return false; 39 } 40 if (create_info.delay_in_minutes == NULL && 41 create_info.when == NULL && 42 create_info.period_in_minutes == NULL) { 43 *error = kNoScheduledTime; 44 return false; 45 } 46 47 // Users can always use an absolute timeout to request an arbitrarily-short or 48 // negative delay. We won't honor the short timeout, but we can't check it 49 // and warn the user because it would introduce race conditions (say they 50 // compute a long-enough timeout, but then the call into the alarms interface 51 // gets delayed past the boundary). However, it's still worth warning about 52 // relative delays that are shorter than we'll honor. 53 if (create_info.delay_in_minutes.get()) { 54 if (*create_info.delay_in_minutes < kReleaseDelayMinimum) { 55 COMPILE_ASSERT(kReleaseDelayMinimum == 1, update_warning_message_below); 56 if (Manifest::IsUnpackedLocation(extension->location())) 57 warnings->push_back(ErrorUtils::FormatErrorMessage( 58 "Alarm delay is less than minimum of 1 minutes." 59 " In released .crx, alarm \"*\" will fire in approximately" 60 " 1 minutes.", 61 alarm_name)); 62 else 63 warnings->push_back(ErrorUtils::FormatErrorMessage( 64 "Alarm delay is less than minimum of 1 minutes." 65 " Alarm \"*\" will fire in approximately 1 minutes.", 66 alarm_name)); 67 } 68 } 69 if (create_info.period_in_minutes.get()) { 70 if (*create_info.period_in_minutes < kReleaseDelayMinimum) { 71 COMPILE_ASSERT(kReleaseDelayMinimum == 1, update_warning_message_below); 72 if (Manifest::IsUnpackedLocation(extension->location())) 73 warnings->push_back(ErrorUtils::FormatErrorMessage( 74 "Alarm period is less than minimum of 1 minutes." 75 " In released .crx, alarm \"*\" will fire approximately" 76 " every 1 minutes.", 77 alarm_name)); 78 else 79 warnings->push_back(ErrorUtils::FormatErrorMessage( 80 "Alarm period is less than minimum of 1 minutes." 81 " Alarm \"*\" will fire approximately every 1 minutes.", 82 alarm_name)); 83 } 84 } 85 86 return true; 87 } 88 89 } // namespace 90 91 AlarmsCreateFunction::AlarmsCreateFunction() 92 : clock_(new base::DefaultClock()), owns_clock_(true) {} 93 94 AlarmsCreateFunction::AlarmsCreateFunction(base::Clock* clock) 95 : clock_(clock), owns_clock_(false) {} 96 97 AlarmsCreateFunction::~AlarmsCreateFunction() { 98 if (owns_clock_) 99 delete clock_; 100 } 101 102 bool AlarmsCreateFunction::RunImpl() { 103 scoped_ptr<alarms::Create::Params> params( 104 alarms::Create::Params::Create(*args_)); 105 EXTENSION_FUNCTION_VALIDATE(params.get()); 106 const std::string& alarm_name = 107 params->name.get() ? *params->name : kDefaultAlarmName; 108 std::vector<std::string> warnings; 109 if (!ValidateAlarmCreateInfo( 110 alarm_name, params->alarm_info, GetExtension(), &error_, &warnings)) 111 return false; 112 for (std::vector<std::string>::const_iterator it = warnings.begin(); 113 it != warnings.end(); ++it) 114 WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING, *it); 115 116 Alarm alarm(alarm_name, 117 params->alarm_info, 118 base::TimeDelta::FromMinutes( 119 Manifest::IsUnpackedLocation(GetExtension()->location()) ? 120 kDevDelayMinimum : kReleaseDelayMinimum), 121 clock_->Now()); 122 AlarmManager::Get(profile())->AddAlarm(extension_id(), alarm); 123 124 return true; 125 } 126 127 bool AlarmsGetFunction::RunImpl() { 128 scoped_ptr<alarms::Get::Params> params(alarms::Get::Params::Create(*args_)); 129 EXTENSION_FUNCTION_VALIDATE(params.get()); 130 131 std::string name = params->name.get() ? *params->name : kDefaultAlarmName; 132 const Alarm* alarm = 133 AlarmManager::Get(profile())->GetAlarm(extension_id(), name); 134 135 if (!alarm) { 136 error_ = ErrorUtils::FormatErrorMessage(kAlarmNotFound, name); 137 return false; 138 } 139 140 results_ = alarms::Get::Results::Create(*alarm->js_alarm); 141 return true; 142 } 143 144 bool AlarmsGetAllFunction::RunImpl() { 145 const AlarmManager::AlarmList* alarms = 146 AlarmManager::Get(profile())->GetAllAlarms(extension_id()); 147 if (alarms) { 148 std::vector<linked_ptr<extensions::api::alarms::Alarm> > create_arg; 149 create_arg.reserve(alarms->size()); 150 for (size_t i = 0, size = alarms->size(); i < size; ++i) { 151 create_arg.push_back((*alarms)[i].js_alarm); 152 } 153 results_ = alarms::GetAll::Results::Create(create_arg); 154 } else { 155 SetResult(new base::ListValue()); 156 } 157 return true; 158 } 159 160 bool AlarmsClearFunction::RunImpl() { 161 scoped_ptr<alarms::Clear::Params> params( 162 alarms::Clear::Params::Create(*args_)); 163 EXTENSION_FUNCTION_VALIDATE(params.get()); 164 165 std::string name = params->name.get() ? *params->name : kDefaultAlarmName; 166 bool success = AlarmManager::Get(profile())->RemoveAlarm(extension_id(), 167 name); 168 169 if (!success) { 170 error_ = ErrorUtils::FormatErrorMessage(kAlarmNotFound, name); 171 return false; 172 } 173 174 return true; 175 } 176 177 bool AlarmsClearAllFunction::RunImpl() { 178 AlarmManager::Get(profile())->RemoveAllAlarms(extension_id()); 179 return true; 180 } 181 182 } // namespace extensions 183