// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/policy/asynchronous_policy_loader.h" #include "base/message_loop.h" #include "base/task.h" #include "content/browser/browser_thread.h" namespace policy { AsynchronousPolicyLoader::AsynchronousPolicyLoader( AsynchronousPolicyProvider::Delegate* delegate, int reload_interval_minutes) : delegate_(delegate), reload_task_(NULL), reload_interval_(base::TimeDelta::FromMinutes(reload_interval_minutes)), origin_loop_(MessageLoop::current()), stopped_(false) {} void AsynchronousPolicyLoader::Init() { policy_.reset(delegate_->Load()); // Initialization can happen early when the file thread is not yet available, // but the subclass of the loader must do some of their initialization on the // file thread. Posting to the file thread directly before it is initialized // will cause the task to be forgotten. Instead, post a task to the ui thread // to delay the remainder of initialization until threading is fully // initialized. BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, NewRunnableMethod( this, &AsynchronousPolicyLoader::InitAfterFileThreadAvailable)); } void AsynchronousPolicyLoader::Stop() { if (!stopped_) { stopped_ = true; delegate_.reset(); FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, observer_list_, OnProviderGoingAway()); BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableMethod(this, &AsynchronousPolicyLoader::StopOnFileThread)); } } AsynchronousPolicyLoader::~AsynchronousPolicyLoader() { } // Manages the life cycle of a new policy map during until its life cycle is // taken over by the policy loader. class UpdatePolicyTask : public Task { public: UpdatePolicyTask(scoped_refptr<AsynchronousPolicyLoader> loader, DictionaryValue* new_policy) : loader_(loader), new_policy_(new_policy) {} virtual void Run() { loader_->UpdatePolicy(new_policy_.release()); } private: scoped_refptr<AsynchronousPolicyLoader> loader_; scoped_ptr<DictionaryValue> new_policy_; DISALLOW_COPY_AND_ASSIGN(UpdatePolicyTask); }; void AsynchronousPolicyLoader::Reload() { if (delegate_.get()) { DictionaryValue* new_policy = delegate_->Load(); PostUpdatePolicyTask(new_policy); } } void AsynchronousPolicyLoader::AddObserver( ConfigurationPolicyProvider::Observer* observer) { observer_list_.AddObserver(observer); } void AsynchronousPolicyLoader::RemoveObserver( ConfigurationPolicyProvider::Observer* observer) { observer_list_.RemoveObserver(observer); } void AsynchronousPolicyLoader::CancelReloadTask() { if (reload_task_) { // Only check the thread if there's still a reload task. During // destruction of unit tests, the message loop destruction can // call this method when the file thread is no longer around, // but in that case reload_task_ is NULL. DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); reload_task_->Cancel(); reload_task_ = NULL; } } void AsynchronousPolicyLoader::ScheduleReloadTask( const base::TimeDelta& delay) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); CancelReloadTask(); reload_task_ = NewRunnableMethod(this, &AsynchronousPolicyLoader::ReloadFromTask); BrowserThread::PostDelayedTask(BrowserThread::FILE, FROM_HERE, reload_task_, delay.InMilliseconds()); } void AsynchronousPolicyLoader::ScheduleFallbackReloadTask() { // As a safeguard in case that the load delegate failed to timely notice a // change in policy, schedule a reload task that'll make us recheck after a // reasonable interval. ScheduleReloadTask(reload_interval_); } void AsynchronousPolicyLoader::ReloadFromTask() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); // Drop the reference to the reload task, since the task might be the only // referrer that keeps us alive, so we should not Cancel() it. reload_task_ = NULL; Reload(); } void AsynchronousPolicyLoader::InitOnFileThread() { } void AsynchronousPolicyLoader::StopOnFileThread() { CancelReloadTask(); } void AsynchronousPolicyLoader::PostUpdatePolicyTask( DictionaryValue* new_policy) { origin_loop_->PostTask(FROM_HERE, new UpdatePolicyTask(this, new_policy)); } void AsynchronousPolicyLoader::UpdatePolicy(DictionaryValue* new_policy_raw) { scoped_ptr<DictionaryValue> new_policy(new_policy_raw); DCHECK(policy_.get()); if (!policy_->Equals(new_policy.get())) { policy_.reset(new_policy.release()); FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer, observer_list_, OnUpdatePolicy()); } } void AsynchronousPolicyLoader::InitAfterFileThreadAvailable() { if (!stopped_) { BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, NewRunnableMethod(this, &AsynchronousPolicyLoader::InitOnFileThread)); } } } // namespace policy