Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / policy / device_cloud_policy_invalidator.cc
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 #include "policy/proto/device_management_backend.pb.h"
39
40 class Profile;
41
42 namespace policy {
43
44 class DeviceCloudPolicyInvalidator::InvalidationServiceObserver
45     : public syncer::InvalidationHandler {
46  public:
47   explicit InvalidationServiceObserver(
48       DeviceCloudPolicyInvalidator* parent,
49       invalidation::InvalidationService* invalidation_service);
50   virtual ~InvalidationServiceObserver();
51
52   invalidation::InvalidationService* GetInvalidationService();
53   bool IsServiceConnected() const;
54
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;
61
62  private:
63   DeviceCloudPolicyInvalidator* parent_;
64   invalidation::InvalidationService* invalidation_service_;
65   bool is_service_connected_;
66
67   DISALLOW_COPY_AND_ASSIGN(InvalidationServiceObserver);
68 };
69
70 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
71     InvalidationServiceObserver(
72         DeviceCloudPolicyInvalidator* parent,
73         invalidation::InvalidationService* invalidation_service)
74     : parent_(parent),
75       invalidation_service_(invalidation_service),
76       is_service_connected_(invalidation_service->GetInvalidatorState() ==
77                                 syncer::INVALIDATIONS_ENABLED) {
78   invalidation_service_->RegisterInvalidationHandler(this);
79 }
80
81 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
82     ~InvalidationServiceObserver() {
83   invalidation_service_->UnregisterInvalidationHandler(this);
84 }
85
86 invalidation::InvalidationService*
87 DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
88     GetInvalidationService() {
89   return invalidation_service_;
90 }
91
92 bool DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
93          IsServiceConnected() const {
94   return is_service_connected_;
95 }
96
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_)
101     return;
102
103   is_service_connected_ = is_service_connected;
104   if (is_service_connected_)
105     parent_->OnInvalidationServiceConnected(invalidation_service_);
106   else
107     parent_->OnInvalidationServiceDisconnected(invalidation_service_);
108 }
109
110 void DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
111     OnIncomingInvalidation(
112         const syncer::ObjectIdInvalidationMap& invalidation_map) {
113 }
114
115 std::string DeviceCloudPolicyInvalidator::InvalidationServiceObserver::
116     GetOwnerName() const {
117   return "DevicePolicy";
118 }
119
120 DeviceCloudPolicyInvalidator::DeviceCloudPolicyInvalidator()
121     : invalidation_service_(NULL),
122       highest_handled_invalidation_version_(0) {
123   // The DeviceCloudPolicyInvalidator should be created before any user
124   // Profiles.
125   DCHECK(g_browser_process->profile_manager()->GetLoadedProfiles().empty());
126
127   // Subscribe to notification about new user profiles becoming available.
128   registrar_.Add(this,
129                  chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
130                  content::NotificationService::AllSources());
131
132   TryToCreateInvalidator();
133 }
134
135 DeviceCloudPolicyInvalidator::~DeviceCloudPolicyInvalidator() {
136   DestroyInvalidator();
137 }
138
139 void DeviceCloudPolicyInvalidator::Observe(
140     int type,
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),
149     // ignore it.
150     return;
151   }
152
153   // Create a state observer for the user's invalidation service.
154   profile_invalidation_service_observers_.push_back(
155       new InvalidationServiceObserver(
156               this,
157               invalidation_provider->GetInvalidationService()));
158
159   TryToCreateInvalidator();
160 }
161
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
168     // connected.
169     return;
170   }
171
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
175     // by it, if any.
176     DestroyInvalidator();
177     DestroyDeviceInvalidationService();
178   }
179
180   // Create a |CloudPolicyInvalidator| backed by the invalidation service which
181   // just connected.
182   CreateInvalidator(invalidation_service);
183 }
184
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.
190     return;
191   }
192
193   // Destroy the |CloudPolicyInvalidator| backed by the invalidation service
194   // which just disconnected.
195   DestroyInvalidator();
196
197   // Try to create a |CloudPolicyInvalidator| backed by another invalidation
198   // service.
199   TryToCreateInvalidator();
200 }
201
202 void DeviceCloudPolicyInvalidator::TryToCreateInvalidator() {
203   if (invalidator_) {
204     // If a |CloudPolicyInvalidator| exists already, return.
205     return;
206   }
207
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());
217       return;
218     }
219   }
220
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(
226             GetUserAgent(),
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(
239                 this,
240                 device_invalidation_service_.get()));
241   }
242
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());
249   }
250 }
251
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);
264 }
265
266 void DeviceCloudPolicyInvalidator::DestroyInvalidator() {
267   if (invalidator_) {
268     highest_handled_invalidation_version_ =
269         invalidator_->highest_handled_invalidation_version();
270     invalidator_->Shutdown();
271   }
272   invalidator_.reset();
273   invalidation_service_ = NULL;
274 }
275
276 void DeviceCloudPolicyInvalidator::DestroyDeviceInvalidationService() {
277   device_invalidation_service_observer_.reset();
278   device_invalidation_service_.reset();
279 }
280
281 }  // namespace policy