chromium/chrome/browser/ash/system_logs/traffic_counters_log_source.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/system_logs/traffic_counters_log_source.h"

#include <sstream>
#include <string>
#include <utility>

#include "ash/public/cpp/network_config_service.h"
#include "base/functional/bind.h"
#include "base/json/json_writer.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "chrome/browser/ash/net/network_health/network_health_manager.h"
#include "chromeos/ash/components/network/network_event_log.h"
#include "content/public/browser/browser_thread.h"

namespace system_logs {

namespace {

constexpr char kTrafficCountersEntry[] = "traffic-counters";

constexpr char kSource[] = "source";
constexpr char kRxBytes[] = "rx_bytes";
constexpr char kTxBytes[] = "tx_bytes";

constexpr char kTrafficCountersKey[] = "traffic_counters";
constexpr char kLastResetTimeKey[] = "last_reset_time";
constexpr char kNotAvailable[] = "Not Available";

std::string GetSourceString(
    chromeos::network_config::mojom::TrafficCounterSource source) {
  std::stringstream ss;
  ss << source;
  return ss.str();
}

base::Value::List ParseTrafficCounters(
    const std::vector<chromeos::network_config::mojom::TrafficCounterPtr>&
        traffic_counters) {
  base::Value::List traffic_counters_list;
  for (const auto& tc : traffic_counters) {
    base::Value::Dict traffic_counter;
    traffic_counter.Set(kSource, GetSourceString(tc->source));
    traffic_counter.Set(kRxBytes, static_cast<double>(tc->rx_bytes));
    traffic_counter.Set(kTxBytes, static_cast<double>(tc->tx_bytes));
    traffic_counters_list.Append(std::move(traffic_counter));
  }
  return traffic_counters_list;
}

}  // namespace

TrafficCountersLogSource::TrafficCountersLogSource()
    : SystemLogsSource("TrafficCountersLog") {
  ash::GetNetworkConfigService(
      remote_cros_network_config_.BindNewPipeAndPassReceiver());
  ash::network_health::NetworkHealthManager::GetInstance()->BindHealthReceiver(
      network_health_service_.BindNewPipeAndPassReceiver());
}

TrafficCountersLogSource::~TrafficCountersLogSource() {}

void TrafficCountersLogSource::Fetch(SysLogsSourceCallback callback) {
  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  DCHECK(!callback.is_null());
  callback_ = std::move(callback);
  traffic_counters_.clear();
  network_health_service_->GetRecentlyActiveNetworks(
      base::BindOnce(&TrafficCountersLogSource::OnGetRecentlyActiveNetworks,
                     weak_factory_.GetWeakPtr()));
}

void TrafficCountersLogSource::OnGetRecentlyActiveNetworks(
    const std::vector<std::string>& guids) {
  total_guids_ = guids.size();
  for (const std::string& guid : guids) {
    remote_cros_network_config_->RequestTrafficCounters(
        guid,
        base::BindOnce(&TrafficCountersLogSource::OnTrafficCountersReceived,
                       weak_factory_.GetWeakPtr(), guid));
  }
}

void TrafficCountersLogSource::OnTrafficCountersReceived(
    const std::string& guid,
    std::vector<chromeos::network_config::mojom::TrafficCounterPtr>
        traffic_counters) {
  remote_cros_network_config_->GetManagedProperties(
      guid, base::BindOnce(&TrafficCountersLogSource::OnGetManagedProperties,
                           weak_factory_.GetWeakPtr(), guid,
                           std::move(traffic_counters)));
}

void TrafficCountersLogSource::OnGetManagedProperties(
    const std::string& guid,
    std::vector<chromeos::network_config::mojom::TrafficCounterPtr>
        traffic_counters,
    chromeos::network_config::mojom::ManagedPropertiesPtr managed_properties) {
  base::Value::Dict tc_dict;
  tc_dict.Set(kTrafficCountersKey, ParseTrafficCounters(traffic_counters));
  if (managed_properties && managed_properties->traffic_counter_properties &&
      managed_properties->traffic_counter_properties->friendly_date
          .has_value()) {
    tc_dict.Set(
        kLastResetTimeKey,
        managed_properties->traffic_counter_properties->friendly_date.value());
  } else {
    tc_dict.Set(kLastResetTimeKey, kNotAvailable);
  }
  traffic_counters_.Set(guid, std::move(tc_dict));
  SendResponseIfDone();
}

void TrafficCountersLogSource::SendResponseIfDone() {
  total_guids_--;
  if (total_guids_ > 0) {
    return;
  }

  std::map<std::string, std::string> response;
  std::string json;
  base::JSONWriter::WriteWithOptions(
      traffic_counters_, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json);
  response[kTrafficCountersEntry] = std::move(json);
  std::move(callback_).Run(
      std::make_unique<SystemLogsResponse>(std::move(response)));
}

}  // namespace system_logs