1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 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) 5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/async_policy_loader.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 83551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/location.h" 93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/sequenced_task_runner.h" 10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/policy_bundle.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::Time; 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::TimeDelta; 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace policy { 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Amount of time to wait for the files on disk to settle before trying to load 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// them. This alleviates the problem of reading partially written files and 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// makes it possible to batch quasi-simultaneous changes. 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kSettleIntervalSeconds = 5; 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The time interval for rechecking policy. This is the fallback in case the 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// implementation never detects changes. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kReloadIntervalSeconds = 15 * 60; 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 303551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)AsyncPolicyLoader::AsyncPolicyLoader( 313551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) scoped_refptr<base::SequencedTaskRunner> task_runner) 323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) : task_runner_(task_runner), 333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) weak_factory_(this) {} 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AsyncPolicyLoader::~AsyncPolicyLoader() {} 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)Time AsyncPolicyLoader::LastModificationTime() { 38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return Time(); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncPolicyLoader::Reload(bool force) { 423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TimeDelta delay; 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Time now = Time::Now(); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if there was a recent modification to the underlying files. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!force && !IsSafeToReload(now, &delay)) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleNextReload(delay); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<PolicyBundle> bundle(Load()); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if there was a modification while reading. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!force && !IsSafeToReload(now, &delay)) { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleNextReload(delay); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Filter out mismatching policies. 61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) schema_map_->FilterBundle(bundle.get()); 6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) update_callback_.Run(bundle.Pass()); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleNextReload(TimeDelta::FromSeconds(kReloadIntervalSeconds)); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 67f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)scoped_ptr<PolicyBundle> AsyncPolicyLoader::InitialLoad( 68f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const scoped_refptr<SchemaMap>& schema_map) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is the first load, early during startup. Use this to record the 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // initial |last_modification_time_|, so that potential changes made before 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // installing the watches can be detected. 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_modification_time_ = LastModificationTime(); 73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) schema_map_ = schema_map; 74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) scoped_ptr<PolicyBundle> bundle(Load()); 75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) // Filter out mismatching policies. 76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) schema_map_->FilterBundle(bundle.get()); 77f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return bundle.Pass(); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncPolicyLoader::Init(const UpdateCallback& update_callback) { 813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(update_callback_.is_null()); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!update_callback.is_null()); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) update_callback_ = update_callback; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) InitOnBackgroundThread(); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There might have been changes to the underlying files since the initial 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // load and before the watchers have been created. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (LastModificationTime() != last_modification_time_) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Reload(false); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Start periodic refreshes. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScheduleNextReload(TimeDelta::FromSeconds(kReloadIntervalSeconds)); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AsyncPolicyLoader::RefreshPolicies(scoped_refptr<SchemaMap> schema_map) { 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) schema_map_ = schema_map; 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) Reload(true); 101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncPolicyLoader::ScheduleNextReload(TimeDelta delay) { 1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) DCHECK(task_runner_->RunsTasksOnCurrentThread()); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) weak_factory_.InvalidateWeakPtrs(); 1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) task_runner_->PostDelayedTask(FROM_HERE, 1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) base::Bind(&AsyncPolicyLoader::Reload, 1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) weak_factory_.GetWeakPtr(), 1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) false /* force */), 1103551c9c881056c480085172ff9840cab31610854Torne (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. 129f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const 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