#include "chrome/browser/ash/borealis/borealis_hardware_checker.h"
#include "ash/constants/ash_features.h"
#include "base/cpu.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/system/sys_info.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "chromeos/ash/components/system/statistics_provider.h"
#include "third_party/re2/src/re2/re2.h"
namespace borealis {
namespace {
constexpr uint64_t kGibi = 1024ull * 1024 * 1024;
constexpr char kIntelCpuRegex[] = "((i[357]-)|(Core.* [357]))";
constexpr char kAmdCpuRegex[] = "Ryzen [357]";
std::string* g_cpu_brand_for_test_ = nullptr;
std::string GetBoardName() {
std::vector<std::string> pieces =
base::SplitString(base::SysInfo::GetLsbReleaseBoard(), "-",
base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
if (pieces.size() >= 2 && pieces[1] == "borealis") {
return pieces[0] + "-" + pieces[1];
}
DCHECK(!pieces.empty());
return pieces[0];
}
bool IsBoard(const std::string& board) {
return GetBoardName() == board;
}
bool BoardIn(const base::flat_set<std::string>& boards) {
return boards.contains(GetBoardName());
}
bool CpuRegexMatches(const std::string& cpu_regex) {
return RE2::PartialMatch(
g_cpu_brand_for_test_ ? *g_cpu_brand_for_test_
: base::CPU::GetInstanceNoAllocation().cpu_brand(),
cpu_regex);
}
bool HasMemory(uint64_t mem_bytes) {
return base::SysInfo::AmountOfPhysicalMemory().InBytesUnsigned() >= mem_bytes;
}
bool HasSufficientHardware(const std::string& cpu_regex) {
return HasMemory(7 * kGibi) && CpuRegexMatches(cpu_regex);
}
bool InTargetSegment() {
return base::FeatureList::IsEnabled(
ash::features::kFeatureManagementBorealis);
}
bool Check() {
if (BoardIn({"hatch", "drallion", "puff"})) {
return HasSufficientHardware(kIntelCpuRegex);
}
if (IsBoard("volteer")) {
return HasSufficientHardware(kIntelCpuRegex);
}
if (BoardIn({"brya", "adlrvp", "brask", "brox"})) {
return HasSufficientHardware(kIntelCpuRegex);
}
if (BoardIn({"guybrush", "majolica"})) {
return HasSufficientHardware(kAmdCpuRegex);
}
if (BoardIn({"aurora", "myst"})) {
return true;
}
if (IsBoard("nissa")) {
return HasSufficientHardware(kIntelCpuRegex) && InTargetSegment();
}
if (IsBoard("skyrim")) {
return HasSufficientHardware(kAmdCpuRegex) && InTargetSegment();
}
if (IsBoard("rex")) {
return HasSufficientHardware(".*");
}
return false;
}
}
void HasSufficientHardware(base::OnceCallback<void(bool)> callback) {
ash::system::StatisticsProvider::GetInstance()
->ScheduleOnMachineStatisticsLoaded(base::BindOnce(
[](base::OnceCallback<void(bool)> callback) {
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, base::MayBlock(), base::BindOnce(&Check),
std::move(callback));
},
std::move(callback)));
}
void SetCpuForTesting(std::string* cpu_brand) {
g_cpu_brand_for_test_ = cpu_brand;
}
}