chromium/chrome/browser/ash/file_manager/io_task_controller.h

// Copyright 2021 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_FILE_MANAGER_IO_TASK_CONTROLLER_H_
#define CHROME_BROWSER_ASH_FILE_MANAGER_IO_TASK_CONTROLLER_H_

#include <map>
#include <memory>

#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "chrome/browser/ash/file_manager/io_task.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
#include "storage/browser/file_system/file_system_file_util.h"

namespace file_manager {

namespace io_task {

// |IOTaskController| queues and executes IOTasks given to it from Files app. It
// also notifies observers when tasks progress or finish. This class must only
// be used from one sequence.
class IOTaskController {
 public:
  IOTaskController();
  IOTaskController(const IOTaskController& other) = delete;
  IOTaskController operator=(const IOTaskController& other) = delete;
  ~IOTaskController();

  class Observer : public base::CheckedObserver {
   public:
    // Called whenever a queued IOTask progresses or completes. Will be called
    // on the same sequence as Add().
    virtual void OnIOTaskStatus(const ProgressStatus& status) = 0;
  };

  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  // Queues an IOTask and returns its ID.
  IOTaskId Add(std::unique_ptr<IOTask> task);

  // Pauses a task from the queue.
  void Pause(IOTaskId task_id, PauseParams params);

  // Resumes a task from the queue.
  void Resume(IOTaskId task_id, ResumeParams params);

  // Cancels or removes a task from the queue.
  void Cancel(IOTaskId task_id);

  // Makes tasks in state::PAUSED emit (broadcast) their progress status.
  void ProgressPausedTasks();

  // Aborts a task from the queue.
  void CompleteWithError(IOTaskId task_id, PolicyError policy_error);

  // The `ProgressStatus` of each task in the queue.
  std::vector<std::reference_wrapper<const ProgressStatus>> TaskStatuses();

  // For tests only; returns the current wake lock counter. This counter is
  // incremented by 1 for every time we get a wake lock and decremented every
  // time we release it.
  int wake_lock_counter_for_tests() const {
    return wake_lock_counter_for_tests_;
  }

 private:
  void MaybeNotifyIOTaskObservers(const ProgressStatus& status);
  void NotifyIOTaskObservers(const ProgressStatus& status);
  void OnIOTaskProgress(const ProgressStatus& status);
  void OnIOTaskComplete(IOTaskId task_id, ProgressStatus status);

  // Service method for lazily getting the wake lock.
  device::mojom::WakeLock* GetWakeLock();

  // Put a new task with the given task_id in the task map. This method also
  // manages the wake lock by requesting a lock if this is the first task. It
  // returns the pointer to the just stored task.
  IOTask* PutIOTask(const IOTaskId task_id, std::unique_ptr<IOTask> task);

  // Removes a task by its ID. This method also manages the wake lock by
  // releasing it if this was the last registered task.
  void RemoveIOTask(const IOTaskId task_id);

  SEQUENCE_CHECKER(sequence_checker_);

  base::ObserverList<Observer> observers_;

  IOTaskId last_id_ = 0;
  std::map<IOTaskId, std::unique_ptr<IOTask>> tasks_;

  // For keeping the device awake during IO tasks.
  mojo::Remote<device::mojom::WakeLock> wake_lock_;

  int wake_lock_counter_for_tests_ = 0;

  // A map of when each task has been last notified to its observers.
  base::flat_map<IOTaskId, base::Time> tasks_last_update_;

  base::WeakPtrFactory<IOTaskController> weak_ptr_factory_{this};
};

}  // namespace io_task

}  // namespace file_manager

#endif  // CHROME_BROWSER_ASH_FILE_MANAGER_IO_TASK_CONTROLLER_H_