Home | History | Annotate | Download | only in policy
      1 // Copyright (c) 2011 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/policy/asynchronous_policy_loader.h"
      6 
      7 #include "base/message_loop.h"
      8 #include "base/task.h"
      9 #include "content/browser/browser_thread.h"
     10 
     11 namespace policy {
     12 
     13 AsynchronousPolicyLoader::AsynchronousPolicyLoader(
     14     AsynchronousPolicyProvider::Delegate* delegate,
     15     int reload_interval_minutes)
     16     : delegate_(delegate),
     17       reload_task_(NULL),
     18       reload_interval_(base::TimeDelta::FromMinutes(reload_interval_minutes)),
     19       origin_loop_(MessageLoop::current()),
     20       stopped_(false) {}
     21 
     22 void AsynchronousPolicyLoader::Init() {
     23   policy_.reset(delegate_->Load());
     24   // Initialization can happen early when the file thread is not yet available,
     25   // but the subclass of the loader must do some of their initialization on the
     26   // file thread. Posting to the file thread directly before it is initialized
     27   // will cause the task to be forgotten. Instead, post a task to the ui thread
     28   // to delay the remainder of initialization until threading is fully
     29   // initialized.
     30   BrowserThread::PostTask(
     31       BrowserThread::UI, FROM_HERE,
     32       NewRunnableMethod(
     33           this,
     34           &AsynchronousPolicyLoader::InitAfterFileThreadAvailable));
     35 }
     36 
     37 void AsynchronousPolicyLoader::Stop() {
     38   if (!stopped_) {
     39     stopped_ = true;
     40     delegate_.reset();
     41     FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
     42                       observer_list_,
     43                       OnProviderGoingAway());
     44     BrowserThread::PostTask(
     45         BrowserThread::FILE, FROM_HERE,
     46         NewRunnableMethod(this, &AsynchronousPolicyLoader::StopOnFileThread));
     47   }
     48 }
     49 
     50 AsynchronousPolicyLoader::~AsynchronousPolicyLoader() {
     51 }
     52 
     53 // Manages the life cycle of a new policy map during until its life cycle is
     54 // taken over by the policy loader.
     55 class UpdatePolicyTask : public Task {
     56  public:
     57   UpdatePolicyTask(scoped_refptr<AsynchronousPolicyLoader> loader,
     58                    DictionaryValue* new_policy)
     59       : loader_(loader),
     60         new_policy_(new_policy) {}
     61 
     62   virtual void Run() {
     63     loader_->UpdatePolicy(new_policy_.release());
     64   }
     65 
     66  private:
     67   scoped_refptr<AsynchronousPolicyLoader> loader_;
     68   scoped_ptr<DictionaryValue> new_policy_;
     69   DISALLOW_COPY_AND_ASSIGN(UpdatePolicyTask);
     70 };
     71 
     72 void AsynchronousPolicyLoader::Reload() {
     73   if (delegate_.get()) {
     74     DictionaryValue* new_policy = delegate_->Load();
     75     PostUpdatePolicyTask(new_policy);
     76   }
     77 }
     78 
     79 void AsynchronousPolicyLoader::AddObserver(
     80     ConfigurationPolicyProvider::Observer* observer) {
     81   observer_list_.AddObserver(observer);
     82 }
     83 
     84 void AsynchronousPolicyLoader::RemoveObserver(
     85     ConfigurationPolicyProvider::Observer* observer) {
     86   observer_list_.RemoveObserver(observer);
     87 }
     88 
     89 void AsynchronousPolicyLoader::CancelReloadTask() {
     90   if (reload_task_) {
     91     // Only check the thread if there's still a reload task. During
     92     // destruction of unit tests, the message loop destruction can
     93     // call this method when the file thread is no longer around,
     94     // but in that case reload_task_ is NULL.
     95     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
     96     reload_task_->Cancel();
     97     reload_task_ = NULL;
     98   }
     99 }
    100 
    101 void AsynchronousPolicyLoader::ScheduleReloadTask(
    102     const base::TimeDelta& delay) {
    103   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    104 
    105   CancelReloadTask();
    106 
    107   reload_task_ =
    108       NewRunnableMethod(this, &AsynchronousPolicyLoader::ReloadFromTask);
    109   BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, reload_task_,
    110                                  delay.InMilliseconds());
    111 }
    112 
    113 void AsynchronousPolicyLoader::ScheduleFallbackReloadTask() {
    114   // As a safeguard in case that the load delegate failed to timely notice a
    115   // change in policy, schedule a reload task that'll make us recheck after a
    116   // reasonable interval.
    117   ScheduleReloadTask(reload_interval_);
    118 }
    119 
    120 void AsynchronousPolicyLoader::ReloadFromTask() {
    121   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    122 
    123   // Drop the reference to the reload task, since the task might be the only
    124   // referrer that keeps us alive, so we should not Cancel() it.
    125   reload_task_ = NULL;
    126 
    127   Reload();
    128 }
    129 
    130 void AsynchronousPolicyLoader::InitOnFileThread() {
    131 }
    132 
    133 void AsynchronousPolicyLoader::StopOnFileThread() {
    134   CancelReloadTask();
    135 }
    136 
    137 void AsynchronousPolicyLoader::PostUpdatePolicyTask(
    138     DictionaryValue* new_policy) {
    139   origin_loop_->PostTask(FROM_HERE, new UpdatePolicyTask(this, new_policy));
    140 }
    141 
    142 void AsynchronousPolicyLoader::UpdatePolicy(DictionaryValue* new_policy_raw) {
    143   scoped_ptr<DictionaryValue> new_policy(new_policy_raw);
    144   DCHECK(policy_.get());
    145   if (!policy_->Equals(new_policy.get())) {
    146     policy_.reset(new_policy.release());
    147     FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
    148                       observer_list_,
    149                       OnUpdatePolicy());
    150   }
    151 }
    152 
    153 void AsynchronousPolicyLoader::InitAfterFileThreadAvailable() {
    154   if (!stopped_) {
    155     BrowserThread::PostTask(
    156         BrowserThread::FILE, FROM_HERE,
    157         NewRunnableMethod(this, &AsynchronousPolicyLoader::InitOnFileThread));
    158   }
    159 }
    160 
    161 }  // namespace policy
    162