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_provider.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
93551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/location.h"
109ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "base/sequenced_task_runner.h"
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/async_policy_loader.h"
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/policy_bundle.h"
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/schema_registry.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace policy {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)AsyncPolicyProvider::AsyncPolicyProvider(
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    SchemaRegistry* registry,
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    scoped_ptr<AsyncPolicyLoader> loader)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : loader_(loader.release()),
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      weak_factory_(this) {
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make an immediate synchronous load on startup.
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  OnLoaderReloaded(loader_->InitialLoad(registry->schema_map()));
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AsyncPolicyProvider::~AsyncPolicyProvider() {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Shutdown() must have been called before.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!loader_);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void AsyncPolicyProvider::Init(SchemaRegistry* registry) {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ConfigurationPolicyProvider::Init(registry);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!loader_)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AsyncPolicyLoader::UpdateCallback callback =
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&AsyncPolicyProvider::LoaderUpdateCallback,
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::MessageLoopProxy::current(),
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_factory_.GetWeakPtr());
453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  bool post = loader_->task_runner()->PostTask(
463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      FROM_HERE,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&AsyncPolicyLoader::Init,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(loader_),
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 callback));
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(post) << "AsyncPolicyProvider::Init() called with threads not running";
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncPolicyProvider::Shutdown() {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note on the lifetime of |loader_|:
563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // The |loader_| lives on the background thread, and is deleted from here.
573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // This means that posting tasks on the |loader_| to the background thread
583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // from the AsyncPolicyProvider is always safe, since a potential DeleteSoon()
593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // is only posted from here. The |loader_| posts back to the
603551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // AsyncPolicyProvider through the |update_callback_|, which has a WeakPtr to
613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // |this|.
623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!loader_->task_runner()->DeleteSoon(FROM_HERE, loader_)) {
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // The background thread doesn't exist; this only happens on unit tests.
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    delete loader_;
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  loader_ = NULL;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ConfigurationPolicyProvider::Shutdown();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncPolicyProvider::RefreshPolicies() {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Subtle: RefreshPolicies() has a contract that requires the next policy
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // update notification (triggered from UpdatePolicy()) to reflect any changes
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // made before this call. So if a caller has modified the policy settings and
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // invoked RefreshPolicies(), then by the next notification these policies
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // should already be provided.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // However, it's also possible that an asynchronous Reload() is in progress
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and just posted OnLoaderReloaded(). Therefore a task is posted to the
803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // background thread before posting the next Reload, to prevent a potential
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // concurrent Reload() from triggering a notification too early. If another
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // refresh task has been posted, it is invalidated now.
833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!loader_)
843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  refresh_callback_.Reset(
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&AsyncPolicyProvider::ReloadAfterRefreshSync,
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                 weak_factory_.GetWeakPtr()));
883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  loader_->task_runner()->PostTaskAndReply(
893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      FROM_HERE,
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(base::DoNothing),
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      refresh_callback_.callback());
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncPolicyProvider::ReloadAfterRefreshSync() {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This task can only enter if it was posted from RefreshPolicies(), and it
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // hasn't been cancelled meanwhile by another call to RefreshPolicies().
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!refresh_callback_.IsCancelled());
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // There can't be another refresh callback pending now, since its creation
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in RefreshPolicies() would have cancelled the current execution. So it's
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // safe to cancel the |refresh_callback_| now, so that OnLoaderReloaded()
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // sees that there is no refresh pending.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  refresh_callback_.Cancel();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!loader_)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
108f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  loader_->task_runner()->PostTask(
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      FROM_HERE,
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      base::Bind(&AsyncPolicyLoader::RefreshPolicies,
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 base::Unretained(loader_),
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                 schema_map()));
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncPolicyProvider::OnLoaderReloaded(scoped_ptr<PolicyBundle> bundle) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only propagate policy updates if there are no pending refreshes, and if
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Shutdown() hasn't been called yet.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (refresh_callback_.IsCancelled() && loader_)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdatePolicy(bundle.Pass());
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AsyncPolicyProvider::LoaderUpdateCallback(
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::MessageLoopProxy> loop,
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::WeakPtr<AsyncPolicyProvider> weak_this,
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<PolicyBundle> bundle) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  loop->PostTask(FROM_HERE,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Bind(&AsyncPolicyProvider::OnLoaderReloaded,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            weak_this,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            base::Passed(&bundle)));
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace policy
135