chromium/chrome/updater/win/task_scheduler.h

// Copyright 2019 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_UPDATER_WIN_TASK_SCHEDULER_H_
#define CHROME_UPDATER_WIN_TASK_SCHEDULER_H_

#include <stdint.h>

#include <memory>
#include <ostream>
#include <string>
#include <vector>

#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"

namespace base {
class CommandLine;
class Time;
}  // namespace base

namespace updater {

enum class UpdaterScope;

// This class wraps a scheduled task and expose an API to parametrize a task
// before calling |Register|, or to verify its existence, or delete it.
class TaskScheduler : public base::RefCountedThreadSafe<TaskScheduler> {
 public:
  // The types of trigger to register for this task. Multiple triggers types can
  // be combined using the bitwise OR operator.
  enum TriggerType {
    // Run when the current user logs on (for user installs). Or when any user
    // logs on (for system installs).
    TRIGGER_TYPE_LOGON = 1 << 0,

    // Run right now (mainly for tests).
    TRIGGER_TYPE_NOW = 1 << 1,

    // Run every hour.
    TRIGGER_TYPE_HOURLY = 1 << 2,

    // Run every five hours.
    TRIGGER_TYPE_EVERY_FIVE_HOURS = 1 << 3,

    TRIGGER_TYPE_MAX = 1 << 4,
  };

  // The log-on requirements for a task to be scheduled. Note that a task can
  // have both the interactive and service bit set. In that case the
  // interactive token will be used when available, and a stored password
  // otherwise.
  enum LogonType {
    LOGON_UNKNOWN = 0,

    // Run the task with the user's interactive token when logged in.
    LOGON_INTERACTIVE = 1 << 0,

    // The task will run whether the user is logged in or not using either a
    // user/password specified at registration time, a service account or a
    // service for user (S4U).
    LOGON_SERVICE = 1 << 1,

    // The task is run as a service for user and as such will be on an
    // invisible desktop.
    LOGON_S4U = 1 << 2,
  };

  // Struct representing a single scheduled task action.
  struct TaskExecAction {
    base::FilePath application_path;
    base::FilePath working_dir;
    std::wstring arguments;
  };

  // Detailed description of a scheduled task. This type is returned by the
  // GetTaskInfo() method.
  struct TaskInfo {
    TaskInfo();
    TaskInfo(const TaskInfo&);
    TaskInfo(TaskInfo&&);
    ~TaskInfo();
    TaskInfo& operator=(const TaskInfo&);
    TaskInfo& operator=(TaskInfo&&);

    std::wstring name;

    // Description of the task.
    std::wstring description;

    // A scheduled task can have more than one action associated with it and
    // actions can be of types other than executables (for example, sending
    // emails). This list however contains only the execution actions.
    std::vector<TaskExecAction> exec_actions;

    // The log-on requirements for the task's actions to be run. A bit mask with
    // the mapping defined by LogonType.
    uint32_t logon_type = 0;

    // User ID under which the task runs.
    std::wstring user_id;

    int trigger_types = 0;
  };

  // Creates an instance of the task scheduler for the given `scope`.
  // `use_task_subfolders` dictates whether the scheduler creates and works with
  // tasks that are created within a subfolder (`true` by default), or tasks
  // that are created at the root folder. When `use_task_subfolders` is `true`,
  // the tasks are created within the subfolder returned by
  // `GetTaskSubfolderName()`.
  static scoped_refptr<TaskScheduler> CreateInstance(
      UpdaterScope scope,
      bool use_task_subfolders = true);

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

  // Identify whether the task is registered or not.
  [[nodiscard]] virtual bool IsTaskRegistered(
      const std::wstring& task_name) = 0;

  // Return the time of the next schedule run for the given task name. Return
  // false on failure.
  // `next_run_time` is returned as local time on the current system, not UTC.
  [[nodiscard]] virtual bool GetNextTaskRunTime(const std::wstring& task_name,
                                                base::Time& next_run_time) = 0;

  // Delete the task if it exists. No-op if the task doesn't exist. Return false
  // on failure to delete an existing task.
  [[nodiscard]] virtual bool DeleteTask(const std::wstring& task_name) = 0;

  // Enable or disable task based on the value of |enabled|. Return true if the
  // task exists and the operation succeeded.
  [[nodiscard]] virtual bool SetTaskEnabled(const std::wstring& task_name,
                                            bool enabled) = 0;

  // Return true if task exists and is enabled.
  [[nodiscard]] virtual bool IsTaskEnabled(const std::wstring& task_name) = 0;

  // Return true if task exists and is running.
  [[nodiscard]] virtual bool IsTaskRunning(const std::wstring& task_name) = 0;

  // List all currently registered scheduled tasks.
  [[nodiscard]] virtual bool GetTaskNameList(
      std::vector<std::wstring>& task_names) = 0;

  // Returns the first instance of a scheduled task installed with the given
  // `task_prefix`.
  [[nodiscard]] virtual std::wstring FindFirstTaskName(
      const std::wstring& task_prefix) = 0;

  // Return detailed information about a task. Return true if no errors were
  // encountered. On error, the struct is left unmodified.
  [[nodiscard]] virtual bool GetTaskInfo(const std::wstring& task_name,
                                         TaskInfo& info) = 0;

  // Returns true if the task folder specified by |folder_name| exists.
  [[nodiscard]] virtual bool HasTaskFolder(const std::wstring& folder_name) = 0;

  // Register the task to run the specified application and using the given
  // `trigger_types`. `trigger_types` is a bitwise OR of one or more types in
  // the `TriggerType` enum.
  [[nodiscard]] virtual bool RegisterTask(const std::wstring& task_name,
                                          const std::wstring& task_description,
                                          const base::CommandLine& run_command,
                                          int trigger_types,
                                          bool hidden) = 0;

  // Returns true if the scheduled task specified by |task_name| can be started
  // successfully or is currently running.
  [[nodiscard]] virtual bool StartTask(const std::wstring& task_name) = 0;

  // Name of the sub-folder that the scheduled tasks are created in, prefixed
  // with the company folder `GetTaskCompanyFolder`.
  [[nodiscard]] virtual std::wstring GetTaskSubfolderName() = 0;

  // Runs `callback` for each task that matches `prefix`.
  virtual void ForEachTaskWithPrefix(
      const std::wstring& prefix,
      base::FunctionRef<void(const std::wstring&)> callback) = 0;

 protected:
  friend class base::RefCountedThreadSafe<TaskScheduler>;
  TaskScheduler();
  virtual ~TaskScheduler() = default;
};

std::ostream& operator<<(std::ostream& stream,
                         const TaskScheduler::TaskExecAction& t);
std::ostream& operator<<(std::ostream& stream,
                         const TaskScheduler::TaskInfo& t);

}  // namespace updater

#endif  // CHROME_UPDATER_WIN_TASK_SCHEDULER_H_