15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/policy/async_policy_loader.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/policy/policy_bundle.h"
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/policy/policy_domain_descriptor.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time;
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta;
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace policy {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Amount of time to wait for the files on disk to settle before trying to load
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// them. This alleviates the problem of reading partially written files and
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// makes it possible to batch quasi-simultaneous changes.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kSettleIntervalSeconds = 5;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The time interval for rechecking policy. This is the fallback in case the
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// implementation never detects changes.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kReloadIntervalSeconds = 15 * 60;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AsyncPolicyLoader::AsyncPolicyLoader()
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : weak_factory_(this) {}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AsyncPolicyLoader::~AsyncPolicyLoader() {}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::Time AsyncPolicyLoader::LastModificationTime() {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return base::Time();
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncPolicyLoader::Reload(bool force) {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimeDelta delay;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time now = Time::Now();
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if there was a recent modification to the underlying files.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!force && !IsSafeToReload(now, &delay)) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleNextReload(delay);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<PolicyBundle> bundle(Load());
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check if there was a modification while reading.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!force && !IsSafeToReload(now, &delay)) {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ScheduleNextReload(delay);
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Filter out mismatching policies.
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  for (DescriptorMap::iterator it = descriptor_map_.begin();
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       it != descriptor_map_.end(); ++it) {
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    it->second->FilterBundle(bundle.get());
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
6490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  update_callback_.Run(bundle.Pass());
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleNextReload(TimeDelta::FromSeconds(kReloadIntervalSeconds));
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void AsyncPolicyLoader::RegisterPolicyDomain(
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    scoped_refptr<const PolicyDomainDescriptor> descriptor) {
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  if (descriptor->domain() != POLICY_DOMAIN_CHROME) {
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    descriptor_map_[descriptor->domain()] = descriptor;
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    Reload(true);
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<PolicyBundle> AsyncPolicyLoader::InitialLoad() {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This is the first load, early during startup. Use this to record the
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // initial |last_modification_time_|, so that potential changes made before
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // installing the watches can be detected.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  last_modification_time_ = LastModificationTime();
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Load();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncPolicyLoader::Init(const UpdateCallback& update_callback) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(update_callback_.is_null());
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!update_callback.is_null());
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  update_callback_ = update_callback;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  InitOnFile();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There might have been changes to the underlying files since the initial
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // load and before the watchers have been created.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (LastModificationTime() != last_modification_time_)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Reload(false);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start periodic refreshes.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScheduleNextReload(TimeDelta::FromSeconds(kReloadIntervalSeconds));
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncPolicyLoader::ScheduleNextReload(TimeDelta delay) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  weak_factory_.InvalidateWeakPtrs();
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostDelayedTask(
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::FILE, FROM_HERE,
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&AsyncPolicyLoader::Reload,
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_factory_.GetWeakPtr(),
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 false  /* force */),
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delay);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AsyncPolicyLoader::IsSafeToReload(const Time& now, TimeDelta* delay) {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Time last_modification = LastModificationTime();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (last_modification.is_null())
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If there was a change since the last recorded modification, wait some more.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const TimeDelta kSettleInterval(
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      TimeDelta::FromSeconds(kSettleIntervalSeconds));
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (last_modification != last_modification_time_) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_modification_time_ = last_modification;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    last_modification_clock_ = now;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *delay = kSettleInterval;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check whether the settle interval has elapsed.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::TimeDelta age = now - last_modification_clock_;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (age < kSettleInterval) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *delay = kSettleInterval - age;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace policy
139