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