auto_enrollment_client.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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)
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NOTREACHED() << "Bad restore mode " << restore_mode;
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return std::string();
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)AutoEnrollmentClient::AutoEnrollmentClient(
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const ProgressCallback& callback,
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    DeviceManagementService* service,
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    PrefService* local_state,
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    scoped_refptr<net::URLRequestContextGetter> system_request_context,
90a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const std::string& server_backed_state_key,
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool retrieve_device_state,
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    int power_initial,
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    int power_limit)
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    : progress_callback_(callback),
95effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      state_(AUTO_ENROLLMENT_STATE_IDLE),
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      has_server_state_(false),
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      device_state_available_(false),
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_id_(base::GenerateGUID()),
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      server_backed_state_key_(server_backed_state_key),
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      retrieve_device_state_(retrieve_device_state),
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      current_power_(power_initial),
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      power_limit_(power_limit),
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      modulus_updates_received_(0),
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_management_service_(service),
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      local_state_(local_state) {
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  request_context_ = new SystemPolicyRequestContext(
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      system_request_context, GetUserAgent());
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK_LE(current_power_, power_limit_);
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!progress_callback_.is_null());
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!server_backed_state_key_.empty()) {
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    server_backed_state_key_hash_ =
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        crypto::SHA256HashString(server_backed_state_key_);
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
117bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben MurdochAutoEnrollmentClient::~AutoEnrollmentClient() {
118bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
119bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AutoEnrollmentClient::RegisterPrefs(PrefRegistrySimple* registry) {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registry->RegisterBooleanPref(prefs::kShouldAutoEnroll, false);
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  registry->RegisterIntegerPref(prefs::kAutoEnrollmentPowerLimit, -1);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::CancelAutoEnrollment() {
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_state->SetBoolean(prefs::kShouldAutoEnroll, false);
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  local_state->ClearPref(prefs::kServerBackedDeviceState);
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local_state->CommitPendingWrite();
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::Start() {
136effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  // (Re-)register the network change observer.
137effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
138effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
139effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Drop the previous job and reset state.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_job_.reset();
142effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  state_ = AUTO_ENROLLMENT_STATE_PENDING;
143a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  time_start_ = base::Time::Now();
144a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  modulus_updates_received_ = 0;
145a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  has_server_state_ = false;
146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  device_state_available_ = false;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
148a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  NextStep();
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
151effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid AutoEnrollmentClient::Retry() {
152effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  RetryStep();
153effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
154effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AutoEnrollmentClient::CancelAndDeleteSoon() {
156a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (time_start_.is_null() || !request_job_) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The client isn't running, just delete it.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delete this;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Client still running, but our owner isn't interested in the result
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // anymore. Wait until the protocol completes to measure the extra time
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // needed.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    time_extra_start_ = base::Time::Now();
164a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    progress_callback_.Reset();
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
168bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochvoid AutoEnrollmentClient::OnNetworkChanged(
169bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    net::NetworkChangeNotifier::ConnectionType type) {
170bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (type != net::NetworkChangeNotifier::CONNECTION_NONE &&
171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      !progress_callback_.is_null()) {
172a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RetryStep();
173bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  }
174bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
175bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AutoEnrollmentClient::GetCachedDecision() {
177a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const PrefService::Preference* has_server_state_pref =
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      local_state_->FindPreference(prefs::kShouldAutoEnroll);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const PrefService::Preference* previous_limit_pref =
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      local_state_->FindPreference(prefs::kAutoEnrollmentPowerLimit);
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool has_server_state = false;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int previous_limit = -1;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
184a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!has_server_state_pref ||
185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      has_server_state_pref->IsDefaultValue() ||
186a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      !has_server_state_pref->GetValue()->GetAsBoolean(&has_server_state) ||
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !previous_limit_pref ||
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      previous_limit_pref->IsDefaultValue() ||
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !previous_limit_pref->GetValue()->GetAsInteger(&previous_limit) ||
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      power_limit_ > previous_limit) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  has_server_state_ = has_server_state;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::RetryStep() {
199a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // If there is a pending request job, let it finish.
200a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (request_job_)
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return true;
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
203a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (GetCachedDecision()) {
204a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // The bucket download check has completed already. If it came back
205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // positive, then device state should be (re-)downloaded.
206a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (has_server_state_) {
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (retrieve_device_state_ && !device_state_available_ &&
208a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          SendDeviceStateRequest()) {
209a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        return true;
210a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      }
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
212a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
213a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Start bucket download.
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (SendBucketDownloadRequest())
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return true;
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return false;
219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
220a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
221effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid AutoEnrollmentClient::ReportProgress(AutoEnrollmentState state) {
222a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  state_ = state;
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (progress_callback_.is_null()) {
224a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this);
225a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    progress_callback_.Run(state_);
227a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
230a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AutoEnrollmentClient::NextStep() {
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!RetryStep()) {
232a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Protocol finished successfully, report result.
233a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    bool trigger_enrollment = false;
234a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (retrieve_device_state_) {
235a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      const base::DictionaryValue* device_state_dict =
236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          local_state_->GetDictionary(prefs::kServerBackedDeviceState);
237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      std::string restore_mode;
238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      device_state_dict->GetString(kDeviceStateRestoreMode, &restore_mode);
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      trigger_enrollment =
240a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          (restore_mode == kDeviceStateRestoreModeReEnrollmentRequested ||
241a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)           restore_mode == kDeviceStateRestoreModeReEnrollmentEnforced);
242a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
243a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      trigger_enrollment = has_server_state_;
244a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
246effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ReportProgress(trigger_enrollment ? AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT
247effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                      : AUTO_ENROLLMENT_STATE_NO_ENROLLMENT);
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
249a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::SendBucketDownloadRequest() {
252a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (server_backed_state_key_hash_.empty())
253a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return false;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Only power-of-2 moduli are supported for now. These are computed by taking
256a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // the lower |current_power_| bits of the hash.
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint64 remainder = 0;
258a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  for (int i = 0; 8 * i < current_power_; ++i) {
259a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    uint64 byte = server_backed_state_key_hash_[31 - i] & 0xff;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    remainder = remainder | (byte << (8 * i));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
262a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  remainder = remainder & ((GG_UINT64_C(1) << current_power_) - 1);
263a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
264effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ReportProgress(AUTO_ENROLLMENT_STATE_PENDING);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_job_.reset(
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      device_management_service_->CreateJob(
268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          DeviceManagementRequestJob::TYPE_AUTO_ENROLLMENT,
269a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          request_context_.get()));
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request_job_->SetClientID(device_id_);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  em::DeviceAutoEnrollmentRequest* request =
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_job_->GetRequest()->mutable_auto_enrollment_request();
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  request->set_remainder(remainder);
274a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request->set_modulus(GG_INT64_C(1) << current_power_);
275a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_job_->Start(
276a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&AutoEnrollmentClient::HandleRequestCompletion,
277a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 base::Unretained(this),
278a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 &AutoEnrollmentClient::OnBucketDownloadRequestCompletion));
279a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
282a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::SendDeviceStateRequest() {
283effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  ReportProgress(AUTO_ENROLLMENT_STATE_PENDING);
284a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
285a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_job_.reset(
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      device_management_service_->CreateJob(
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          DeviceManagementRequestJob::TYPE_DEVICE_STATE_RETRIEVAL,
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          request_context_.get()));
289a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_job_->SetClientID(device_id_);
290a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  em::DeviceStateRetrievalRequest* request =
291a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      request_job_->GetRequest()->mutable_device_state_retrieval_request();
292a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request->set_server_backed_state_key(server_backed_state_key_);
293a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_job_->Start(
294a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::Bind(&AutoEnrollmentClient::HandleRequestCompletion,
295a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 base::Unretained(this),
296a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 &AutoEnrollmentClient::OnDeviceStateRequestCompletion));
297a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return true;
298a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
299a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
300a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AutoEnrollmentClient::HandleRequestCompletion(
301a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    RequestCompletionHandler handler,
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeviceManagementStatus status,
303b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    int net_error,
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const em::DeviceManagementResponse& response) {
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  UMA_HISTOGRAM_SPARSE_SLOWLY(kUMARequestStatus, status);
306a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (status != DM_STATUS_SUCCESS) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Auto enrollment error: " << status;
308b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    if (status == DM_STATUS_REQUEST_FAILED)
309b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)      UMA_HISTOGRAM_SPARSE_SLOWLY(kUMANetworkErrorCode, -net_error);
310a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    request_job_.reset();
311a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
312a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    // Abort if CancelAndDeleteSoon has been called meanwhile.
313a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (progress_callback_.is_null()) {
314a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this);
315a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    } else {
316effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      ReportProgress(status == DM_STATUS_REQUEST_FAILED
317effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         ? AUTO_ENROLLMENT_STATE_CONNECTION_ERROR
318effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                         : AUTO_ENROLLMENT_STATE_SERVER_ERROR);
319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
323a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool progress = (this->*handler)(status, net_error, response);
324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request_job_.reset();
325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (progress)
326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    NextStep();
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  else
328effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ReportProgress(AUTO_ENROLLMENT_STATE_SERVER_ERROR);
329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
330a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
331a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::OnBucketDownloadRequestCompletion(
332a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DeviceManagementStatus status,
333a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int net_error,
334a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const em::DeviceManagementResponse& response) {
335a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool progress = false;
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const em::DeviceAutoEnrollmentResponse& enrollment_response =
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      response.auto_enrollment_response();
338a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!response.has_auto_enrollment_response()) {
339a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "Server failed to provide auto-enrollment response.";
340a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else if (enrollment_response.has_expected_modulus()) {
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Server is asking us to retry with a different modulus.
342a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    modulus_updates_received_++;
343a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int64 modulus = enrollment_response.expected_modulus();
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int power = NextPowerOf2(modulus);
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((GG_INT64_C(1) << power) != modulus) {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(WARNING) << "Auto enrollment: the server didn't ask for a power-of-2 "
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << "modulus. Using the closest power-of-2 instead "
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   << "(" << modulus << " vs 2^" << power << ")";
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (modulus_updates_received_ >= 2) {
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Auto enrollment error: already retried with an updated "
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << "modulus but the server asked for a new one again: "
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << power;
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (power > power_limit_) {
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOG(ERROR) << "Auto enrollment error: the server asked for a larger "
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << "modulus than the client accepts (" << power << " vs "
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 << power_limit_ << ").";
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Retry at most once with the modulus that the server requested.
361a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      if (power <= current_power_) {
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOG(WARNING) << "Auto enrollment: the server asked to use a modulus ("
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     << power << ") that isn't larger than the first used ("
364a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                     << current_power_ << "). Retrying anyway.";
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
366bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      // Remember this value, so that eventual retries start with the correct
367bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch      // modulus.
368a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      current_power_ = power;
369a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return true;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Server should have sent down a list of hashes to try.
373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    has_server_state_ = IsIdHashInProtobuf(enrollment_response.hash());
37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // Cache the current decision in local_state, so that it is reused in case
37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    // the device reboots before enrolling.
376a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    local_state_->SetBoolean(prefs::kShouldAutoEnroll, has_server_state_);
37790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    local_state_->SetInteger(prefs::kAutoEnrollmentPowerLimit, power_limit_);
37890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    local_state_->CommitPendingWrite();
379a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    VLOG(1) << "Auto enrollment check complete, has_server_state_ = "
380a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)            << has_server_state_;
381a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    progress = true;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
384a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Bucket download done, update UMA.
385a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  UpdateBucketDownloadTimingHistograms();
386a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return progress;
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
389a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::OnDeviceStateRequestCompletion(
390a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    DeviceManagementStatus status,
391a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    int net_error,
392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const enterprise_management::DeviceManagementResponse& response) {
393a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  bool progress = false;
394a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!response.has_device_state_retrieval_response()) {
395a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    LOG(ERROR) << "Server failed to provide auto-enrollment response.";
396a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  } else {
397a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const em::DeviceStateRetrievalResponse& state_response =
398a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        response.device_state_retrieval_response();
399a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    {
400a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      DictionaryPrefUpdate dict(local_state_, prefs::kServerBackedDeviceState);
401a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      UpdateDict(dict.Get(),
402a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 kDeviceStateManagementDomain,
403a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 state_response.has_management_domain(),
404a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 new base::StringValue(state_response.management_domain()));
405a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
406a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      std::string restore_mode =
407a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          ConvertRestoreMode(state_response.restore_mode());
408a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      UpdateDict(dict.Get(),
409a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 kDeviceStateRestoreMode,
410a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 !restore_mode.empty(),
411a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                 new base::StringValue(restore_mode));
412a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    }
413a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    local_state_->CommitPendingWrite();
414a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    device_state_available_ = true;
415a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    progress = true;
416a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
417a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
418a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return progress;
419a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
420a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
421a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)bool AutoEnrollmentClient::IsIdHashInProtobuf(
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const google::protobuf::RepeatedPtrField<std::string>& hashes) {
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < hashes.size(); ++i) {
424a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if (hashes.Get(i) == server_backed_state_key_hash_)
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
430a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void AutoEnrollmentClient::UpdateBucketDownloadTimingHistograms() {
431116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // The minimum time can't be 0, must be at least 1.
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const base::TimeDelta kMin = base::TimeDelta::FromMilliseconds(1);
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const base::TimeDelta kMax = base::TimeDelta::FromMinutes(5);
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // However, 0 can still be sampled.
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const base::TimeDelta kZero = base::TimeDelta::FromMilliseconds(0);
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static const int kBuckets = 50;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Time now = base::Time::Now();
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!time_start_.is_null()) {
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::TimeDelta delta = now - time_start_;
441b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    UMA_HISTOGRAM_CUSTOM_TIMES(kUMAProtocolTime, delta, kMin, kMax, kBuckets);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::TimeDelta delta = kZero;
444bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  if (!time_extra_start_.is_null())
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    delta = now - time_extra_start_;
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This samples |kZero| when there was no need for extra time, so that we can
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // measure the ratio of users that succeeded without needing a delay to the
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // total users going through OOBE.
449b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  UMA_HISTOGRAM_CUSTOM_TIMES(kUMAExtraTime, delta, kMin, kMax, kBuckets);
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace policy
453