Home | History | Annotate | Download | only in cloud
      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 "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/metrics/histogram.h"
     13 #include "base/sequenced_task_runner.h"
     14 #include "base/time/default_tick_clock.h"
     15 #include "base/time/tick_clock.h"
     16 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
     17 
     18 namespace policy {
     19 
     20 namespace {
     21 
     22 // The maximum rate at which to refresh policies.
     23 const size_t kMaxRefreshesPerHour = 5;
     24 
     25 }  // namespace
     26 
     27 #if defined(OS_ANDROID) || defined(OS_IOS)
     28 
     29 const int64 CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs =
     30     24 * 60 * 60 * 1000;  // 1 day.
     31 const int64 CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs =
     32     24 * 60 * 60 * 1000;  // 1 day.
     33 // Delay for periodic refreshes when the invalidations service is available,
     34 // in milliseconds.
     35 // TODO(joaodasilva): increase this value once we're confident that the
     36 // invalidations channel works as expected.
     37 const int64 CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs =
     38     24 * 60 * 60 * 1000;  // 1 day.
     39 const int64 CloudPolicyRefreshScheduler::kInitialErrorRetryDelayMs =
     40     5 * 60 * 1000;  // 5 minutes.
     41 const int64 CloudPolicyRefreshScheduler::kRefreshDelayMinMs =
     42     30 * 60 * 1000;  // 30 minutes.
     43 const int64 CloudPolicyRefreshScheduler::kRefreshDelayMaxMs =
     44     7 * 24 * 60 * 60 * 1000;  // 1 week.
     45 
     46 #else
     47 
     48 const int64 CloudPolicyRefreshScheduler::kDefaultRefreshDelayMs =
     49     3 * 60 * 60 * 1000;  // 3 hours.
     50 const int64 CloudPolicyRefreshScheduler::kUnmanagedRefreshDelayMs =
     51     24 * 60 * 60 * 1000;  // 1 day.
     52 // Delay for periodic refreshes when the invalidations service is available,
     53 // in milliseconds.
     54 // TODO(joaodasilva): increase this value once we're confident that the
     55 // invalidations channel works as expected.
     56 const int64 CloudPolicyRefreshScheduler::kWithInvalidationsRefreshDelayMs =
     57     3 * 60 * 60 * 1000;  // 3 hours.
     58 const int64 CloudPolicyRefreshScheduler::kInitialErrorRetryDelayMs =
     59     5 * 60 * 1000;  // 5 minutes.
     60 const int64 CloudPolicyRefreshScheduler::kRefreshDelayMinMs =
     61     30 * 60 * 1000;  // 30 minutes.
     62 const int64 CloudPolicyRefreshScheduler::kRefreshDelayMaxMs =
     63     24 * 60 * 60 * 1000;  // 1 day.
     64 
     65 #endif
     66 
     67 CloudPolicyRefreshScheduler::CloudPolicyRefreshScheduler(
     68     CloudPolicyClient* client,
     69     CloudPolicyStore* store,
     70     const scoped_refptr<base::SequencedTaskRunner>& task_runner)
     71     : client_(client),
     72       store_(store),
     73       task_runner_(task_runner),
     74       error_retry_delay_ms_(kInitialErrorRetryDelayMs),
     75       refresh_delay_ms_(kDefaultRefreshDelayMs),
     76       rate_limiter_(kMaxRefreshesPerHour,
     77                     base::TimeDelta::FromHours(1),
     78                     base::Bind(&CloudPolicyRefreshScheduler::RefreshNow,
     79                                base::Unretained(this)),
     80                     task_runner_,
     81                     scoped_ptr<base::TickClock>(new base::DefaultTickClock())),
     82       invalidations_available_(false),
     83       creation_time_(base::Time::NowFromSystemTime()) {
     84   client_->AddObserver(this);
     85   store_->AddObserver(this);
     86   net::NetworkChangeNotifier::AddIPAddressObserver(this);
     87 
     88   UpdateLastRefreshFromPolicy();
     89   ScheduleRefresh();
     90 }
     91 
     92 CloudPolicyRefreshScheduler::~CloudPolicyRefreshScheduler() {
     93   store_->RemoveObserver(this);
     94   client_->RemoveObserver(this);
     95   net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
     96 }
     97 
     98 void CloudPolicyRefreshScheduler::SetRefreshDelay(int64 refresh_delay) {
     99   refresh_delay_ms_ = std::min(std::max(refresh_delay, kRefreshDelayMinMs),
    100                                kRefreshDelayMaxMs);
    101   ScheduleRefresh();
    102 }
    103 
    104 void CloudPolicyRefreshScheduler::RefreshSoon() {
    105   rate_limiter_.PostRequest();
    106 }
    107 
    108 void CloudPolicyRefreshScheduler::SetInvalidationServiceAvailability(
    109     bool is_available) {
    110   if (!creation_time_.is_null()) {
    111     base::TimeDelta elapsed = base::Time::NowFromSystemTime() - creation_time_;
    112     UMA_HISTOGRAM_MEDIUM_TIMES("Enterprise.PolicyInvalidationsStartupTime",
    113                                elapsed);
    114     creation_time_ = base::Time();
    115   }
    116 
    117   if (is_available == invalidations_available_) {
    118     // No change in state.
    119     return;
    120   }
    121 
    122   invalidations_available_ = is_available;
    123 
    124   // Schedule a refresh since the refresh delay has been updated.
    125   ScheduleRefresh();
    126 }
    127 
    128 void CloudPolicyRefreshScheduler::OnPolicyFetched(CloudPolicyClient* client) {
    129   error_retry_delay_ms_ = kInitialErrorRetryDelayMs;
    130 
    131   // Schedule the next refresh.
    132   last_refresh_ = base::Time::NowFromSystemTime();
    133   ScheduleRefresh();
    134 }
    135 
    136 void CloudPolicyRefreshScheduler::OnRegistrationStateChanged(
    137     CloudPolicyClient* client) {
    138   error_retry_delay_ms_ = kInitialErrorRetryDelayMs;
    139 
    140   // The client might have registered, so trigger an immediate refresh.
    141   RefreshNow();
    142 }
    143 
    144 void CloudPolicyRefreshScheduler::OnClientError(CloudPolicyClient* client) {
    145   // Save the status for below.
    146   DeviceManagementStatus status = client_->status();
    147 
    148   // Schedule an error retry if applicable.
    149   last_refresh_ = base::Time::NowFromSystemTime();
    150   ScheduleRefresh();
    151 
    152   // Update the retry delay.
    153   if (client->is_registered() &&
    154       (status == DM_STATUS_REQUEST_FAILED ||
    155        status == DM_STATUS_TEMPORARY_UNAVAILABLE)) {
    156     error_retry_delay_ms_ = std::min(error_retry_delay_ms_ * 2,
    157                                      refresh_delay_ms_);
    158   } else {
    159     error_retry_delay_ms_ = kInitialErrorRetryDelayMs;
    160   }
    161 }
    162 
    163 void CloudPolicyRefreshScheduler::OnStoreLoaded(CloudPolicyStore* store) {
    164   UpdateLastRefreshFromPolicy();
    165 
    166   // Re-schedule the next refresh in case the is_managed bit changed.
    167   ScheduleRefresh();
    168 }
    169 
    170 void CloudPolicyRefreshScheduler::OnStoreError(CloudPolicyStore* store) {
    171   // If |store_| fails, the is_managed bit that it provides may become stale.
    172   // The best guess in that situation is to assume is_managed didn't change and
    173   // continue using the stale information. Thus, no specific response to a store
    174   // error is required. NB: Changes to is_managed fire OnStoreLoaded().
    175 }
    176 
    177 void CloudPolicyRefreshScheduler::OnIPAddressChanged() {
    178   if (client_->status() == DM_STATUS_REQUEST_FAILED)
    179     RefreshSoon();
    180 }
    181 
    182 void CloudPolicyRefreshScheduler::UpdateLastRefreshFromPolicy() {
    183   if (!last_refresh_.is_null())
    184     return;
    185 
    186   // If the client has already fetched policy, assume that happened recently. If
    187   // that assumption ever breaks, the proper thing to do probably is to move the
    188   // |last_refresh_| bookkeeping to CloudPolicyClient.
    189   if (!client_->responses().empty()) {
    190     last_refresh_ = base::Time::NowFromSystemTime();
    191     return;
    192   }
    193 
    194 #if defined(OS_ANDROID) || defined(OS_IOS)
    195   // Refreshing on mobile platforms:
    196   // - if no user is signed-in then the |client_| is never registered and
    197   //   nothing happens here.
    198   // - if the user is signed-in but isn't enterprise then the |client_| is
    199   //   never registered and nothing happens here.
    200   // - if the user is signed-in but isn't registered for policy yet then the
    201   //   |client_| isn't registered either; the UserPolicySigninService will try
    202   //   to register, and OnRegistrationStateChanged() will be invoked later.
    203   // - if the client is signed-in and has policy then its timestamp is used to
    204   //   determine when to perform the next fetch, which will be once the cached
    205   //   version is considered "old enough".
    206   //
    207   // If there is an old policy cache then a fetch will be performed "soon"; if
    208   // that fetch fails then a retry is attempted after a delay, with exponential
    209   // backoff. If those fetches keep failing then the cached timestamp is *not*
    210   // updated, and another fetch (and subsequent retries) will be attempted
    211   // again on the next startup.
    212   //
    213   // But if the cached policy is considered fresh enough then we try to avoid
    214   // fetching again on startup; the Android logic differs from the desktop in
    215   // this aspect.
    216   if (store_->has_policy() && store_->policy()->has_timestamp()) {
    217     last_refresh_ =
    218         base::Time::UnixEpoch() +
    219         base::TimeDelta::FromMilliseconds(store_->policy()->timestamp());
    220   }
    221 #else
    222   // If there is a cached non-managed response, make sure to only re-query the
    223   // server after kUnmanagedRefreshDelayMs. NB: For existing policy, an
    224   // immediate refresh is intentional.
    225   if (store_->has_policy() && store_->policy()->has_timestamp() &&
    226       !store_->is_managed()) {
    227     last_refresh_ =
    228         base::Time::UnixEpoch() +
    229         base::TimeDelta::FromMilliseconds(store_->policy()->timestamp());
    230   }
    231 #endif
    232 }
    233 
    234 void CloudPolicyRefreshScheduler::RefreshNow() {
    235   last_refresh_ = base::Time();
    236   ScheduleRefresh();
    237 }
    238 
    239 void CloudPolicyRefreshScheduler::ScheduleRefresh() {
    240   // If the client isn't registered, there is nothing to do.
    241   if (!client_->is_registered()) {
    242     refresh_callback_.Cancel();
    243     return;
    244   }
    245 
    246   // If policy invalidations are available then periodic updates are done at
    247   // a much lower rate; otherwise use the |refresh_delay_ms_| value.
    248   int64 refresh_delay_ms =
    249       invalidations_available_ ? kWithInvalidationsRefreshDelayMs
    250                                : refresh_delay_ms_;
    251 
    252   // If there is a registration, go by the client's status. That will tell us
    253   // what the appropriate refresh delay should be.
    254   switch (client_->status()) {
    255     case DM_STATUS_SUCCESS:
    256       if (store_->is_managed())
    257         RefreshAfter(refresh_delay_ms);
    258       else
    259         RefreshAfter(kUnmanagedRefreshDelayMs);
    260       return;
    261     case DM_STATUS_SERVICE_ACTIVATION_PENDING:
    262     case DM_STATUS_SERVICE_POLICY_NOT_FOUND:
    263       RefreshAfter(refresh_delay_ms);
    264       return;
    265     case DM_STATUS_REQUEST_FAILED:
    266     case DM_STATUS_TEMPORARY_UNAVAILABLE:
    267       RefreshAfter(error_retry_delay_ms_);
    268       return;
    269     case DM_STATUS_REQUEST_INVALID:
    270     case DM_STATUS_HTTP_STATUS_ERROR:
    271     case DM_STATUS_RESPONSE_DECODING_ERROR:
    272     case DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED:
    273       RefreshAfter(kUnmanagedRefreshDelayMs);
    274       return;
    275     case DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID:
    276     case DM_STATUS_SERVICE_DEVICE_NOT_FOUND:
    277     case DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER:
    278     case DM_STATUS_SERVICE_DEVICE_ID_CONFLICT:
    279     case DM_STATUS_SERVICE_MISSING_LICENSES:
    280     case DM_STATUS_SERVICE_DEPROVISIONED:
    281     case DM_STATUS_SERVICE_DOMAIN_MISMATCH:
    282       // Need a re-registration, no use in retrying.
    283       refresh_callback_.Cancel();
    284       return;
    285   }
    286 
    287   NOTREACHED() << "Invalid client status " << client_->status();
    288   RefreshAfter(kUnmanagedRefreshDelayMs);
    289 }
    290 
    291 void CloudPolicyRefreshScheduler::PerformRefresh() {
    292   if (client_->is_registered()) {
    293     // Update |last_refresh_| so another fetch isn't triggered inadvertently.
    294     last_refresh_ = base::Time::NowFromSystemTime();
    295 
    296     // The result of this operation will be reported through a callback, at
    297     // which point the next refresh will be scheduled.
    298     client_->FetchPolicy();
    299     return;
    300   }
    301 
    302   // This should never happen, as the registration change should have been
    303   // handled via OnRegistrationStateChanged().
    304   NOTREACHED();
    305 }
    306 
    307 void CloudPolicyRefreshScheduler::RefreshAfter(int delta_ms) {
    308   base::TimeDelta delta(base::TimeDelta::FromMilliseconds(delta_ms));
    309   refresh_callback_.Cancel();
    310 
    311   // Schedule the callback.
    312   base::TimeDelta delay =
    313       std::max((last_refresh_ + delta) - base::Time::NowFromSystemTime(),
    314                base::TimeDelta());
    315   refresh_callback_.Reset(
    316       base::Bind(&CloudPolicyRefreshScheduler::PerformRefresh,
    317                  base::Unretained(this)));
    318   task_runner_->PostDelayedTask(FROM_HERE, refresh_callback_.callback(), delay);
    319 }
    320 
    321 }  // namespace policy
    322