1 // Copyright 2014 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 "chrome/browser/chromeos/policy/device_cloud_policy_invalidator.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "base/time/clock.h"
13 #include "base/time/default_clock.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/browser_process_platform_part_chromeos.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
18 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
19 #include "chrome/browser/chromeos/policy/ticl_device_settings_provider.h"
20 #include "chrome/browser/chromeos/settings/device_identity_provider.h"
21 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
22 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
23 #include "chrome/browser/policy/cloud/cloud_policy_invalidator.h"
24 #include "chrome/browser/profiles/profile_manager.h"
25 #include "chrome/common/chrome_content_client.h"
26 #include "components/invalidation/invalidation_handler.h"
27 #include "components/invalidation/invalidation_service.h"
28 #include "components/invalidation/invalidation_state_tracker.h"
29 #include "components/invalidation/invalidator_state.h"
30 #include "components/invalidation/invalidator_storage.h"
31 #include "components/invalidation/profile_invalidation_provider.h"
32 #include "components/invalidation/ticl_invalidation_service.h"
33 #include "components/invalidation/ticl_settings_provider.h"
34 #include "content/public/browser/notification_details.h"
35 #include "content/public/browser/notification_service.h"
36 #include "google_apis/gaia/identity_provider.h"
37 #include "net/url_request/url_request_context_getter.h"
38 #include "policy/proto/device_management_backend.pb.h"
44 class DeviceCloudPolicyInvalidator::InvalidationServiceObserver
45 : public syncer::InvalidationHandler {
47 explicit InvalidationServiceObserver(
48 DeviceCloudPolicyInvalidator* parent,
49 invalidation::InvalidationService* invalidation_service);
50 virtual ~InvalidationServiceObserver();
52 invalidation::InvalidationService* GetInvalidationService();
53 bool IsServiceConnected() const;
55 // public syncer::InvalidationHandler:
56 virtual void OnInvalidatorStateChange(
57 syncer::InvalidatorState state) OVERRIDE;
58 virtual void OnIncomingInvalidation(
59 const syncer::ObjectIdInvalidationMap& invalidation_map) OVERRIDE;
60 virtual std::string GetOwnerName() const OVERRIDE;
63 DeviceCloudPolicyInvalidator* parent_;
64 invalidation::InvalidationService* invalidation_service_;
65 bool is_service_connected_;
67 DISALLOW_COPY_AND_ASSIGN(InvalidationServiceObserver);
70 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
71 InvalidationServiceObserver(
72 DeviceCloudPolicyInvalidator* parent,
73 invalidation::InvalidationService* invalidation_service)
75 invalidation_service_(invalidation_service),
76 is_service_connected_(invalidation_service->GetInvalidatorState() ==
77 syncer::INVALIDATIONS_ENABLED) {
78 invalidation_service_->RegisterInvalidationHandler(this);
81 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
82 ~InvalidationServiceObserver() {
83 invalidation_service_->UnregisterInvalidationHandler(this);
86 invalidation::InvalidationService*
87 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
88 GetInvalidationService() {
89 return invalidation_service_;
92 bool DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
93 IsServiceConnected() const {
94 return is_service_connected_;
97 void DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
98 OnInvalidatorStateChange(syncer::InvalidatorState state) {
99 const bool is_service_connected = (state == syncer::INVALIDATIONS_ENABLED);
100 if (is_service_connected == is_service_connected_)
103 is_service_connected_ = is_service_connected;
104 if (is_service_connected_)
105 parent_->OnInvalidationServiceConnected(invalidation_service_);
107 parent_->OnInvalidationServiceDisconnected(invalidation_service_);
110 void DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
111 OnIncomingInvalidation(
112 const syncer::ObjectIdInvalidationMap& invalidation_map) {
115 std::string DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
116 GetOwnerName() const {
117 return "DevicePolicy";
120 DeviceCloudPolicyInvalidator::DeviceCloudPolicyInvalidator()
121 : invalidation_service_(NULL),
122 highest_handled_invalidation_version_(0) {
123 // The DeviceCloudPolicyInvalidator should be created before any user
125 DCHECK(g_browser_process->profile_manager()->GetLoadedProfiles().empty());
127 // Subscribe to notification about new user profiles becoming available.
129 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
130 content::NotificationService::AllSources());
132 TryToCreateInvalidator();
135 DeviceCloudPolicyInvalidator::~DeviceCloudPolicyInvalidator() {
136 DestroyInvalidator();
139 void DeviceCloudPolicyInvalidator::Observe(
141 const content::NotificationSource& source,
142 const content::NotificationDetails& details) {
143 DCHECK_EQ(chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, type);
144 invalidation::ProfileInvalidationProvider* invalidation_provider =
145 invalidation::ProfileInvalidationProviderFactory::GetForProfile(
146 content::Details<Profile>(details).ptr());
147 if (!invalidation_provider) {
148 // If the Profile does not support invalidation (e.g. guest, incognito),
153 // Create a state observer for the user's invalidation service.
154 profile_invalidation_service_observers_.push_back(
155 new InvalidationServiceObserver(
157 invalidation_provider->GetInvalidationService()));
159 TryToCreateInvalidator();
162 void DeviceCloudPolicyInvalidator::OnInvalidationServiceConnected(
163 invalidation::InvalidationService* invalidation_service) {
164 if (!device_invalidation_service_) {
165 // The lack of a device-global invalidation service implies that a
166 // |CloudPolicyInvalidator| backed by another connected service exists
167 // already. There is no need to switch from that to the service which just
172 if (invalidation_service != device_invalidation_service_.get()) {
173 // If an invalidation service other than the device-global one connected,
174 // destroy the device-global service and the |CloudPolicyInvalidator| backed
176 DestroyInvalidator();
177 DestroyDeviceInvalidationService();
180 // Create a |CloudPolicyInvalidator| backed by the invalidation service which
182 CreateInvalidator(invalidation_service);
185 void DeviceCloudPolicyInvalidator::OnInvalidationServiceDisconnected(
186 invalidation::InvalidationService* invalidation_service) {
187 if (invalidation_service != invalidation_service_) {
188 // If the invalidation service which disconnected is not backing the current
189 // |CloudPolicyInvalidator|, return.
193 // Destroy the |CloudPolicyInvalidator| backed by the invalidation service
194 // which just disconnected.
195 DestroyInvalidator();
197 // Try to create a |CloudPolicyInvalidator| backed by another invalidation
199 TryToCreateInvalidator();
202 void DeviceCloudPolicyInvalidator::TryToCreateInvalidator() {
204 // If a |CloudPolicyInvalidator| exists already, return.
208 for (ScopedVector<InvalidationServiceObserver>::const_iterator it =
209 profile_invalidation_service_observers_.begin();
210 it != profile_invalidation_service_observers_.end(); ++it) {
211 if ((*it)->IsServiceConnected()) {
212 // If a connected invalidation service belonging to a logged-in user is
213 // found, create a |CloudPolicyInvalidator| backed by that service and
214 // destroy the device-global service, if any.
215 DestroyDeviceInvalidationService();
216 CreateInvalidator((*it)->GetInvalidationService());
221 if (!device_invalidation_service_) {
222 // If no other connected invalidation service was found, ensure that a
223 // device-global service is running.
224 device_invalidation_service_.reset(
225 new invalidation::TiclInvalidationService(
227 scoped_ptr<IdentityProvider>(new chromeos::DeviceIdentityProvider(
228 chromeos::DeviceOAuth2TokenServiceFactory::Get())),
229 scoped_ptr<invalidation::TiclSettingsProvider>(
230 new TiclDeviceSettingsProvider),
231 g_browser_process->gcm_driver(),
232 g_browser_process->system_request_context()));
233 device_invalidation_service_->Init(
234 scoped_ptr<syncer::InvalidationStateTracker>(
235 new invalidation::InvalidatorStorage(
236 g_browser_process->local_state())));
237 device_invalidation_service_observer_.reset(
238 new InvalidationServiceObserver(
240 device_invalidation_service_.get()));
243 if (device_invalidation_service_observer_->IsServiceConnected()) {
244 // If the device-global invalidation service is connected, create a
245 // |CloudPolicyInvalidator| backed by it. Otherwise, a
246 // |CloudPolicyInvalidator| will be created later when a connected service
247 // becomes available.
248 CreateInvalidator(device_invalidation_service_.get());
252 void DeviceCloudPolicyInvalidator::CreateInvalidator(
253 invalidation::InvalidationService* invalidation_service) {
254 invalidation_service_ = invalidation_service;
255 DCHECK(!invalidator_);
256 invalidator_.reset(new CloudPolicyInvalidator(
257 enterprise_management::DeviceRegisterRequest::DEVICE,
258 g_browser_process->platform_part()->browser_policy_connector_chromeos()->
259 GetDeviceCloudPolicyManager()->core(),
260 base::MessageLoopProxy::current(),
261 scoped_ptr<base::Clock>(new base::DefaultClock()),
262 highest_handled_invalidation_version_));
263 invalidator_->Initialize(invalidation_service);
266 void DeviceCloudPolicyInvalidator::DestroyInvalidator() {
268 highest_handled_invalidation_version_ =
269 invalidator_->highest_handled_invalidation_version();
270 invalidator_->Shutdown();
272 invalidator_.reset();
273 invalidation_service_ = NULL;
276 void DeviceCloudPolicyInvalidator::DestroyDeviceInvalidationService() {
277 device_invalidation_service_observer_.reset();
278 device_invalidation_service_.reset();
281 } // namespace policy