// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/extensions/api/alarms/alarms_api.h" #include "base/strings/string_number_conversions.h" #include "base/time/clock.h" #include "base/time/default_clock.h" #include "base/values.h" #include "chrome/browser/extensions/api/alarms/alarm_manager.h" #include "chrome/common/extensions/api/alarms.h" #include "extensions/common/error_utils.h" namespace alarms = extensions::api::alarms; namespace extensions { namespace { const char kDefaultAlarmName[] = ""; const char kAlarmNotFound[] = "No alarm named '*' exists."; const char kBothRelativeAndAbsoluteTime[] = "Cannot set both when and delayInMinutes."; const char kNoScheduledTime[] = "Must set at least one of when, delayInMinutes, or periodInMinutes."; const int kReleaseDelayMinimum = 1; const int kDevDelayMinimum = 0; bool ValidateAlarmCreateInfo(const std::string& alarm_name, const alarms::AlarmCreateInfo& create_info, const Extension* extension, std::string* error, std::vector* warnings) { if (create_info.delay_in_minutes.get() && create_info.when.get()) { *error = kBothRelativeAndAbsoluteTime; return false; } if (create_info.delay_in_minutes == NULL && create_info.when == NULL && create_info.period_in_minutes == NULL) { *error = kNoScheduledTime; return false; } // Users can always use an absolute timeout to request an arbitrarily-short or // negative delay. We won't honor the short timeout, but we can't check it // and warn the user because it would introduce race conditions (say they // compute a long-enough timeout, but then the call into the alarms interface // gets delayed past the boundary). However, it's still worth warning about // relative delays that are shorter than we'll honor. if (create_info.delay_in_minutes.get()) { if (*create_info.delay_in_minutes < kReleaseDelayMinimum) { COMPILE_ASSERT(kReleaseDelayMinimum == 1, update_warning_message_below); if (Manifest::IsUnpackedLocation(extension->location())) warnings->push_back(ErrorUtils::FormatErrorMessage( "Alarm delay is less than minimum of 1 minutes." " In released .crx, alarm \"*\" will fire in approximately" " 1 minutes.", alarm_name)); else warnings->push_back(ErrorUtils::FormatErrorMessage( "Alarm delay is less than minimum of 1 minutes." " Alarm \"*\" will fire in approximately 1 minutes.", alarm_name)); } } if (create_info.period_in_minutes.get()) { if (*create_info.period_in_minutes < kReleaseDelayMinimum) { COMPILE_ASSERT(kReleaseDelayMinimum == 1, update_warning_message_below); if (Manifest::IsUnpackedLocation(extension->location())) warnings->push_back(ErrorUtils::FormatErrorMessage( "Alarm period is less than minimum of 1 minutes." " In released .crx, alarm \"*\" will fire approximately" " every 1 minutes.", alarm_name)); else warnings->push_back(ErrorUtils::FormatErrorMessage( "Alarm period is less than minimum of 1 minutes." " Alarm \"*\" will fire approximately every 1 minutes.", alarm_name)); } } return true; } } // namespace AlarmsCreateFunction::AlarmsCreateFunction() : clock_(new base::DefaultClock()), owns_clock_(true) {} AlarmsCreateFunction::AlarmsCreateFunction(base::Clock* clock) : clock_(clock), owns_clock_(false) {} AlarmsCreateFunction::~AlarmsCreateFunction() { if (owns_clock_) delete clock_; } bool AlarmsCreateFunction::RunImpl() { scoped_ptr params( alarms::Create::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); const std::string& alarm_name = params->name.get() ? *params->name : kDefaultAlarmName; std::vector warnings; if (!ValidateAlarmCreateInfo( alarm_name, params->alarm_info, GetExtension(), &error_, &warnings)) { return false; } for (std::vector::const_iterator it = warnings.begin(); it != warnings.end(); ++it) WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING, *it); Alarm alarm(alarm_name, params->alarm_info, base::TimeDelta::FromMinutes( Manifest::IsUnpackedLocation(GetExtension()->location()) ? kDevDelayMinimum : kReleaseDelayMinimum), clock_->Now()); AlarmManager::Get(GetProfile())->AddAlarm( extension_id(), alarm, base::Bind(&AlarmsCreateFunction::Callback, this)); return true; } void AlarmsCreateFunction::Callback() { SendResponse(true); } bool AlarmsGetFunction::RunImpl() { scoped_ptr params(alarms::Get::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); std::string name = params->name.get() ? *params->name : kDefaultAlarmName; AlarmManager::Get(GetProfile()) ->GetAlarm(extension_id(), name, base::Bind(&AlarmsGetFunction::Callback, this, name)); return true; } void AlarmsGetFunction::Callback( const std::string& name, extensions::Alarm* alarm) { if (alarm) { results_ = alarms::Get::Results::Create(*alarm->js_alarm); SendResponse(true); } else { error_ = ErrorUtils::FormatErrorMessage(kAlarmNotFound, name); SendResponse(false); } } bool AlarmsGetAllFunction::RunImpl() { AlarmManager::Get(GetProfile())->GetAllAlarms( extension_id(), base::Bind(&AlarmsGetAllFunction::Callback, this)); return true; } void AlarmsGetAllFunction::Callback(const AlarmList* alarms) { if (alarms) { std::vector > create_arg; create_arg.reserve(alarms->size()); for (size_t i = 0, size = alarms->size(); i < size; ++i) { create_arg.push_back((*alarms)[i].js_alarm); } results_ = alarms::GetAll::Results::Create(create_arg); } else { SetResult(new base::ListValue()); } SendResponse(true); } bool AlarmsClearFunction::RunImpl() { scoped_ptr params( alarms::Clear::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); std::string name = params->name.get() ? *params->name : kDefaultAlarmName; AlarmManager::Get(GetProfile()) ->RemoveAlarm(extension_id(), name, base::Bind(&AlarmsClearFunction::Callback, this, name)); return true; } void AlarmsClearFunction::Callback(const std::string& name, bool success) { if (!success) error_ = ErrorUtils::FormatErrorMessage(kAlarmNotFound, name); SendResponse(success); } bool AlarmsClearAllFunction::RunImpl() { AlarmManager::Get(GetProfile())->RemoveAllAlarms( extension_id(), base::Bind(&AlarmsClearAllFunction::Callback, this)); return true; } void AlarmsClearAllFunction::Callback() { SendResponse(true); } } // namespace extensions