Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(861)

Side by Side Diff: chrome/browser/extensions/extension_idle_api.cc

Issue 10750016: Moved c/b/e/*idle* to c/b/e/api/idle/ (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: -> extensions namespace Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/extension_idle_api.h"
6
7 #include <algorithm>
8 #include <map>
9 #include <string>
10
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/json/json_writer.h"
14 #include "base/message_loop.h"
15 #include "base/stl_util.h"
16 #include "base/time.h"
17 #include "chrome/browser/extensions/extension_event_router.h"
18 #include "chrome/browser/extensions/extension_host.h"
19 #include "chrome/browser/extensions/extension_idle_api_constants.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/common/extensions/extension.h"
23 #include "content/public/browser/render_view_host.h"
24
25 namespace keys = extension_idle_api_constants;
26
27 namespace {
28
29 const int kIdlePollInterval = 1; // Number of seconds between status checks
30 // when polling for active.
31 const int kThrottleInterval = 1; // Number of seconds to throttle idle checks
32 // for. Return the previously checked idle
33 // state if the next check is faster than this
34 const int kMinThreshold = 15; // In seconds. Set >1 sec for security concerns.
35 const int kMaxThreshold = 4*60*60; // Four hours, in seconds. Not set
36 // arbitrarily high for security concerns.
37 const unsigned int kMaxCacheSize = 100; // Number of state queries to cache.
38
39 // Calculates the error query interval has in respect to idle interval.
40 // The error is defined as amount of the query interval that is not part of the
41 // idle interval.
42 double QueryErrorFromIdle(double idle_start,
43 double idle_end,
44 double query_start,
45 double query_end) {
46 return query_end - idle_end + std::max(0., idle_start - query_start);
47 }
48
49 // Internal class which is used to poll for changes in the system idle state.
50 class ExtensionIdlePollingTask {
51 public:
52 explicit ExtensionIdlePollingTask(int threshold, IdleState last_state,
53 Profile* profile) : threshold_(threshold), last_state_(last_state),
54 profile_(profile) {}
55
56 // Check if we're active; then restart the polling task. Do this till we are
57 // are in active state.
58 void CheckIdleState();
59 void IdleStateCallback(IdleState state);
60
61 // Create a poll task to check for Idle state
62 static void CreateNewPollTask(int threshold, IdleState state,
63 Profile* profile);
64
65 private:
66 int threshold_;
67 IdleState last_state_;
68 Profile* profile_;
69
70 static bool poll_task_running_;
71
72 DISALLOW_COPY_AND_ASSIGN(ExtensionIdlePollingTask);
73 };
74
75 // Implementation of ExtensionIdlePollingTask.
76 bool ExtensionIdlePollingTask::poll_task_running_ = false;
77
78 void ExtensionIdlePollingTask::IdleStateCallback(IdleState current_state) {
79 // If we just came into an active state, notify the extension.
80 if (IDLE_STATE_ACTIVE == current_state && last_state_ != current_state)
81 ExtensionIdleEventRouter::OnIdleStateChange(profile_, current_state);
82
83 ExtensionIdlePollingTask::poll_task_running_ = false;
84
85 ExtensionIdleCache::UpdateCache(threshold_, current_state);
86
87 // Startup another polling task as we exit.
88 if (current_state != IDLE_STATE_ACTIVE)
89 ExtensionIdlePollingTask::CreateNewPollTask(threshold_, current_state,
90 profile_);
91
92 // This instance won't be needed anymore.
93 delete this;
94 }
95
96 void ExtensionIdlePollingTask::CheckIdleState() {
97 CalculateIdleState(threshold_,
98 base::Bind(&ExtensionIdlePollingTask::IdleStateCallback,
99 base::Unretained(this)));
100 }
101
102 // static
103 void ExtensionIdlePollingTask::CreateNewPollTask(int threshold, IdleState state,
104 Profile* profile) {
105 if (ExtensionIdlePollingTask::poll_task_running_) return;
106
107 ExtensionIdlePollingTask::poll_task_running_ = true;
108 MessageLoop::current()->PostDelayedTask(
109 FROM_HERE,
110 base::Bind(&ExtensionIdlePollingTask::CheckIdleState, base::Unretained(
111 new ExtensionIdlePollingTask(threshold, state, profile))),
112 base::TimeDelta::FromSeconds(kIdlePollInterval));
113 }
114
115
116 const char* IdleStateToDescription(IdleState state) {
117 if (IDLE_STATE_ACTIVE == state)
118 return keys::kStateActive;
119 if (IDLE_STATE_IDLE == state)
120 return keys::kStateIdle;
121 return keys::kStateLocked;
122 };
123
124 // Helper function for reporting the idle state. The lifetime of the object
125 // returned is controlled by the caller.
126 StringValue* CreateIdleValue(IdleState idle_state) {
127 StringValue* result = new StringValue(IdleStateToDescription(idle_state));
128 return result;
129 }
130
131 int CheckThresholdBounds(int timeout) {
132 if (timeout < kMinThreshold) return kMinThreshold;
133 if (timeout > kMaxThreshold) return kMaxThreshold;
134 return timeout;
135 }
136
137 }; // namespace
138
139 void ExtensionIdleEventRouter::OnIdleStateChange(Profile* profile,
140 IdleState state) {
141 // Prepare the single argument of the current state.
142 ListValue args;
143 args.Append(CreateIdleValue(state));
144 std::string json_args;
145 base::JSONWriter::Write(&args, &json_args);
146
147 profile->GetExtensionEventRouter()->DispatchEventToRenderers(
148 keys::kOnStateChanged, json_args, profile, GURL(), EventFilteringInfo());
149 }
150
151 bool ExtensionIdleQueryStateFunction::RunImpl() {
152 int threshold;
153 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &threshold));
154 threshold = CheckThresholdBounds(threshold);
155
156 IdleState state = ExtensionIdleCache::CalculateIdleState(threshold);
157 if (state != IDLE_STATE_UNKNOWN) {
158 SetResult(CreateIdleValue(state));
159 SendResponse(true);
160 return true;
161 }
162
163 CalculateIdleState(threshold,
164 base::Bind(&ExtensionIdleQueryStateFunction::IdleStateCallback,
165 this, threshold));
166 // Don't send the response, it'll be sent by our callback
167 return true;
168 }
169
170 void ExtensionIdleQueryStateFunction::IdleStateCallback(int threshold,
171 IdleState state) {
172 // If our state is not active, make sure we're running a polling task to check
173 // for active state and report it when it changes to active.
174 if (state != IDLE_STATE_ACTIVE) {
175 ExtensionIdlePollingTask::CreateNewPollTask(threshold, state, profile_);
176 }
177
178 SetResult(CreateIdleValue(state));
179
180 ExtensionIdleCache::UpdateCache(threshold, state);
181
182 SendResponse(true);
183 }
184
185 ExtensionIdleCache::CacheData ExtensionIdleCache::cached_data =
186 {-1, -1, -1, -1};
187
188 IdleState ExtensionIdleCache::CalculateIdleState(int threshold) {
189 return CalculateState(threshold, base::Time::Now().ToDoubleT());
190 }
191
192 void ExtensionIdleCache::UpdateCache(int threshold, IdleState state) {
193 Update(threshold, state, base::Time::Now().ToDoubleT());
194 }
195
196 IdleState ExtensionIdleCache::CalculateState(int threshold, double now) {
197 if (threshold < kMinThreshold)
198 return IDLE_STATE_UNKNOWN;
199 double threshold_moment = now - static_cast<double>(threshold);
200 double throttle_interval = static_cast<double>(kThrottleInterval);
201
202 // We test for IDEL_STATE_LOCKED first, because the result should be
203 // independent of the data for idle and active state. If last state was
204 // LOCKED and test for LOCKED is satisfied we should always return LOCKED.
205 if (cached_data.latest_locked > 0 &&
206 now - cached_data.latest_locked < throttle_interval)
207 return IDLE_STATE_LOCKED;
208
209 // If thershold moment is beyond the moment after whih we are certain we have
210 // been active, return active state. We allow kThrottleInterval error.
211 if (cached_data.latest_known_active > 0 &&
212 threshold_moment - cached_data.latest_known_active < throttle_interval)
213 return IDLE_STATE_ACTIVE;
214
215 // If total error that query interval has in respect to last recorded idle
216 // interval is less than kThrottleInterval, return IDLE state.
217 // query interval is the interval [now, now - threshold] and the error is
218 // defined as amount of query interval that is outside of idle interval.
219 double error_from_idle =
220 QueryErrorFromIdle(cached_data.idle_interval_start,
221 cached_data.idle_interval_end, threshold_moment, now);
222 if (cached_data.idle_interval_end > 0 &&
223 error_from_idle < throttle_interval)
224 return IDLE_STATE_IDLE;
225
226 return IDLE_STATE_UNKNOWN;
227 }
228
229 void ExtensionIdleCache::Update(int threshold, IdleState state, double now) {
230 if (threshold < kMinThreshold)
231 return;
232 double threshold_moment = now - static_cast<double>(threshold);
233 switch (state) {
234 case IDLE_STATE_IDLE:
235 if (threshold_moment > cached_data.idle_interval_end) {
236 // Cached and new interval don't overlap. We disregard the cached one.
237 cached_data.idle_interval_start = threshold_moment;
238 } else {
239 // Cached and new interval overlap, so we can combine them. We set
240 // the cached interval begining to less recent one.
241 cached_data.idle_interval_start =
242 std::min(cached_data.idle_interval_start, threshold_moment);
243 }
244 cached_data.idle_interval_end = now;
245 // Reset data for LOCKED state, since the last query result is not
246 // LOCKED.
247 cached_data.latest_locked = -1;
248 break;
249 case IDLE_STATE_ACTIVE:
250 if (threshold_moment > cached_data.latest_known_active)
251 cached_data.latest_known_active = threshold_moment;
252 // Reset data for LOCKED state, since the last query result is not
253 // LOCKED.
254 cached_data.latest_locked = -1;
255 break;
256 case IDLE_STATE_LOCKED:
257 if (threshold_moment > cached_data.latest_locked)
258 cached_data.latest_locked = now;
259 break;
260 default:
261 return;
262 }
263 }
264
265 int ExtensionIdleCache::get_min_threshold() {
266 return kMinThreshold;
267 }
268
269 double ExtensionIdleCache::get_throttle_interval() {
270 return static_cast<double>(kThrottleInterval);
271 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698