Home | History | Annotate | Download | only in policy
      1 // Copyright (c) 2012 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_local_account_policy_service.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/command_line.h"
     12 #include "base/file_util.h"
     13 #include "base/files/file_enumerator.h"
     14 #include "base/logging.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/message_loop/message_loop_proxy.h"
     17 #include "base/path_service.h"
     18 #include "base/sequenced_task_runner.h"
     19 #include "base/stl_util.h"
     20 #include "base/strings/string_number_conversions.h"
     21 #include "chrome/browser/browser_process.h"
     22 #include "chrome/browser/chromeos/policy/device_local_account.h"
     23 #include "chrome/browser/chromeos/policy/device_local_account_external_data_service.h"
     24 #include "chrome/browser/chromeos/policy/device_local_account_policy_store.h"
     25 #include "chrome/browser/chromeos/settings/device_settings_service.h"
     26 #include "chrome/common/chrome_content_client.h"
     27 #include "chromeos/chromeos_paths.h"
     28 #include "chromeos/dbus/session_manager_client.h"
     29 #include "chromeos/settings/cros_settings_names.h"
     30 #include "chromeos/settings/cros_settings_provider.h"
     31 #include "components/policy/core/browser/browser_policy_connector.h"
     32 #include "components/policy/core/common/cloud/cloud_policy_client.h"
     33 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
     34 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
     35 #include "components/policy/core/common/cloud/device_management_service.h"
     36 #include "components/policy/core/common/cloud/resource_cache.h"
     37 #include "components/policy/core/common/cloud/system_policy_request_context.h"
     38 #include "components/policy/core/common/policy_switches.h"
     39 #include "content/public/browser/browser_thread.h"
     40 #include "net/url_request/url_request_context_getter.h"
     41 #include "policy/policy_constants.h"
     42 #include "policy/proto/device_management_backend.pb.h"
     43 #include "url/gurl.h"
     44 
     45 namespace em = enterprise_management;
     46 
     47 namespace policy {
     48 
     49 namespace {
     50 
     51 // Creates and initializes a cloud policy client. Returns NULL if the device
     52 // doesn't have credentials in device settings (i.e. is not
     53 // enterprise-enrolled).
     54 scoped_ptr<CloudPolicyClient> CreateClient(
     55     chromeos::DeviceSettingsService* device_settings_service,
     56     DeviceManagementService* device_management_service,
     57     scoped_refptr<net::URLRequestContextGetter> system_request_context) {
     58   const em::PolicyData* policy_data = device_settings_service->policy_data();
     59   if (!policy_data ||
     60       !policy_data->has_request_token() ||
     61       !policy_data->has_device_id() ||
     62       !device_management_service) {
     63     return scoped_ptr<CloudPolicyClient>();
     64   }
     65 
     66   scoped_refptr<net::URLRequestContextGetter> request_context =
     67       new SystemPolicyRequestContext(
     68           system_request_context, GetUserAgent());
     69 
     70   scoped_ptr<CloudPolicyClient> client(
     71       new CloudPolicyClient(std::string(), std::string(),
     72                             kPolicyVerificationKeyHash,
     73                             USER_AFFILIATION_MANAGED,
     74                             NULL, device_management_service, request_context));
     75   client->SetupRegistration(policy_data->request_token(),
     76                             policy_data->device_id());
     77   return client.Pass();
     78 }
     79 
     80 // Get the subdirectory of the force-installed extension cache and the component
     81 // policy cache used for |account_id|.
     82 std::string GetCacheSubdirectoryForAccountID(const std::string& account_id) {
     83   return base::HexEncode(account_id.c_str(), account_id.size());
     84 }
     85 
     86 // Cleans up the cache directory by removing subdirectories that are not found
     87 // in |subdirectories_to_keep|. Only caches whose cache directory is found in
     88 // |subdirectories_to_keep| may be running while the clean-up is in progress.
     89 void DeleteOrphanedCaches(
     90     const base::FilePath& cache_root_dir,
     91     const std::set<std::string>& subdirectories_to_keep) {
     92   base::FileEnumerator enumerator(cache_root_dir,
     93                                   false,
     94                                   base::FileEnumerator::DIRECTORIES);
     95   for (base::FilePath path = enumerator.Next(); !path.empty();
     96        path = enumerator.Next()) {
     97     const std::string subdirectory(path.BaseName().MaybeAsASCII());
     98     if (!ContainsKey(subdirectories_to_keep, subdirectory))
     99       base::DeleteFile(path, true);
    100   }
    101 }
    102 
    103 // Removes the subdirectory belonging to |account_id_to_delete| from the cache
    104 // directory. No cache belonging to |account_id_to_delete| may be running while
    105 // the removal is in progress.
    106 void DeleteObsoleteExtensionCache(const std::string& account_id_to_delete) {
    107   base::FilePath cache_root_dir;
    108   CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
    109                          &cache_root_dir));
    110   const base::FilePath path = cache_root_dir.Append(
    111       GetCacheSubdirectoryForAccountID(account_id_to_delete));
    112   if (base::DirectoryExists(path))
    113     base::DeleteFile(path, true);
    114 }
    115 
    116 }  // namespace
    117 
    118 DeviceLocalAccountPolicyBroker::DeviceLocalAccountPolicyBroker(
    119     const DeviceLocalAccount& account,
    120     const base::FilePath& component_policy_cache_path,
    121     scoped_ptr<DeviceLocalAccountPolicyStore> store,
    122     scoped_refptr<DeviceLocalAccountExternalDataManager> external_data_manager,
    123     const base::Closure& policy_update_callback,
    124     const scoped_refptr<base::SequencedTaskRunner>& task_runner)
    125     : account_id_(account.account_id),
    126       user_id_(account.user_id),
    127       component_policy_cache_path_(component_policy_cache_path),
    128       store_(store.Pass()),
    129       extension_tracker_(account, store_.get(), &schema_registry_),
    130       external_data_manager_(external_data_manager),
    131       core_(PolicyNamespaceKey(dm_protocol::kChromePublicAccountPolicyType,
    132                                store_->account_id()),
    133             store_.get(),
    134             task_runner),
    135       policy_update_callback_(policy_update_callback) {
    136   base::FilePath cache_root_dir;
    137   CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
    138                          &cache_root_dir));
    139   extension_loader_ = new chromeos::DeviceLocalAccountExternalPolicyLoader(
    140       store_.get(),
    141       cache_root_dir.Append(
    142           GetCacheSubdirectoryForAccountID(account.account_id)));
    143   store_->AddObserver(this);
    144 
    145   // Unblock the |schema_registry_| so that the |component_policy_service_|
    146   // starts using it.
    147   schema_registry_.RegisterComponent(
    148       PolicyNamespace(POLICY_DOMAIN_CHROME, ""),
    149       g_browser_process->browser_policy_connector()->GetChromeSchema());
    150   schema_registry_.SetReady(POLICY_DOMAIN_CHROME);
    151   schema_registry_.SetReady(POLICY_DOMAIN_EXTENSIONS);
    152 }
    153 
    154 DeviceLocalAccountPolicyBroker::~DeviceLocalAccountPolicyBroker() {
    155   store_->RemoveObserver(this);
    156   external_data_manager_->SetPolicyStore(NULL);
    157   external_data_manager_->Disconnect();
    158 }
    159 
    160 void DeviceLocalAccountPolicyBroker::Initialize() {
    161   store_->Load();
    162 }
    163 
    164 void DeviceLocalAccountPolicyBroker::ConnectIfPossible(
    165     chromeos::DeviceSettingsService* device_settings_service,
    166     DeviceManagementService* device_management_service,
    167     scoped_refptr<net::URLRequestContextGetter> request_context) {
    168   if (core_.client())
    169     return;
    170 
    171   scoped_ptr<CloudPolicyClient> client(CreateClient(device_settings_service,
    172                                                     device_management_service,
    173                                                     request_context));
    174   if (!client)
    175     return;
    176 
    177   core_.Connect(client.Pass());
    178   external_data_manager_->Connect(request_context);
    179   core_.StartRefreshScheduler();
    180   UpdateRefreshDelay();
    181   CreateComponentCloudPolicyService(request_context);
    182 }
    183 
    184 void DeviceLocalAccountPolicyBroker::UpdateRefreshDelay() {
    185   if (core_.refresh_scheduler()) {
    186     const base::Value* policy_value =
    187         store_->policy_map().GetValue(key::kPolicyRefreshRate);
    188     int delay = 0;
    189     if (policy_value && policy_value->GetAsInteger(&delay))
    190       core_.refresh_scheduler()->SetRefreshDelay(delay);
    191   }
    192 }
    193 
    194 std::string DeviceLocalAccountPolicyBroker::GetDisplayName() const {
    195   std::string display_name;
    196   const base::Value* display_name_value =
    197       store_->policy_map().GetValue(policy::key::kUserDisplayName);
    198   if (display_name_value)
    199     display_name_value->GetAsString(&display_name);
    200   return display_name;
    201 }
    202 
    203 void DeviceLocalAccountPolicyBroker::OnStoreLoaded(CloudPolicyStore* store) {
    204   UpdateRefreshDelay();
    205   policy_update_callback_.Run();
    206 }
    207 
    208 void DeviceLocalAccountPolicyBroker::OnStoreError(CloudPolicyStore* store) {
    209   policy_update_callback_.Run();
    210 }
    211 
    212 void DeviceLocalAccountPolicyBroker::OnComponentCloudPolicyUpdated() {
    213   policy_update_callback_.Run();
    214 }
    215 
    216 void DeviceLocalAccountPolicyBroker::CreateComponentCloudPolicyService(
    217     const scoped_refptr<net::URLRequestContextGetter>& request_context) {
    218   if (CommandLine::ForCurrentProcess()->HasSwitch(
    219           switches::kDisableComponentCloudPolicy)) {
    220     // Disabled via the command line.
    221     return;
    222   }
    223 
    224   scoped_ptr<ResourceCache> resource_cache(
    225       new ResourceCache(component_policy_cache_path_,
    226                         content::BrowserThread::GetMessageLoopProxyForThread(
    227                             content::BrowserThread::FILE)));
    228 
    229   component_policy_service_.reset(new ComponentCloudPolicyService(
    230       this,
    231       &schema_registry_,
    232       core(),
    233       resource_cache.Pass(),
    234       request_context,
    235       content::BrowserThread::GetMessageLoopProxyForThread(
    236           content::BrowserThread::FILE),
    237       content::BrowserThread::GetMessageLoopProxyForThread(
    238           content::BrowserThread::IO)));
    239 }
    240 
    241 DeviceLocalAccountPolicyService::DeviceLocalAccountPolicyService(
    242     chromeos::SessionManagerClient* session_manager_client,
    243     chromeos::DeviceSettingsService* device_settings_service,
    244     chromeos::CrosSettings* cros_settings,
    245     scoped_refptr<base::SequencedTaskRunner> store_background_task_runner,
    246     scoped_refptr<base::SequencedTaskRunner> extension_cache_task_runner,
    247     scoped_refptr<base::SequencedTaskRunner>
    248         external_data_service_backend_task_runner,
    249     scoped_refptr<base::SequencedTaskRunner> io_task_runner,
    250     scoped_refptr<net::URLRequestContextGetter> request_context)
    251     : session_manager_client_(session_manager_client),
    252       device_settings_service_(device_settings_service),
    253       cros_settings_(cros_settings),
    254       device_management_service_(NULL),
    255       waiting_for_cros_settings_(false),
    256       orphan_extension_cache_deletion_state_(NOT_STARTED),
    257       store_background_task_runner_(store_background_task_runner),
    258       extension_cache_task_runner_(extension_cache_task_runner),
    259       request_context_(request_context),
    260       local_accounts_subscription_(cros_settings_->AddSettingsObserver(
    261           chromeos::kAccountsPrefDeviceLocalAccounts,
    262           base::Bind(&DeviceLocalAccountPolicyService::
    263                          UpdateAccountListIfNonePending,
    264                      base::Unretained(this)))),
    265       weak_factory_(this) {
    266   CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_COMPONENT_POLICY,
    267                          &component_policy_cache_root_));
    268   external_data_service_.reset(new DeviceLocalAccountExternalDataService(
    269       this,
    270       external_data_service_backend_task_runner,
    271       io_task_runner));
    272   UpdateAccountList();
    273 }
    274 
    275 DeviceLocalAccountPolicyService::~DeviceLocalAccountPolicyService() {
    276   DCHECK(!request_context_);
    277   DCHECK(policy_brokers_.empty());
    278 }
    279 
    280 void DeviceLocalAccountPolicyService::Shutdown() {
    281   device_management_service_ = NULL;
    282   request_context_ = NULL;
    283   DeleteBrokers(&policy_brokers_);
    284 }
    285 
    286 void DeviceLocalAccountPolicyService::Connect(
    287     DeviceManagementService* device_management_service) {
    288   DCHECK(!device_management_service_);
    289   device_management_service_ = device_management_service;
    290 
    291   // Connect the brokers.
    292   for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
    293        it != policy_brokers_.end(); ++it) {
    294     it->second->ConnectIfPossible(device_settings_service_,
    295                                   device_management_service_,
    296                                   request_context_);
    297   }
    298 }
    299 
    300 DeviceLocalAccountPolicyBroker*
    301     DeviceLocalAccountPolicyService::GetBrokerForUser(
    302         const std::string& user_id) {
    303   PolicyBrokerMap::iterator entry = policy_brokers_.find(user_id);
    304   if (entry == policy_brokers_.end())
    305     return NULL;
    306 
    307   return entry->second;
    308 }
    309 
    310 bool DeviceLocalAccountPolicyService::IsPolicyAvailableForUser(
    311     const std::string& user_id) {
    312   DeviceLocalAccountPolicyBroker* broker = GetBrokerForUser(user_id);
    313   return broker && broker->core()->store()->is_managed();
    314 }
    315 
    316 void DeviceLocalAccountPolicyService::AddObserver(Observer* observer) {
    317   observers_.AddObserver(observer);
    318 }
    319 
    320 void DeviceLocalAccountPolicyService::RemoveObserver(Observer* observer) {
    321   observers_.RemoveObserver(observer);
    322 }
    323 
    324 bool DeviceLocalAccountPolicyService::IsExtensionCacheDirectoryBusy(
    325     const std::string& account_id) {
    326   return busy_extension_cache_directories_.find(account_id) !=
    327             busy_extension_cache_directories_.end();
    328 }
    329 
    330 void DeviceLocalAccountPolicyService::StartExtensionCachesIfPossible() {
    331   for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
    332        it != policy_brokers_.end(); ++it) {
    333     if (!it->second->extension_loader()->IsCacheRunning() &&
    334         !IsExtensionCacheDirectoryBusy(it->second->account_id())) {
    335       it->second->extension_loader()->StartCache(extension_cache_task_runner_);
    336     }
    337   }
    338 }
    339 
    340 bool DeviceLocalAccountPolicyService::StartExtensionCacheForAccountIfPresent(
    341     const std::string& account_id) {
    342   for (PolicyBrokerMap::iterator it = policy_brokers_.begin();
    343        it != policy_brokers_.end(); ++it) {
    344     if (it->second->account_id() == account_id) {
    345       DCHECK(!it->second->extension_loader()->IsCacheRunning());
    346       it->second->extension_loader()->StartCache(extension_cache_task_runner_);
    347       return true;
    348     }
    349   }
    350   return false;
    351 }
    352 
    353 void DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted() {
    354   DCHECK_EQ(IN_PROGRESS, orphan_extension_cache_deletion_state_);
    355 
    356   orphan_extension_cache_deletion_state_ = DONE;
    357   StartExtensionCachesIfPossible();
    358 }
    359 
    360 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown(
    361     const std::string& account_id) {
    362   DCHECK_NE(NOT_STARTED, orphan_extension_cache_deletion_state_);
    363   DCHECK(IsExtensionCacheDirectoryBusy(account_id));
    364 
    365   // The account with |account_id| was deleted and the broker for it has shut
    366   // down completely.
    367 
    368   if (StartExtensionCacheForAccountIfPresent(account_id)) {
    369     // If another account with the same ID was created in the meantime, its
    370     // extension cache is started, reusing the cache directory. The directory no
    371     // longer needs to be marked as busy in this case.
    372     busy_extension_cache_directories_.erase(account_id);
    373     return;
    374   }
    375 
    376   // If no account with |account_id| exists anymore, the cache directory should
    377   // be removed. The directory must stay marked as busy while the removal is in
    378   // progress.
    379   extension_cache_task_runner_->PostTaskAndReply(
    380       FROM_HERE,
    381       base::Bind(&DeleteObsoleteExtensionCache, account_id),
    382       base::Bind(&DeviceLocalAccountPolicyService::
    383                      OnObsoleteExtensionCacheDeleted,
    384                  weak_factory_.GetWeakPtr(),
    385                  account_id));
    386 }
    387 
    388 void DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheDeleted(
    389     const std::string& account_id) {
    390   DCHECK_EQ(DONE, orphan_extension_cache_deletion_state_);
    391   DCHECK(IsExtensionCacheDirectoryBusy(account_id));
    392 
    393   // The cache directory for |account_id| has been deleted. The directory no
    394   // longer needs to be marked as busy.
    395   busy_extension_cache_directories_.erase(account_id);
    396 
    397   // If another account with the same ID was created in the meantime, start its
    398   // extension cache, creating a new cache directory.
    399   StartExtensionCacheForAccountIfPresent(account_id);
    400 }
    401 
    402 void DeviceLocalAccountPolicyService::UpdateAccountListIfNonePending() {
    403   // Avoid unnecessary calls to UpdateAccountList(): If an earlier call is still
    404   // pending (because the |cros_settings_| are not trusted yet), the updated
    405   // account list will be processed by that call when it eventually runs.
    406   if (!waiting_for_cros_settings_)
    407     UpdateAccountList();
    408 }
    409 
    410 void DeviceLocalAccountPolicyService::UpdateAccountList() {
    411   chromeos::CrosSettingsProvider::TrustedStatus status =
    412       cros_settings_->PrepareTrustedValues(
    413           base::Bind(&DeviceLocalAccountPolicyService::UpdateAccountList,
    414                      weak_factory_.GetWeakPtr()));
    415   switch (status) {
    416     case chromeos::CrosSettingsProvider::TRUSTED:
    417       waiting_for_cros_settings_ = false;
    418       break;
    419     case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
    420       waiting_for_cros_settings_ = true;
    421       return;
    422     case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
    423       waiting_for_cros_settings_ = false;
    424       return;
    425   }
    426 
    427   // Update |policy_brokers_|, keeping existing entries.
    428   PolicyBrokerMap old_policy_brokers;
    429   policy_brokers_.swap(old_policy_brokers);
    430   std::set<std::string> subdirectories_to_keep;
    431   const std::vector<DeviceLocalAccount> device_local_accounts =
    432       GetDeviceLocalAccounts(cros_settings_);
    433   for (std::vector<DeviceLocalAccount>::const_iterator it =
    434            device_local_accounts.begin();
    435        it != device_local_accounts.end(); ++it) {
    436     PolicyBrokerMap::iterator broker_it = old_policy_brokers.find(it->user_id);
    437 
    438     scoped_ptr<DeviceLocalAccountPolicyBroker> broker;
    439     bool broker_initialized = false;
    440     if (broker_it != old_policy_brokers.end()) {
    441       // Reuse the existing broker if present.
    442       broker.reset(broker_it->second);
    443       old_policy_brokers.erase(broker_it);
    444       broker_initialized = true;
    445     } else {
    446       scoped_ptr<DeviceLocalAccountPolicyStore> store(
    447           new DeviceLocalAccountPolicyStore(it->account_id,
    448                                             session_manager_client_,
    449                                             device_settings_service_,
    450                                             store_background_task_runner_));
    451       scoped_refptr<DeviceLocalAccountExternalDataManager>
    452           external_data_manager =
    453               external_data_service_->GetExternalDataManager(it->account_id,
    454                                                              store.get());
    455       broker.reset(new DeviceLocalAccountPolicyBroker(
    456           *it,
    457           component_policy_cache_root_.Append(
    458               GetCacheSubdirectoryForAccountID(it->account_id)),
    459           store.Pass(),
    460           external_data_manager,
    461           base::Bind(&DeviceLocalAccountPolicyService::NotifyPolicyUpdated,
    462                      base::Unretained(this),
    463                      it->user_id),
    464           base::MessageLoopProxy::current()));
    465     }
    466 
    467     // Fire up the cloud connection for fetching policy for the account from
    468     // the cloud if this is an enterprise-managed device.
    469     broker->ConnectIfPossible(device_settings_service_,
    470                               device_management_service_,
    471                               request_context_);
    472 
    473     policy_brokers_[it->user_id] = broker.release();
    474     if (!broker_initialized) {
    475       // The broker must be initialized after it has been added to
    476       // |policy_brokers_|.
    477       policy_brokers_[it->user_id]->Initialize();
    478     }
    479 
    480     subdirectories_to_keep.insert(
    481         GetCacheSubdirectoryForAccountID(it->account_id));
    482   }
    483 
    484   if (orphan_extension_cache_deletion_state_ == NOT_STARTED) {
    485     DCHECK(old_policy_brokers.empty());
    486     DCHECK(busy_extension_cache_directories_.empty());
    487 
    488     // If this method is running for the first time, no extension caches have
    489     // been started yet. Take this opportunity to do a clean-up by removing
    490     // orphaned cache directories not found in |subdirectories_to_keep| from the
    491     // cache directory.
    492     orphan_extension_cache_deletion_state_ = IN_PROGRESS;
    493 
    494     base::FilePath cache_root_dir;
    495     CHECK(PathService::Get(chromeos::DIR_DEVICE_LOCAL_ACCOUNT_EXTENSIONS,
    496                            &cache_root_dir));
    497     extension_cache_task_runner_->PostTaskAndReply(
    498         FROM_HERE,
    499         base::Bind(
    500             &DeleteOrphanedCaches, cache_root_dir, subdirectories_to_keep),
    501         base::Bind(
    502             &DeviceLocalAccountPolicyService::OnOrphanedExtensionCachesDeleted,
    503             weak_factory_.GetWeakPtr()));
    504 
    505     // Start the extension caches for all brokers. These belong to accounts in
    506     // |account_ids| and are not affected by the clean-up.
    507     StartExtensionCachesIfPossible();
    508   } else {
    509     // If this method has run before, obsolete brokers may exist. Shut down
    510     // their extension caches and delete the brokers.
    511     DeleteBrokers(&old_policy_brokers);
    512 
    513     if (orphan_extension_cache_deletion_state_ == DONE) {
    514       // If the initial clean-up of orphaned cache directories has been
    515       // complete, start any extension caches that are not running yet but can
    516       // be started now because their cache directories are not busy.
    517       StartExtensionCachesIfPossible();
    518     }
    519   }
    520 
    521   // Purge the component policy caches of any accounts that have been removed.
    522   // Do this only after any obsolete brokers have been destroyed.
    523   // TODO(joaodasilva): for now this must be posted to the FILE thread,
    524   // to avoid racing with the ComponentCloudPolicyStore. Use a task runner
    525   // once that class supports another background thread too.
    526   content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
    527                                    base::Bind(&DeleteOrphanedCaches,
    528                                               component_policy_cache_root_,
    529                                               subdirectories_to_keep));
    530 
    531   FOR_EACH_OBSERVER(Observer, observers_, OnDeviceLocalAccountsChanged());
    532 }
    533 
    534 void DeviceLocalAccountPolicyService::DeleteBrokers(PolicyBrokerMap* map) {
    535   for (PolicyBrokerMap::iterator it = map->begin(); it != map->end(); ++it) {
    536     scoped_refptr<chromeos::DeviceLocalAccountExternalPolicyLoader>
    537         extension_loader = it->second->extension_loader();
    538     if (extension_loader->IsCacheRunning()) {
    539       DCHECK(!IsExtensionCacheDirectoryBusy(it->second->account_id()));
    540       busy_extension_cache_directories_.insert(it->second->account_id());
    541       extension_loader->StopCache(base::Bind(
    542           &DeviceLocalAccountPolicyService::OnObsoleteExtensionCacheShutdown,
    543           weak_factory_.GetWeakPtr(),
    544           it->second->account_id()));
    545     }
    546 
    547     delete it->second;
    548   }
    549   map->clear();
    550 }
    551 
    552 DeviceLocalAccountPolicyBroker*
    553     DeviceLocalAccountPolicyService::GetBrokerForStore(
    554         CloudPolicyStore* store) {
    555   for (PolicyBrokerMap::iterator it(policy_brokers_.begin());
    556        it != policy_brokers_.end(); ++it) {
    557     if (it->second->core()->store() == store)
    558       return it->second;
    559   }
    560   return NULL;
    561 }
    562 
    563 void DeviceLocalAccountPolicyService::NotifyPolicyUpdated(
    564     const std::string& user_id) {
    565   FOR_EACH_OBSERVER(Observer, observers_, OnPolicyUpdated(user_id));
    566 }
    567 
    568 }  // namespace policy
    569