device_cloud_policy_invalidator.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
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.
4
5#include "chrome/browser/chromeos/policy/device_cloud_policy_invalidator.h"
6
7#include <string>
8#include <vector>
9
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
39class Profile;
40
41namespace policy {
42
43class DeviceCloudPolicyInvalidator::InvalidationServiceObserver
44    : public syncer::InvalidationHandler {
45 public:
46  explicit InvalidationServiceObserver(
47      DeviceCloudPolicyInvalidator* parent,
48      invalidation::InvalidationService* invalidation_service);
49  virtual ~InvalidationServiceObserver();
50
51  invalidation::InvalidationService* GetInvalidationService();
52  bool IsServiceConnected() const;
53
54  // public syncer::InvalidationHandler:
55  virtual void OnInvalidatorStateChange(
56      syncer::InvalidatorState state) OVERRIDE;
57  virtual void OnIncomingInvalidation(
58      const syncer::ObjectIdInvalidationMap& invalidation_map) OVERRIDE;
59  virtual std::string GetOwnerName() const OVERRIDE;
60
61 private:
62  DeviceCloudPolicyInvalidator* parent_;
63  invalidation::InvalidationService* invalidation_service_;
64  bool is_service_connected_;
65
66  DISALLOW_COPY_AND_ASSIGN(InvalidationServiceObserver);
67};
68
69DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
70    InvalidationServiceObserver(
71        DeviceCloudPolicyInvalidator* parent,
72        invalidation::InvalidationService* invalidation_service)
73    : parent_(parent),
74      invalidation_service_(invalidation_service),
75      is_service_connected_(invalidation_service->GetInvalidatorState() ==
76                                syncer::INVALIDATIONS_ENABLED) {
77  invalidation_service_->RegisterInvalidationHandler(this);
78}
79
80DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
81    ~InvalidationServiceObserver() {
82  invalidation_service_->UnregisterInvalidationHandler(this);
83}
84
85invalidation::InvalidationService*
86DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
87    GetInvalidationService() {
88  return invalidation_service_;
89}
90
91bool DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
92         IsServiceConnected() const {
93  return is_service_connected_;
94}
95
96void DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
97    OnInvalidatorStateChange(syncer::InvalidatorState state) {
98  const bool is_service_connected = (state == syncer::INVALIDATIONS_ENABLED);
99  if (is_service_connected == is_service_connected_)
100    return;
101
102  is_service_connected_ = is_service_connected;
103  if (is_service_connected_)
104    parent_->OnInvalidationServiceConnected(invalidation_service_);
105  else
106    parent_->OnInvalidationServiceDisconnected(invalidation_service_);
107}
108
109void DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
110    OnIncomingInvalidation(
111        const syncer::ObjectIdInvalidationMap& invalidation_map) {
112}
113
114std::string DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
115    GetOwnerName() const {
116  return "DevicePolicy";
117}
118
119DeviceCloudPolicyInvalidator::DeviceCloudPolicyInvalidator()
120    : invalidation_service_(NULL) {
121  // The DeviceCloudPolicyInvalidator should be created before any user
122  // Profiles.
123  DCHECK(g_browser_process->profile_manager()->GetLoadedProfiles().empty());
124
125  // Subscribe to notification about new user profiles becoming available.
126  registrar_.Add(this,
127                 chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
128                 content::NotificationService::AllSources());
129
130  TryToCreateInvalidator();
131}
132
133DeviceCloudPolicyInvalidator::~DeviceCloudPolicyInvalidator() {
134  DestroyInvalidator();
135}
136
137void DeviceCloudPolicyInvalidator::Observe(
138    int type,
139    const content::NotificationSource& source,
140    const content::NotificationDetails& details) {
141  DCHECK_EQ(chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, type);
142  invalidation::ProfileInvalidationProvider* invalidation_provider =
143      invalidation::ProfileInvalidationProviderFactory::GetForProfile(
144          content::Details<Profile>(details).ptr());
145  if (!invalidation_provider) {
146    // If the Profile does not support invalidation (e.g. guest, incognito),
147    // ignore it.
148    return;
149  }
150
151  // Create a state observer for the user's invalidation service.
152  profile_invalidation_service_observers_.push_back(
153      new InvalidationServiceObserver(
154              this,
155              invalidation_provider->GetInvalidationService()));
156
157  TryToCreateInvalidator();
158}
159
160void DeviceCloudPolicyInvalidator::OnInvalidationServiceConnected(
161    invalidation::InvalidationService* invalidation_service) {
162  if (!device_invalidation_service_) {
163    // The lack of a device-global invalidation service implies that a
164    // |CloudPolicyInvalidator| backed by another connected service exists
165    // already. There is no need to switch from that to the service which just
166    // connected.
167    return;
168  }
169
170  if (invalidation_service != device_invalidation_service_.get()) {
171    // If an invalidation service other than the device-global one connected,
172    // destroy the device-global service and the |CloudPolicyInvalidator| backed
173    // by it, if any.
174    DestroyInvalidator();
175    DestroyDeviceInvalidationService();
176  }
177
178  // Create a |CloudPolicyInvalidator| backed by the invalidation service which
179  // just connected.
180  CreateInvalidator(invalidation_service);
181}
182
183void DeviceCloudPolicyInvalidator::OnInvalidationServiceDisconnected(
184    invalidation::InvalidationService* invalidation_service) {
185  if (invalidation_service != invalidation_service_) {
186    // If the invalidation service which disconnected is not backing the current
187    // |CloudPolicyInvalidator|, return.
188    return;
189  }
190
191  // Destroy the |CloudPolicyInvalidator| backed by the invalidation service
192  // which just disconnected.
193  DestroyInvalidator();
194
195  // Try to create a |CloudPolicyInvalidator| backed by another invalidation
196  // service.
197  TryToCreateInvalidator();
198}
199
200void DeviceCloudPolicyInvalidator::TryToCreateInvalidator() {
201  if (invalidator_) {
202    // If a |CloudPolicyInvalidator| exists already, return.
203    return;
204  }
205
206  for (ScopedVector<InvalidationServiceObserver>::const_iterator it =
207           profile_invalidation_service_observers_.begin();
208           it != profile_invalidation_service_observers_.end(); ++it) {
209    if ((*it)->IsServiceConnected()) {
210      // If a connected invalidation service belonging to a logged-in user is
211      // found, create a |CloudPolicyInvalidator| backed by that service and
212      // destroy the device-global service, if any.
213      DestroyDeviceInvalidationService();
214      CreateInvalidator((*it)->GetInvalidationService());
215      return;
216    }
217  }
218
219  if (!device_invalidation_service_) {
220    // If no other connected invalidation service was found, ensure that a
221    // device-global service is running.
222    device_invalidation_service_.reset(
223        new invalidation::TiclInvalidationService(
224            GetUserAgent(),
225            scoped_ptr<IdentityProvider>(new chromeos::DeviceIdentityProvider(
226                chromeos::DeviceOAuth2TokenServiceFactory::Get())),
227            scoped_ptr<invalidation::TiclSettingsProvider>(
228                new TiclDeviceSettingsProvider),
229            g_browser_process->gcm_driver(),
230            g_browser_process->system_request_context()));
231    device_invalidation_service_->Init(
232        scoped_ptr<syncer::InvalidationStateTracker>(
233            new invalidation::InvalidatorStorage(
234                    g_browser_process->local_state())));
235    device_invalidation_service_observer_.reset(
236        new InvalidationServiceObserver(
237                this,
238                device_invalidation_service_.get()));
239  }
240
241  if (device_invalidation_service_observer_->IsServiceConnected()) {
242    // If the device-global invalidation service is connected, create a
243    // |CloudPolicyInvalidator| backed by it. Otherwise,  a
244    // |CloudPolicyInvalidator| will be created later when a connected service
245    // becomes available.
246    CreateInvalidator(device_invalidation_service_.get());
247  }
248}
249
250void DeviceCloudPolicyInvalidator::CreateInvalidator(
251    invalidation::InvalidationService* invalidation_service) {
252  invalidation_service_ = invalidation_service;
253  invalidator_.reset(new CloudPolicyInvalidator(
254      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
255          GetDeviceCloudPolicyManager()->core(),
256      base::MessageLoopProxy::current(),
257      scoped_ptr<base::Clock>(new base::DefaultClock())));
258  invalidator_->Initialize(invalidation_service);
259}
260
261void DeviceCloudPolicyInvalidator::DestroyInvalidator() {
262  if (invalidator_)
263    invalidator_->Shutdown();
264  invalidator_.reset();
265  invalidation_service_ = NULL;
266}
267
268void DeviceCloudPolicyInvalidator::DestroyDeviceInvalidationService() {
269  device_invalidation_service_observer_.reset();
270  device_invalidation_service_.reset();
271}
272
273}  // namespace policy
274