1// Copyright 2016 The Chromium Authors 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/system/sys_info.h" 6 7#import <Foundation/Foundation.h> 8#include <mach/mach_host.h> 9#include <mach/mach_init.h> 10#include <stddef.h> 11#include <stdint.h> 12#include <sys/sysctl.h> 13#include <sys/types.h> 14 15#include <optional> 16#include <string_view> 17 18#include "base/apple/scoped_mach_port.h" 19#include "base/check_op.h" 20#include "base/debug/stack_trace.h" 21#include "base/feature_list.h" 22#include "base/mac/mac_util.h" 23#include "base/no_destructor.h" 24#include "base/notreached.h" 25#include "base/numerics/safe_conversions.h" 26#include "base/posix/sysctl.h" 27#include "base/process/process_metrics.h" 28#include "base/strings/string_number_conversions.h" 29#include "base/strings/string_util.h" 30#include "base/strings/stringprintf.h" 31#include "base/synchronization/lock.h" 32#include "base/system/sys_info_internal.h" 33 34namespace base { 35 36namespace { 37 38// Whether this process has CPU security mitigations enabled. 39bool g_is_cpu_security_mitigation_enabled = false; 40 41// Whether NumberOfProcessors() was called. Used to detect when the CPU security 42// mitigations state changes after a call to NumberOfProcessors(). 43bool g_is_cpu_security_mitigation_enabled_read = false; 44 45} // namespace 46 47namespace internal { 48 49std::optional<int> NumberOfPhysicalProcessors() { 50 return GetSysctlIntValue("hw.physicalcpu_max"); 51} 52 53std::optional<int> NumberOfProcessorsWhenCpuSecurityMitigationEnabled() { 54 g_is_cpu_security_mitigation_enabled_read = true; 55 56 if (!g_is_cpu_security_mitigation_enabled || 57 !FeatureList::IsEnabled(kNumberOfCoresWithCpuSecurityMitigation)) { 58 return std::nullopt; 59 } 60 return NumberOfPhysicalProcessors(); 61} 62 63} // namespace internal 64 65BASE_FEATURE(kNumberOfCoresWithCpuSecurityMitigation, 66 "NumberOfCoresWithCpuSecurityMitigation", 67 FEATURE_ENABLED_BY_DEFAULT); 68 69// static 70std::string SysInfo::OperatingSystemName() { 71 return "Mac OS X"; 72} 73 74// static 75std::string SysInfo::OperatingSystemVersion() { 76 int32_t major, minor, bugfix; 77 OperatingSystemVersionNumbers(&major, &minor, &bugfix); 78 return base::StringPrintf("%d.%d.%d", major, minor, bugfix); 79} 80 81// static 82void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version, 83 int32_t* minor_version, 84 int32_t* bugfix_version) { 85 NSOperatingSystemVersion version = 86 NSProcessInfo.processInfo.operatingSystemVersion; 87 *major_version = saturated_cast<int32_t>(version.majorVersion); 88 *minor_version = saturated_cast<int32_t>(version.minorVersion); 89 *bugfix_version = saturated_cast<int32_t>(version.patchVersion); 90} 91 92// static 93std::string SysInfo::OperatingSystemArchitecture() { 94 switch (mac::GetCPUType()) { 95 case mac::CPUType::kIntel: 96 return "x86_64"; 97 case mac::CPUType::kTranslatedIntel: 98 case mac::CPUType::kArm: 99 return "arm64"; 100 } 101} 102 103// static 104uint64_t SysInfo::AmountOfPhysicalMemoryImpl() { 105 struct host_basic_info hostinfo; 106 mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; 107 base::apple::ScopedMachSendRight host(mach_host_self()); 108 int result = host_info(host.get(), HOST_BASIC_INFO, 109 reinterpret_cast<host_info_t>(&hostinfo), &count); 110 if (result != KERN_SUCCESS) { 111 NOTREACHED(); 112 return 0; 113 } 114 DCHECK_EQ(HOST_BASIC_INFO_COUNT, count); 115 return hostinfo.max_mem; 116} 117 118// static 119uint64_t SysInfo::AmountOfAvailablePhysicalMemoryImpl() { 120 SystemMemoryInfoKB info; 121 if (!GetSystemMemoryInfo(&info)) 122 return 0; 123 // We should add inactive file-backed memory also but there is no such 124 // information from Mac OS unfortunately. 125 return checked_cast<uint64_t>(info.free + info.speculative) * 1024; 126} 127 128// static 129std::string SysInfo::CPUModelName() { 130 return StringSysctlByName("machdep.cpu.brand_string").value_or(std::string{}); 131} 132 133// static 134std::string SysInfo::HardwareModelName() { 135 // The old "hw.machine" and "hw.model" sysctls are discouraged in favor of the 136 // new "hw.product" and "hw.target". See 137 // https://github.com/apple-oss-distributions/xnu/blob/aca3beaa3dfbd42498b42c5e5ce20a938e6554e5/bsd/sys/sysctl.h#L1168-L1169 138 // and 139 // https://github.com/apple-oss-distributions/xnu/blob/aca3beaa3dfbd42498b42c5e5ce20a938e6554e5/bsd/kern/kern_mib.c#L534-L536 140 if (base::mac::MacOSMajorVersion() < 11) { 141 return StringSysctl({CTL_HW, HW_MODEL}).value_or(std::string{}); 142 } else { 143 return StringSysctl({CTL_HW, HW_PRODUCT}).value_or(std::string{}); 144 } 145} 146 147// static 148std::optional<SysInfo::HardwareModelNameSplit> 149SysInfo::SplitHardwareModelNameDoNotUse(std::string_view name) { 150 size_t number_loc = name.find_first_of("0123456789"); 151 if (number_loc == std::string::npos) { 152 return std::nullopt; 153 } 154 size_t comma_loc = name.find(',', number_loc); 155 if (comma_loc == std::string::npos) { 156 return std::nullopt; 157 } 158 159 HardwareModelNameSplit split; 160 if (!StringToInt(name.substr(0u, comma_loc).substr(number_loc), 161 &split.model) || 162 !StringToInt(name.substr(comma_loc + 1), &split.variant)) { 163 return std::nullopt; 164 } 165 split.category = name.substr(0u, number_loc); 166 return split; 167} 168 169// static 170SysInfo::HardwareInfo SysInfo::GetHardwareInfoSync() { 171 HardwareInfo info; 172 info.manufacturer = "Apple Inc."; 173 info.model = HardwareModelName(); 174 DCHECK(IsStringUTF8(info.manufacturer)); 175 DCHECK(IsStringUTF8(info.model)); 176 return info; 177} 178 179// static 180void SysInfo::SetCpuSecurityMitigationsEnabled() { 181 // Setting `g_is_cpu_security_mitigation_enabled_read` after it has been read 182 // is disallowed because it could indicate that some code got a number of 183 // processor computed without all the required state. 184 CHECK(!g_is_cpu_security_mitigation_enabled_read); 185 186 g_is_cpu_security_mitigation_enabled = true; 187} 188 189// static 190void SysInfo::ResetCpuSecurityMitigationsEnabledForTesting() { 191 g_is_cpu_security_mitigation_enabled_read = false; 192 g_is_cpu_security_mitigation_enabled = false; 193} 194 195} // namespace base 196