Index: chrome/browser/signin/easy_unlock_service_signin_chromeos.cc |
diff --git a/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc b/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc |
index 5004a1697071210bc5cff695b5e942655174acab..f4f45811a6c3dd51a98244387f4cf4ff1aaf9e2f 100644 |
--- a/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc |
+++ b/chrome/browser/signin/easy_unlock_service_signin_chromeos.cc |
@@ -4,29 +4,100 @@ |
#include "chrome/browser/signin/easy_unlock_service_signin_chromeos.h" |
+#include "base/basictypes.h" |
#include "base/bind.h" |
#include "base/command_line.h" |
+#include "base/location.h" |
#include "base/logging.h" |
-#include "base/values.h" |
+#include "base/stl_util.h" |
+#include "base/thread_task_runner_handle.h" |
+#include "base/time/time.h" |
#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h" |
#include "chrome/browser/chromeos/login/session/user_session_manager.h" |
#include "chromeos/chromeos_switches.h" |
#include "chromeos/login/auth/user_context.h" |
+namespace { |
+ |
+// The maximum allowed backoff interval when waiting for cryptohome to start. |
+uint32 kMaxCryptohomeBackoffIntervalMs = 10000u; |
+ |
+// If the data load fails, the initial interval after which the load will be |
+// retried. Further intervals will exponentially increas by factor 2. |
+uint32 kInitialCryptohomeBackoffIntervalMs = 200u; |
+ |
+// Calculates the backoff interval that should be used next. |
+// |backoff| The last backoff interval used. |
+uint32 GetNextBackoffInterval(uint32 backoff) { |
+ if (backoff == 0u) |
+ return kInitialCryptohomeBackoffIntervalMs; |
+ return backoff * 2; |
+} |
+ |
+void LoadDataForUser( |
+ const std::string& user_id, |
+ uint32 backoff_ms, |
+ const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback); |
+ |
+// Callback passed to |LoadDataForUser()|. |
+// If |LoadDataForUser| function succeeded, it invokes |callback| with the |
+// results. |
+// If |LoadDataForUser| failed and further retries are allowed, schedules new |
+// |LoadDataForUser| call with some backoff. If no further retires are allowed, |
+// it invokes |callback| with the |LoadDataForUser| results. |
+void RetryDataLoadOnError( |
+ const std::string& user_id, |
+ uint32 backoff_ms, |
+ const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback, |
+ bool success, |
+ const chromeos::EasyUnlockDeviceKeyDataList& data_list) { |
+ if (success) { |
+ callback.Run(success, data_list); |
+ return; |
+ } |
+ |
+ uint32 next_backoff_ms = GetNextBackoffInterval(backoff_ms); |
+ if (next_backoff_ms > kMaxCryptohomeBackoffIntervalMs) { |
+ callback.Run(false, data_list); |
+ return; |
+ } |
+ |
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
+ FROM_HERE, |
+ base::Bind(&LoadDataForUser, user_id, next_backoff_ms, callback), |
+ base::TimeDelta::FromMilliseconds(next_backoff_ms)); |
+} |
+ |
+// Loads device data list associated with the user's Easy unlock keys. |
+void LoadDataForUser( |
+ const std::string& user_id, |
+ uint32 backoff_ms, |
+ const chromeos::EasyUnlockKeyManager::GetDeviceDataListCallback& callback) { |
+ chromeos::EasyUnlockKeyManager* key_manager = |
+ chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager(); |
+ DCHECK(key_manager); |
+ |
+ key_manager->GetDeviceDataList( |
+ chromeos::UserContext(user_id), |
+ base::Bind(&RetryDataLoadOnError, user_id, backoff_ms, callback)); |
+} |
+ |
+} // namespace |
+ |
+EasyUnlockServiceSignin::UserData::UserData() |
+ : state(EasyUnlockServiceSignin::USER_DATA_STATE_INITIAL) { |
+} |
+ |
+EasyUnlockServiceSignin::UserData::~UserData() {} |
+ |
EasyUnlockServiceSignin::EasyUnlockServiceSignin(Profile* profile) |
: EasyUnlockService(profile), |
+ allow_cryptohome_backoff_(true), |
weak_ptr_factory_(this) { |
} |
EasyUnlockServiceSignin::~EasyUnlockServiceSignin() { |
-} |
- |
-void EasyUnlockServiceSignin::SetAssociatedUser(const std::string& user_id) { |
- if (user_id_ == user_id) |
- return; |
- |
- user_id_ = user_id; |
- FetchCryptohomeKeys(); |
+ STLDeleteContainerPairSecondPointers(user_data_.begin(), user_data_.end()); |
} |
EasyUnlockService::Type EasyUnlockServiceSignin::GetType() const { |
@@ -42,7 +113,6 @@ void EasyUnlockServiceSignin::LaunchSetup() { |
} |
const base::DictionaryValue* EasyUnlockServiceSignin::GetPermitAccess() const { |
- // TODO(tbarzic): Implement this (http://crbug.com/401634). |
return NULL; |
} |
@@ -56,7 +126,10 @@ void EasyUnlockServiceSignin::ClearPermitAccess() { |
} |
const base::ListValue* EasyUnlockServiceSignin::GetRemoteDevices() const { |
- return remote_devices_value_.get(); |
+ const UserData* data = FindLoadedDataForCurrentUser(); |
+ if (!data) |
+ return NULL; |
+ return &data->remote_devices_value; |
} |
void EasyUnlockServiceSignin::SetRemoteDevices( |
@@ -82,52 +155,72 @@ EasyUnlockService::TurnOffFlowStatus |
} |
std::string EasyUnlockServiceSignin::GetChallenge() const { |
+ const UserData* data = FindLoadedDataForCurrentUser(); |
// TODO(xiyuan): Use correct remote device instead of hard coded first one. |
- size_t device_index = 0; |
- return device_index < remote_devices_.size() |
- ? remote_devices_[device_index].challenge |
- : std::string(); |
+ uint32 device_index = 0; |
+ if (!data || data->devices.size() <= device_index) |
+ return std::string(); |
+ return data->devices[device_index].challenge; |
} |
void EasyUnlockServiceSignin::InitializeInternal() { |
} |
bool EasyUnlockServiceSignin::IsAllowedInternal() { |
- return !user_id_.empty() && !remote_devices_.empty() && |
+ return !user_id_.empty() && |
+ FindLoadedDataForCurrentUser() && |
CommandLine::ForCurrentProcess()->HasSwitch( |
chromeos::switches::kEnableEasySignin); |
} |
-void EasyUnlockServiceSignin::FetchCryptohomeKeys() { |
- remote_devices_.clear(); |
- remote_devices_value_.reset(); |
- if (user_id_.empty()) { |
- UpdateAppState(); |
+void EasyUnlockServiceSignin::LoadCurrentUserDataIfNeeded() { |
+ if (user_id_.empty() || |
+ !CommandLine::ForCurrentProcess()->HasSwitch( |
+ chromeos::switches::kEnableEasySignin)) |
return; |
- } |
- chromeos::EasyUnlockKeyManager* key_manager = |
- chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager(); |
- DCHECK(key_manager); |
- key_manager->GetDeviceDataList( |
- chromeos::UserContext(user_id_), |
- base::Bind(&EasyUnlockServiceSignin::OnCryptohomeKeysFetched, |
- weak_ptr_factory_.GetWeakPtr())); |
+ std::map<std::string, UserData*>::iterator it = user_data_.find(user_id_); |
+ if (it == user_data_.end()) |
+ user_data_.insert(std::make_pair(user_id_, new UserData())); |
+ |
+ UserData* data = user_data_[user_id_]; |
+ |
+ if (data->state != USER_DATA_STATE_INITIAL) |
+ return; |
+ data->state = USER_DATA_STATE_LOADING; |
+ |
+ LoadDataForUser( |
+ user_id_, |
+ allow_cryptohome_backoff_ ? 0u : kMaxCryptohomeBackoffIntervalMs, |
+ base::Bind(&EasyUnlockServiceSignin::OnUserDataLoaded, |
+ weak_ptr_factory_.GetWeakPtr(), |
+ user_id_)); |
} |
-void EasyUnlockServiceSignin::OnCryptohomeKeysFetched( |
+void EasyUnlockServiceSignin::OnUserDataLoaded( |
+ const std::string& user_id, |
bool success, |
const chromeos::EasyUnlockDeviceKeyDataList& devices) { |
- if (!success) { |
- LOG(WARNING) << "Easy unlock cryptohome keys not found for user " |
- << user_id_; |
- return; |
+ allow_cryptohome_backoff_ = false; |
+ |
+ UserData* data = user_data_[user_id_]; |
+ data->state = USER_DATA_STATE_LOADED; |
+ if (success) { |
+ data->devices = devices; |
+ chromeos::EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList( |
+ user_id, devices, &data->remote_devices_value); |
} |
+} |
- remote_devices_ = devices; |
- remote_devices_value_.reset(new base::ListValue); |
- chromeos::EasyUnlockKeyManager::DeviceDataListToRemoteDeviceList( |
- user_id_, remote_devices_, remote_devices_value_.get()); |
- |
- UpdateAppState(); |
+const EasyUnlockServiceSignin::UserData* |
+ EasyUnlockServiceSignin::FindLoadedDataForCurrentUser() const { |
+ if (user_id_.empty()) |
+ return NULL; |
+ std::map<std::string, UserData*>::const_iterator it = |
+ user_data_.find(user_id_); |
+ if (it == user_data_.end()) |
+ return NULL; |
+ if (it->second->state != USER_DATA_STATE_LOADED) |
+ return NULL; |
+ return it->second; |
} |