Index: chrome/browser/policy/cloud_policy_controller.cc |
diff --git a/chrome/browser/policy/cloud_policy_controller.cc b/chrome/browser/policy/cloud_policy_controller.cc |
deleted file mode 100644 |
index bd4b9b56d8095c935152072364fd163b60f6e603..0000000000000000000000000000000000000000 |
--- a/chrome/browser/policy/cloud_policy_controller.cc |
+++ /dev/null |
@@ -1,481 +0,0 @@ |
-// 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/policy/cloud_policy_controller.h" |
- |
-#include <algorithm> |
-#include <string> |
- |
-#include "base/bind.h" |
-#include "base/guid.h" |
-#include "base/logging.h" |
-#include "base/metrics/histogram.h" |
-#include "base/rand_util.h" |
-#include "chrome/browser/policy/browser_policy_connector.h" |
-#include "chrome/browser/policy/cloud_policy_cache_base.h" |
-#include "chrome/browser/policy/cloud_policy_constants.h" |
-#include "chrome/browser/policy/cloud_policy_subsystem.h" |
-#include "chrome/browser/policy/delayed_work_scheduler.h" |
-#include "chrome/browser/policy/device_management_service.h" |
-#include "chrome/browser/policy/device_token_fetcher.h" |
-#include "chrome/browser/policy/enterprise_metrics.h" |
-#include "chrome/browser/policy/policy_notifier.h" |
- |
-namespace policy { |
- |
-namespace { |
- |
-// The maximum ratio in percent of the policy refresh rate we use for adjusting |
-// the policy refresh time instant. The rationale is to avoid load spikes from |
-// many devices that were set up in sync for some reason. |
-const int kPolicyRefreshDeviationFactorPercent = 10; |
-// Maximum deviation we are willing to accept. |
-const int64 kPolicyRefreshDeviationMaxInMilliseconds = 30 * 60 * 1000; |
- |
-// These are the base values for delays before retrying after an error. They |
-// will be doubled each time they are used. |
-const int64 kPolicyRefreshErrorDelayInMilliseconds = |
- 5 * 60 * 1000; // 5 minutes. |
- |
-// Default value for the policy refresh rate. |
-const int kPolicyRefreshRateInMilliseconds = 3 * 60 * 60 * 1000; // 3 hours. |
- |
-// Records the UMA metric corresponding to |status|, if it represents an error. |
-// Also records that a fetch response was received. |
-void SampleErrorStatus(DeviceManagementStatus status) { |
- UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, |
- kMetricPolicyFetchResponseReceived, |
- kMetricPolicySize); |
- int sample = -1; |
- switch (status) { |
- case DM_STATUS_SUCCESS: |
- return; |
- case DM_STATUS_SERVICE_POLICY_NOT_FOUND: |
- sample = kMetricPolicyFetchNotFound; |
- break; |
- case DM_STATUS_SERVICE_DEVICE_NOT_FOUND: |
- sample = kMetricPolicyFetchInvalidToken; |
- break; |
- case DM_STATUS_RESPONSE_DECODING_ERROR: |
- sample = kMetricPolicyFetchBadResponse; |
- break; |
- case DM_STATUS_REQUEST_FAILED: |
- case DM_STATUS_REQUEST_INVALID: |
- case DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID: |
- sample = kMetricPolicyFetchRequestFailed; |
- break; |
- case DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED: |
- case DM_STATUS_SERVICE_DEVICE_ID_CONFLICT: |
- case DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER: |
- case DM_STATUS_TEMPORARY_UNAVAILABLE: |
- case DM_STATUS_SERVICE_ACTIVATION_PENDING: |
- case DM_STATUS_HTTP_STATUS_ERROR: |
- case DM_STATUS_SERVICE_MISSING_LICENSES: |
- sample = kMetricPolicyFetchServerFailed; |
- break; |
- } |
- if (sample != -1) |
- UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, sample, kMetricPolicySize); |
- else |
- NOTREACHED(); |
-} |
- |
-} // namespace |
- |
-namespace em = enterprise_management; |
- |
-CloudPolicyController::CloudPolicyController( |
- DeviceManagementService* service, |
- CloudPolicyCacheBase* cache, |
- DeviceTokenFetcher* token_fetcher, |
- CloudPolicyDataStore* data_store, |
- PolicyNotifier* notifier) { |
- Initialize(service, |
- cache, |
- token_fetcher, |
- data_store, |
- notifier, |
- new DelayedWorkScheduler); |
-} |
- |
-CloudPolicyController::~CloudPolicyController() { |
- data_store_->RemoveObserver(this); |
- scheduler_->CancelDelayedWork(); |
-} |
- |
-void CloudPolicyController::SetRefreshRate(int64 refresh_rate_milliseconds) { |
- policy_refresh_rate_ms_ = refresh_rate_milliseconds; |
- |
- // Reschedule the refresh task if necessary. |
- if (state_ == STATE_POLICY_VALID) { |
- scheduler_->CancelDelayedWork(); |
- base::Time now(base::Time::NowFromSystemTime()); |
- ScheduleDelayedWorkTask( |
- (GetLastRefreshTime(now) + GetRefreshDelay()) - now); |
- } |
-} |
- |
-void CloudPolicyController::Retry() { |
- scheduler_->CancelDelayedWork(); |
- DoWork(); |
-} |
- |
-void CloudPolicyController::Reset() { |
- SetState(STATE_TOKEN_UNAVAILABLE); |
-} |
- |
-void CloudPolicyController::RefreshPolicies(bool wait_for_auth_token) { |
- // This call must eventually trigger a notification to the cache. |
- if (data_store_->device_token().empty()) { |
- // The DMToken has to be fetched. |
- if (ReadyToFetchToken()) { |
- SetState(STATE_TOKEN_UNAVAILABLE); |
- } else if (!wait_for_auth_token) { |
- // The controller doesn't have enough material to start a token fetch, |
- // but observers of the cache are waiting for the refresh. |
- SetState(STATE_TOKEN_UNMANAGED); |
- } |
- } else { |
- // The token is valid, so the next step is to fetch policy. |
- SetState(STATE_TOKEN_VALID); |
- } |
-} |
- |
-void CloudPolicyController::OnPolicyFetchCompleted( |
- DeviceManagementStatus status, |
- const em::DeviceManagementResponse& response) { |
- if (status == DM_STATUS_SUCCESS && !response.has_policy_response()) { |
- // Handled below. |
- status = DM_STATUS_RESPONSE_DECODING_ERROR; |
- } |
- |
- SampleErrorStatus(status); |
- |
- switch (status) { |
- case DM_STATUS_SUCCESS: { |
- const em::DevicePolicyResponse& policy_response( |
- response.policy_response()); |
- if (policy_response.response_size() > 0) { |
- if (policy_response.response_size() > 1) { |
- LOG(WARNING) << "More than one policy in the response of the device " |
- << "management server, discarding."; |
- } |
- const em::PolicyFetchResponse& fetch_response( |
- policy_response.response(0)); |
- if (!fetch_response.has_error_code() || |
- fetch_response.error_code() == dm_protocol::POLICY_FETCH_SUCCESS) { |
- if (cache_->SetPolicy(fetch_response)) |
- SetState(STATE_POLICY_VALID); |
- else |
- SetState(STATE_POLICY_ERROR); |
- } else { |
- UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, |
- kMetricPolicyFetchBadResponse, |
- kMetricPolicySize); |
- SetState(STATE_POLICY_UNAVAILABLE); |
- } |
- } else { |
- UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyFetchBadResponse, |
- kMetricPolicySize); |
- SetState(STATE_POLICY_UNAVAILABLE); |
- } |
- return; |
- } |
- case DM_STATUS_SERVICE_DEVICE_NOT_FOUND: |
- case DM_STATUS_SERVICE_DEVICE_ID_CONFLICT: |
- case DM_STATUS_SERVICE_MANAGEMENT_TOKEN_INVALID: |
- LOG(WARNING) << "The device token was either invalid or unknown to the " |
- << "device manager, re-registering device."; |
- // Will retry fetching a token but gracefully backing off. |
- SetState(STATE_TOKEN_ERROR); |
- return; |
- case DM_STATUS_SERVICE_INVALID_SERIAL_NUMBER: |
- VLOG(1) << "The device is no longer enlisted for the domain."; |
- token_fetcher_->SetSerialNumberInvalidState(); |
- SetState(STATE_TOKEN_ERROR); |
- return; |
- case DM_STATUS_SERVICE_MISSING_LICENSES: |
- VLOG(1) << "There are no valid licenses for this domain left."; |
- token_fetcher_->SetMissingLicensesState(); |
- SetState(STATE_TOKEN_UNMANAGED); |
- return; |
- case DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED: |
- VLOG(1) << "The device is no longer managed."; |
- token_fetcher_->SetUnmanagedState(); |
- SetState(STATE_TOKEN_UNMANAGED); |
- return; |
- case DM_STATUS_SERVICE_POLICY_NOT_FOUND: |
- case DM_STATUS_REQUEST_INVALID: |
- case DM_STATUS_SERVICE_ACTIVATION_PENDING: |
- case DM_STATUS_RESPONSE_DECODING_ERROR: |
- case DM_STATUS_HTTP_STATUS_ERROR: |
- VLOG(1) << "An error in the communication with the policy server occurred" |
- << ", will retry in a few hours."; |
- SetState(STATE_POLICY_UNAVAILABLE); |
- return; |
- case DM_STATUS_REQUEST_FAILED: |
- case DM_STATUS_TEMPORARY_UNAVAILABLE: |
- VLOG(1) << "A temporary error in the communication with the policy server" |
- << " occurred."; |
- // Will retry last operation but gracefully backing off. |
- SetState(STATE_POLICY_ERROR); |
- return; |
- } |
- |
- NOTREACHED(); |
- SetState(STATE_POLICY_ERROR); |
-} |
- |
-void CloudPolicyController::OnDeviceTokenChanged() { |
- if (data_store_->device_token().empty()) { |
- // Additionally clear the generated device id to ensure we don't reuse old |
- // ids which could be potentially used for user tracking. |
- data_store_->set_device_id(std::string()); |
- SetState(STATE_TOKEN_UNAVAILABLE); |
- } else { |
- SetState(STATE_TOKEN_VALID); |
- } |
-} |
- |
-void CloudPolicyController::OnCredentialsChanged() { |
- // This notification is only interesting if we don't have a device token. |
- // If we already have a device token, that must be matching the current |
- // user, because (1) we always recreate the policy subsystem after user |
- // login (2) tokens are cached per user. |
- if (data_store_->device_token().empty()) { |
- notifier_->Inform(CloudPolicySubsystem::UNENROLLED, |
- CloudPolicySubsystem::NO_DETAILS, |
- PolicyNotifier::POLICY_CONTROLLER); |
- effective_policy_refresh_error_delay_ms_ = |
- kPolicyRefreshErrorDelayInMilliseconds; |
- SetState(STATE_TOKEN_UNAVAILABLE); |
- } |
-} |
- |
-CloudPolicyController::CloudPolicyController( |
- DeviceManagementService* service, |
- CloudPolicyCacheBase* cache, |
- DeviceTokenFetcher* token_fetcher, |
- CloudPolicyDataStore* data_store, |
- PolicyNotifier* notifier, |
- DelayedWorkScheduler* scheduler) { |
- Initialize(service, |
- cache, |
- token_fetcher, |
- data_store, |
- notifier, |
- scheduler); |
-} |
- |
-void CloudPolicyController::Initialize( |
- DeviceManagementService* service, |
- CloudPolicyCacheBase* cache, |
- DeviceTokenFetcher* token_fetcher, |
- CloudPolicyDataStore* data_store, |
- PolicyNotifier* notifier, |
- DelayedWorkScheduler* scheduler) { |
- DCHECK(cache); |
- |
- service_ = service; |
- cache_ = cache; |
- token_fetcher_ = token_fetcher; |
- data_store_ = data_store; |
- notifier_ = notifier; |
- state_ = STATE_TOKEN_UNAVAILABLE; |
- policy_refresh_rate_ms_ = kPolicyRefreshRateInMilliseconds; |
- effective_policy_refresh_error_delay_ms_ = |
- kPolicyRefreshErrorDelayInMilliseconds; |
- scheduler_.reset(scheduler); |
- data_store_->AddObserver(this); |
- if (!data_store_->device_token().empty()) |
- SetState(STATE_TOKEN_VALID); |
- else |
- SetState(STATE_TOKEN_UNAVAILABLE); |
-} |
- |
-bool CloudPolicyController::ReadyToFetchToken() { |
- return data_store_->token_cache_loaded() && |
- !data_store_->user_name().empty() && |
- data_store_->has_auth_token(); |
-} |
- |
-void CloudPolicyController::FetchToken() { |
- if (ReadyToFetchToken()) { |
- if (BrowserPolicyConnector::IsNonEnterpriseUser(data_store_->user_name())) { |
- SetState(STATE_TOKEN_UNMANAGED); |
- } else { |
- // Either use an already prepopulated id or generate a new random device |
- // id. (It'll only be kept if registration succeeds.) |
- if (data_store_->device_id().empty()) |
- data_store_->set_device_id(base::GenerateGUID()); |
- token_fetcher_->FetchToken(); |
- } |
- } else { |
- VLOG(1) << "Not ready to fetch DMToken yet, will try again later."; |
- } |
-} |
- |
-void CloudPolicyController::SendPolicyRequest() { |
- DCHECK(!data_store_->device_token().empty()); |
- |
- if (!data_store_->policy_fetching_enabled()) |
- return; |
- |
- request_job_.reset( |
- service_->CreateJob(DeviceManagementRequestJob::TYPE_POLICY_FETCH)); |
- request_job_->SetDMToken(data_store_->device_token()); |
- request_job_->SetClientID(data_store_->device_id()); |
- request_job_->SetUserAffiliation(data_store_->user_affiliation()); |
- |
- em::DeviceManagementRequest* request = request_job_->GetRequest(); |
- em::PolicyFetchRequest* fetch_request = |
- request->mutable_policy_request()->add_request(); |
- fetch_request->set_signature_type(em::PolicyFetchRequest::SHA1_RSA); |
- fetch_request->set_policy_type(data_store_->policy_type()); |
- if (cache_->machine_id_missing() && !data_store_->machine_id().empty()) |
- fetch_request->set_machine_id(data_store_->machine_id()); |
- if (!cache_->is_unmanaged() && |
- !cache_->last_policy_refresh_time().is_null()) { |
- base::TimeDelta timestamp = |
- cache_->last_policy_refresh_time() - base::Time::UnixEpoch(); |
- fetch_request->set_timestamp(timestamp.InMilliseconds()); |
- } |
- int key_version = 0; |
- if (cache_->GetPublicKeyVersion(&key_version)) |
- fetch_request->set_public_key_version(key_version); |
- |
-#if defined(OS_CHROMEOS) |
- if (data_store_->device_status_collector()) { |
- data_store_->device_status_collector()->GetStatus( |
- request->mutable_device_status_report_request()); |
- } |
-#endif |
- |
- request_job_->Start(base::Bind(&CloudPolicyController::OnPolicyFetchCompleted, |
- base::Unretained(this))); |
- UMA_HISTOGRAM_ENUMERATION(kMetricPolicy, kMetricPolicyFetchRequested, |
- kMetricPolicySize); |
-} |
- |
-void CloudPolicyController::DoWork() { |
- switch (state_) { |
- case STATE_TOKEN_UNAVAILABLE: |
- case STATE_TOKEN_ERROR: |
- FetchToken(); |
- return; |
- case STATE_TOKEN_VALID: |
- case STATE_POLICY_VALID: |
- case STATE_POLICY_ERROR: |
- case STATE_POLICY_UNAVAILABLE: |
- SendPolicyRequest(); |
- return; |
- case STATE_TOKEN_UNMANAGED: |
- return; |
- } |
- |
- NOTREACHED() << "Unhandled state" << state_; |
-} |
- |
-void CloudPolicyController::SetState( |
- CloudPolicyController::ControllerState new_state) { |
- state_ = new_state; |
- |
- request_job_.reset(); // Stop any pending requests. |
- |
- base::Time now(base::Time::NowFromSystemTime()); |
- base::Time last_refresh(GetLastRefreshTime(now)); |
- base::Time refresh_at; |
- |
- // Determine when to take the next step. |
- bool inform_notifier_done = false; |
- switch (state_) { |
- case STATE_TOKEN_UNMANAGED: |
- notifier_->Inform(CloudPolicySubsystem::UNMANAGED, |
- CloudPolicySubsystem::NO_DETAILS, |
- PolicyNotifier::POLICY_CONTROLLER); |
- break; |
- case STATE_TOKEN_UNAVAILABLE: |
- // The controller is not yet initialized and needs to immediately fetch |
- // token and policy if present. |
- case STATE_TOKEN_VALID: |
- // Immediately try to fetch the token on initialization or policy after a |
- // token update. Subsequent retries will respect the back-off strategy. |
- refresh_at = now; |
- // |notifier_| isn't informed about anything at this point, we wait for |
- // the result of the next action first. |
- break; |
- case STATE_POLICY_VALID: |
- // Delay is only reset if the policy fetch operation was successful. This |
- // will ensure the server won't get overloaded with retries in case of |
- // a bug on either side. |
- effective_policy_refresh_error_delay_ms_ = |
- kPolicyRefreshErrorDelayInMilliseconds; |
- refresh_at = last_refresh + GetRefreshDelay(); |
- notifier_->Inform(CloudPolicySubsystem::SUCCESS, |
- CloudPolicySubsystem::NO_DETAILS, |
- PolicyNotifier::POLICY_CONTROLLER); |
- break; |
- case STATE_TOKEN_ERROR: |
- notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR, |
- CloudPolicySubsystem::BAD_DMTOKEN, |
- PolicyNotifier::POLICY_CONTROLLER); |
- inform_notifier_done = true; |
- case STATE_POLICY_ERROR: |
- if (!inform_notifier_done) { |
- notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR, |
- CloudPolicySubsystem::POLICY_NETWORK_ERROR, |
- PolicyNotifier::POLICY_CONTROLLER); |
- } |
- refresh_at = now + base::TimeDelta::FromMilliseconds( |
- effective_policy_refresh_error_delay_ms_); |
- effective_policy_refresh_error_delay_ms_ = |
- std::min(effective_policy_refresh_error_delay_ms_ * 2, |
- policy_refresh_rate_ms_); |
- break; |
- case STATE_POLICY_UNAVAILABLE: |
- effective_policy_refresh_error_delay_ms_ = policy_refresh_rate_ms_; |
- refresh_at = now + base::TimeDelta::FromMilliseconds( |
- effective_policy_refresh_error_delay_ms_); |
- notifier_->Inform(CloudPolicySubsystem::NETWORK_ERROR, |
- CloudPolicySubsystem::POLICY_NETWORK_ERROR, |
- PolicyNotifier::POLICY_CONTROLLER); |
- break; |
- } |
- |
- // Update the delayed work task. |
- scheduler_->CancelDelayedWork(); |
- if (!refresh_at.is_null()) |
- ScheduleDelayedWorkTask(refresh_at - now); |
- |
- // Inform the cache if a fetch attempt has completed. This happens if policy |
- // has been succesfully fetched, or if token or policy fetching failed. |
- if (state_ != STATE_TOKEN_UNAVAILABLE && state_ != STATE_TOKEN_VALID) |
- cache_->SetFetchingDone(); |
-} |
- |
-base::TimeDelta CloudPolicyController::GetRefreshDelay() { |
- int64 deviation = (kPolicyRefreshDeviationFactorPercent * |
- policy_refresh_rate_ms_) / 100; |
- deviation = std::min(deviation, kPolicyRefreshDeviationMaxInMilliseconds); |
- return base::TimeDelta::FromMilliseconds( |
- policy_refresh_rate_ms_ - base::RandGenerator(deviation + 1)); |
-} |
- |
-void CloudPolicyController::ScheduleDelayedWorkTask( |
- const base::TimeDelta& delay) { |
- int64 effective_delay = std::max<int64>(delay.InMilliseconds(), 0); |
- scheduler_->PostDelayedWork( |
- base::Bind(&CloudPolicyController::DoWork, base::Unretained(this)), |
- effective_delay); |
-} |
- |
-base::Time CloudPolicyController::GetLastRefreshTime(const base::Time& now) { |
- base::Time last_refresh(cache_->last_policy_refresh_time()); |
- if (last_refresh.is_null()) |
- last_refresh = now; |
- |
- return last_refresh; |
-} |
- |
-} // namespace policy |