Home | History | Annotate | Download | only in extensions
      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:
     54   explicit ExtensionIdlePollingTask(Profile* profile) : profile_(profile) {}
     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 
     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.
     76 StringValue* CreateIdleValue(IdleState idle_state) {
     77   StringValue* result = new StringValue(IdleStateToDescription(idle_state));
     78   return result;
     79 }
     80 
     81 int CheckThresholdBounds(int timeout) {
     82   if (timeout < kMinThreshold) return kMinThreshold;
     83   if (timeout > kMaxThreshold) return kMaxThreshold;
     84   return timeout;
     85 }
     86 
     87 IdleState CalculateIdleStateAndUpdateTimestamp(int threshold) {
     88   polling_data.timestamp = base::Time::Now().ToDoubleT();
     89   return CalculateIdleState(threshold);
     90 }
     91 
     92 void CreateNewPollTask(Profile* profile) {
     93   MessageLoop::current()->PostDelayedTask(
     94       FROM_HERE,
     95       new ExtensionIdlePollingTask(profile),
     96       kIdlePollInterval * 1000);
     97 }
     98 
     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 
    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 
    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 
    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