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 } 113 DCHECK_EQ(HOST_BASIC_INFO_COUNT, count); 114 return hostinfo.max_mem; 115} 116 117// static 118uint64_t SysInfo::AmountOfAvailablePhysicalMemoryImpl() { 119 SystemMemoryInfoKB info; 120 if (!GetSystemMemoryInfo(&info)) 121 return 0; 122 // We should add inactive file-backed memory also but there is no such 123 // information from Mac OS unfortunately. 124 return checked_cast<uint64_t>(info.free + info.speculative) * 1024; 125} 126 127// static 128std::string SysInfo::CPUModelName() { 129 return StringSysctlByName("machdep.cpu.brand_string").value_or(std::string{}); 130} 131 132// static 133std::string SysInfo::HardwareModelName() { 134 // Note that there is lots of code out there that uses "hw.model", but that is 135 // deprecated in favor of "hw.product" as used here. See the sysctl.h file for 136 // more info. 137 return StringSysctl({CTL_HW, HW_PRODUCT}).value_or(std::string{}); 138} 139 140// static 141std::optional<SysInfo::HardwareModelNameSplit> 142SysInfo::SplitHardwareModelNameDoNotUse(std::string_view name) { 143 size_t number_loc = name.find_first_of("0123456789"); 144 if (number_loc == std::string::npos) { 145 return std::nullopt; 146 } 147 size_t comma_loc = name.find(',', number_loc); 148 if (comma_loc == std::string::npos) { 149 return std::nullopt; 150 } 151 152 HardwareModelNameSplit split; 153 if (!StringToInt(name.substr(0u, comma_loc).substr(number_loc), 154 &split.model) || 155 !StringToInt(name.substr(comma_loc + 1), &split.variant)) { 156 return std::nullopt; 157 } 158 split.category = name.substr(0u, number_loc); 159 return split; 160} 161 162// static 163SysInfo::HardwareInfo SysInfo::GetHardwareInfoSync() { 164 HardwareInfo info; 165 info.manufacturer = "Apple Inc."; 166 info.model = HardwareModelName(); 167 DCHECK(IsStringUTF8(info.manufacturer)); 168 DCHECK(IsStringUTF8(info.model)); 169 return info; 170} 171 172// static 173void SysInfo::SetCpuSecurityMitigationsEnabled() { 174 // Setting `g_is_cpu_security_mitigation_enabled_read` after it has been read 175 // is disallowed because it could indicate that some code got a number of 176 // processor computed without all the required state. 177 CHECK(!g_is_cpu_security_mitigation_enabled_read); 178 179 g_is_cpu_security_mitigation_enabled = true; 180} 181 182// static 183void SysInfo::ResetCpuSecurityMitigationsEnabledForTesting() { 184 g_is_cpu_security_mitigation_enabled_read = false; 185 g_is_cpu_security_mitigation_enabled = false; 186} 187 188} // namespace base 189