blob: b6941c4a10c1360fecd36592a5ad04b5817b33c5 [file] [log] [blame]
// Copyright 2020 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "typecd/utils.h"
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <base/files/file_enumerator.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <re2/re2.h>
#include "typecd/metrics_allowlist.h"
namespace {
constexpr char kTbtDeviceRegex[] = "[0-9]+\\-[0-9]+";
constexpr char kTbtDeviceDir[] = "sys/bus/thunderbolt/devices";
constexpr char kBusnum[] = "busnum";
constexpr char kDevnum[] = "devnum";
constexpr char kDuration[] = "power/connected_duration";
constexpr char kSocIdPath[] = "sys/devices/soc0/soc_id";
constexpr char kMtk8196[] = "MT8196";
} // namespace
namespace typecd {
bool ReadHexFromPath(const base::FilePath& path, uint32_t* val) {
std::string val_str;
if (!base::ReadFileToString(path, &val_str)) {
LOG(ERROR) << "Couldn't read value from path " << path;
return false;
}
base::TrimWhitespaceASCII(val_str, base::TRIM_TRAILING, &val_str);
if (!base::HexStringToUInt(val_str.c_str(), val)) {
LOG(ERROR) << "Error parsing hex value: " << val_str;
return false;
}
return true;
}
std::string FormatHexString(uint32_t val, int width) {
std::stringstream out;
out << std::hex << std::setfill('0') << std::setw(width) << val;
return out.str();
}
bool DeviceComp(policy::DevicePolicy::UsbDeviceId dev1,
policy::DevicePolicy::UsbDeviceId dev2) {
// Allowlist entries are first sorted by VID.
if (dev1.vendor_id < dev2.vendor_id) {
return true;
} else if (dev1.vendor_id > dev2.vendor_id) {
return false;
}
// If 2 entries have the same VID, they are sorted by PID.
return (dev1.product_id < dev2.product_id);
}
bool DeviceInMetricsAllowlist(uint16_t vendor_id, uint16_t product_id) {
policy::DevicePolicy::UsbDeviceId device = {vendor_id, product_id};
return std::binary_search(std::begin(kMetricsAllowlist),
std::end(kMetricsAllowlist), device, DeviceComp);
}
int GetTbtDeviceCount() {
int ret = 0;
base::FileEnumerator tbt_links(
base::FilePath(kTbtDeviceDir), false,
base::FileEnumerator::FILES | base::FileEnumerator::SHOW_SYM_LINKS);
for (base::FilePath tbt_link = tbt_links.Next(); !tbt_link.empty();
tbt_link = tbt_links.Next()) {
if (RE2::FullMatch(tbt_link.BaseName().value(), kTbtDeviceRegex)) {
ret++;
}
}
return ret;
}
int ReadUsbProp(base::FilePath usb_device, std::string prop) {
int ret;
std::string prop_str;
if (base::ReadFileToString(usb_device.Append(prop), &prop_str)) {
base::TrimWhitespaceASCII(prop_str, base::TRIM_ALL, &prop_str);
if (base::StringToInt(prop_str, &ret)) {
return ret;
}
}
return 0;
}
std::string GetConnectionId(std::string boot_id, base::FilePath usb_device) {
struct timespec ts;
int64_t duration, connect_time;
clock_gettime(CLOCK_MONOTONIC, &ts);
duration = static_cast<int64_t>(ReadUsbProp(usb_device, kDuration) / 1000);
connect_time = (ts.tv_sec - duration) / 60;
return base::StringPrintf(
"%s.%s.%s.%s", boot_id.c_str(), std::to_string(connect_time).c_str(),
std::to_string(ReadUsbProp(usb_device, kBusnum)).c_str(),
std::to_string(ReadUsbProp(usb_device, kDevnum)).c_str());
}
bool AddUsbLimitWatcher() {
std::string soc_id;
if (!base::ReadFileToString(base::FilePath(kSocIdPath), &soc_id)) {
return false;
}
base::TrimWhitespaceASCII(soc_id, base::TRIM_TRAILING, &soc_id);
return soc_id == kMtk8196;
}
int GetUsbDeviceCount(base::FilePath usb_dir, std::string device_re) {
int device_count = 0;
base::FileEnumerator usb_links(
usb_dir, false,
base::FileEnumerator::FILES | base::FileEnumerator::SHOW_SYM_LINKS);
for (base::FilePath usb_link = usb_links.Next(); !usb_link.empty();
usb_link = usb_links.Next()) {
if (RE2::FullMatch(usb_link.BaseName().value(), device_re)) {
device_count++;
}
}
return device_count;
}
} // namespace typecd