| // Copyright (c) 2012 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_local_account_policy_service.h" |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/command_line.h" |
| #include "base/files/file_enumerator.h" |
| #include "base/files/file_util.h" |
| #include "base/logging.h" |
| #include "base/path_service.h" |
| #include "base/sequenced_task_runner.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/task_scheduler/post_task.h" |
| #include "base/task_scheduler/task_traits.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator.h" |
| #include "chrome/browser/chromeos/policy/device_local_account.h" |
| #include "chrome/browser/chromeos/policy/device_local_account_external_data_service.h" |
| #include "chrome/browser/chromeos/policy/device_local_account_policy_store.h" |
| #include "chrome/browser/chromeos/settings/device_settings_service.h" |
| #include "chrome/browser/policy/chrome_browser_policy_connector.h" |
| #include "chrome/common/chrome_content_client.h" |
| #include "chromeos/chromeos_paths.h" |
| #include "chromeos/dbus/session_manager_client.h" |
| #include "chromeos/settings/cros_settings_names.h" |
| #include "chromeos/settings/cros_settings_provider.h" |
| #include "components/policy/core/common/cloud/cloud_policy_client.h" |
| #include "components/policy/core/common/cloud/cloud_policy_constants.h" |
| #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h" |
| #include "components/policy/core/common/cloud/device_management_service.h" |
| #include "components/policy/core/common/cloud/resource_cache.h" |
| #include "components/policy/core/common/policy_namespace.h" |
| #include "components/policy/core/common/policy_switches.h" |
| #include "components/policy/policy_constants.h" |
| #include "components/policy/proto/device_management_backend.pb.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "net/url_request/url_request_context_getter.h" |
| #include "url/gurl.h" |
| |
| namespace em = enterprise_management; |
| |
| namespace policy { |
| |
| namespace { |
| |
| // Device local accounts are always affiliated. |
| std::string GetDeviceDMToken( |
| chromeos::DeviceSettingsService* device_settings_service, |
| const std::vector<std::string>& user_affiliation_ids) { |
| return device_settings_service->policy_data()->request_token(); |
| } |
| |
| // Creates and initializes a cloud policy client. Returns nullptr if the device |
| // doesn't have credentials in device settings (i.e. is not |
| // enterprise-enrolled). |
| std::unique_ptr<CloudPolicyClient> CreateClient( |
| chromeos::DeviceSettingsService* device_settings_service, |
| DeviceManagementService* device_management_service, |
| scoped_refptr<net::URLRequestContextGetter> system_request_context, |
| scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory) { |
| const em::PolicyData* policy_data = device_settings_service->policy_data(); |
| if (!policy_data || |
| !policy_data->has_request_token() || |
| !policy_data->has_device_id() || |
| !device_management_service) { |
| return std::unique_ptr<CloudPolicyClient>(); |
| } |
| |
| std::unique_ptr<CloudPolicyClient> client = |
| std::make_unique<CloudPolicyClient>( |
| std::string() /* machine_id */, std::string() /* machine_model */, |
| std::string() /* brand_code */, device_management_service, |
| system_request_context, system_url_loader_factory, |
| nullptr /* signing_service */, |
| base::BindRepeating(&GetDeviceDMToken, device_settings_service)); |
| std::vector<std::string> user_affiliation_ids( |
| policy_data->user_affiliation_ids().begin(), |
| policy_data->user_affiliation_ids().end()); |
| client->SetupRegistration(policy_data->request_token(), |
| policy_data->device_id(), user_affiliation_ids); |
| return client; |
| } |
| |
| // Get the subdirectory of the force-installed extension cache and the component |
| // policy cache used for |account_id|. |
| std::string GetCacheSubdirectoryForAccountID(const std::string& account_id) { |
| return base::HexEncode(account_id.c_str(), account_id.size()); |
| } |
| |
| // Cleans up the cache directory by removing subdirectories that are not found |
| // in |subdirectories_to_keep|. Only caches whose cache directory is found in |
| // |subdirectories_to_keep| may be running while the clean-up is in progress. |
| void DeleteOrphanedCaches( |
| const base::FilePath& cache_root_dir, |
| const std::set<std::string>& subdirectories_to_keep) { |
| base::FileEnumerator enumerator(cache_root_dir, |
| false, |
| base::FileEnumerator::DIRECTORIES); |
| for (base::FilePath path = enumerator.Next(); !path.empty(); |
| path = enumerator.Next()) { |
| const std::string subdirectory(path.BaseName().MaybeAsASCII()); |
| if (!base::ContainsKey(subdirectories_to_keep, subdirectory)) |
| base::DeleteFile(path, true); |
| } |
| } |
| |
| // Removes the subdirectory belonging to |account_id_to_delete| from the cache |
| // directory. No cache belonging to |account_id_to_delete| may be running while |
| // the removal is in progress. |
| void DeleteObsoleteExtensionCache(const std::string& account_id_to_delete) { |
| base::FilePath cache_root_dir; |
| CHECK(base::PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS, |
| &cache_root_dir)); |
| const base::FilePath path = cache_root_dir.Append( |
| GetCacheSubdirectoryForAccountID(account_id_to_delete)); |
| if (base::DirectoryExists(path)) |
| base::DeleteFile(path, true); |
| } |
| |
| } // namespace |
| |
| DeviceLocalAccountPolicyBroker::DeviceLocalAccountPolicyBroker( |
| const DeviceLocalAccount& account, |
| const base::FilePath& component_policy_cache_path, |
| std::unique_ptr<DeviceLocalAccountPolicyStore> store, |
| scoped_refptr<DeviceLocalAccountExternalDataManager> external_data_manager, |
| const base::Closure& policy_update_callback, |
| const scoped_refptr<base::SequencedTaskRunner>& task_runner, |
| const scoped_refptr<base::SequencedTaskRunner>& resource_cache_task_runner, |
| AffiliatedInvalidationServiceProvider* invalidation_service_provider) |
| : invalidation_service_provider_(invalidation_service_provider), |
| account_id_(account.account_id), |
| user_id_(account.user_id), |
| component_policy_cache_path_(component_policy_cache_path), |
| store_(std::move(store)), |
| external_data_manager_(external_data_manager), |
| core_(dm_protocol::kChromePublicAccountPolicyType, |
| store_->account_id(), |
| store_.get(), |
| task_runner), |
| policy_update_callback_(policy_update_callback), |
| resource_cache_task_runner_(resource_cache_task_runner) { |
| if (account.type != DeviceLocalAccount::TYPE_ARC_KIOSK_APP) { |
| extension_tracker_.reset(new DeviceLocalAccountExtensionTracker( |
| account, store_.get(), &schema_registry_)); |
| } |
| base::FilePath cache_root_dir; |
| CHECK(base::PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS, |
| &cache_root_dir)); |
| extension_loader_ = new chromeos::DeviceLocalAccountExternalPolicyLoader( |
| store_.get(), |
| cache_root_dir.Append( |
| GetCacheSubdirectoryForAccountID(account.account_id))); |
| store_->AddObserver(this); |
| |
| // Unblock the |schema_registry_| so that the |component_policy_service_| |
| // starts using it. |
| schema_registry_.RegisterComponent( |
| PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()), |
| g_browser_process->browser_policy_connector()->GetChromeSchema()); |
| schema_registry_.SetAllDomainsReady(); |
| } |
| |
| DeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() { |
| store_->RemoveObserver(this); |
| external_data_manager_->SetPolicyStore(nullptr); |
| external_data_manager_->Disconnect(); |
| } |
| |
| void DeviceLocalAccountPolicyBroker::Initialize() { |
| store_->Load(); |
| } |
| |
| void DeviceLocalAccountPolicyBroker::LoadImmediately() { |
| store_->LoadImmediately(); |
| } |
| |
| bool DeviceLocalAccountPolicyBroker::HasInvalidatorForTest() const { |
| return invalidator_ != nullptr; |
| } |
| |
| void DeviceLocalAccountPolicyBroker::ConnectIfPossible( |
| chromeos::DeviceSettingsService* device_settings_service, |
| DeviceManagementService* device_management_service, |
| scoped_refptr<net::URLRequestContextGetter> request_context, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) { |
| if (core_.client()) |
| return; |
| |
| std::unique_ptr<CloudPolicyClient> client( |
| CreateClient(device_settings_service, device_management_service, |
| request_context, url_loader_factory)); |
| if (!client) |
| return; |
| |
| CreateComponentCloudPolicyService(request_context, client.get()); |
| core_.Connect(std::move(client)); |
| external_data_manager_->Connect(request_context); |
| core_.StartRefreshScheduler(); |
| UpdateRefreshDelay(); |
| invalidator_.reset(new AffiliatedCloudPolicyInvalidator( |
| em::DeviceRegisterRequest::DEVICE, |
| &core_, |
| invalidation_service_provider_)); |
| } |
| |
| void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() { |
| if (core_.refresh_scheduler()) { |
| const base::Value* policy_value = |
| store_->policy_map().GetValue(key::kPolicyRefreshRate); |
| int delay = 0; |
| if (policy_value && policy_value->GetAsInteger(&delay)) |
| core_.refresh_scheduler()->SetDesiredRefreshDelay(delay); |
| } |
| } |
| |
| std::string DeviceLocalAccountPolicyBroker::GetDisplayName() const { |
| std::string display_name; |
| const base::Value* display_name_value = |
| store_->policy_map().GetValue(policy::key::kUserDisplayName); |
| if (display_name_value) |
| display_name_value->GetAsString(&display_name); |
| return display_name; |
| } |
| |
| void DeviceLocalAccountPolicyBroker::OnStoreLoaded(CloudPolicyStore* store) { |
| UpdateRefreshDelay(); |
| policy_update_callback_.Run(); |
| } |
| |
| void DeviceLocalAccountPolicyBroker::OnStoreError(CloudPolicyStore* store) { |
| policy_update_callback_.Run(); |
| } |
| |
| void DeviceLocalAccountPolicyBroker::OnComponentCloudPolicyUpdated() { |
| policy_update_callback_.Run(); |
| } |
| |
| void DeviceLocalAccountPolicyBroker::CreateComponentCloudPolicyService( |
| const scoped_refptr<net::URLRequestContextGetter>& request_context, |
| CloudPolicyClient* client) { |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kDisableComponentCloudPolicy)) { |
| // Disabled via the command line. |
| return; |
| } |
| |
| std::unique_ptr<ResourceCache> resource_cache(new ResourceCache( |
| component_policy_cache_path_, resource_cache_task_runner_)); |
| |
| component_policy_service_.reset(new ComponentCloudPolicyService( |
| dm_protocol::kChromeExtensionPolicyType, this, &schema_registry_, core(), |
| client, std::move(resource_cache), request_context, |
| resource_cache_task_runner_, |
| content::BrowserThread::GetTaskRunnerForThread( |
| content::BrowserThread::IO))); |
| } |
| |
| DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService( |
| chromeos::SessionManagerClient* session_manager_client, |
| chromeos::DeviceSettingsService* device_settings_service, |
| chromeos::CrosSettings* cros_settings, |
| AffiliatedInvalidationServiceProvider* invalidation_service_provider, |
| scoped_refptr<base::SequencedTaskRunner> store_background_task_runner, |
| scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner, |
| scoped_refptr<base::SequencedTaskRunner> |
| external_data_service_backend_task_runner, |
| scoped_refptr<base::SequencedTaskRunner> io_task_runner, |
| scoped_refptr<net::URLRequestContextGetter> request_context, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) |
| : session_manager_client_(session_manager_client), |
| device_settings_service_(device_settings_service), |
| cros_settings_(cros_settings), |
| invalidation_service_provider_(invalidation_service_provider), |
| device_management_service_(nullptr), |
| waiting_for_cros_settings_(false), |
| orphan_extension_cache_deletion_state_(NOT_STARTED), |
| store_background_task_runner_(store_background_task_runner), |
| extension_cache_task_runner_(extension_cache_task_runner), |
| resource_cache_task_runner_(base::CreateSequencedTaskRunnerWithTraits( |
| {base::MayBlock(), base::TaskPriority::BACKGROUND})), |
| request_context_(request_context), |
| url_loader_factory_(url_loader_factory), |
| local_accounts_subscription_(cros_settings_->AddSettingsObserver( |
| chromeos::kAccountsPrefDeviceLocalAccounts, |
| base::Bind( |
| &DeviceLocalAccountPolicyService::UpdateAccountListIfNonePending, |
| base::Unretained(this)))), |
| weak_factory_(this) { |
| CHECK(base::PathService::Get( |
| chromeos::DIR_DEVICE_LOCAL_ACCOUNT_COMPONENT_POLICY, |
| &component_policy_cache_root_)); |
| external_data_service_.reset(new DeviceLocalAccountExternalDataService( |
| this, |
| external_data_service_backend_task_runner, |
| io_task_runner)); |
| UpdateAccountList(); |
| } |
| |
| DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() { |
| DCHECK(!request_context_.get()); |
| DCHECK(policy_brokers_.empty()); |
| } |
| |
| void DeviceLocalAccountPolicyService::Shutdown() { |
| device_management_service_ = nullptr; |
| request_context_ = nullptr; |
| DeleteBrokers(&policy_brokers_); |
| } |
| |
| void DeviceLocalAccountPolicyService::Connect( |
| DeviceManagementService* device_management_service) { |
| DCHECK(!device_management_service_); |
| device_management_service_ = device_management_service; |
| |
| // Connect the brokers. |
| for (PolicyBrokerMap::iterator it(policy_brokers_.begin()); |
| it != policy_brokers_.end(); ++it) { |
| it->second->ConnectIfPossible(device_settings_service_, |
| device_management_service_, request_context_, |
| url_loader_factory_); |
| } |
| } |
| |
| DeviceLocalAccountPolicyBroker* |
| DeviceLocalAccountPolicyService::GetBrokerForUser( |
| const std::string& user_id) { |
| PolicyBrokerMap::iterator entry = policy_brokers_.find(user_id); |
| if (entry == policy_brokers_.end()) |
| return nullptr; |
| |
| return entry->second; |
| } |
| |
| bool DeviceLocalAccountPolicyService::IsPolicyAvailableForUser( |
| const std::string& user_id) { |
| DeviceLocalAccountPolicyBroker* broker = GetBrokerForUser(user_id); |
| return broker && broker->core()->store()->is_managed(); |
| } |
| |
| void DeviceLocalAccountPolicyService::AddObserver(Observer* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void DeviceLocalAccountPolicyService::RemoveObserver(Observer* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| bool DeviceLocalAccountPolicyService::IsExtensionCacheDirectoryBusy( |
| const std::string& account_id) { |
| return busy_extension_cache_directories_.find(account_id) != |
| busy_extension_cache_directories_.end(); |
| } |
| |
| void DeviceLocalAccountPolicyService::StartExtensionCachesIfPossible() { |
| for (PolicyBrokerMap::iterator it = policy_brokers_.begin(); |
| it != policy_brokers_.end(); ++it) { |
| if (!it->second->extension_loader()->IsCacheRunning() && |
| !IsExtensionCacheDirectoryBusy(it->second->account_id())) { |
| it->second->extension_loader()->StartCache(extension_cache_task_runner_); |
| } |
| } |
| } |
| |
| bool DeviceLocalAccountPolicyService::StartExtensionCacheForAccountIfPresent( |
| const std::string& account_id) { |
| for (PolicyBrokerMap::iterator it = policy_brokers_.begin(); |
| it != policy_brokers_.end(); ++it) { |
| if (it->second->account_id() == account_id) { |
| DCHECK(!it->second->extension_loader()->IsCacheRunning()); |
| it->second->extension_loader()->StartCache(extension_cache_task_runner_); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted() { |
| DCHECK_EQ(IN_PROGRESS, orphan_extension_cache_deletion_state_); |
| |
| orphan_extension_cache_deletion_state_ = DONE; |
| StartExtensionCachesIfPossible(); |
| } |
| |
| void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown( |
| const std::string& account_id) { |
| DCHECK_NE(NOT_STARTED, orphan_extension_cache_deletion_state_); |
| DCHECK(IsExtensionCacheDirectoryBusy(account_id)); |
| |
| // The account with |account_id| was deleted and the broker for it has shut |
| // down completely. |
| |
| if (StartExtensionCacheForAccountIfPresent(account_id)) { |
| // If another account with the same ID was created in the meantime, its |
| // extension cache is started, reusing the cache directory. The directory no |
| // longer needs to be marked as busy in this case. |
| busy_extension_cache_directories_.erase(account_id); |
| return; |
| } |
| |
| // If no account with |account_id| exists anymore, the cache directory should |
| // be removed. The directory must stay marked as busy while the removal is in |
| // progress. |
| extension_cache_task_runner_->PostTaskAndReply( |
| FROM_HERE, base::BindOnce(&DeleteObsoleteExtensionCache, account_id), |
| base::BindOnce( |
| &DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheDeleted, |
| weak_factory_.GetWeakPtr(), account_id)); |
| } |
| |
| void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheDeleted( |
| const std::string& account_id) { |
| DCHECK_EQ(DONE, orphan_extension_cache_deletion_state_); |
| DCHECK(IsExtensionCacheDirectoryBusy(account_id)); |
| |
| // The cache directory for |account_id| has been deleted. The directory no |
| // longer needs to be marked as busy. |
| busy_extension_cache_directories_.erase(account_id); |
| |
| // If another account with the same ID was created in the meantime, start its |
| // extension cache, creating a new cache directory. |
| StartExtensionCacheForAccountIfPresent(account_id); |
| } |
| |
| void DeviceLocalAccountPolicyService::UpdateAccountListIfNonePending() { |
| // Avoid unnecessary calls to UpdateAccountList(): If an earlier call is still |
| // pending (because the |cros_settings_| are not trusted yet), the updated |
| // account list will be processed by that call when it eventually runs. |
| if (!waiting_for_cros_settings_) |
| UpdateAccountList(); |
| } |
| |
| void DeviceLocalAccountPolicyService::UpdateAccountList() { |
| chromeos::CrosSettingsProvider::TrustedStatus status = |
| cros_settings_->PrepareTrustedValues( |
| base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList, |
| weak_factory_.GetWeakPtr())); |
| switch (status) { |
| case chromeos::CrosSettingsProvider::TRUSTED: |
| waiting_for_cros_settings_ = false; |
| break; |
| case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED: |
| waiting_for_cros_settings_ = true; |
| // Purposely break to allow initialization with temporarily untrusted |
| // settings so that a crash-n-restart public session have its loader |
| // properly registered as ExtensionService's external provider. |
| break; |
| case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED: |
| waiting_for_cros_settings_ = false; |
| return; |
| } |
| |
| // Update |policy_brokers_|, keeping existing entries. |
| PolicyBrokerMap old_policy_brokers; |
| policy_brokers_.swap(old_policy_brokers); |
| std::set<std::string> subdirectories_to_keep; |
| const std::vector<DeviceLocalAccount> device_local_accounts = |
| GetDeviceLocalAccounts(cros_settings_); |
| for (std::vector<DeviceLocalAccount>::const_iterator it = |
| device_local_accounts.begin(); |
| it != device_local_accounts.end(); ++it) { |
| PolicyBrokerMap::iterator broker_it = old_policy_brokers.find(it->user_id); |
| |
| std::unique_ptr<DeviceLocalAccountPolicyBroker> broker; |
| bool broker_initialized = false; |
| if (broker_it != old_policy_brokers.end()) { |
| // Reuse the existing broker if present. |
| broker.reset(broker_it->second); |
| old_policy_brokers.erase(broker_it); |
| broker_initialized = true; |
| } else { |
| std::unique_ptr<DeviceLocalAccountPolicyStore> store( |
| new DeviceLocalAccountPolicyStore( |
| it->account_id, session_manager_client_, device_settings_service_, |
| store_background_task_runner_)); |
| scoped_refptr<DeviceLocalAccountExternalDataManager> |
| external_data_manager = |
| external_data_service_->GetExternalDataManager(it->account_id, |
| store.get()); |
| broker.reset(new DeviceLocalAccountPolicyBroker( |
| *it, |
| component_policy_cache_root_.Append( |
| GetCacheSubdirectoryForAccountID(it->account_id)), |
| std::move(store), external_data_manager, |
| base::Bind(&DeviceLocalAccountPolicyService::NotifyPolicyUpdated, |
| base::Unretained(this), it->user_id), |
| base::ThreadTaskRunnerHandle::Get(), resource_cache_task_runner_, |
| invalidation_service_provider_)); |
| } |
| |
| // Fire up the cloud connection for fetching policy for the account from |
| // the cloud if this is an enterprise-managed device. |
| broker->ConnectIfPossible(device_settings_service_, |
| device_management_service_, request_context_, |
| url_loader_factory_); |
| |
| policy_brokers_[it->user_id] = broker.release(); |
| if (!broker_initialized) { |
| // The broker must be initialized after it has been added to |
| // |policy_brokers_|. |
| policy_brokers_[it->user_id]->Initialize(); |
| } |
| |
| subdirectories_to_keep.insert( |
| GetCacheSubdirectoryForAccountID(it->account_id)); |
| } |
| |
| if (orphan_extension_cache_deletion_state_ == NOT_STARTED) { |
| DCHECK(old_policy_brokers.empty()); |
| DCHECK(busy_extension_cache_directories_.empty()); |
| |
| // If this method is running for the first time, no extension caches have |
| // been started yet. Take this opportunity to do a clean-up by removing |
| // orphaned cache directories not found in |subdirectories_to_keep| from the |
| // cache directory. |
| orphan_extension_cache_deletion_state_ = IN_PROGRESS; |
| |
| base::FilePath cache_root_dir; |
| CHECK(base::PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS, |
| &cache_root_dir)); |
| extension_cache_task_runner_->PostTaskAndReply( |
| FROM_HERE, |
| base::BindOnce(&DeleteOrphanedCaches, cache_root_dir, |
| subdirectories_to_keep), |
| base::BindOnce( |
| &DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted, |
| weak_factory_.GetWeakPtr())); |
| |
| // Start the extension caches for all brokers. These belong to accounts in |
| // |account_ids| and are not affected by the clean-up. |
| StartExtensionCachesIfPossible(); |
| } else { |
| // If this method has run before, obsolete brokers may exist. Shut down |
| // their extension caches and delete the brokers. |
| DeleteBrokers(&old_policy_brokers); |
| |
| if (orphan_extension_cache_deletion_state_ == DONE) { |
| // If the initial clean-up of orphaned cache directories has been |
| // complete, start any extension caches that are not running yet but can |
| // be started now because their cache directories are not busy. |
| StartExtensionCachesIfPossible(); |
| } |
| } |
| |
| // Purge the component policy caches of any accounts that have been removed. |
| // Do this only after any obsolete brokers have been destroyed. This races |
| // with ComponentCloudPolicyStore so make sure they both run on the same task |
| // runner. |
| resource_cache_task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&DeleteOrphanedCaches, component_policy_cache_root_, |
| subdirectories_to_keep)); |
| |
| for (auto& observer : observers_) |
| observer.OnDeviceLocalAccountsChanged(); |
| } |
| |
| void DeviceLocalAccountPolicyService::DeleteBrokers(PolicyBrokerMap* map) { |
| for (PolicyBrokerMap::iterator it = map->begin(); it != map->end(); ++it) { |
| scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader> |
| extension_loader = it->second->extension_loader(); |
| if (extension_loader->IsCacheRunning()) { |
| DCHECK(!IsExtensionCacheDirectoryBusy(it->second->account_id())); |
| busy_extension_cache_directories_.insert(it->second->account_id()); |
| extension_loader->StopCache(base::Bind( |
| &DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown, |
| weak_factory_.GetWeakPtr(), |
| it->second->account_id())); |
| } |
| |
| delete it->second; |
| } |
| map->clear(); |
| } |
| |
| void DeviceLocalAccountPolicyService::NotifyPolicyUpdated( |
| const std::string& user_id) { |
| for (auto& observer : observers_) |
| observer.OnPolicyUpdated(user_id); |
| } |
| |
| } // namespace policy |