Home | History | Annotate | Download | only in alarms
      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