ambient_access_token_controller.cc 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/ambient/ambient_access_token_controller.h"
  5. #include "ash/login/ui/lock_screen.h"
  6. #include "ash/public/cpp/ambient/ambient_client.h"
  7. #include "base/bind.h"
  8. #include "base/logging.h"
  9. #include "base/rand_util.h"
  10. #include "base/time/time.h"
  11. namespace ash {
  12. namespace {
  13. constexpr int kMaxRetries = 3;
  14. constexpr net::BackoffEntry::Policy kRetryBackoffPolicy = {
  15. 0, // Number of initial errors to ignore.
  16. 1000, // Initial delay in ms.
  17. 2.0, // Factor by which the waiting time will be multiplied.
  18. 0.2, // Fuzzing percentage.
  19. 60 * 1000, // Maximum delay in ms.
  20. -1, // Never discard the entry.
  21. true, // Use initial delay.
  22. };
  23. } // namespace
  24. AmbientAccessTokenController::AmbientAccessTokenController()
  25. : refresh_token_retry_backoff_(&kRetryBackoffPolicy) {}
  26. AmbientAccessTokenController::~AmbientAccessTokenController() = default;
  27. void AmbientAccessTokenController::RequestAccessToken(
  28. AccessTokenCallback callback,
  29. bool may_refresh_token_on_lock) {
  30. // |token_refresh_timer_| may become stale during sleeping.
  31. if (token_refresh_timer_.IsRunning())
  32. token_refresh_timer_.AbandonAndStop();
  33. if (!access_token_.empty()) {
  34. DCHECK(!has_pending_request_);
  35. // Return the token if there is enough time to use the access token when
  36. // requested.
  37. if (expiration_time_ - base::Time::Now() > token_usage_time_buffer_) {
  38. RunCallback(std::move(callback));
  39. return;
  40. }
  41. access_token_ = std::string();
  42. expiration_time_ = base::Time::Now();
  43. }
  44. if (!may_refresh_token_on_lock && LockScreen::HasInstance()) {
  45. RunCallback(std::move(callback));
  46. return;
  47. }
  48. callbacks_.emplace_back(std::move(callback));
  49. if (has_pending_request_)
  50. return;
  51. RefreshAccessToken();
  52. }
  53. void AmbientAccessTokenController::RefreshAccessToken() {
  54. DCHECK(!token_refresh_timer_.IsRunning());
  55. has_pending_request_ = true;
  56. AmbientClient::Get()->RequestAccessToken(
  57. base::BindOnce(&AmbientAccessTokenController::AccessTokenRefreshed,
  58. weak_factory_.GetWeakPtr()));
  59. }
  60. void AmbientAccessTokenController::AccessTokenRefreshed(
  61. const std::string& gaia_id,
  62. const std::string& access_token,
  63. const base::Time& expiration_time) {
  64. has_pending_request_ = false;
  65. if (gaia_id.empty() || access_token.empty()) {
  66. refresh_token_retry_backoff_.InformOfRequest(/*succeeded=*/false);
  67. if (refresh_token_retry_backoff_.failure_count() <= kMaxRetries) {
  68. LOG(WARNING) << "Unable to refresh access token. Retrying..";
  69. RetryRefreshAccessToken();
  70. } else {
  71. LOG(ERROR) << "Unable to refresh access token. All retries attempted.";
  72. NotifyAccessTokenRefreshed();
  73. }
  74. return;
  75. }
  76. DVLOG(1) << "Access token fetched.";
  77. DCHECK(gaia_id_.empty() || gaia_id_ == gaia_id);
  78. refresh_token_retry_backoff_.Reset();
  79. gaia_id_ = gaia_id;
  80. access_token_ = access_token;
  81. expiration_time_ = expiration_time;
  82. NotifyAccessTokenRefreshed();
  83. }
  84. void AmbientAccessTokenController::RetryRefreshAccessToken() {
  85. base::TimeDelta backoff_delay =
  86. refresh_token_retry_backoff_.GetTimeUntilRelease();
  87. token_refresh_timer_.Start(
  88. FROM_HERE, backoff_delay,
  89. base::BindOnce(&AmbientAccessTokenController::RefreshAccessToken,
  90. base::Unretained(this)));
  91. }
  92. void AmbientAccessTokenController::NotifyAccessTokenRefreshed() {
  93. for (auto& callback : callbacks_)
  94. RunCallback(std::move(callback));
  95. callbacks_.clear();
  96. }
  97. void AmbientAccessTokenController::RunCallback(AccessTokenCallback callback) {
  98. std::move(callback).Run(gaia_id_, access_token_);
  99. }
  100. void AmbientAccessTokenController::SetTokenUsageBufferForTesting(
  101. base::TimeDelta time) {
  102. token_usage_time_buffer_ = time;
  103. }
  104. base::TimeDelta AmbientAccessTokenController::GetTimeUntilReleaseForTesting() {
  105. return refresh_token_retry_backoff_.GetTimeUntilRelease();
  106. }
  107. } // namespace ash