chromium/chrome/browser/ash/policy/reporting/event_based_logs/event_observer_base.h

// Copyright 2024 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_REPORTING_EVENT_BASED_LOGS_EVENT_OBSERVER_BASE_H_
#define CHROME_BROWSER_ASH_POLICY_REPORTING_EVENT_BASED_LOGS_EVENT_OBSERVER_BASE_H_

#include <optional>
#include <set>
#include <string>

#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "chrome/browser/ash/policy/reporting/event_based_logs/event_based_log_uploader.h"
#include "chrome/browser/support_tool/data_collection_module.pb.h"
#include "components/reporting/util/status.h"

namespace policy {

enum class EventBasedUploadStatus {
  // Upload triggered successfully.
  kSuccess,
  // Upload can't be triggered. This failure can occur due to internal reporting
  // pipeline or log collection errors. Callers have option to retry triggering
  // the upload in this case.
  kFailure,
  // Upload is declined because upload wait period is not finished yet.
  kDeclined,
};

// Base class that the event observers who want to upload event based logs needs
// to implement. `EventObserverBase` gives the functionality that is needed to
// trigger the log upload to the server.
//
// EXAMPLE
// class FooEventObserver : public policy::EventObserverBase, FooEventSource {
//  public:
//   // Need to add a new `ash::reporting::TriggerEventType` to define the
//   // observed event.
//   ash::reporting::TriggerEventType GetEventType() override {
//     return ash::reporting::TriggerEventType::<FOO>;
//   }
//   // Select which logs to upload by implementing this.
//   std::set<support_tool::DataCollectorType> GetDataCollectorTypes() override
//   {
//     return {support_tool::DataCollectorType::XX};
//   }
//   // FooEventSource observer.
//   void OnFooOccurred(FooEvent event) {
//     // Trigger log upload here.
//     TriggerLogUpload(upload_id, base::DoNothing());
//   }
//   void OnCriticalFooOccurred(FooEvent event) {
//     // Trigger log upload here. It is possible to override the default time
//     // limit for critical events to upload more frequently. Please reach out
//     // to get guidance if you consider this option.
//     TriggerLogUpload(upload_id, base::BindOnce(&DoSomethingWithUploadResult),
//                      base::Hours(1));
//   }
// };
class EventObserverBase {
 public:
  EventObserverBase();

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

  virtual ~EventObserverBase();

  // Returns the event type that has triggered the log upload. Inheritors of
  // this class must add a new event type to `ash::reporting::TriggerEventType`
  // when they start observing a new event.
  virtual ash::reporting::TriggerEventType GetEventType() const = 0;

  // Returns the set of `support_tool::DataCollectorType`s that is related to
  // the event this observer is observing. Inheritors of this class must
  // override this to select which log files to upload.
  virtual std::set<support_tool::DataCollectorType> GetDataCollectorTypes()
      const = 0;

  // Returns the event name of the event that the observer observes.
  std::string GetEventName() const;

  // Triggers the upload of the log types from `GetDataCollectorTypes()`.
  // Delegates the log upload to `EventBasedLogUploader` with the required
  // information. If an upload of the same event type has been done in last
  // `upload_wait_period` hours, the upload won't be triggered. The
  // callers of this function can override `upload_wait_period` to upload more
  // frequently but by default it's 24 hours. This is the recommendation. Please
  // reach out to discuss if your use-case requires different frequency.
  // The callers of this function can set `on_upload_triggered` callback to
  // handle different states according to their use-case.
  void TriggerLogUpload(
      std::optional<std::string> upload_id,
      base::OnceCallback<void(EventBasedUploadStatus)> on_upload_triggered,
      base::TimeDelta upload_wait_period = base::Hours(24));

  void SetLogUploaderForTesting(
      std::unique_ptr<EventBasedLogUploader> log_uploader);

 private:
  // Checks if the upload wait period is finished since the last event based log
  // upload for `GetEventType()`.
  bool IsUploadWaitPeriodFinished(base::TimeDelta upload_wait_period) const;

  // Called by `log_uploader_` when log upload triggered by `TriggerLogUpload()`
  // function is completed. Records the upload time to prefs if upload has
  // succeeded and resets the `log_uploader_`.
  void OnLogUploaderDone(reporting::Status status);

  // This function should be called when upload is enqueued to reporting
  // service. It will record the upload time for the event type to local
  // settings prefs.
  void RecordUploadTime(base::Time timestamp);

  SEQUENCE_CHECKER(sequence_checker_);
  std::unique_ptr<EventBasedLogUploader> log_uploader_;
  // This callback is set by the caller of `TriggerLogUpload()` function and
  // will be called when the log upload is triggered. The caller can handle the
  // result status using this callback.
  base::OnceCallback<void(EventBasedUploadStatus)> on_log_upload_triggered_;
  base::WeakPtrFactory<EventObserverBase> weak_ptr_factory_{this};
};

}  // namespace policy

#endif  // CHROME_BROWSER_ASH_POLICY_REPORTING_EVENT_BASED_LOGS_EVENT_OBSERVER_BASE_H_