xref: /aosp_15_r20/external/libchrome/components/policy/core/common/async_policy_provider.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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.
4 
5 #include "components/policy/core/common/async_policy_provider.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/location.h"
12 #include "base/sequenced_task_runner.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/threading/thread_task_runner_handle.h"
15 #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 
19 namespace policy {
20 
AsyncPolicyProvider(SchemaRegistry * registry,std::unique_ptr<AsyncPolicyLoader> loader)21 AsyncPolicyProvider::AsyncPolicyProvider(
22     SchemaRegistry* registry,
23     std::unique_ptr<AsyncPolicyLoader> loader)
24     : loader_(std::move(loader)), weak_factory_(this) {
25   // Make an immediate synchronous load on startup.
26   OnLoaderReloaded(loader_->InitialLoad(registry->schema_map()));
27 }
28 
~AsyncPolicyProvider()29 AsyncPolicyProvider::~AsyncPolicyProvider() {
30   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
31 }
32 
Init(SchemaRegistry * registry)33 void AsyncPolicyProvider::Init(SchemaRegistry* registry) {
34   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
35   ConfigurationPolicyProvider::Init(registry);
36 
37   if (!loader_)
38     return;
39 
40   AsyncPolicyLoader::UpdateCallback callback =
41       base::Bind(&AsyncPolicyProvider::LoaderUpdateCallback,
42                  base::ThreadTaskRunnerHandle::Get(),
43                  weak_factory_.GetWeakPtr());
44   bool post = loader_->task_runner()->PostTask(
45       FROM_HERE,
46       base::Bind(&AsyncPolicyLoader::Init,
47                  base::Unretained(loader_.get()),
48                  callback));
49   DCHECK(post) << "AsyncPolicyProvider::Init() called with threads not running";
50 }
51 
Shutdown()52 void AsyncPolicyProvider::Shutdown() {
53   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
54   // 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|.
61   // 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;
66   ConfigurationPolicyProvider::Shutdown();
67 }
68 
RefreshPolicies()69 void AsyncPolicyProvider::RefreshPolicies() {
70   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
71 
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()));
87   loader_->task_runner()->PostTaskAndReply(FROM_HERE, base::DoNothing(),
88                                            refresh_callback_.callback());
89 }
90 
ReloadAfterRefreshSync()91 void AsyncPolicyProvider::ReloadAfterRefreshSync() {
92   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
93   // 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,
108                  base::Unretained(loader_.get()),
109                  schema_map()));
110 }
111 
OnLoaderReloaded(std::unique_ptr<PolicyBundle> bundle)112 void AsyncPolicyProvider::OnLoaderReloaded(
113     std::unique_ptr<PolicyBundle> bundle) {
114   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
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(std::move(bundle));
119 }
120 
121 // static
LoaderUpdateCallback(scoped_refptr<base::SingleThreadTaskRunner> runner,base::WeakPtr<AsyncPolicyProvider> weak_this,std::unique_ptr<PolicyBundle> bundle)122 void AsyncPolicyProvider::LoaderUpdateCallback(
123     scoped_refptr<base::SingleThreadTaskRunner> runner,
124     base::WeakPtr<AsyncPolicyProvider> weak_this,
125     std::unique_ptr<PolicyBundle> bundle) {
126   runner->PostTask(FROM_HERE,
127                    base::BindOnce(&AsyncPolicyProvider::OnLoaderReloaded,
128                                   weak_this, std::move(bundle)));
129 }
130 
131 }  // namespace policy
132