Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/policy/cloud/component_cloud_policy_service.h" | 5 #include "chrome/browser/policy/cloud/component_cloud_policy_service.h" |
| 6 | 6 |
| 7 #include <map> | |
| 8 #include <string> | 7 #include <string> |
| 9 #include <utility> | |
| 10 | 8 |
| 11 #include "base/bind.h" | 9 #include "base/bind.h" |
| 12 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
| 13 #include "base/location.h" | 11 #include "base/location.h" |
| 14 #include "base/logging.h" | 12 #include "base/logging.h" |
| 15 #include "base/message_loop/message_loop_proxy.h" | 13 #include "base/message_loop/message_loop_proxy.h" |
| 16 #include "base/pickle.h" | |
| 17 #include "base/sequenced_task_runner.h" | 14 #include "base/sequenced_task_runner.h" |
| 18 #include "base/stl_util.h" | 15 #include "base/time/time.h" |
| 16 #include "chrome/browser/policy/cloud/cloud_policy_constants.h" | |
| 19 #include "chrome/browser/policy/cloud/component_cloud_policy_store.h" | 17 #include "chrome/browser/policy/cloud/component_cloud_policy_store.h" |
| 20 #include "chrome/browser/policy/cloud/component_cloud_policy_updater.h" | 18 #include "chrome/browser/policy/cloud/component_cloud_policy_updater.h" |
| 21 #include "chrome/browser/policy/cloud/external_policy_data_fetcher.h" | 19 #include "chrome/browser/policy/cloud/external_policy_data_fetcher.h" |
| 22 #include "chrome/browser/policy/cloud/resource_cache.h" | 20 #include "chrome/browser/policy/cloud/resource_cache.h" |
| 23 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h" | 21 #include "chrome/browser/policy/proto/cloud/device_management_backend.pb.h" |
| 24 #include "chrome/browser/policy/schema_map.h" | 22 #include "chrome/browser/policy/schema_map.h" |
| 25 #include "components/policy/core/common/schema.h" | 23 #include "components/policy/core/common/schema.h" |
| 26 #include "net/url_request/url_request_context_getter.h" | 24 #include "net/url_request/url_request_context_getter.h" |
| 27 | 25 |
| 28 namespace em = enterprise_management; | 26 namespace em = enterprise_management; |
| 29 | 27 |
| 30 namespace policy { | 28 namespace policy { |
| 31 | 29 |
| 32 const char ComponentCloudPolicyService::kComponentNamespaceCache[] = | |
| 33 "component-namespace-cache"; | |
| 34 | |
| 35 namespace { | 30 namespace { |
| 36 | 31 |
| 37 bool NotInSchemaMap(const scoped_refptr<SchemaMap> schema_map, | 32 bool NotInSchemaMap(const scoped_refptr<SchemaMap> schema_map, |
| 38 PolicyDomain domain, | 33 PolicyDomain domain, |
| 39 const std::string& component_id) { | 34 const std::string& component_id) { |
| 40 return schema_map->GetSchema(PolicyNamespace(domain, component_id)) == NULL; | 35 return schema_map->GetSchema(PolicyNamespace(domain, component_id)) == NULL; |
| 41 } | 36 } |
| 42 | 37 |
| 38 bool ToPolicyNamespaceKey(const PolicyNamespace& ns, PolicyNamespaceKey* key) { | |
| 39 if (!ComponentCloudPolicyStore::GetPolicyType(ns.domain, &key->first)) | |
| 40 return false; | |
| 41 key->second = ns.component_id; | |
| 42 return true; | |
| 43 } | |
| 44 | |
| 45 bool ToPolicyNamespace(const PolicyNamespaceKey& key, PolicyNamespace* ns) { | |
| 46 if (!ComponentCloudPolicyStore::GetPolicyDomain(key.first, &ns->domain)) | |
| 47 return false; | |
| 48 ns->component_id = key.second; | |
| 49 return true; | |
| 50 } | |
| 51 | |
| 43 } // namespace | 52 } // namespace |
| 44 | 53 |
| 45 ComponentCloudPolicyService::Delegate::~Delegate() {} | 54 ComponentCloudPolicyService::Delegate::~Delegate() {} |
| 46 | 55 |
| 47 // Owns the objects that live on the background thread, and posts back to the | 56 // Owns the objects that live on the background thread, and posts back to the |
| 48 // thread that the ComponentCloudPolicyService runs on whenever the policy | 57 // thread that the ComponentCloudPolicyService runs on whenever the policy |
| 49 // changes. | 58 // changes. |
| 50 class ComponentCloudPolicyService::Backend | 59 class ComponentCloudPolicyService::Backend |
| 51 : public ComponentCloudPolicyStore::Delegate { | 60 : public ComponentCloudPolicyStore::Delegate { |
| 52 public: | 61 public: |
| 53 // This class can be instantiated on any thread but from then on, may be | 62 // This class can be instantiated on any thread but from then on, may be |
| 54 // accessed via the |task_runner_| only. Policy changes are posted to the | 63 // accessed via the |task_runner_| only. Policy changes are posted to the |
| 55 // |service| via the |service_task_runner|. The |cache| is used to load and | 64 // |service| via the |service_task_runner|. The |cache| is used to load and |
| 56 // store local copies of the downloaded policies. | 65 // store local copies of the downloaded policies. |
| 57 Backend(base::WeakPtr<ComponentCloudPolicyService> service, | 66 Backend(base::WeakPtr<ComponentCloudPolicyService> service, |
| 58 scoped_refptr<base::SequencedTaskRunner> task_runner, | 67 scoped_refptr<base::SequencedTaskRunner> task_runner, |
| 59 scoped_refptr<base::SequencedTaskRunner> service_task_runner, | 68 scoped_refptr<base::SequencedTaskRunner> service_task_runner, |
| 60 scoped_ptr<ResourceCache> cache); | 69 scoped_ptr<ResourceCache> cache, |
| 70 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher); | |
| 71 | |
| 61 virtual ~Backend(); | 72 virtual ~Backend(); |
| 62 | 73 |
| 63 // This is invoked right after the constructor but on the background thread. | 74 // |username| and |dm_token| will be used to validate the cached policies. |
| 64 // Used to create the store on the right thread. | 75 void SetCredentials(const std::string& username, const std::string& dm_token); |
| 65 void Init(); | |
| 66 | 76 |
| 67 // Reads the initial list of components and the initial policy. | 77 // Loads the |store_| and starts downloading updates. |
| 68 void FinalizeInit(); | 78 void Init(scoped_refptr<SchemaMap> schema_map); |
| 69 | |
| 70 // Allows downloading of external data via the |external_policy_data_fetcher|. | |
| 71 void Connect( | |
| 72 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher); | |
| 73 | |
| 74 // Stops updating remote data. Cached policies are still served. | |
| 75 void Disconnect(); | |
| 76 | |
| 77 // Loads the initial policies from the store. |username| and |dm_token| are | |
| 78 // used to validate the cached policies. | |
| 79 void SetCredentials(const std::string& username, const std::string& dm_token); | |
| 80 | 79 |
| 81 // Passes a policy protobuf to the backend, to start its validation and | 80 // Passes a policy protobuf to the backend, to start its validation and |
| 82 // eventual download of the policy data on the background thread. | 81 // eventual download of the policy data on the background thread. |
| 83 // This is ignored if the backend isn't connected. | |
| 84 void UpdateExternalPolicy(scoped_ptr<em::PolicyFetchResponse> response); | 82 void UpdateExternalPolicy(scoped_ptr<em::PolicyFetchResponse> response); |
| 85 | 83 |
| 86 // ComponentCloudPolicyStore::Delegate implementation: | 84 // ComponentCloudPolicyStore::Delegate implementation: |
| 87 virtual void OnComponentCloudPolicyStoreUpdated() OVERRIDE; | 85 virtual void OnComponentCloudPolicyStoreUpdated() OVERRIDE; |
| 88 | 86 |
| 89 // Passes the current SchemaMap so that the disk cache can purge components | 87 // Passes the current SchemaMap so that the disk cache can purge components |
| 90 // that aren't being tracked anymore. | 88 // that aren't being tracked anymore. |
| 91 void OnSchemasUpdated(scoped_refptr<SchemaMap> schema_map); | 89 // |removed| is a list of namespaces that were present in the previous |
| 90 // schema and have been removed in the updated version. | |
| 91 void OnSchemasUpdated(scoped_refptr<SchemaMap> schema_map, | |
| 92 scoped_ptr<PolicyNamespaceList> removed); | |
| 92 | 93 |
| 93 private: | 94 private: |
| 94 scoped_ptr<PolicyNamespaceKeys> ReadCachedComponents(); | |
| 95 | |
| 96 // The ComponentCloudPolicyService that owns |this|. Used to inform the | 95 // The ComponentCloudPolicyService that owns |this|. Used to inform the |
| 97 // |service_| when policy changes. | 96 // |service_| when policy changes. |
| 98 base::WeakPtr<ComponentCloudPolicyService> service_; | 97 base::WeakPtr<ComponentCloudPolicyService> service_; |
| 99 | 98 |
| 100 // The thread that |this| runs on. Used to post tasks to be run by |this|. | 99 // The thread that |this| runs on. Used to post tasks to be run by |this|. |
| 101 scoped_refptr<base::SequencedTaskRunner> task_runner_; | 100 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| 102 | 101 |
| 103 // The thread that the |service_| runs on. Used to post policy changes to the | 102 // The thread that the |service_| runs on. Used to post policy changes to the |
| 104 // right thread. | 103 // right thread. |
| 105 scoped_refptr<base::SequencedTaskRunner> service_task_runner_; | 104 scoped_refptr<base::SequencedTaskRunner> service_task_runner_; |
| 106 | 105 |
| 107 scoped_ptr<ResourceCache> cache_; | 106 scoped_ptr<ResourceCache> cache_; |
| 108 scoped_ptr<ComponentCloudPolicyStore> store_; | 107 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher_; |
| 108 ComponentCloudPolicyStore store_; | |
| 109 scoped_ptr<ComponentCloudPolicyUpdater> updater_; | 109 scoped_ptr<ComponentCloudPolicyUpdater> updater_; |
| 110 scoped_refptr<SchemaMap> schema_map_; | 110 scoped_refptr<SchemaMap> schema_map_; |
| 111 | 111 |
| 112 DISALLOW_COPY_AND_ASSIGN(Backend); | 112 DISALLOW_COPY_AND_ASSIGN(Backend); |
| 113 }; | 113 }; |
| 114 | 114 |
| 115 ComponentCloudPolicyService::Backend::Backend( | 115 ComponentCloudPolicyService::Backend::Backend( |
| 116 base::WeakPtr<ComponentCloudPolicyService> service, | 116 base::WeakPtr<ComponentCloudPolicyService> service, |
| 117 scoped_refptr<base::SequencedTaskRunner> task_runner, | 117 scoped_refptr<base::SequencedTaskRunner> task_runner, |
| 118 scoped_refptr<base::SequencedTaskRunner> service_task_runner, | 118 scoped_refptr<base::SequencedTaskRunner> service_task_runner, |
| 119 scoped_ptr<ResourceCache> cache) | 119 scoped_ptr<ResourceCache> cache, |
| 120 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher) | |
| 120 : service_(service), | 121 : service_(service), |
| 121 task_runner_(task_runner), | 122 task_runner_(task_runner), |
| 122 service_task_runner_(service_task_runner), | 123 service_task_runner_(service_task_runner), |
| 123 cache_(cache.Pass()) {} | 124 cache_(cache.Pass()), |
| 125 external_policy_data_fetcher_(external_policy_data_fetcher.Pass()), | |
| 126 store_(this, cache_.get()) {} | |
| 124 | 127 |
| 125 ComponentCloudPolicyService::Backend::~Backend() {} | 128 ComponentCloudPolicyService::Backend::~Backend() {} |
| 126 | 129 |
| 127 void ComponentCloudPolicyService::Backend::Init() { | 130 void ComponentCloudPolicyService::Backend::SetCredentials( |
| 128 DCHECK(!store_); | 131 const std::string& username, |
| 129 store_.reset(new ComponentCloudPolicyStore(this, cache_.get())); | 132 const std::string& dm_token) { |
| 133 store_.SetCredentials(username, dm_token); | |
| 130 } | 134 } |
| 131 | 135 |
| 132 void ComponentCloudPolicyService::Backend::FinalizeInit() { | 136 void ComponentCloudPolicyService::Backend::Init( |
| 133 // Read the components that were cached in the last OnSchemasUpdated() call. | 137 scoped_refptr<SchemaMap> schema_map) { |
| 134 scoped_ptr<PolicyNamespaceKeys> components = ReadCachedComponents(); | 138 DCHECK(!schema_map_); |
| 135 | 139 |
| 136 // Read the initial policy. | 140 OnSchemasUpdated(schema_map, scoped_ptr<PolicyNamespaceList>()); |
| 137 store_->Load(); | 141 |
| 138 scoped_ptr<PolicyBundle> policy(new PolicyBundle); | 142 // Read the initial policy. Note that this does not trigger notifications |
| 139 policy->CopyFrom(store_->policy()); | 143 // through OnComponentCloudPolicyStoreUpdated. |
| 144 store_.Load(); | |
| 145 scoped_ptr<PolicyBundle> bundle(new PolicyBundle); | |
| 146 bundle->CopyFrom(store_.policy()); | |
| 147 | |
| 148 // Start downloading any pending data. | |
| 149 updater_.reset(new ComponentCloudPolicyUpdater( | |
| 150 task_runner_, external_policy_data_fetcher_.Pass(), &store_)); | |
| 140 | 151 |
| 141 service_task_runner_->PostTask( | 152 service_task_runner_->PostTask( |
| 142 FROM_HERE, | 153 FROM_HERE, |
| 143 base::Bind(&ComponentCloudPolicyService::OnBackendInitialized, | 154 base::Bind(&ComponentCloudPolicyService::OnBackendInitialized, |
| 144 service_, | 155 service_, |
| 145 base::Passed(&components), | 156 base::Passed(&bundle))); |
| 146 base::Passed(&policy))); | |
| 147 } | |
| 148 | |
| 149 void ComponentCloudPolicyService::Backend::SetCredentials( | |
| 150 const std::string& username, | |
| 151 const std::string& dm_token) { | |
| 152 store_->SetCredentials(username, dm_token); | |
| 153 } | |
| 154 | |
| 155 void ComponentCloudPolicyService::Backend::Connect( | |
| 156 scoped_ptr<ExternalPolicyDataFetcher> external_policy_data_fetcher) { | |
| 157 updater_.reset(new ComponentCloudPolicyUpdater( | |
| 158 task_runner_, | |
| 159 external_policy_data_fetcher.Pass(), | |
| 160 store_.get())); | |
| 161 } | |
| 162 | |
| 163 void ComponentCloudPolicyService::Backend::Disconnect() { | |
| 164 updater_.reset(); | |
| 165 } | 157 } |
| 166 | 158 |
| 167 void ComponentCloudPolicyService::Backend::UpdateExternalPolicy( | 159 void ComponentCloudPolicyService::Backend::UpdateExternalPolicy( |
| 168 scoped_ptr<em::PolicyFetchResponse> response) { | 160 scoped_ptr<em::PolicyFetchResponse> response) { |
| 169 if (updater_) | 161 updater_->UpdateExternalPolicy(response.Pass()); |
| 170 updater_->UpdateExternalPolicy(response.Pass()); | |
| 171 } | 162 } |
| 172 | 163 |
| 173 void ComponentCloudPolicyService::Backend:: | 164 void ComponentCloudPolicyService::Backend:: |
| 174 OnComponentCloudPolicyStoreUpdated() { | 165 OnComponentCloudPolicyStoreUpdated() { |
| 175 if (!schema_map_) { | 166 if (!schema_map_) { |
| 176 // No schemas have been registered yet, so keep serving the initial policy | 167 // Ignore notifications triggered by the initial Purge. |
| 177 // obtained from FinalizeInit(). | |
| 178 return; | 168 return; |
| 179 } | 169 } |
| 180 | 170 |
| 181 scoped_ptr<PolicyBundle> bundle(new PolicyBundle); | 171 scoped_ptr<PolicyBundle> bundle(new PolicyBundle); |
| 182 bundle->CopyFrom(store_->policy()); | 172 bundle->CopyFrom(store_.policy()); |
| 183 schema_map_->FilterBundle(bundle.get()); | 173 schema_map_->FilterBundle(bundle.get()); |
| 184 service_task_runner_->PostTask( | 174 service_task_runner_->PostTask( |
| 185 FROM_HERE, | 175 FROM_HERE, |
| 186 base::Bind(&ComponentCloudPolicyService::OnPolicyUpdated, | 176 base::Bind(&ComponentCloudPolicyService::OnPolicyUpdated, |
| 187 service_, | 177 service_, |
| 188 base::Passed(&bundle))); | 178 base::Passed(&bundle))); |
| 189 } | 179 } |
| 190 | 180 |
| 191 void ComponentCloudPolicyService::Backend::OnSchemasUpdated( | 181 void ComponentCloudPolicyService::Backend::OnSchemasUpdated( |
| 192 scoped_refptr<SchemaMap> schema_map) { | 182 scoped_refptr<SchemaMap> schema_map, |
| 193 // Store the current list of components in the cache. | 183 scoped_ptr<PolicyNamespaceList> removed) { |
| 184 // Purge any components that have been removed. | |
| 194 const DomainMap& domains = schema_map->GetDomains(); | 185 const DomainMap& domains = schema_map->GetDomains(); |
| 195 for (DomainMap::const_iterator domain = domains.begin(); | 186 for (DomainMap::const_iterator domain = domains.begin(); |
| 196 domain != domains.end(); ++domain) { | 187 domain != domains.end(); ++domain) { |
| 197 std::string domain_policy_type; | 188 store_.Purge(domain->first, |
| 198 if (!ComponentCloudPolicyStore::GetPolicyType(domain->first, | 189 base::Bind(&NotInSchemaMap, schema_map, domain->first)); |
| 199 &domain_policy_type)) { | |
| 200 continue; | |
| 201 } | |
| 202 Pickle pickle; | |
| 203 const ComponentMap& components = domain->second; | |
| 204 for (ComponentMap::const_iterator comp = components.begin(); | |
| 205 comp != components.end(); ++comp) { | |
| 206 pickle.WriteString(comp->first); | |
| 207 } | |
| 208 std::string data(reinterpret_cast<const char*>(pickle.data()), | |
| 209 pickle.size()); | |
| 210 cache_->Store(kComponentNamespaceCache, domain_policy_type, data); | |
| 211 | |
| 212 // Purge any components that have been removed. | |
| 213 if (store_) { | |
| 214 store_->Purge(domain->first, | |
| 215 base::Bind(&NotInSchemaMap, schema_map, domain->first)); | |
| 216 } | |
| 217 } | 190 } |
| 218 | 191 |
| 219 // Serve policies that may have updated while the backend was waiting for | 192 // Set |schema_map_| after purging so that the notifications from the store |
| 220 // the schema_map. | 193 // are ignored on the first OnSchemasUpdated() call from Init(). |
| 221 const bool trigger_update = !schema_map_; | |
| 222 schema_map_ = schema_map; | 194 schema_map_ = schema_map; |
| 223 if (trigger_update) | |
| 224 OnComponentCloudPolicyStoreUpdated(); | |
| 225 } | |
| 226 | 195 |
| 227 scoped_ptr<ComponentCloudPolicyService::PolicyNamespaceKeys> | 196 if (removed) { |
| 228 ComponentCloudPolicyService::Backend::ReadCachedComponents() { | 197 for (size_t i = 0; i < removed->size(); ++i) |
| 229 scoped_ptr<PolicyNamespaceKeys> keys(new PolicyNamespaceKeys); | 198 updater_->CancelUpdate((*removed)[i]); |
| 230 std::map<std::string, std::string> contents; | |
| 231 cache_->LoadAllSubkeys(kComponentNamespaceCache, &contents); | |
| 232 for (std::map<std::string, std::string>::iterator it = contents.begin(); | |
| 233 it != contents.end(); ++it) { | |
| 234 PolicyDomain domain; | |
| 235 if (ComponentCloudPolicyStore::GetPolicyDomain(it->first, &domain)) { | |
| 236 const Pickle pickle(it->second.data(), it->second.size()); | |
| 237 PickleIterator pickit(pickle); | |
| 238 std::string id; | |
| 239 while (pickit.ReadString(&id)) | |
| 240 keys->insert(std::make_pair(it->first, id)); | |
| 241 } else { | |
| 242 cache_->Delete(kComponentNamespaceCache, it->first); | |
| 243 } | |
| 244 } | 199 } |
| 245 return keys.Pass(); | |
| 246 } | 200 } |
| 247 | 201 |
| 248 ComponentCloudPolicyService::ComponentCloudPolicyService( | 202 ComponentCloudPolicyService::ComponentCloudPolicyService( |
| 249 Delegate* delegate, | 203 Delegate* delegate, |
| 204 SchemaRegistry* schema_registry, | |
| 250 CloudPolicyStore* store, | 205 CloudPolicyStore* store, |
| 251 scoped_ptr<ResourceCache> cache, | 206 scoped_ptr<ResourceCache> cache, |
| 207 CloudPolicyClient* client, | |
| 208 scoped_refptr<net::URLRequestContextGetter> request_context, | |
| 252 scoped_refptr<base::SequencedTaskRunner> backend_task_runner, | 209 scoped_refptr<base::SequencedTaskRunner> backend_task_runner, |
| 253 scoped_refptr<base::SequencedTaskRunner> io_task_runner) | 210 scoped_refptr<base::SequencedTaskRunner> io_task_runner) |
| 254 : delegate_(delegate), | 211 : delegate_(delegate), |
| 212 schema_registry_(schema_registry), | |
| 213 store_(store), | |
| 214 client_(client), | |
| 215 request_context_(request_context), | |
| 255 backend_task_runner_(backend_task_runner), | 216 backend_task_runner_(backend_task_runner), |
| 256 io_task_runner_(io_task_runner), | 217 io_task_runner_(io_task_runner), |
| 257 client_(NULL), | 218 current_schema_map_(new SchemaMap), |
| 258 store_(store), | 219 schema_update_timer_(false, false), |
|
bartfab (slow)
2013/11/15 12:20:31
Nit: If you used a OneShotTimer instead of a Timer
Joao da Silva
2013/11/15 14:58:08
Dude, I can't read code. I thought again that OneS
| |
| 259 is_initialized_(false), | 220 is_initialized_(false), |
| 260 has_initial_keys_(false), | 221 has_credentials_(false), |
| 261 weak_ptr_factory_(this) { | 222 weak_ptr_factory_(this) { |
| 223 schema_registry_->AddObserver(this); | |
| 262 store_->AddObserver(this); | 224 store_->AddObserver(this); |
| 225 client_->AddObserver(this); | |
| 263 | 226 |
| 264 backend_.reset(new Backend(weak_ptr_factory_.GetWeakPtr(), | 227 external_policy_data_fetcher_backend_.reset( |
| 265 backend_task_runner_, | 228 new ExternalPolicyDataFetcherBackend(io_task_runner_, request_context)); |
| 266 base::MessageLoopProxy::current(), | 229 |
| 267 cache.Pass())); | 230 backend_.reset( |
| 268 backend_task_runner_->PostTask( | 231 new Backend(weak_ptr_factory_.GetWeakPtr(), |
| 269 FROM_HERE, base::Bind(&Backend::Init, base::Unretained(backend_.get()))); | 232 backend_task_runner_, |
| 233 base::MessageLoopProxy::current(), | |
| 234 cache.Pass(), | |
| 235 external_policy_data_fetcher_backend_->CreateFrontend( | |
| 236 backend_task_runner_))); | |
| 270 | 237 |
| 271 if (store_->is_initialized()) | 238 if (store_->is_initialized()) |
| 272 InitializeBackend(); | 239 OnStoreLoaded(store_); |
| 273 } | 240 } |
| 274 | 241 |
| 275 ComponentCloudPolicyService::~ComponentCloudPolicyService() { | 242 ComponentCloudPolicyService::~ComponentCloudPolicyService() { |
| 276 DCHECK(CalledOnValidThread()); | 243 DCHECK(CalledOnValidThread()); |
| 244 schema_registry_->RemoveObserver(this); | |
| 277 store_->RemoveObserver(this); | 245 store_->RemoveObserver(this); |
| 278 if (client_) | 246 client_->RemoveObserver(this); |
| 279 client_->RemoveObserver(this); | 247 |
| 248 // Remove all the namespaces from |client_| but don't send this empty schema | |
| 249 // to the backend, to avoid dropping the caches. | |
| 250 if (is_initialized()) { | |
| 251 scoped_refptr<SchemaMap> empty(new SchemaMap); | |
| 252 SetCurrentSchema(empty, false); | |
| 253 } | |
| 254 | |
| 280 io_task_runner_->DeleteSoon(FROM_HERE, | 255 io_task_runner_->DeleteSoon(FROM_HERE, |
| 281 external_policy_data_fetcher_backend_.release()); | 256 external_policy_data_fetcher_backend_.release()); |
| 282 backend_task_runner_->DeleteSoon(FROM_HERE, backend_.release()); | 257 backend_task_runner_->DeleteSoon(FROM_HERE, backend_.release()); |
| 283 } | 258 } |
| 284 | 259 |
| 285 // static | 260 // static |
| 286 bool ComponentCloudPolicyService::SupportsDomain(PolicyDomain domain) { | 261 bool ComponentCloudPolicyService::SupportsDomain(PolicyDomain domain) { |
| 287 return ComponentCloudPolicyStore::SupportsDomain(domain); | 262 return ComponentCloudPolicyStore::SupportsDomain(domain); |
| 288 } | 263 } |
| 289 | 264 |
| 290 void ComponentCloudPolicyService::Connect( | |
| 291 CloudPolicyClient* client, | |
| 292 scoped_refptr<net::URLRequestContextGetter> request_context) { | |
| 293 DCHECK(CalledOnValidThread()); | |
| 294 DCHECK(!client_); | |
| 295 client_ = client; | |
| 296 client_->AddObserver(this); | |
| 297 DCHECK(!external_policy_data_fetcher_backend_); | |
| 298 external_policy_data_fetcher_backend_.reset( | |
| 299 new ExternalPolicyDataFetcherBackend(io_task_runner_, | |
| 300 request_context)); | |
| 301 // Create the updater in the backend. | |
| 302 backend_task_runner_->PostTask(FROM_HERE, base::Bind( | |
| 303 &Backend::Connect, | |
| 304 base::Unretained(backend_.get()), | |
| 305 base::Passed(external_policy_data_fetcher_backend_->CreateFrontend( | |
| 306 backend_task_runner_)))); | |
| 307 if (is_initialized()) | |
| 308 InitializeClient(); | |
| 309 } | |
| 310 | |
| 311 void ComponentCloudPolicyService::Disconnect() { | |
| 312 DCHECK(CalledOnValidThread()); | |
| 313 if (client_) { | |
| 314 // Unregister all the current components. | |
| 315 RemoveNamespacesToFetch(keys_); | |
| 316 | |
| 317 client_->RemoveObserver(this); | |
| 318 client_ = NULL; | |
| 319 | |
| 320 io_task_runner_->DeleteSoon( | |
| 321 FROM_HERE, external_policy_data_fetcher_backend_.release()); | |
| 322 backend_task_runner_->PostTask( | |
| 323 FROM_HERE, | |
| 324 base::Bind(&Backend::Disconnect, base::Unretained(backend_.get()))); | |
| 325 } | |
| 326 } | |
| 327 | |
| 328 void ComponentCloudPolicyService::OnSchemasUpdated( | |
| 329 const scoped_refptr<SchemaMap>& schema_map) { | |
| 330 DCHECK(CalledOnValidThread()); | |
| 331 | |
| 332 // Send the new schemas to the backend, to purge the cache. | |
| 333 backend_task_runner_->PostTask(FROM_HERE, | |
| 334 base::Bind(&Backend::OnSchemasUpdated, | |
| 335 base::Unretained(backend_.get()), | |
| 336 schema_map)); | |
| 337 | |
| 338 // Register the current list of components for supported domains at the | |
| 339 // |client_|. | |
| 340 PolicyNamespaceKeys new_keys; | |
| 341 const DomainMap& domains = schema_map->GetDomains(); | |
| 342 for (DomainMap::const_iterator domain = domains.begin(); | |
| 343 domain != domains.end(); ++domain) { | |
| 344 std::string domain_policy_type; | |
| 345 if (!ComponentCloudPolicyStore::GetPolicyType(domain->first, | |
| 346 &domain_policy_type)) { | |
| 347 continue; | |
| 348 } | |
| 349 const ComponentMap& components = domain->second; | |
| 350 for (ComponentMap::const_iterator comp = components.begin(); | |
| 351 comp != components.end(); ++comp) { | |
| 352 new_keys.insert(std::make_pair(domain_policy_type, comp->first)); | |
| 353 } | |
| 354 } | |
| 355 | |
| 356 if (client_ && is_initialized() && UpdateClientNamespaces(keys_, new_keys)) | |
| 357 delegate_->OnComponentCloudPolicyRefreshNeeded(); | |
| 358 | |
| 359 keys_.swap(new_keys); | |
| 360 has_initial_keys_ = true; | |
| 361 } | |
| 362 | |
| 363 void ComponentCloudPolicyService::OnPolicyFetched(CloudPolicyClient* client) { | 265 void ComponentCloudPolicyService::OnPolicyFetched(CloudPolicyClient* client) { |
| 364 DCHECK(CalledOnValidThread()); | 266 DCHECK(CalledOnValidThread()); |
| 365 DCHECK_EQ(client_, client); | 267 DCHECK_EQ(client_, client); |
| 268 | |
| 269 if (!is_initialized() || !has_credentials_) | |
| 270 return; | |
| 271 | |
| 366 // Pass each PolicyFetchResponse whose policy type is registered to the | 272 // Pass each PolicyFetchResponse whose policy type is registered to the |
| 367 // Backend. | 273 // Backend. |
| 368 const CloudPolicyClient::ResponseMap& responses = client_->responses(); | 274 const CloudPolicyClient::ResponseMap& responses = client_->responses(); |
| 369 for (CloudPolicyClient::ResponseMap::const_iterator it = responses.begin(); | 275 for (CloudPolicyClient::ResponseMap::const_iterator it = responses.begin(); |
| 370 it != responses.end(); ++it) { | 276 it != responses.end(); ++it) { |
| 371 const PolicyNamespaceKey& key(it->first); | 277 PolicyNamespace ns; |
| 372 if (ContainsKey(keys_, key)) { | 278 if (ToPolicyNamespace(it->first, &ns) && |
| 279 current_schema_map_->GetSchema(ns)) { | |
| 373 scoped_ptr<em::PolicyFetchResponse> response( | 280 scoped_ptr<em::PolicyFetchResponse> response( |
| 374 new em::PolicyFetchResponse(*it->second)); | 281 new em::PolicyFetchResponse(*it->second)); |
| 375 backend_task_runner_->PostTask( | 282 backend_task_runner_->PostTask( |
| 376 FROM_HERE, | 283 FROM_HERE, |
| 377 base::Bind(&Backend::UpdateExternalPolicy, | 284 base::Bind(&Backend::UpdateExternalPolicy, |
| 378 base::Unretained(backend_.get()), | 285 base::Unretained(backend_.get()), |
| 379 base::Passed(&response))); | 286 base::Passed(&response))); |
| 380 } | 287 } |
| 381 } | 288 } |
| 382 } | 289 } |
| 383 | 290 |
| 384 void ComponentCloudPolicyService::OnRegistrationStateChanged( | 291 void ComponentCloudPolicyService::OnRegistrationStateChanged( |
| 385 CloudPolicyClient* client) { | 292 CloudPolicyClient* client) { |
| 386 DCHECK(CalledOnValidThread()); | 293 DCHECK(CalledOnValidThread()); |
| 387 // Ignored. | 294 // Ignored. |
| 388 } | 295 } |
| 389 | 296 |
| 390 void ComponentCloudPolicyService::OnClientError(CloudPolicyClient* client) { | 297 void ComponentCloudPolicyService::OnClientError(CloudPolicyClient* client) { |
| 391 DCHECK(CalledOnValidThread()); | 298 DCHECK(CalledOnValidThread()); |
| 392 // Ignored. | 299 // Ignored. |
| 393 } | 300 } |
| 394 | 301 |
| 395 void ComponentCloudPolicyService::OnStoreLoaded(CloudPolicyStore* store) { | 302 void ComponentCloudPolicyService::OnStoreLoaded(CloudPolicyStore* store) { |
| 396 DCHECK(CalledOnValidThread()); | 303 DCHECK(CalledOnValidThread()); |
| 397 DCHECK_EQ(store_, store); | 304 DCHECK_EQ(store_, store); |
| 398 if (store_->is_initialized()) { | 305 |
| 306 if (!store_->is_initialized()) | |
| 307 return; | |
| 308 | |
| 309 // Send the current credentials to the backend, if they haven't been sent | |
|
bartfab (slow)
2013/11/15 12:20:31
Nit: This comment says that credentials are sent i
Joao da Silva
2013/11/15 14:58:08
Done.
| |
| 310 // before. Usually this happens at startup if the user already had a cached | |
| 311 // cloud policy; otherwise it happens right after the initial registration | |
| 312 // for cloud policy. | |
| 313 const em::PolicyData* policy = store_->policy(); | |
| 314 if (!has_credentials_ && policy && policy->has_username() && | |
| 315 policy->has_request_token()) { | |
| 316 backend_task_runner_->PostTask(FROM_HERE, | |
| 317 base::Bind(&Backend::SetCredentials, | |
| 318 base::Unretained(backend_.get()), | |
| 319 policy->username(), | |
| 320 policy->request_token())); | |
| 321 has_credentials_ = true; | |
| 399 if (is_initialized()) { | 322 if (is_initialized()) { |
| 400 // The backend is already initialized; update the credentials, in case | 323 // This was the first policy fetch for this client. Process any |
| 401 // a new dmtoken or server key became available. | 324 // PolicyFetchResponses that the client may have now; processing them |
| 402 SetCredentialsAndReloadClient(); | 325 // before the credentials were sent to the backend would fail validation. |
| 403 } else { | 326 OnPolicyFetched(client_); |
| 404 // The |store_| just became ready; initialize the backend now. | |
| 405 InitializeBackend(); | |
| 406 } | 327 } |
| 407 } | 328 } |
| 329 | |
| 330 if (!is_initialized()) | |
| 331 InitializeIfReady(); | |
| 408 } | 332 } |
| 409 | 333 |
| 410 void ComponentCloudPolicyService::OnStoreError(CloudPolicyStore* store) { | 334 void ComponentCloudPolicyService::OnStoreError(CloudPolicyStore* store) { |
| 411 DCHECK(CalledOnValidThread()); | 335 DCHECK(CalledOnValidThread()); |
| 412 OnStoreLoaded(store); | 336 OnStoreLoaded(store); |
| 413 } | 337 } |
| 414 | 338 |
| 415 void ComponentCloudPolicyService::InitializeBackend() { | 339 void ComponentCloudPolicyService::OnSchemaRegistryReady() { |
| 416 DCHECK(CalledOnValidThread()); | 340 DCHECK(CalledOnValidThread()); |
| 417 DCHECK(!is_initialized()); | 341 InitializeIfReady(); |
| 418 DCHECK(store_->is_initialized()); | 342 } |
| 419 | 343 |
| 420 // Set the credentials for the initial policy load, if available. | 344 void ComponentCloudPolicyService::OnSchemaRegistryUpdated( |
| 421 SetCredentialsAndReloadClient(); | 345 bool has_new_schemas) { |
| 346 DCHECK(CalledOnValidThread()); | |
| 422 | 347 |
| 423 backend_task_runner_->PostTask( | 348 if (!is_initialized()) |
| 349 return; | |
| 350 | |
| 351 // When an extension is reloaded or updated, it triggers an unregister quickly | |
| 352 // followed by a register in the SchemaRegistry. If the intermediate version | |
| 353 // of the SchemaMap is passed to the backend then it will drop the cached | |
| 354 // policy for that extension and will trigger a new policy fetch soon after. | |
| 355 // Delaying the schema update here coalesces both updates into one, and the | |
| 356 // new schema will equal the older version in case of extension updates. | |
| 357 // | |
| 358 // TODO(joaodasilva): Increase this delay to 10 seconds. For now it's | |
| 359 // immediate so that tests don't get delayed. | |
| 360 schema_update_timer_.Start( | |
| 424 FROM_HERE, | 361 FROM_HERE, |
| 425 base::Bind(&Backend::FinalizeInit, base::Unretained(backend_.get()))); | 362 base::TimeDelta::FromSeconds(0), |
| 363 base::Bind(&ComponentCloudPolicyService::SetCurrentSchema, | |
| 364 base::Unretained(this), | |
| 365 schema_registry_->schema_map(), | |
| 366 true)); | |
| 367 } | |
| 368 | |
| 369 void ComponentCloudPolicyService::InitializeIfReady() { | |
| 370 DCHECK(CalledOnValidThread()); | |
| 371 if (!schema_registry_->IsReady() || !store_->is_initialized()) | |
| 372 return; | |
| 373 backend_task_runner_->PostTask(FROM_HERE, | |
| 374 base::Bind(&Backend::Init, | |
| 375 base::Unretained(backend_.get()), | |
| 376 schema_registry_->schema_map())); | |
| 426 } | 377 } |
| 427 | 378 |
| 428 void ComponentCloudPolicyService::OnBackendInitialized( | 379 void ComponentCloudPolicyService::OnBackendInitialized( |
| 429 scoped_ptr<PolicyNamespaceKeys> initial_keys, | |
| 430 scoped_ptr<PolicyBundle> initial_policy) { | 380 scoped_ptr<PolicyBundle> initial_policy) { |
| 431 DCHECK(CalledOnValidThread()); | 381 DCHECK(CalledOnValidThread()); |
| 432 // InitializeBackend() may be called multiple times if the |store_| fires | |
| 433 // events while the backend is loading. | |
| 434 if (is_initialized()) | |
| 435 return; | |
| 436 | 382 |
| 437 // OnSchemasUpdated() may have been called while the backend was initializing; | 383 is_initialized_ = true; |
| 438 // in that case ignore the cached keys. | |
| 439 if (!has_initial_keys_) | |
| 440 keys_.swap(*initial_keys); | |
| 441 | 384 |
| 442 // A client may have already connected while the backend was initializing. | 385 // Send the current schema to the backend, in case it has changed while the |
| 443 if (client_) | 386 // backend was initializing. |
| 444 InitializeClient(); | 387 SetCurrentSchema(schema_registry_->schema_map(), true); |
| 445 | 388 |
| 446 // Set the initial policy, and send the initial update callback. | 389 // Process any PolicyFetchResponses that the client may already have, or that |
| 447 is_initialized_ = true; | 390 // may have been received while the backend was initializing. |
| 391 OnPolicyFetched(client_); | |
| 392 | |
| 393 // Finally tell the Delegate that the initial policy is available. | |
| 448 OnPolicyUpdated(initial_policy.Pass()); | 394 OnPolicyUpdated(initial_policy.Pass()); |
| 449 } | 395 } |
| 450 | 396 |
| 451 void ComponentCloudPolicyService::InitializeClient() { | 397 void ComponentCloudPolicyService::SetCurrentSchema( |
| 398 const scoped_refptr<SchemaMap>& new_schema_map, | |
| 399 bool send_to_backend) { | |
| 452 DCHECK(CalledOnValidThread()); | 400 DCHECK(CalledOnValidThread()); |
| 453 // Register all the current components. | 401 DCHECK(is_initialized()); |
| 454 AddNamespacesToFetch(keys_); | 402 |
| 455 // The client may already have PolicyFetchResponses for registered components; | 403 scoped_ptr<PolicyNamespaceList> removed(new PolicyNamespaceList); |
| 456 // load them now. | 404 PolicyNamespaceList added; |
| 457 OnPolicyFetched(client_); | 405 new_schema_map->GetChanges(current_schema_map_, removed.get(), &added); |
| 458 if (!keys_.empty() && is_initialized()) | 406 |
| 407 current_schema_map_ = new_schema_map; | |
| 408 | |
| 409 for (size_t i = 0; i < removed->size(); ++i) { | |
| 410 PolicyNamespaceKey key; | |
| 411 if (ToPolicyNamespaceKey((*removed)[i], &key)) | |
| 412 client_->RemoveNamespaceToFetch(key); | |
| 413 } | |
| 414 | |
| 415 bool added_namespaces_to_client = false; | |
| 416 for (size_t i = 0; i < added.size(); ++i) { | |
| 417 PolicyNamespaceKey key; | |
| 418 if (ToPolicyNamespaceKey(added[i], &key)) { | |
| 419 client_->AddNamespaceToFetch(key); | |
| 420 added_namespaces_to_client = true; | |
| 421 } | |
| 422 } | |
| 423 | |
| 424 if (added_namespaces_to_client) | |
| 459 delegate_->OnComponentCloudPolicyRefreshNeeded(); | 425 delegate_->OnComponentCloudPolicyRefreshNeeded(); |
| 426 | |
| 427 if (send_to_backend) { | |
| 428 backend_task_runner_->PostTask(FROM_HERE, | |
| 429 base::Bind(&Backend::OnSchemasUpdated, | |
| 430 base::Unretained(backend_.get()), | |
| 431 current_schema_map_, | |
| 432 base::Passed(&removed))); | |
| 433 } | |
| 460 } | 434 } |
| 461 | 435 |
| 462 void ComponentCloudPolicyService::OnPolicyUpdated( | 436 void ComponentCloudPolicyService::OnPolicyUpdated( |
| 463 scoped_ptr<PolicyBundle> policy) { | 437 scoped_ptr<PolicyBundle> policy) { |
| 464 DCHECK(CalledOnValidThread()); | 438 DCHECK(CalledOnValidThread()); |
| 465 policy_.Swap(policy.get()); | 439 policy_.Swap(policy.get()); |
| 466 // Don't propagate updates until the initial store Load() has been done. | 440 delegate_->OnComponentCloudPolicyUpdated(); |
| 467 if (is_initialized()) | |
| 468 delegate_->OnComponentCloudPolicyUpdated(); | |
| 469 } | |
| 470 | |
| 471 void ComponentCloudPolicyService::SetCredentialsAndReloadClient() { | |
| 472 DCHECK(CalledOnValidThread()); | |
| 473 const em::PolicyData* policy = store_->policy(); | |
| 474 if (!policy || !policy->has_username() || !policy->has_request_token()) | |
| 475 return; | |
| 476 backend_task_runner_->PostTask(FROM_HERE, | |
| 477 base::Bind(&Backend::SetCredentials, | |
| 478 base::Unretained(backend_.get()), | |
| 479 policy->username(), | |
| 480 policy->request_token())); | |
| 481 // If this was the initial register, or if the signing key changed, then the | |
| 482 // previous OnPolicyFetched() call had its PolicyFetchResponses rejected | |
| 483 // because the credentials weren't updated yet. Reload all the responses in | |
| 484 // the client now to handle those cases; if those responses have already been | |
| 485 // validated then they will be ignored. | |
| 486 if (client_) | |
| 487 OnPolicyFetched(client_); | |
| 488 } | |
| 489 | |
| 490 bool ComponentCloudPolicyService::UpdateClientNamespaces( | |
| 491 const PolicyNamespaceKeys& old_keys, | |
| 492 const PolicyNamespaceKeys& new_keys) { | |
| 493 DCHECK(CalledOnValidThread()); | |
| 494 PolicyNamespaceKeys added = | |
| 495 base::STLSetDifference<PolicyNamespaceKeys>(new_keys, old_keys); | |
| 496 PolicyNamespaceKeys removed = | |
| 497 base::STLSetDifference<PolicyNamespaceKeys>(old_keys, new_keys); | |
| 498 AddNamespacesToFetch(added); | |
| 499 RemoveNamespacesToFetch(removed); | |
| 500 return !added.empty(); | |
| 501 } | |
| 502 | |
| 503 void ComponentCloudPolicyService::AddNamespacesToFetch( | |
| 504 const PolicyNamespaceKeys& keys) { | |
| 505 DCHECK(CalledOnValidThread()); | |
| 506 for (PolicyNamespaceKeys::const_iterator it = keys.begin(); | |
| 507 it != keys.end(); ++it) { | |
| 508 client_->AddNamespaceToFetch(*it); | |
| 509 } | |
| 510 } | |
| 511 | |
| 512 void ComponentCloudPolicyService::RemoveNamespacesToFetch( | |
| 513 const PolicyNamespaceKeys& keys) { | |
| 514 DCHECK(CalledOnValidThread()); | |
| 515 for (PolicyNamespaceKeys::const_iterator it = keys.begin(); | |
| 516 it != keys.end(); ++it) { | |
| 517 client_->RemoveNamespaceToFetch(*it); | |
| 518 } | |
| 519 } | 441 } |
| 520 | 442 |
| 521 } // namespace policy | 443 } // namespace policy |
| OLD | NEW |