1 // Copyright 2015 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/affiliated_invalidation_service_provider_impl.h"
9 #include "base/logging.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/browser_process_platform_part_chromeos.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
14 #include "chrome/browser/chromeos/policy/ticl_device_settings_provider.h"
15 #include "chrome/browser/chromeos/profiles/profile_helper.h"
16 #include "chrome/browser/chromeos/settings/device_identity_provider.h"
17 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
18 #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/common/chrome_content_client.h"
22 #include "components/invalidation/invalidation_handler.h"
23 #include "components/invalidation/invalidation_service.h"
24 #include "components/invalidation/invalidation_state_tracker.h"
25 #include "components/invalidation/invalidator_state.h"
26 #include "components/invalidation/invalidator_storage.h"
27 #include "components/invalidation/profile_invalidation_provider.h"
28 #include "components/invalidation/ticl_invalidation_service.h"
29 #include "components/invalidation/ticl_settings_provider.h"
30 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
31 #include "components/user_manager/user.h"
32 #include "content/public/browser/notification_details.h"
33 #include "content/public/browser/notification_service.h"
34 #include "google_apis/gaia/identity_provider.h"
38 class AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver
39 : public syncer::InvalidationHandler
{
41 explicit InvalidationServiceObserver(
42 AffiliatedInvalidationServiceProviderImpl
* parent
,
43 invalidation::InvalidationService
* invalidation_service
);
44 ~InvalidationServiceObserver() override
;
46 invalidation::InvalidationService
* GetInvalidationService();
47 bool IsServiceConnected() const;
49 // public syncer::InvalidationHandler:
50 void OnInvalidatorStateChange(syncer::InvalidatorState state
) override
;
51 void OnIncomingInvalidation(
52 const syncer::ObjectIdInvalidationMap
& invalidation_map
) override
;
53 std::string
GetOwnerName() const override
;
56 AffiliatedInvalidationServiceProviderImpl
* parent_
;
57 invalidation::InvalidationService
* invalidation_service_
;
58 bool is_service_connected_
;
59 bool is_observer_ready_
;
61 DISALLOW_COPY_AND_ASSIGN(InvalidationServiceObserver
);
64 AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
65 InvalidationServiceObserver(
66 AffiliatedInvalidationServiceProviderImpl
* parent
,
67 invalidation::InvalidationService
* invalidation_service
)
69 invalidation_service_(invalidation_service
),
70 is_service_connected_(false),
71 is_observer_ready_(false) {
72 invalidation_service_
->RegisterInvalidationHandler(this);
73 is_service_connected_
= invalidation_service
->GetInvalidatorState() ==
74 syncer::INVALIDATIONS_ENABLED
;
75 is_observer_ready_
= true;
78 AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
79 ~InvalidationServiceObserver() {
80 is_observer_ready_
= false;
81 invalidation_service_
->UnregisterInvalidationHandler(this);
84 invalidation::InvalidationService
*
85 AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
86 GetInvalidationService() {
87 return invalidation_service_
;
90 bool AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
91 IsServiceConnected() const {
92 return is_service_connected_
;
95 void AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
96 OnInvalidatorStateChange(syncer::InvalidatorState state
) {
97 if (!is_observer_ready_
)
100 const bool is_service_connected
= (state
== syncer::INVALIDATIONS_ENABLED
);
101 if (is_service_connected
== is_service_connected_
)
104 is_service_connected_
= is_service_connected
;
105 if (is_service_connected_
)
106 parent_
->OnInvalidationServiceConnected(invalidation_service_
);
108 parent_
->OnInvalidationServiceDisconnected(invalidation_service_
);
111 void AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
112 OnIncomingInvalidation(
113 const syncer::ObjectIdInvalidationMap
& invalidation_map
) {
117 AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
118 GetOwnerName() const {
119 return "AffiliatedInvalidationService";
122 AffiliatedInvalidationServiceProviderImpl::
123 AffiliatedInvalidationServiceProviderImpl()
124 : invalidation_service_(nullptr),
126 is_shut_down_(false) {
127 // The AffiliatedInvalidationServiceProviderImpl should be created before any
129 DCHECK(g_browser_process
->profile_manager()->GetLoadedProfiles().empty());
131 // Subscribe to notification about new user profiles becoming available.
133 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED
,
134 content::NotificationService::AllSources());
137 AffiliatedInvalidationServiceProviderImpl::
138 ~AffiliatedInvalidationServiceProviderImpl() {
139 // Verify that the provider was shut down first.
140 DCHECK(is_shut_down_
);
143 void AffiliatedInvalidationServiceProviderImpl::Observe(
145 const content::NotificationSource
& source
,
146 const content::NotificationDetails
& details
) {
147 DCHECK_EQ(chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED
, type
);
148 DCHECK(!is_shut_down_
);
149 Profile
* profile
= content::Details
<Profile
>(details
).ptr();
150 invalidation::ProfileInvalidationProvider
* invalidation_provider
=
151 invalidation::ProfileInvalidationProviderFactory::GetForProfile(profile
);
152 if (!invalidation_provider
) {
153 // If the Profile does not support invalidation (e.g. guest, incognito),
157 const user_manager::User
* user
=
158 chromeos::ProfileHelper::Get()->GetUserByProfile(profile
);
160 g_browser_process
->platform_part()->browser_policy_connector_chromeos()->
161 GetUserAffiliation(user
->email()) != USER_AFFILIATION_MANAGED
) {
162 // If the Profile belongs to a user who is not affiliated with the device's
163 // enrollment domain, ignore it.
167 // Create a state observer for the user's invalidation service.
168 invalidation::InvalidationService
* invalidation_service
=
169 invalidation_provider
->GetInvalidationService();
170 profile_invalidation_service_observers_
.push_back(
171 new InvalidationServiceObserver(this, invalidation_service
));
173 if (profile_invalidation_service_observers_
.back()->IsServiceConnected()) {
174 // If the invalidation service is connected, check whether to switch to it.
175 OnInvalidationServiceConnected(invalidation_service
);
179 void AffiliatedInvalidationServiceProviderImpl::RegisterConsumer(
180 Consumer
* consumer
) {
181 if (consumers_
.HasObserver(consumer
) || is_shut_down_
)
184 consumers_
.AddObserver(consumer
);
187 if (invalidation_service_
)
188 consumer
->OnInvalidationServiceSet(invalidation_service_
);
189 else if (consumer_count_
== 1)
190 FindConnectedInvalidationService();
193 void AffiliatedInvalidationServiceProviderImpl::UnregisterConsumer(
194 Consumer
* consumer
) {
195 if (!consumers_
.HasObserver(consumer
))
198 consumers_
.RemoveObserver(consumer
);
201 if (invalidation_service_
&& consumer_count_
== 0) {
202 invalidation_service_
= nullptr;
203 DestroyDeviceInvalidationService();
207 void AffiliatedInvalidationServiceProviderImpl::Shutdown() {
208 is_shut_down_
= true;
210 registrar_
.RemoveAll();
211 profile_invalidation_service_observers_
.clear();
212 device_invalidation_service_observer_
.reset();
214 if (invalidation_service_
) {
215 invalidation_service_
= nullptr;
216 // Explicitly notify consumers that the invalidation service they were using
217 // is no longer available.
218 SetInvalidationService(nullptr);
221 DestroyDeviceInvalidationService();
224 invalidation::TiclInvalidationService
*
225 AffiliatedInvalidationServiceProviderImpl::
226 GetDeviceInvalidationServiceForTest() const {
227 return device_invalidation_service_
.get();
230 void AffiliatedInvalidationServiceProviderImpl::OnInvalidationServiceConnected(
231 invalidation::InvalidationService
* invalidation_service
) {
232 DCHECK(!is_shut_down_
);
234 if (consumer_count_
== 0) {
235 // If there are no consumers, no invalidation service is required.
239 if (!device_invalidation_service_
) {
240 // The lack of a device-global invalidation service implies that another
241 // connected invalidation service is being made available to consumers
242 // already. There is no need to switch from that to the service which just
247 // Make the invalidation service that just connected available to consumers.
248 invalidation_service_
= nullptr;
249 SetInvalidationService(invalidation_service
);
251 if (invalidation_service_
&&
252 device_invalidation_service_
&&
253 invalidation_service_
!= device_invalidation_service_
.get()) {
254 // If a different invalidation service is being made available to consumers
255 // now, destroy the device-global one.
256 DestroyDeviceInvalidationService();
262 AffiliatedInvalidationServiceProviderImpl::OnInvalidationServiceDisconnected(
263 invalidation::InvalidationService
* invalidation_service
) {
264 DCHECK(!is_shut_down_
);
266 if (invalidation_service
!= invalidation_service_
) {
267 // If the invalidation service which disconnected was not being made
268 // available to consumers, return.
272 // The invalidation service which disconnected was being made available to
273 // consumers. Stop making it available.
274 DCHECK(consumer_count_
);
275 invalidation_service_
= nullptr;
277 // Try to make another invalidation service available to consumers.
278 FindConnectedInvalidationService();
280 // If no other connected invalidation service was found, explicitly notify
281 // consumers that the invalidation service they were using is no longer
283 if (!invalidation_service_
)
284 SetInvalidationService(nullptr);
288 AffiliatedInvalidationServiceProviderImpl::FindConnectedInvalidationService() {
289 DCHECK(!invalidation_service_
);
290 DCHECK(consumer_count_
);
291 DCHECK(!is_shut_down_
);
293 for (ScopedVector
<InvalidationServiceObserver
>::const_iterator it
=
294 profile_invalidation_service_observers_
.begin();
295 it
!= profile_invalidation_service_observers_
.end(); ++it
) {
296 if ((*it
)->IsServiceConnected()) {
297 // If a connected invalidation service belonging to an affiliated
298 // logged-in user is found, make it available to consumers.
299 DestroyDeviceInvalidationService();
300 SetInvalidationService((*it
)->GetInvalidationService());
305 if (!device_invalidation_service_
) {
306 // If no other connected invalidation service was found and no device-global
307 // invalidation service exists, create one.
308 device_invalidation_service_
.reset(
309 new invalidation::TiclInvalidationService(
311 scoped_ptr
<IdentityProvider
>(new chromeos::DeviceIdentityProvider(
312 chromeos::DeviceOAuth2TokenServiceFactory::Get())),
313 scoped_ptr
<invalidation::TiclSettingsProvider
>(
314 new TiclDeviceSettingsProvider
),
315 g_browser_process
->gcm_driver(),
316 g_browser_process
->system_request_context()));
317 device_invalidation_service_
->Init(
318 scoped_ptr
<syncer::InvalidationStateTracker
>(
319 new invalidation::InvalidatorStorage(
320 g_browser_process
->local_state())));
321 device_invalidation_service_observer_
.reset(
322 new InvalidationServiceObserver(
324 device_invalidation_service_
.get()));
327 if (device_invalidation_service_observer_
->IsServiceConnected()) {
328 // If the device-global invalidation service is connected already, make it
329 // available to consumers immediately. Otherwise, the invalidation service
330 // will be made available to clients when it successfully connects.
331 OnInvalidationServiceConnected(device_invalidation_service_
.get());
335 void AffiliatedInvalidationServiceProviderImpl::SetInvalidationService(
336 invalidation::InvalidationService
* invalidation_service
) {
337 DCHECK(!invalidation_service_
);
338 invalidation_service_
= invalidation_service
;
339 FOR_EACH_OBSERVER(Consumer
,
341 OnInvalidationServiceSet(invalidation_service_
));
345 AffiliatedInvalidationServiceProviderImpl::DestroyDeviceInvalidationService() {
346 device_invalidation_service_observer_
.reset();
347 device_invalidation_service_
.reset();
350 } // namespace policy