[Smart Lock] Record a detailed UMA metric for each unlock attempt by Smart Lock users.
[chromium-blink-merge.git] / extensions / browser / quota_service.cc
blobdbd11768bf76bc88cab7b25563208656aeedbd8d
1 // Copyright 2013 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.
5 #include "extensions/browser/quota_service.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/stl_util.h"
9 #include "extensions/browser/extension_function.h"
10 #include "extensions/common/error_utils.h"
12 namespace {
14 // If the browser stays open long enough, we reset state once a day.
15 // Whatever this value is, it should be an order of magnitude longer than
16 // the longest interval in any of the QuotaLimitHeuristics in use.
17 const int kPurgeIntervalInDays = 1;
19 const char kOverQuotaError[] = "This request exceeds the * quota.";
21 } // namespace
23 namespace extensions {
25 QuotaService::QuotaService() {
26 if (base::MessageLoop::current() != NULL) { // Null in unit tests.
27 purge_timer_.Start(FROM_HERE,
28 base::TimeDelta::FromDays(kPurgeIntervalInDays),
29 this,
30 &QuotaService::Purge);
34 QuotaService::~QuotaService() {
35 DCHECK(CalledOnValidThread());
36 purge_timer_.Stop();
37 Purge();
40 std::string QuotaService::Assess(const std::string& extension_id,
41 ExtensionFunction* function,
42 const base::ListValue* args,
43 const base::TimeTicks& event_time) {
44 DCHECK(CalledOnValidThread());
46 if (function->ShouldSkipQuotaLimiting())
47 return std::string();
49 // Lookup function list for extension.
50 FunctionHeuristicsMap& functions = function_heuristics_[extension_id];
52 // Lookup heuristics for function, create if necessary.
53 QuotaLimitHeuristics& heuristics = functions[function->name()];
54 if (heuristics.empty())
55 function->GetQuotaLimitHeuristics(&heuristics);
57 if (heuristics.empty())
58 return std::string(); // No heuristic implies no limit.
60 QuotaLimitHeuristic* failed_heuristic = NULL;
61 for (QuotaLimitHeuristics::iterator heuristic = heuristics.begin();
62 heuristic != heuristics.end();
63 ++heuristic) {
64 // Apply heuristic to each item (bucket).
65 if (!(*heuristic)->ApplyToArgs(args, event_time)) {
66 failed_heuristic = *heuristic;
67 break;
71 if (!failed_heuristic)
72 return std::string();
74 std::string error = failed_heuristic->GetError();
75 DCHECK_GT(error.length(), 0u);
76 return error;
79 void QuotaService::PurgeFunctionHeuristicsMap(FunctionHeuristicsMap* map) {
80 FunctionHeuristicsMap::iterator heuristics = map->begin();
81 while (heuristics != map->end()) {
82 STLDeleteElements(&heuristics->second);
83 map->erase(heuristics++);
87 void QuotaService::Purge() {
88 DCHECK(CalledOnValidThread());
89 std::map<std::string, FunctionHeuristicsMap>::iterator it =
90 function_heuristics_.begin();
91 for (; it != function_heuristics_.end(); function_heuristics_.erase(it++))
92 PurgeFunctionHeuristicsMap(&it->second);
95 void QuotaLimitHeuristic::Bucket::Reset(const Config& config,
96 const base::TimeTicks& start) {
97 num_tokens_ = config.refill_token_count;
98 expiration_ = start + config.refill_interval;
101 void QuotaLimitHeuristic::SingletonBucketMapper::GetBucketsForArgs(
102 const base::ListValue* args,
103 BucketList* buckets) {
104 buckets->push_back(&bucket_);
107 QuotaLimitHeuristic::QuotaLimitHeuristic(const Config& config,
108 BucketMapper* map,
109 const std::string& name)
110 : config_(config), bucket_mapper_(map), name_(name) {}
112 QuotaLimitHeuristic::~QuotaLimitHeuristic() {}
114 bool QuotaLimitHeuristic::ApplyToArgs(const base::ListValue* args,
115 const base::TimeTicks& event_time) {
116 BucketList buckets;
117 bucket_mapper_->GetBucketsForArgs(args, &buckets);
118 for (BucketList::iterator i = buckets.begin(); i != buckets.end(); ++i) {
119 if ((*i)->expiration().is_null()) // A brand new bucket.
120 (*i)->Reset(config_, event_time);
121 if (!Apply(*i, event_time))
122 return false; // It only takes one to spoil it for everyone.
124 return true;
127 std::string QuotaLimitHeuristic::GetError() const {
128 return extensions::ErrorUtils::FormatErrorMessage(kOverQuotaError, name_);
131 bool QuotaService::TimedLimit::Apply(Bucket* bucket,
132 const base::TimeTicks& event_time) {
133 if (event_time > bucket->expiration())
134 bucket->Reset(config(), event_time);
136 return bucket->DeductToken();
139 } // namespace extensions