xref: /aosp_15_r20/external/cronet/base/system/sys_info_mac.mm (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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