chromium/ash/hud_display/ash_tracing_manager.cc

// 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.

#include "ash/hud_display/ash_tracing_manager.h"

#include <vector>

#include "ash/hud_display/ash_tracing_request.h"
#include "ash/session/session_controller_impl.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/sequence_checker.h"
#include "base/strings/stringprintf.h"

namespace ash {
namespace hud_display {

AshTracingManager::AshTracingManager() {
  SessionController::Get()->AddObserver(this);
}

AshTracingManager::~AshTracingManager() {
  if (SessionController::Get())
    SessionController::Get()->RemoveObserver(this);
}

// static
AshTracingManager& AshTracingManager::Get() {
  static base::NoDestructor<AshTracingManager> manager;
  return *manager;
}

bool AshTracingManager::IsBusy() const {
  if (tracing_requests_.empty())
    return false;

  switch (GetLastRequestStatus()) {
    case AshTracingRequest::Status::kEmpty:
      [[fallthrough]];
    case AshTracingRequest::Status::kInitialized:
      return true;
    case AshTracingRequest::Status::kStarted:
      return false;
    case AshTracingRequest::Status::kStopping:
      return true;
    case AshTracingRequest::Status::kPendingMount:
      [[fallthrough]];
    case AshTracingRequest::Status::kWritingFile:
      [[fallthrough]];
    case AshTracingRequest::Status::kCompleted:
      return false;
  }
}

bool AshTracingManager::IsTracingStarted() const {
  if (tracing_requests_.empty())
    return false;

  switch (GetLastRequestStatus()) {
    case AshTracingRequest::Status::kEmpty:
      [[fallthrough]];
    case AshTracingRequest::Status::kInitialized:
      [[fallthrough]];
    case AshTracingRequest::Status::kStarted:
      [[fallthrough]];
    case AshTracingRequest::Status::kStopping:
      return true;
    case AshTracingRequest::Status::kPendingMount:
      [[fallthrough]];
    case AshTracingRequest::Status::kWritingFile:
      [[fallthrough]];
    case AshTracingRequest::Status::kCompleted:
      return false;
  }
}

std::string AshTracingManager::GetStatusMessage() const {
  std::string result;
  if (tracing_requests_.empty())
    return result;

  unsigned started = 0;
  unsigned waiting_for_login = 0;
  unsigned writing_trace_file = 0;
  unsigned completed = 0;
  for (const auto& request : tracing_requests_) {
    switch (request->status()) {
      case AshTracingRequest::Status::kEmpty:
        [[fallthrough]];
      case AshTracingRequest::Status::kInitialized:
        [[fallthrough]];
      case AshTracingRequest::Status::kStarted:
        [[fallthrough]];
      case AshTracingRequest::Status::kStopping:
        ++started;
        break;
      case AshTracingRequest::Status::kPendingMount:
        ++waiting_for_login;
        break;
      case AshTracingRequest::Status::kWritingFile:
        ++writing_trace_file;
        break;
      case AshTracingRequest::Status::kCompleted:
        ++completed;
    }
  }
  if (started)
    result = base::StringPrintf("%u active", started);

  if (waiting_for_login) {
    if (!result.empty())
      result += ", ";

    result += base::StringPrintf("%u pending login", waiting_for_login);
  }
  if (writing_trace_file) {
    if (!result.empty())
      result += ", ";

    result += base::StringPrintf("%u writing", writing_trace_file);
  }
  if (completed) {
    if (!result.empty())
      result += ", ";

    result += base::StringPrintf("%u completed", completed);
  }
  if (!result.empty())
    result = std::string("Tracing: ") + result + ".";

  return result;
}

void AshTracingManager::Start() {
  DCHECK(!IsBusy());
  DCHECK(!IsTracingStarted());
  tracing_requests_.push_back(std::make_unique<AshTracingRequest>(this));
}

void AshTracingManager::Stop() {
  DCHECK(!tracing_requests_.empty());
  DCHECK_EQ(GetLastRequestStatus(), AshTracingRequest::Status::kStarted);
  tracing_requests_.back()->Stop();
}

void AshTracingManager::AddObserver(AshTracingManager::Observer* observer) {
  observers_.AddObserver(observer);
}

void AshTracingManager::RemoveObserver(AshTracingManager::Observer* observer) {
  observers_.RemoveObserver(observer);
}

void AshTracingManager::OnRequestStatusChanged(AshTracingRequest* request) {
  for (Observer& observer : observers_)
    observer.OnTracingStatusChange();
}

void AshTracingManager::OnFirstSessionStarted() {
  for (auto& request : tracing_requests_)
    request->OnUserLoggedIn();
}

const std::vector<std::unique_ptr<AshTracingRequest>>&
AshTracingManager::GetTracingRequestsForTesting() const {
  return tracing_requests_;
}

AshTracingRequest::Status AshTracingManager::GetLastRequestStatus() const {
  return tracing_requests_.back()->status();
}

}  // namespace hud_display
}  // namespace ash