15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/guid.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/location.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
11b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)#include "base/metrics/sparse_histogram.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_registry_simple.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/prefs/pref_service.h"
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h"
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/chromeos/policy/server_backed_device_state.h"
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/common/chrome_content_client.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/pref_names.h"
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/cloud/device_management_service.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "components/policy/core/common/cloud/system_policy_request_context.h"
2368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/sha2.h"
2568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "policy/proto/device_management_backend.pb.h"
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "url/gurl.h"
2868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
2968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)using content::BrowserThread;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace em = enterprise_management;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace policy {
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
37b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)// UMA histogram names.
38b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char kUMAProtocolTime[] = "Enterprise.AutoEnrollmentProtocolTime";
39b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char kUMAExtraTime[] = "Enterprise.AutoEnrollmentExtraTime";
40b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char kUMARequestStatus[] = "Enterprise.AutoEnrollmentRequestStatus";
41b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char kUMANetworkErrorCode[] =
42b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    "Enterprise.AutoEnrollmentRequestNetworkErrorCode";
43b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the power of the next power-of-2 starting at |value|.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int NextPowerOf2(int64 value) {
46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  for (int i = 0; i <= AutoEnrollmentClient::kMaximumPower; ++i) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((GG_INT64_C(1) << i) >= value)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return i;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No other value can be represented in an int64.
51effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  return AutoEnrollmentClient::kMaximumPower + 1;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Sets or clears a value in a dictionary.
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void UpdateDict(base::DictionaryValue* dict,
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                const char* pref_path,
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                bool set_or_clear,
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                base::Value* value) {
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scoped_ptr<base::Value> scoped_value(value);
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (set_or_clear)
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    dict->Set(pref_path, scoped_value.release());
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  else
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    dict->Remove(pref_path, NULL);
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Converts a restore mode enum value from the DM protocol into the
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// corresponding prefs string constant.
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string ConvertRestoreMode(
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    em::DeviceStateRetrievalResponse::RestoreMode restore_mode) {
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  switch (restore_mode) {
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case em::DeviceStateRetrievalResponse::RESTORE_MODE_NONE:
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return std::string();
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_REQUESTED:
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return kDeviceStateRestoreModeReEnrollmentRequested;
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    case em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED:
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return kDeviceStateRestoreModeReEnrollmentEnforced;
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Return is required to avoid compiler warning.
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NOTREACHED() << "Bad restore mode " << restore_mode;
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return std::string();
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)AutoEnrollmentClient::AutoEnrollmentClient(
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const ProgressCallback& callback,
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    DeviceManagementService* service,
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    PrefService* local_state,
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    scoped_refptr<net::URLRequestContextGetter> system_request_context,
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& server_backed_state_key,
92a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool retrieve_device_state,
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    int power_initial,
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    int power_limit)
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : progress_callback_(callback),
96effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      state_(AUTO_ENROLLMENT_STATE_IDLE),
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      has_server_state_(false),
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      device_state_available_(false),
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_id_(base::GenerateGUID()),
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      server_backed_state_key_(server_backed_state_key),
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      retrieve_device_state_(retrieve_device_state),
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      current_power_(power_initial),
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      power_limit_(power_limit),
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      modulus_updates_received_(0),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_management_service_(service),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      local_state_(local_state) {
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  request_context_ = new SystemPolicyRequestContext(
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      system_request_context, GetUserAgent());
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_LE(current_power_, power_limit_);
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!progress_callback_.is_null());
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!server_backed_state_key_.empty()) {
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    server_backed_state_key_hash_ =
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        crypto::SHA256HashString(server_backed_state_key_);
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
118bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochAutoEnrollmentClient::~AutoEnrollmentClient() {
119bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
120bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutoEnrollmentClient::RegisterPrefs(PrefRegistrySimple* registry) {
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registry->RegisterBooleanPref(prefs::kShouldAutoEnroll, false);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registry->RegisterIntegerPref(prefs::kAutoEnrollmentPowerLimit, -1);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::CancelAutoEnrollment() {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_state->SetBoolean(prefs::kShouldAutoEnroll, false);
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  local_state->ClearPref(prefs::kServerBackedDeviceState);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_state->CommitPendingWrite();
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::Start() {
137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // (Re-)register the network change observer.
138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
140effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Drop the previous job and reset state.
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_job_.reset();
143effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  state_ = AUTO_ENROLLMENT_STATE_PENDING;
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  time_start_ = base::Time::Now();
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  modulus_updates_received_ = 0;
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  has_server_state_ = false;
147a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device_state_available_ = false;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
149a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NextStep();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid AutoEnrollmentClient::Retry() {
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  RetryStep();
154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::CancelAndDeleteSoon() {
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (time_start_.is_null() || !request_job_) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The client isn't running, just delete it.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete this;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Client still running, but our owner isn't interested in the result
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // anymore. Wait until the protocol completes to measure the extra time
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // needed.
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    time_extra_start_ = base::Time::Now();
165a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    progress_callback_.Reset();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
169bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid AutoEnrollmentClient::OnNetworkChanged(
170bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    net::NetworkChangeNotifier::ConnectionType type) {
171bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (type != net::NetworkChangeNotifier::CONNECTION_NONE &&
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      !progress_callback_.is_null()) {
173a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RetryStep();
174bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  }
175bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
176bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AutoEnrollmentClient::GetCachedDecision() {
178a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const PrefService::Preference* has_server_state_pref =
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      local_state_->FindPreference(prefs::kShouldAutoEnroll);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PrefService::Preference* previous_limit_pref =
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      local_state_->FindPreference(prefs::kAutoEnrollmentPowerLimit);
182a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool has_server_state = false;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int previous_limit = -1;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!has_server_state_pref ||
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      has_server_state_pref->IsDefaultValue() ||
187a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      !has_server_state_pref->GetValue()->GetAsBoolean(&has_server_state) ||
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !previous_limit_pref ||
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous_limit_pref->IsDefaultValue() ||
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !previous_limit_pref->GetValue()->GetAsInteger(&previous_limit) ||
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      power_limit_ > previous_limit) {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  has_server_state_ = has_server_state;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::RetryStep() {
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If there is a pending request job, let it finish.
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (request_job_)
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return true;
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (GetCachedDecision()) {
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // The bucket download check has completed already. If it came back
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // positive, then device state should be (re-)downloaded.
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (has_server_state_) {
208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (retrieve_device_state_ && !device_state_available_ &&
209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          SendDeviceStateRequest()) {
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        return true;
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Start bucket download.
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (SendBucketDownloadRequest())
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return true;
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
221a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
222effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid AutoEnrollmentClient::ReportProgress(AutoEnrollmentState state) {
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  state_ = state;
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (progress_callback_.is_null()) {
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this);
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    progress_callback_.Run(state_);
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AutoEnrollmentClient::NextStep() {
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!RetryStep()) {
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Protocol finished successfully, report result.
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool trigger_enrollment = false;
235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (retrieve_device_state_) {
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const base::DictionaryValue* device_state_dict =
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          local_state_->GetDictionary(prefs::kServerBackedDeviceState);
238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      std::string restore_mode;
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      device_state_dict->GetString(kDeviceStateRestoreMode, &restore_mode);
240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      trigger_enrollment =
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          (restore_mode == kDeviceStateRestoreModeReEnrollmentRequested ||
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)           restore_mode == kDeviceStateRestoreModeReEnrollmentEnforced);
243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      trigger_enrollment = has_server_state_;
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
246a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
247effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ReportProgress(trigger_enrollment ? AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT
248effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                      : AUTO_ENROLLMENT_STATE_NO_ENROLLMENT);
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
250a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::SendBucketDownloadRequest() {
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (server_backed_state_key_hash_.empty())
254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only power-of-2 moduli are supported for now. These are computed by taking
257a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // the lower |current_power_| bits of the hash.
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint64 remainder = 0;
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (int i = 0; 8 * i < current_power_; ++i) {
260a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uint64 byte = server_backed_state_key_hash_[31 - i] & 0xff;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    remainder = remainder | (byte << (8 * i));
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  remainder = remainder & ((GG_UINT64_C(1) << current_power_) - 1);
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
265effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ReportProgress(AUTO_ENROLLMENT_STATE_PENDING);
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_job_.reset(
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_management_service_->CreateJob(
269a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT,
270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          request_context_.get()));
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_job_->SetClientID(device_id_);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  em::DeviceAutoEnrollmentRequest* request =
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_job_->GetRequest()->mutable_auto_enrollment_request();
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->set_remainder(remainder);
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request->set_modulus(GG_INT64_C(1) << current_power_);
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_job_->Start(
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&AutoEnrollmentClient::HandleRequestCompletion,
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 base::Unretained(this),
279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 &AutoEnrollmentClient::OnBucketDownloadRequestCompletion));
280a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
283a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::SendDeviceStateRequest() {
284effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ReportProgress(AUTO_ENROLLMENT_STATE_PENDING);
285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_job_.reset(
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      device_management_service_->CreateJob(
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          DeviceManagementRequestJob::TYPE_DEVICE_STATE_RETRIEVAL,
289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          request_context_.get()));
290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_job_->SetClientID(device_id_);
291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  em::DeviceStateRetrievalRequest* request =
292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      request_job_->GetRequest()->mutable_device_state_retrieval_request();
293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request->set_server_backed_state_key(server_backed_state_key_);
294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_job_->Start(
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&AutoEnrollmentClient::HandleRequestCompletion,
296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 base::Unretained(this),
297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 &AutoEnrollmentClient::OnDeviceStateRequestCompletion));
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AutoEnrollmentClient::HandleRequestCompletion(
302a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RequestCompletionHandler handler,
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeviceManagementStatus status,
304b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int net_error,
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const em::DeviceManagementResponse& response) {
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  UMA_HISTOGRAM_SPARSE_SLOWLY(kUMARequestStatus, status);
307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (status != DM_STATUS_SUCCESS) {
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Auto enrollment error: " << status;
309b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (status == DM_STATUS_REQUEST_FAILED)
310b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      UMA_HISTOGRAM_SPARSE_SLOWLY(kUMANetworkErrorCode, -net_error);
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    request_job_.reset();
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Abort if CancelAndDeleteSoon has been called meanwhile.
314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (progress_callback_.is_null()) {
315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this);
316a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
317effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      ReportProgress(status == DM_STATUS_REQUEST_FAILED
318effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         ? AUTO_ENROLLMENT_STATE_CONNECTION_ERROR
319effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         : AUTO_ENROLLMENT_STATE_SERVER_ERROR);
320a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool progress = (this->*handler)(status, net_error, response);
325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_job_.reset();
326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (progress)
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    NextStep();
328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  else
329effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ReportProgress(AUTO_ENROLLMENT_STATE_SERVER_ERROR);
330a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
331a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::OnBucketDownloadRequestCompletion(
333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DeviceManagementStatus status,
334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int net_error,
335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const em::DeviceManagementResponse& response) {
336a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool progress = false;
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const em::DeviceAutoEnrollmentResponse& enrollment_response =
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response.auto_enrollment_response();
339a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!response.has_auto_enrollment_response()) {
340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "Server failed to provide auto-enrollment response.";
341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else if (enrollment_response.has_expected_modulus()) {
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Server is asking us to retry with a different modulus.
343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    modulus_updates_received_++;
344a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 modulus = enrollment_response.expected_modulus();
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int power = NextPowerOf2(modulus);
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((GG_INT64_C(1) << power) != modulus) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Auto enrollment: the server didn't ask for a power-of-2 "
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << "modulus. Using the closest power-of-2 instead "
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << "(" << modulus << " vs 2^" << power << ")";
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (modulus_updates_received_ >= 2) {
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Auto enrollment error: already retried with an updated "
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << "modulus but the server asked for a new one again: "
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << power;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (power > power_limit_) {
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Auto enrollment error: the server asked for a larger "
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << "modulus than the client accepts (" << power << " vs "
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << power_limit_ << ").";
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Retry at most once with the modulus that the server requested.
362a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (power <= current_power_) {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(WARNING) << "Auto enrollment: the server asked to use a modulus ("
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     << power << ") that isn't larger than the first used ("
365a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     << current_power_ << "). Retrying anyway.";
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
367bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      // Remember this value, so that eventual retries start with the correct
368bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      // modulus.
369a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      current_power_ = power;
370a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return true;
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Server should have sent down a list of hashes to try.
374a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    has_server_state_ = IsIdHashInProtobuf(enrollment_response.hash());
37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Cache the current decision in local_state, so that it is reused in case
37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // the device reboots before enrolling.
377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    local_state_->SetBoolean(prefs::kShouldAutoEnroll, has_server_state_);
37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    local_state_->SetInteger(prefs::kAutoEnrollmentPowerLimit, power_limit_);
37990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    local_state_->CommitPendingWrite();
380a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << "Auto enrollment check complete, has_server_state_ = "
381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            << has_server_state_;
382a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    progress = true;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Bucket download done, update UMA.
386a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  UpdateBucketDownloadTimingHistograms();
387a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return progress;
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
390a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::OnDeviceStateRequestCompletion(
391a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DeviceManagementStatus status,
392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int net_error,
393a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const enterprise_management::DeviceManagementResponse& response) {
394a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool progress = false;
395a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!response.has_device_state_retrieval_response()) {
396a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "Server failed to provide auto-enrollment response.";
397a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
398a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const em::DeviceStateRetrievalResponse& state_response =
399a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        response.device_state_retrieval_response();
400a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    {
401a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      DictionaryPrefUpdate dict(local_state_, prefs::kServerBackedDeviceState);
402a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      UpdateDict(dict.Get(),
403a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 kDeviceStateManagementDomain,
404a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 state_response.has_management_domain(),
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 new base::StringValue(state_response.management_domain()));
406a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
407a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      std::string restore_mode =
408a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          ConvertRestoreMode(state_response.restore_mode());
409a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      UpdateDict(dict.Get(),
410a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 kDeviceStateRestoreMode,
411a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 !restore_mode.empty(),
412a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 new base::StringValue(restore_mode));
413a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
414a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    local_state_->CommitPendingWrite();
415a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    device_state_available_ = true;
416a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    progress = true;
417a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
418a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
419a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return progress;
420a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
421a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
422a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::IsIdHashInProtobuf(
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const google::protobuf::RepeatedPtrField<std::string>& hashes) {
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < hashes.size(); ++i) {
425a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (hashes.Get(i) == server_backed_state_key_hash_)
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
431a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AutoEnrollmentClient::UpdateBucketDownloadTimingHistograms() {
432116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // The minimum time can't be 0, must be at least 1.
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const base::TimeDelta kMin = base::TimeDelta::FromMilliseconds(1);
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const base::TimeDelta kMax = base::TimeDelta::FromMinutes(5);
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // However, 0 can still be sampled.
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const base::TimeDelta kZero = base::TimeDelta::FromMilliseconds(0);
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kBuckets = 50;
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time now = base::Time::Now();
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!time_start_.is_null()) {
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta delta = now - time_start_;
442b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES(kUMAProtocolTime, delta, kMin, kMax, kBuckets);
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta delta = kZero;
445bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (!time_extra_start_.is_null())
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delta = now - time_extra_start_;
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This samples |kZero| when there was no need for extra time, so that we can
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // measure the ratio of users that succeeded without needing a delay to the
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // total users going through OOBE.
450b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_TIMES(kUMAExtraTime, delta, kMin, kMax, kBuckets);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace policy
454