// 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_TASK_MANAGER_SAMPLING_TASK_GROUP_H_
#define CHROME_BROWSER_TASK_MANAGER_SAMPLING_TASK_GROUP_H_

#include <stddef.h>
#include <stdint.h>

#include <optional>
#include <vector>

#include "base/byte_size.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process_handle.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "chrome/browser/task_manager/providers/task.h"
#include "chrome/browser/task_manager/sampling/shared_sampler.h"
#include "chrome/browser/task_manager/sampling/task_group_sampler.h"
#include "chrome/browser/task_manager/task_manager_observer.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/task_manager/sampling/arc_shared_sampler.h"
#endif  // BUILDFLAG(IS_CHROMEOS)

namespace gpu {
struct VideoMemoryUsageStats;
}

namespace task_manager {

// A mask for refresh flags that are not supported by VM tasks.
inline constexpr int kUnsupportedVMRefreshFlags =
    REFRESH_TYPE_CPU | REFRESH_TYPE_SWAPPED_MEM | REFRESH_TYPE_GPU_MEMORY |
    REFRESH_TYPE_V8_MEMORY | REFRESH_TYPE_SQLITE_MEMORY |
    REFRESH_TYPE_WEBCACHE_STATS | REFRESH_TYPE_NETWORK_USAGE |
    REFRESH_TYPE_IDLE_WAKEUPS | REFRESH_TYPE_HANDLES | REFRESH_TYPE_START_TIME |
    REFRESH_TYPE_CPU_TIME | REFRESH_TYPE_PRIORITY |
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
    REFRESH_TYPE_FD_COUNT |
#endif
    REFRESH_TYPE_HARD_FAULTS;

class SharedSampler;

// Defines a group of tasks tracked by the task manager which belong to the same
// process. This class lives on the UI thread.
class TaskGroup {
 public:
  TaskGroup(
      base::ProcessHandle proc_handle,
      base::ProcessId proc_id,
      bool is_running_in_vm,
      const base::RepeatingClosure& on_background_calculations_done,
      const scoped_refptr<SharedSampler>& shared_sampler,
      const scoped_refptr<base::SequencedTaskRunner>& blocking_pool_runner);
  TaskGroup(const TaskGroup&) = delete;
  TaskGroup& operator=(const TaskGroup&) = delete;
  ~TaskGroup();

  // Adds and removes the given |task| to this group. |task| must be running on
  // the same process represented by this group.
  void AddTask(Task* task);
  void RemoveTask(Task* task);

  void Refresh(const gpu::VideoMemoryUsageStats& gpu_memory_stats,
               base::TimeDelta update_interval,
               int64_t refresh_flags);

  Task* GetTaskById(TaskId task_id) const;

  // This is to be called after the task manager had informed its observers with
  // OnTasksRefreshedWithBackgroundCalculations() to begin another cycle for
  // this notification type.
  void ClearCurrentBackgroundCalculationsFlags();

  // True if all enabled background operations calculating resource usage of the
  // process represented by this TaskGroup have completed.
  bool AreBackgroundCalculationsDone() const;

#if BUILDFLAG(IS_CHROMEOS)
  void SetArcSampler(ArcSharedSampler* sampler);
#endif  // BUILDFLAG(IS_CHROMEOS)

  const base::ProcessHandle& process_handle() const { return process_handle_; }
  const base::ProcessId& process_id() const { return process_id_; }

  const std::vector<raw_ptr<Task, VectorExperimental>>& tasks() const {
    return tasks_;
  }
  size_t num_tasks() const { return tasks().size(); }
  bool empty() const { return tasks().empty(); }

  double platform_independent_cpu_usage() const {
    return platform_independent_cpu_usage_;
  }
  void set_platform_independent_cpu_usage(double cpu_usage) {
    platform_independent_cpu_usage_ = cpu_usage;
  }
  base::Time start_time() const { return start_time_; }
  base::TimeDelta cpu_time() const { return cpu_time_; }
  void set_footprint(base::ByteSize footprint) {
    memory_footprint_ = footprint;
  }
  std::optional<base::ByteSize> footprint_bytes() const {
    return memory_footprint_;
  }
#if BUILDFLAG(IS_CHROMEOS)
  std::optional<base::ByteSize> swapped_bytes() const { return swapped_mem_; }
  void set_swapped_bytes(base::ByteSize swapped_bytes) {
    swapped_mem_ = swapped_bytes;
  }
#endif  // BUILDFLAG(IS_CHROMEOS)
  std::optional<base::ByteSize> gpu_memory() const { return gpu_memory_; }
  void set_gpu_memory(base::ByteSize gpu_mem_bytes) {
    gpu_memory_ = gpu_mem_bytes;
  }
  bool gpu_memory_has_duplicates() const { return gpu_memory_has_duplicates_; }
  void set_gpu_memory_has_duplicates(bool has_duplicates) {
    gpu_memory_has_duplicates_ = has_duplicates;
  }
  std::optional<base::ByteSize> per_process_network_usage_rate() const {
    return per_process_network_usage_rate_;
  }
  bool is_backgrounded() const { return is_backgrounded_; }
  void set_is_backgrounded(bool is_backgrounded) {
    is_backgrounded_ = is_backgrounded;
  }

#if BUILDFLAG(IS_WIN)
  int64_t gdi_current_handles() const { return gdi_current_handles_; }
  int64_t gdi_peak_handles() const { return gdi_peak_handles_; }
  int64_t user_current_handles() const { return user_current_handles_; }
  int64_t user_peak_handles() const { return user_peak_handles_; }
  int64_t hard_faults_per_second() const { return hard_faults_per_second_; }
#endif  // BUILDFLAG(IS_WIN)

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
  int open_fd_count() const { return open_fd_count_; }
  void set_open_fd_count(int open_fd_count) { open_fd_count_ = open_fd_count; }
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)

  int idle_wakeups_per_second() const { return idle_wakeups_per_second_; }
  void set_idle_wakeups_per_second(int idle_wakeups) {
    idle_wakeups_per_second_ = idle_wakeups;
  }

 private:
  void RefreshGpuMemory(const gpu::VideoMemoryUsageStats& gpu_memory_stats);

  void RefreshWindowsHandles();

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
  void OnOpenFdCountRefreshDone(int open_fd_count);
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)

  void OnCpuRefreshDone(double cpu_usage);
  void OnSwappedMemRefreshDone(base::ByteSize swapped_mem_bytes);
  void OnProcessPriorityDone(base::Process::Priority priority);
  void OnIdleWakeupsRefreshDone(int idle_wakeups_per_second);

  void OnSamplerRefreshDone(
      std::optional<SharedSampler::SamplingResult> results);

#if BUILDFLAG(IS_CHROMEOS)
  void OnArcSamplerRefreshDone(
      std::optional<ArcSharedSampler::MemoryFootprintBytes> results);
#endif  // BUILDFLAG(IS_CHROMEOS)

  void OnBackgroundRefreshTypeFinished(int64_t finished_refresh_type);

  // The process' handle and ID.
  base::ProcessHandle process_handle_;
  base::ProcessId process_id_;
  bool is_running_in_vm_;

  // This is a callback into the TaskManagerImpl to inform it that the
  // background calculations for this TaskGroup has finished.
  const base::RepeatingClosure on_background_calculations_done_;

  scoped_refptr<TaskGroupSampler> worker_thread_sampler_;

  scoped_refptr<SharedSampler> shared_sampler_;
#if BUILDFLAG(IS_CHROMEOS)
  // Shared sampler that retrieves memory footprint for all ARC processes.
  raw_ptr<ArcSharedSampler> arc_shared_sampler_ = nullptr;  // Not owned
#endif  // BUILDFLAG(IS_CHROMEOS)

  // Lists the Tasks in this TaskGroup.
  // Tasks are not owned by the TaskGroup. They're owned by the TaskProviders.
  std::vector<raw_ptr<Task, VectorExperimental>> tasks_;

  // Flags will be used to determine when the background calculations has
  // completed for the enabled refresh types for this TaskGroup.
  int64_t expected_on_bg_done_flags_;
  int64_t current_on_bg_done_flags_;

  // The per process resources usages.
  double platform_independent_cpu_usage_ =
      std::numeric_limits<double>::quiet_NaN();
  base::Time start_time_;     // Only calculated On Windows now.
  base::TimeDelta cpu_time_;  // Only calculated On Windows now.
  std::optional<base::ByteSize> swapped_mem_;
  std::optional<base::ByteSize> memory_footprint_;
  std::optional<base::ByteSize> gpu_memory_;

  // The network usage in bytes per second as the sum of all network usages of
  // the individual tasks sharing the same process.
  std::optional<base::ByteSize> per_process_network_usage_rate_;

#if BUILDFLAG(IS_WIN)
  // Windows GDI and USER Handles.
  int64_t gdi_current_handles_ = -1;
  int64_t gdi_peak_handles_ = -1;
  int64_t user_current_handles_ = -1;
  int64_t user_peak_handles_ = -1;
  int64_t hard_faults_per_second_ = -1;
#endif  // BUILDFLAG(IS_WIN)
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
  // The number of file descriptors currently open by the process.
  int open_fd_count_ = -1;
#endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
  int idle_wakeups_per_second_ = -1;
  bool gpu_memory_has_duplicates_ = false;
  bool is_backgrounded_ = false;

  // Always keep this the last member of this class so that it's the first to be
  // destroyed.
  base::WeakPtrFactory<TaskGroup> weak_ptr_factory_{this};
};

}  // namespace task_manager

#endif  // CHROME_BROWSER_TASK_MANAGER_SAMPLING_TASK_GROUP_H_
