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