// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/chromeos/policy/device_cloud_policy_invalidator.h" #include #include #include "base/logging.h" #include "base/message_loop/message_loop_proxy.h" #include "base/time/clock.h" #include "base/time/default_clock.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process_platform_part_chromeos.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" #include "chrome/browser/chromeos/policy/ticl_device_settings_provider.h" #include "chrome/browser/chromeos/settings/device_identity_provider.h" #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h" #include "chrome/browser/invalidation/profile_invalidation_provider_factory.h" #include "chrome/browser/policy/cloud/cloud_policy_invalidator.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/chrome_content_client.h" #include "components/invalidation/invalidation_service.h" #include "components/invalidation/invalidator_storage.h" #include "components/invalidation/profile_invalidation_provider.h" #include "components/invalidation/ticl_invalidation_service.h" #include "components/invalidation/ticl_settings_provider.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_service.h" #include "google_apis/gaia/identity_provider.h" #include "net/url_request/url_request_context_getter.h" #include "sync/internal_api/public/base/invalidator_state.h" #include "sync/notifier/invalidation_handler.h" #include "sync/notifier/invalidation_state_tracker.h" class Profile; namespace policy { class DeviceCloudPolicyInvalidator::InvalidationServiceObserver : public syncer::InvalidationHandler { public: explicit InvalidationServiceObserver( DeviceCloudPolicyInvalidator* parent, invalidation::InvalidationService* invalidation_service); virtual ~InvalidationServiceObserver(); invalidation::InvalidationService* GetInvalidationService(); bool IsServiceConnected() const; // public syncer::InvalidationHandler: virtual void OnInvalidatorStateChange( syncer::InvalidatorState state) OVERRIDE; virtual void OnIncomingInvalidation( const syncer::ObjectIdInvalidationMap& invalidation_map) OVERRIDE; virtual std::string GetOwnerName() const OVERRIDE; private: DeviceCloudPolicyInvalidator* parent_; invalidation::InvalidationService* invalidation_service_; bool is_service_connected_; DISALLOW_COPY_AND_ASSIGN(InvalidationServiceObserver); }; DeviceCloudPolicyInvalidator::InvalidationServiceObserver:: InvalidationServiceObserver( DeviceCloudPolicyInvalidator* parent, invalidation::InvalidationService* invalidation_service) : parent_(parent), invalidation_service_(invalidation_service), is_service_connected_(invalidation_service->GetInvalidatorState() == syncer::INVALIDATIONS_ENABLED) { invalidation_service_->RegisterInvalidationHandler(this); } DeviceCloudPolicyInvalidator::InvalidationServiceObserver:: ~InvalidationServiceObserver() { invalidation_service_->UnregisterInvalidationHandler(this); } invalidation::InvalidationService* DeviceCloudPolicyInvalidator::InvalidationServiceObserver:: GetInvalidationService() { return invalidation_service_; } bool DeviceCloudPolicyInvalidator::InvalidationServiceObserver:: IsServiceConnected() const { return is_service_connected_; } void DeviceCloudPolicyInvalidator::InvalidationServiceObserver:: OnInvalidatorStateChange(syncer::InvalidatorState state) { const bool is_service_connected = (state == syncer::INVALIDATIONS_ENABLED); if (is_service_connected == is_service_connected_) return; is_service_connected_ = is_service_connected; if (is_service_connected_) parent_->OnInvalidationServiceConnected(invalidation_service_); else parent_->OnInvalidationServiceDisconnected(invalidation_service_); } void DeviceCloudPolicyInvalidator::InvalidationServiceObserver:: OnIncomingInvalidation( const syncer::ObjectIdInvalidationMap& invalidation_map) { } std::string DeviceCloudPolicyInvalidator::InvalidationServiceObserver:: GetOwnerName() const { return "DevicePolicy"; } DeviceCloudPolicyInvalidator::DeviceCloudPolicyInvalidator() : invalidation_service_(NULL) { // The DeviceCloudPolicyInvalidator should be created before any user // Profiles. DCHECK(g_browser_process->profile_manager()->GetLoadedProfiles().empty()); // Subscribe to notification about new user profiles becoming available. registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, content::NotificationService::AllSources()); TryToCreateInvalidator(); } DeviceCloudPolicyInvalidator::~DeviceCloudPolicyInvalidator() { DestroyInvalidator(); } void DeviceCloudPolicyInvalidator::Observe( int type, const content::NotificationSource& source, const content::NotificationDetails& details) { DCHECK_EQ(chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED, type); invalidation::ProfileInvalidationProvider* invalidation_provider = invalidation::ProfileInvalidationProviderFactory::GetForProfile( content::Details(details).ptr()); if (!invalidation_provider) { // If the Profile does not support invalidation (e.g. guest, incognito), // ignore it. return; } // Create a state observer for the user's invalidation service. profile_invalidation_service_observers_.push_back( new InvalidationServiceObserver( this, invalidation_provider->GetInvalidationService())); TryToCreateInvalidator(); } void DeviceCloudPolicyInvalidator::OnInvalidationServiceConnected( invalidation::InvalidationService* invalidation_service) { if (!device_invalidation_service_) { // The lack of a device-global invalidation service implies that a // |CloudPolicyInvalidator| backed by another connected service exists // already. There is no need to switch from that to the service which just // connected. return; } if (invalidation_service != device_invalidation_service_.get()) { // If an invalidation service other than the device-global one connected, // destroy the device-global service and the |CloudPolicyInvalidator| backed // by it, if any. DestroyInvalidator(); DestroyDeviceInvalidationService(); } // Create a |CloudPolicyInvalidator| backed by the invalidation service which // just connected. CreateInvalidator(invalidation_service); } void DeviceCloudPolicyInvalidator::OnInvalidationServiceDisconnected( invalidation::InvalidationService* invalidation_service) { if (invalidation_service != invalidation_service_) { // If the invalidation service which disconnected is not backing the current // |CloudPolicyInvalidator|, return. return; } // Destroy the |CloudPolicyInvalidator| backed by the invalidation service // which just disconnected. DestroyInvalidator(); // Try to create a |CloudPolicyInvalidator| backed by another invalidation // service. TryToCreateInvalidator(); } void DeviceCloudPolicyInvalidator::TryToCreateInvalidator() { if (invalidator_) { // If a |CloudPolicyInvalidator| exists already, return. return; } for (ScopedVector::const_iterator it = profile_invalidation_service_observers_.begin(); it != profile_invalidation_service_observers_.end(); ++it) { if ((*it)->IsServiceConnected()) { // If a connected invalidation service belonging to a logged-in user is // found, create a |CloudPolicyInvalidator| backed by that service and // destroy the device-global service, if any. DestroyDeviceInvalidationService(); CreateInvalidator((*it)->GetInvalidationService()); return; } } if (!device_invalidation_service_) { // If no other connected invalidation service was found, ensure that a // device-global service is running. device_invalidation_service_.reset( new invalidation::TiclInvalidationService( GetUserAgent(), scoped_ptr(new chromeos::DeviceIdentityProvider( chromeos::DeviceOAuth2TokenServiceFactory::Get())), scoped_ptr( new TiclDeviceSettingsProvider), g_browser_process->gcm_driver(), g_browser_process->system_request_context())); device_invalidation_service_->Init( scoped_ptr( new invalidation::InvalidatorStorage( g_browser_process->local_state()))); device_invalidation_service_observer_.reset( new InvalidationServiceObserver( this, device_invalidation_service_.get())); } if (device_invalidation_service_observer_->IsServiceConnected()) { // If the device-global invalidation service is connected, create a // |CloudPolicyInvalidator| backed by it. Otherwise, a // |CloudPolicyInvalidator| will be created later when a connected service // becomes available. CreateInvalidator(device_invalidation_service_.get()); } } void DeviceCloudPolicyInvalidator::CreateInvalidator( invalidation::InvalidationService* invalidation_service) { invalidation_service_ = invalidation_service; invalidator_.reset(new CloudPolicyInvalidator( g_browser_process->platform_part()->browser_policy_connector_chromeos()-> GetDeviceCloudPolicyManager()->core(), base::MessageLoopProxy::current(), scoped_ptr(new base::DefaultClock()))); invalidator_->Initialize(invalidation_service); } void DeviceCloudPolicyInvalidator::DestroyInvalidator() { if (invalidator_) invalidator_->Shutdown(); invalidator_.reset(); invalidation_service_ = NULL; } void DeviceCloudPolicyInvalidator::DestroyDeviceInvalidationService() { device_invalidation_service_observer_.reset(); device_invalidation_service_.reset(); } } // namespace policy