chromium/chrome/browser/ash/policy/uploading/heartbeat_scheduler.h

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_POLICY_UPLOADING_HEARTBEAT_SCHEDULER_H_
#define CHROME_BROWSER_ASH_POLICY_UPLOADING_HEARTBEAT_SCHEDULER_H_

#include <stdint.h>

#include <memory>
#include <string>

#include "base/cancelable_callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chromeos/ash/components/settings/cros_settings.h"
#include "components/gcm_driver/gcm_app_handler.h"
#include "components/gcm_driver/gcm_client.h"
#include "components/gcm_driver/gcm_connection_observer.h"
#include "components/policy/core/common/cloud/cloud_policy_client.h"
#include "components/policy/core/common/cloud/cloud_policy_store.h"

namespace base {
class SequencedTaskRunner;
}

namespace gcm {
class GCMDriver;
}

namespace policy {

class HeartbeatRegistrationHelper;

// Class responsible for periodically sending heartbeats to the policy service
// for monitoring device connectivity.
class HeartbeatScheduler : public gcm::GCMAppHandler,
                           gcm::GCMConnectionObserver {
 public:
  // Default interval for how often we send up a heartbeat.
  static const base::TimeDelta kDefaultHeartbeatInterval;

  // Constructor. |cloud_policy_client| will be used to send registered GCM id
  // to DM server, and can be null. |driver| can be null for tests.
  HeartbeatScheduler(
      gcm::GCMDriver* driver,
      CloudPolicyClient* cloud_policy_client,
      CloudPolicyStore* cloud_policy_store,
      const std::string& device_id,
      const scoped_refptr<base::SequencedTaskRunner>& task_runner);

  HeartbeatScheduler(const HeartbeatScheduler&) = delete;
  HeartbeatScheduler& operator=(const HeartbeatScheduler&) = delete;

  ~HeartbeatScheduler() override;

  // Returns the time of the last heartbeat, or Time(0) if no heartbeat
  // has ever happened.
  base::Time last_heartbeat() const { return last_heartbeat_; }

  // GCMAppHandler overrides.
  void ShutdownHandler() override;
  void OnStoreReset() override;
  void OnMessage(const std::string& app_id,
                 const gcm::IncomingMessage& message) override;
  void OnMessagesDeleted(const std::string& app_id) override;
  void OnSendError(const std::string& app_id,
                   const gcm::GCMClient::SendErrorDetails& details) override;
  void OnSendAcknowledged(const std::string& app_id,
                          const std::string& message_id) override;

  // GCMConnectionObserver overrides.
  void OnConnected(const net::IPEndPoint&) override;

 private:
  // Callback invoked periodically to send a heartbeat to the policy service.
  void SendHeartbeat();

  // Invoked after GCM registration has successfully completed.
  void OnRegistrationComplete(const std::string& registration_id);

  // Invoked after a heartbeat has been sent to the server.
  void OnHeartbeatSent(const std::string& message_id,
                       gcm::GCMClient::Result result);

  // Invoked after a upstream notification sign up message has been sent.
  void OnUpstreamNotificationSent(const std::string& message_id,
                                  gcm::GCMClient::Result result);

  // Helper method that figures out when the next heartbeat should
  // be scheduled.
  void ScheduleNextHeartbeat();

  // Updates the heartbeat-enabled status and frequency from settings and
  // schedules the next heartbeat.
  void RefreshHeartbeatSettings();

  // Ensures that the passed interval is within a valid range (not too large or
  // too small).
  base::TimeDelta EnsureValidHeartbeatInterval(const base::TimeDelta& interval);

  // Shuts down our GCM connection (called when heartbeats are disabled).
  void ShutdownGCM();

  // Callback for the GCM id update request.
  void OnGcmIdUpdateRequestSent(bool status);

  // Helper function to signup for upstream notification.
  void SignUpUpstreamNotification();

  // TaskRunner used for scheduling heartbeats.
  const scoped_refptr<base::SequencedTaskRunner> task_runner_;

  // Obfuscated customerId the device is enrolled into.
  // Only set for device policy.
  std::string customer_id_;

  // The device_id for this device - sent up with the enrollment domain with
  // heartbeats to identify the device to the server.
  const std::string device_id_;

  // True if heartbeats are enabled. Kept cached in this object because
  // CrosSettings can switch to an untrusted state temporarily, and we want
  // to use the last-known trusted values.
  bool heartbeat_enabled_;

  // Cached copy of the current heartbeat interval, in milliseconds.
  base::TimeDelta heartbeat_interval_;

  // Subscriptions for callbacks for changes in the heartbeat settings.
  base::CallbackListSubscription heartbeat_frequency_subscription_;
  base::CallbackListSubscription heartbeat_enabled_subscription_;

  // The time the last heartbeat was sent.
  base::Time last_heartbeat_;

  // Callback invoked via a delay to send a heartbeat.
  base::CancelableOnceClosure heartbeat_callback_;

  raw_ptr<CloudPolicyClient> cloud_policy_client_;

  raw_ptr<CloudPolicyStore> cloud_policy_store_;

  // The GCMDriver used to send heartbeat messages.
  const raw_ptr<gcm::GCMDriver> gcm_driver_;

  // The GCM registration ID - if empty, we are not registered yet.
  std::string registration_id_;

  // If true, we are already registered with GCM and should unregister when
  // destroyed.
  bool registered_app_handler_ = false;

  // Helper class to manage registering with the GCM server, including
  // retries, etc.
  std::unique_ptr<HeartbeatRegistrationHelper> registration_helper_;

  // Note: This should remain the last member so it'll be destroyed and
  // invalidate the weak pointers before any other members are destroyed.
  base::WeakPtrFactory<HeartbeatScheduler> weak_factory_{this};
};

}  // namespace policy

#endif  // CHROME_BROWSER_ASH_POLICY_UPLOADING_HEARTBEAT_SCHEDULER_H_