• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2010 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 // This implementation supposes a single extension thread and synchronized
6 // method invokation.
7 
8 #include "chrome/browser/extensions/extension_idle_api.h"
9 
10 #include <string>
11 
12 #include "base/json/json_writer.h"
13 #include "base/message_loop.h"
14 #include "base/stl_util-inl.h"
15 #include "base/task.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/browser/renderer_host/render_view_host.h"
24 
25 namespace keys = extension_idle_api_constants;
26 
27 namespace {
28 
29 const int kIdlePollInterval = 15;  // Number of seconds between status checks
30                                    // when polling for active.
31 const int kMinThreshold = 15;  // In seconds.  Set >1 sec for security concerns.
32 const int kMaxThreshold = 60*60;  // One hours, in seconds.  Not set arbitrarily
33                                   // high for security concerns.
34 
35 struct ExtensionIdlePollingData {
36   IdleState state;
37   double timestamp;
38 };
39 
40 // Static variables shared between instances of polling.
41 static ExtensionIdlePollingData polling_data;
42 
43 // Forward declaration of utility methods.
44 static const char* IdleStateToDescription(IdleState state);
45 static StringValue* CreateIdleValue(IdleState idle_state);
46 static int CheckThresholdBounds(int timeout);
47 static IdleState CalculateIdleStateAndUpdateTimestamp(int threshold);
48 static void CreateNewPollTask(Profile* profile);
49 static IdleState ThrottledCalculateIdleState(int threshold, Profile* profile);
50 
51 // Internal object which watches for changes in the system idle state.
52 class ExtensionIdlePollingTask : public Task {
53  public:
ExtensionIdlePollingTask(Profile * profile)54   explicit ExtensionIdlePollingTask(Profile* profile) : profile_(profile) {}
~ExtensionIdlePollingTask()55   virtual ~ExtensionIdlePollingTask() {}
56 
57   // Overridden from Task.
58   virtual void Run();
59 
60  private:
61   Profile* profile_;
62 
63   DISALLOW_COPY_AND_ASSIGN(ExtensionIdlePollingTask);
64 };
65 
IdleStateToDescription(IdleState state)66 const char* IdleStateToDescription(IdleState state) {
67   if (IDLE_STATE_ACTIVE == state)
68     return keys::kStateActive;
69   if (IDLE_STATE_IDLE == state)
70     return keys::kStateIdle;
71   return keys::kStateLocked;
72 };
73 
74 // Helper function for reporting the idle state.  The lifetime of the object
75 // returned is controlled by the caller.
CreateIdleValue(IdleState idle_state)76 StringValue* CreateIdleValue(IdleState idle_state) {
77   StringValue* result = new StringValue(IdleStateToDescription(idle_state));
78   return result;
79 }
80 
CheckThresholdBounds(int timeout)81 int CheckThresholdBounds(int timeout) {
82   if (timeout < kMinThreshold) return kMinThreshold;
83   if (timeout > kMaxThreshold) return kMaxThreshold;
84   return timeout;
85 }
86 
CalculateIdleStateAndUpdateTimestamp(int threshold)87 IdleState CalculateIdleStateAndUpdateTimestamp(int threshold) {
88   polling_data.timestamp = base::Time::Now().ToDoubleT();
89   return CalculateIdleState(threshold);
90 }
91 
CreateNewPollTask(Profile * profile)92 void CreateNewPollTask(Profile* profile) {
93   MessageLoop::current()->PostDelayedTask(
94       FROM_HERE,
95       new ExtensionIdlePollingTask(profile),
96       kIdlePollInterval * 1000);
97 }
98 
ThrottledCalculateIdleState(int threshold,Profile * profile)99 IdleState ThrottledCalculateIdleState(int threshold, Profile* profile) {
100   // If we are not active we should be polling.
101   if (IDLE_STATE_ACTIVE != polling_data.state)
102     return polling_data.state;
103 
104   // Only allow one check per threshold.
105   double time_now = base::Time::Now().ToDoubleT();
106   double delta = time_now - polling_data.timestamp;
107   if (delta < threshold)
108     return polling_data.state;
109 
110   // Update the new state with a poll.  Note this updates time of last check.
111   polling_data.state = CalculateIdleStateAndUpdateTimestamp(threshold);
112 
113   if (IDLE_STATE_ACTIVE != polling_data.state)
114     CreateNewPollTask(profile);
115 
116   return polling_data.state;
117 }
118 
Run()119 void ExtensionIdlePollingTask::Run() {
120   IdleState state = CalculateIdleStateAndUpdateTimestamp(
121       kIdlePollInterval);
122   if (state != polling_data.state) {
123     polling_data.state = state;
124 
125     // Inform of change if the current state is IDLE_STATE_ACTIVE.
126     if (IDLE_STATE_ACTIVE == polling_data.state)
127       ExtensionIdleEventRouter::OnIdleStateChange(profile_, state);
128   }
129 
130   // Create a secondary polling task until an active state is reached.
131   if (IDLE_STATE_ACTIVE != polling_data.state)
132     CreateNewPollTask(profile_);
133 }
134 
135 };  // namespace
136 
RunImpl()137 bool ExtensionIdleQueryStateFunction::RunImpl() {
138   int threshold;
139   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &threshold));
140   threshold = CheckThresholdBounds(threshold);
141   IdleState state = ThrottledCalculateIdleState(threshold, profile());
142   result_.reset(CreateIdleValue(state));
143   return true;
144 }
145 
OnIdleStateChange(Profile * profile,IdleState state)146 void ExtensionIdleEventRouter::OnIdleStateChange(Profile* profile,
147                                                  IdleState state) {
148   // Prepare the single argument of the current state.
149   ListValue args;
150   args.Append(CreateIdleValue(state));
151   std::string json_args;
152   base::JSONWriter::Write(&args, false, &json_args);
153 
154   profile->GetExtensionEventRouter()->DispatchEventToRenderers(
155       keys::kOnStateChanged, json_args, profile, GURL());
156 }
157