Merge: Fix device registration expiration with system clock adjusted

When system clock is being adjusted on device during registration,
the registration process could prematurely be considered expired
when the clock rolls forward. Change the logic to use retry counters
instead of absolute expiration time to mitigate this problem.

BUG: 26107811, 26266459
Change-Id: I31de553bedabd7b501ed1d222932d4f379018dd2
Reviewed-on: https://weave-review.googlesource.com/1893
Reviewed-by: Vitaly Buka <vitalybuka@google.com>
(cherry picked from commit b3de3512f0276c7af73b3f2de0637c423d459f2e)
Reviewed-on: https://weave-review.googlesource.com/2046
Reviewed-by: Gene Gutnik <gene@google.com>
Reviewed-by: Paul Westbrook <pwestbro@google.com>
diff --git a/src/privet/cloud_delegate.cc b/src/privet/cloud_delegate.cc
index fddc8e1..c78c426 100644
--- a/src/privet/cloud_delegate.cc
+++ b/src/privet/cloud_delegate.cc
@@ -29,7 +29,7 @@
 const BackoffEntry::Policy register_backoff_policy = {0,    1000, 2.0,  0.2,
                                                       5000, -1,   false};
 
-const int kMaxDeviceRegistrationTimeMinutes = 5;
+const int kMaxDeviceRegistrationRetries = 100;  // ~ 8 minutes @5s retries.
 
 CommandInstance* ReturnNotFound(const std::string& command_id,
                                 ErrorPtr* error) {
@@ -112,22 +112,24 @@
   bool Setup(const std::string& ticket_id,
              const std::string& user,
              ErrorPtr* error) override {
-    if (setup_state_.IsStatusEqual(SetupState::kInProgress)) {
-      Error::AddTo(error, FROM_HERE, errors::kDomain, errors::kDeviceBusy,
-                   "Setup in progress");
-      return false;
-    }
     VLOG(1) << "GCD Setup started. ticket_id: " << ticket_id
             << ", user:" << user;
+    // Set (or reset) the retry counter, since we are starting a new
+    // registration process.
+    registation_retry_count_ = kMaxDeviceRegistrationRetries;
+    ticket_id_ = ticket_id;
+    if (setup_state_.IsStatusEqual(SetupState::kInProgress)) {
+      // Another registration is in progress. In case it fails, we will use
+      // the new ticket ID when retrying the request.
+      return true;
+    }
     setup_state_ = SetupState(SetupState::kInProgress);
     setup_weak_factory_.InvalidateWeakPtrs();
     backoff_entry_.Reset();
-    base::Time deadline = base::Time::Now();
-    deadline += base::TimeDelta::FromMinutes(kMaxDeviceRegistrationTimeMinutes);
     task_runner_->PostDelayedTask(
         FROM_HERE,
         base::Bind(&CloudDelegateImpl::CallManagerRegisterDevice,
-                   setup_weak_factory_.GetWeakPtr(), ticket_id, deadline),
+                   setup_weak_factory_.GetWeakPtr()),
         {});
     // Return true because we initiated setup.
     return true;
@@ -262,10 +264,10 @@
     setup_state_ = SetupState(SetupState::kSuccess);
   }
 
-  void CallManagerRegisterDevice(const std::string& ticket_id,
-                                 const base::Time& deadline) {
+  void CallManagerRegisterDevice() {
     ErrorPtr error;
-    if (base::Time::Now() > deadline) {
+    CHECK_GE(registation_retry_count_, 0);
+    if (registation_retry_count_-- == 0) {
       Error::AddTo(&error, FROM_HERE, errors::kDomain, errors::kInvalidState,
                    "Failed to register device");
       setup_state_ = SetupState{std::move(error)};
@@ -273,21 +275,18 @@
     }
 
     device_->RegisterDevice(
-        ticket_id,
-        base::Bind(&CloudDelegateImpl::RegisterDeviceDone,
-                   setup_weak_factory_.GetWeakPtr(), ticket_id, deadline));
+        ticket_id_, base::Bind(&CloudDelegateImpl::RegisterDeviceDone,
+                               setup_weak_factory_.GetWeakPtr()));
   }
 
-  void RegisterDeviceDone(const std::string& ticket_id,
-                          const base::Time& deadline,
-                          ErrorPtr error) {
+  void RegisterDeviceDone(ErrorPtr error) {
     if (error) {
       // Registration failed. Retry with backoff.
       backoff_entry_.InformOfRequest(false);
       return task_runner_->PostDelayedTask(
           FROM_HERE,
           base::Bind(&CloudDelegateImpl::CallManagerRegisterDevice,
-                     setup_weak_factory_.GetWeakPtr(), ticket_id, deadline),
+                     setup_weak_factory_.GetWeakPtr()),
           backoff_entry_.GetTimeUntilRelease());
     }
     backoff_entry_.InformOfRequest(true);
@@ -345,6 +344,12 @@
   // Current commands definitions.
   base::DictionaryValue command_defs_;
 
+  // Ticket ID for registering the device.
+  std::string ticket_id_;
+
+  // Number of remaining retries for device registration process.
+  int registation_retry_count_{0};
+
   // Map of command IDs to user IDs.
   std::map<std::string, uint64_t> command_owners_;