Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / components / policy / core / common / async_policy_provider.cc
blobae08b209efb78d754da5910356821d7513d00c43
1 // Copyright 2013 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.
5 #include "components/policy/core/common/async_policy_provider.h"
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/location.h"
10 #include "base/sequenced_task_runner.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "components/policy/core/common/async_policy_loader.h"
14 #include "components/policy/core/common/policy_bundle.h"
15 #include "components/policy/core/common/schema_registry.h"
17 namespace policy {
19 AsyncPolicyProvider::AsyncPolicyProvider(
20 SchemaRegistry* registry,
21 scoped_ptr<AsyncPolicyLoader> loader)
22 : loader_(loader.Pass()),
23 weak_factory_(this) {
24 // Make an immediate synchronous load on startup.
25 OnLoaderReloaded(loader_->InitialLoad(registry->schema_map()));
28 AsyncPolicyProvider::~AsyncPolicyProvider() {
29 DCHECK(CalledOnValidThread());
32 void AsyncPolicyProvider::Init(SchemaRegistry* registry) {
33 DCHECK(CalledOnValidThread());
34 ConfigurationPolicyProvider::Init(registry);
36 if (!loader_)
37 return;
39 AsyncPolicyLoader::UpdateCallback callback =
40 base::Bind(&AsyncPolicyProvider::LoaderUpdateCallback,
41 base::ThreadTaskRunnerHandle::Get(),
42 weak_factory_.GetWeakPtr());
43 bool post = loader_->task_runner()->PostTask(
44 FROM_HERE,
45 base::Bind(&AsyncPolicyLoader::Init,
46 base::Unretained(loader_.get()),
47 callback));
48 DCHECK(post) << "AsyncPolicyProvider::Init() called with threads not running";
51 void AsyncPolicyProvider::Shutdown() {
52 DCHECK(CalledOnValidThread());
53 // Note on the lifetime of |loader_|:
54 // The |loader_| lives on the background thread, and is deleted from here.
55 // This means that posting tasks on the |loader_| to the background thread
56 // from the AsyncPolicyProvider is always safe, since a potential DeleteSoon()
57 // is only posted from here. The |loader_| posts back to the
58 // AsyncPolicyProvider through the |update_callback_|, which has a WeakPtr to
59 // |this|.
60 // If threads are spinning, delete the loader on the thread it lives on. If
61 // there are no threads, kill it immediately.
62 AsyncPolicyLoader* loader_to_delete = loader_.release();
63 if (!loader_to_delete->task_runner()->DeleteSoon(FROM_HERE, loader_to_delete))
64 delete loader_to_delete;
65 ConfigurationPolicyProvider::Shutdown();
68 void AsyncPolicyProvider::RefreshPolicies() {
69 DCHECK(CalledOnValidThread());
71 // Subtle: RefreshPolicies() has a contract that requires the next policy
72 // update notification (triggered from UpdatePolicy()) to reflect any changes
73 // made before this call. So if a caller has modified the policy settings and
74 // invoked RefreshPolicies(), then by the next notification these policies
75 // should already be provided.
76 // However, it's also possible that an asynchronous Reload() is in progress
77 // and just posted OnLoaderReloaded(). Therefore a task is posted to the
78 // background thread before posting the next Reload, to prevent a potential
79 // concurrent Reload() from triggering a notification too early. If another
80 // refresh task has been posted, it is invalidated now.
81 if (!loader_)
82 return;
83 refresh_callback_.Reset(
84 base::Bind(&AsyncPolicyProvider::ReloadAfterRefreshSync,
85 weak_factory_.GetWeakPtr()));
86 loader_->task_runner()->PostTaskAndReply(
87 FROM_HERE,
88 base::Bind(base::DoNothing),
89 refresh_callback_.callback());
92 void AsyncPolicyProvider::ReloadAfterRefreshSync() {
93 DCHECK(CalledOnValidThread());
94 // This task can only enter if it was posted from RefreshPolicies(), and it
95 // hasn't been cancelled meanwhile by another call to RefreshPolicies().
96 DCHECK(!refresh_callback_.IsCancelled());
97 // There can't be another refresh callback pending now, since its creation
98 // in RefreshPolicies() would have cancelled the current execution. So it's
99 // safe to cancel the |refresh_callback_| now, so that OnLoaderReloaded()
100 // sees that there is no refresh pending.
101 refresh_callback_.Cancel();
103 if (!loader_)
104 return;
106 loader_->task_runner()->PostTask(
107 FROM_HERE,
108 base::Bind(&AsyncPolicyLoader::RefreshPolicies,
109 base::Unretained(loader_.get()),
110 schema_map()));
113 void AsyncPolicyProvider::OnLoaderReloaded(scoped_ptr<PolicyBundle> bundle) {
114 DCHECK(CalledOnValidThread());
115 // Only propagate policy updates if there are no pending refreshes, and if
116 // Shutdown() hasn't been called yet.
117 if (refresh_callback_.IsCancelled() && loader_)
118 UpdatePolicy(bundle.Pass());
121 // static
122 void AsyncPolicyProvider::LoaderUpdateCallback(
123 scoped_refptr<base::SingleThreadTaskRunner> runner,
124 base::WeakPtr<AsyncPolicyProvider> weak_this,
125 scoped_ptr<PolicyBundle> bundle) {
126 runner->PostTask(FROM_HERE,
127 base::Bind(&AsyncPolicyProvider::OnLoaderReloaded,
128 weak_this,
129 base::Passed(&bundle)));
132 } // namespace policy