blob: 9fe4153204da8b5a7bf1b438610dbf0ba6c185b1 [file] [log] [blame]
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +09001// 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.
4
5#include "components/policy/core/common/async_policy_provider.h"
6
dchengde26e0f2015-12-27 07:45:17 +09007#include <utility>
8
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +09009#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/location.h"
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090012#include "base/sequenced_task_runner.h"
pranay.kumarc9519fe2015-05-12 19:19:49 +090013#include "base/single_thread_task_runner.h"
gab7440e372016-05-12 05:35:01 +090014#include "base/threading/thread_task_runner_handle.h"
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090015#include "components/policy/core/common/async_policy_loader.h"
16#include "components/policy/core/common/policy_bundle.h"
17#include "components/policy/core/common/schema_registry.h"
18
19namespace policy {
20
dcheng5d618aa2016-04-21 08:57:08 +090021AsyncPolicyProvider::AsyncPolicyProvider(
22 SchemaRegistry* registry,
23 std::unique_ptr<AsyncPolicyLoader> loader)
dchengde26e0f2015-12-27 07:45:17 +090024 : loader_(std::move(loader)), weak_factory_(this) {
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090025 // Make an immediate synchronous load on startup.
26 OnLoaderReloaded(loader_->InitialLoad(registry->schema_map()));
27}
28
29AsyncPolicyProvider::~AsyncPolicyProvider() {
gab43980712017-05-30 20:29:07 +090030 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090031}
32
33void AsyncPolicyProvider::Init(SchemaRegistry* registry) {
gab43980712017-05-30 20:29:07 +090034 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090035 ConfigurationPolicyProvider::Init(registry);
36
37 if (!loader_)
38 return;
39
40 AsyncPolicyLoader::UpdateCallback callback =
41 base::Bind(&AsyncPolicyProvider::LoaderUpdateCallback,
pranay.kumarc9519fe2015-05-12 19:19:49 +090042 base::ThreadTaskRunnerHandle::Get(),
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090043 weak_factory_.GetWeakPtr());
44 bool post = loader_->task_runner()->PostTask(
45 FROM_HERE,
46 base::Bind(&AsyncPolicyLoader::Init,
mnissler3a138002014-12-04 22:47:22 +090047 base::Unretained(loader_.get()),
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090048 callback));
49 DCHECK(post) << "AsyncPolicyProvider::Init() called with threads not running";
50}
51
52void AsyncPolicyProvider::Shutdown() {
gab43980712017-05-30 20:29:07 +090053 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090054 // Note on the lifetime of |loader_|:
55 // The |loader_| lives on the background thread, and is deleted from here.
56 // This means that posting tasks on the |loader_| to the background thread
57 // from the AsyncPolicyProvider is always safe, since a potential DeleteSoon()
58 // is only posted from here. The |loader_| posts back to the
59 // AsyncPolicyProvider through the |update_callback_|, which has a WeakPtr to
60 // |this|.
mnissler3a138002014-12-04 22:47:22 +090061 // If threads are spinning, delete the loader on the thread it lives on. If
62 // there are no threads, kill it immediately.
63 AsyncPolicyLoader* loader_to_delete = loader_.release();
64 if (!loader_to_delete->task_runner()->DeleteSoon(FROM_HERE, loader_to_delete))
65 delete loader_to_delete;
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090066 ConfigurationPolicyProvider::Shutdown();
67}
68
69void AsyncPolicyProvider::RefreshPolicies() {
gab43980712017-05-30 20:29:07 +090070 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090071
72 // Subtle: RefreshPolicies() has a contract that requires the next policy
73 // update notification (triggered from UpdatePolicy()) to reflect any changes
74 // made before this call. So if a caller has modified the policy settings and
75 // invoked RefreshPolicies(), then by the next notification these policies
76 // should already be provided.
77 // However, it's also possible that an asynchronous Reload() is in progress
78 // and just posted OnLoaderReloaded(). Therefore a task is posted to the
79 // background thread before posting the next Reload, to prevent a potential
80 // concurrent Reload() from triggering a notification too early. If another
81 // refresh task has been posted, it is invalidated now.
82 if (!loader_)
83 return;
84 refresh_callback_.Reset(
85 base::Bind(&AsyncPolicyProvider::ReloadAfterRefreshSync,
86 weak_factory_.GetWeakPtr()));
Peter Kasting24efe5e2018-02-24 09:03:01 +090087 loader_->task_runner()->PostTaskAndReply(FROM_HERE, base::DoNothing(),
88 refresh_callback_.callback());
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090089}
90
91void AsyncPolicyProvider::ReloadAfterRefreshSync() {
gab43980712017-05-30 20:29:07 +090092 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +090093 // This task can only enter if it was posted from RefreshPolicies(), and it
94 // hasn't been cancelled meanwhile by another call to RefreshPolicies().
95 DCHECK(!refresh_callback_.IsCancelled());
96 // There can't be another refresh callback pending now, since its creation
97 // in RefreshPolicies() would have cancelled the current execution. So it's
98 // safe to cancel the |refresh_callback_| now, so that OnLoaderReloaded()
99 // sees that there is no refresh pending.
100 refresh_callback_.Cancel();
101
102 if (!loader_)
103 return;
104
105 loader_->task_runner()->PostTask(
106 FROM_HERE,
107 base::Bind(&AsyncPolicyLoader::RefreshPolicies,
mnissler3a138002014-12-04 22:47:22 +0900108 base::Unretained(loader_.get()),
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +0900109 schema_map()));
110}
111
dcheng5d618aa2016-04-21 08:57:08 +0900112void AsyncPolicyProvider::OnLoaderReloaded(
113 std::unique_ptr<PolicyBundle> bundle) {
gab43980712017-05-30 20:29:07 +0900114 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +0900115 // 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_)
dchengde26e0f2015-12-27 07:45:17 +0900118 UpdatePolicy(std::move(bundle));
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +0900119}
120
121// static
122void AsyncPolicyProvider::LoaderUpdateCallback(
pranay.kumarc9519fe2015-05-12 19:19:49 +0900123 scoped_refptr<base::SingleThreadTaskRunner> runner,
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +0900124 base::WeakPtr<AsyncPolicyProvider> weak_this,
dcheng5d618aa2016-04-21 08:57:08 +0900125 std::unique_ptr<PolicyBundle> bundle) {
pranay.kumarc9519fe2015-05-12 19:19:49 +0900126 runner->PostTask(FROM_HERE,
Claudio DeSouza1181b422018-02-22 02:27:16 +0900127 base::BindOnce(&AsyncPolicyProvider::OnLoaderReloaded,
128 weak_this, std::move(bundle)));
dconnelly@chromium.orgdba78872013-12-04 13:46:59 +0900129}
130
131} // namespace policy