| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/system/sys_info.h" |
| |
| #import <Foundation/Foundation.h> |
| #include <mach/mach_host.h> |
| #include <mach/mach_init.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <sys/sysctl.h> |
| #include <sys/types.h> |
| |
| #include <string_view> |
| |
| #include "base/apple/scoped_mach_port.h" |
| #include "base/check_op.h" |
| #include "base/debug/stack_trace.h" |
| #include "base/feature_list.h" |
| #include "base/mac/mac_util.h" |
| #include "base/no_destructor.h" |
| #include "base/notreached.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/posix/sysctl.h" |
| #include "base/process/process_metrics.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/synchronization/lock.h" |
| #include "base/system/sys_info_internal.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| namespace base { |
| |
| namespace { |
| |
| // Whether this process has CPU security mitigations enabled. |
| bool g_is_cpu_security_mitigation_enabled = false; |
| |
| // Whether NumberOfProcessors() was called. Used to detect when the CPU security |
| // mitigations state changes after a call to NumberOfProcessors(). |
| bool g_is_cpu_security_mitigation_enabled_read = false; |
| |
| } // namespace |
| |
| namespace internal { |
| |
| absl::optional<int> NumberOfPhysicalProcessors() { |
| return GetSysctlIntValue("hw.physicalcpu_max"); |
| } |
| |
| absl::optional<int> NumberOfProcessorsWhenCpuSecurityMitigationEnabled() { |
| g_is_cpu_security_mitigation_enabled_read = true; |
| |
| if (!g_is_cpu_security_mitigation_enabled || |
| !FeatureList::IsEnabled(kNumberOfCoresWithCpuSecurityMitigation)) { |
| return absl::nullopt; |
| } |
| return NumberOfPhysicalProcessors(); |
| } |
| |
| } // namespace internal |
| |
| BASE_FEATURE(kNumberOfCoresWithCpuSecurityMitigation, |
| "NumberOfCoresWithCpuSecurityMitigation", |
| FEATURE_ENABLED_BY_DEFAULT); |
| |
| // static |
| std::string SysInfo::OperatingSystemName() { |
| return "Mac OS X"; |
| } |
| |
| // static |
| std::string SysInfo::OperatingSystemVersion() { |
| int32_t major, minor, bugfix; |
| OperatingSystemVersionNumbers(&major, &minor, &bugfix); |
| return base::StringPrintf("%d.%d.%d", major, minor, bugfix); |
| } |
| |
| // static |
| void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version, |
| int32_t* minor_version, |
| int32_t* bugfix_version) { |
| NSOperatingSystemVersion version = |
| NSProcessInfo.processInfo.operatingSystemVersion; |
| *major_version = saturated_cast<int32_t>(version.majorVersion); |
| *minor_version = saturated_cast<int32_t>(version.minorVersion); |
| *bugfix_version = saturated_cast<int32_t>(version.patchVersion); |
| } |
| |
| // static |
| std::string SysInfo::OperatingSystemArchitecture() { |
| switch (mac::GetCPUType()) { |
| case mac::CPUType::kIntel: |
| return "x86_64"; |
| case mac::CPUType::kTranslatedIntel: |
| case mac::CPUType::kArm: |
| return "arm64"; |
| } |
| } |
| |
| // static |
| uint64_t SysInfo::AmountOfPhysicalMemoryImpl() { |
| struct host_basic_info hostinfo; |
| mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; |
| base::apple::ScopedMachSendRight host(mach_host_self()); |
| int result = host_info(host.get(), HOST_BASIC_INFO, |
| reinterpret_cast<host_info_t>(&hostinfo), &count); |
| if (result != KERN_SUCCESS) { |
| NOTREACHED(); |
| return 0; |
| } |
| DCHECK_EQ(HOST_BASIC_INFO_COUNT, count); |
| return hostinfo.max_mem; |
| } |
| |
| // static |
| uint64_t SysInfo::AmountOfAvailablePhysicalMemoryImpl() { |
| SystemMemoryInfoKB info; |
| if (!GetSystemMemoryInfo(&info)) |
| return 0; |
| // We should add inactive file-backed memory also but there is no such |
| // information from Mac OS unfortunately. |
| return checked_cast<uint64_t>(info.free + info.speculative) * 1024; |
| } |
| |
| // static |
| std::string SysInfo::CPUModelName() { |
| return StringSysctlByName("machdep.cpu.brand_string").value_or(std::string{}); |
| } |
| |
| // static |
| std::string SysInfo::HardwareModelName() { |
| // The old "hw.machine" and "hw.model" sysctls are discouraged in favor of the |
| // new "hw.product" and "hw.target". See |
| // https://github.com/apple-oss-distributions/xnu/blob/aca3beaa3dfbd42498b42c5e5ce20a938e6554e5/bsd/sys/sysctl.h#L1168-L1169 |
| // and |
| // https://github.com/apple-oss-distributions/xnu/blob/aca3beaa3dfbd42498b42c5e5ce20a938e6554e5/bsd/kern/kern_mib.c#L534-L536 |
| if (base::mac::MacOSMajorVersion() < 11) { |
| return StringSysctl({CTL_HW, HW_MODEL}).value_or(std::string{}); |
| } else { |
| return StringSysctl({CTL_HW, HW_PRODUCT}).value_or(std::string{}); |
| } |
| } |
| |
| // static |
| absl::optional<SysInfo::HardwareModelNameSplit> |
| SysInfo::SplitHardwareModelNameDoNotUse(std::string_view name) { |
| size_t number_loc = name.find_first_of("0123456789"); |
| if (number_loc == std::string::npos) { |
| return absl::nullopt; |
| } |
| size_t comma_loc = name.find(',', number_loc); |
| if (comma_loc == std::string::npos) { |
| return absl::nullopt; |
| } |
| |
| HardwareModelNameSplit split; |
| const auto* begin = name.begin(); |
| if (!StringToInt(std::string_view(begin + number_loc, begin + comma_loc), |
| &split.model) || |
| !StringToInt(std::string_view(begin + comma_loc + 1, name.end()), |
| &split.variant)) { |
| return absl::nullopt; |
| } |
| split.category = name.substr(0, number_loc); |
| return split; |
| } |
| |
| // static |
| SysInfo::HardwareInfo SysInfo::GetHardwareInfoSync() { |
| HardwareInfo info; |
| info.manufacturer = "Apple Inc."; |
| info.model = HardwareModelName(); |
| DCHECK(IsStringUTF8(info.manufacturer)); |
| DCHECK(IsStringUTF8(info.model)); |
| return info; |
| } |
| |
| // static |
| void SysInfo::SetCpuSecurityMitigationsEnabled() { |
| // Setting `g_is_cpu_security_mitigation_enabled_read` after it has been read |
| // is disallowed because it could indicate that some code got a number of |
| // processor computed without all the required state. |
| CHECK(!g_is_cpu_security_mitigation_enabled_read); |
| |
| g_is_cpu_security_mitigation_enabled = true; |
| } |
| |
| // static |
| void SysInfo::ResetCpuSecurityMitigationsEnabledForTesting() { |
| g_is_cpu_security_mitigation_enabled_read = false; |
| g_is_cpu_security_mitigation_enabled = false; |
| } |
| |
| } // namespace base |