1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303
  304
  305
  306
  307
  308
  309
  310
  311
  312
  313
  314
  315
  316
  317
  318
  319
  320
  321
  322
  323
  324
  325
  326
  327
  328
  329
  330
  331
  332
  333
  334
  335
  336
  337
  338
  339
  340
  341
  342
  343
  344
  345
  346
  347
  348
  349
  350
  351
  352
  353
  354
  355
  356
  357
  358
  359
  360

base / system / sys_info.h [blame]

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_SYSTEM_SYS_INFO_H_
#define BASE_SYSTEM_SYS_INFO_H_

#include <stddef.h>
#include <stdint.h>

#include <map>
#include <optional>
#include <string>
#include <string_view>

#include "base/base_export.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/metrics/field_trial_params.h"
#include "base/time/time.h"
#include "build/build_config.h"

#if BUILDFLAG(IS_MAC)
#include "base/feature_list.h"
#endif

namespace base {

#if BUILDFLAG(IS_MAC)
// When enabled, NumberOfProcessors() returns the number of physical processors
// instead of the number of logical processors if CPU security mitigations are
// enabled for the current process.
BASE_EXPORT BASE_DECLARE_FEATURE(kNumberOfCoresWithCpuSecurityMitigation);
#endif

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Strings for environment variables.
BASE_EXPORT extern const char kLsbReleaseKey[];
BASE_EXPORT extern const char kLsbReleaseTimeKey[];
#endif

namespace debug {
FORWARD_DECLARE_TEST(SystemMetricsTest, ParseMeminfo);
}

namespace test {
class ScopedAmountOfPhysicalMemoryOverride;
}

class FilePath;
struct SystemMemoryInfoKB;

class BASE_EXPORT SysInfo {
 public:
  // Returns the number of processors/cores available for the current
  // application. This is typically the number of logical cores installed on the
  // system, but could instead be the number of physical cores when
  // SetCpuSecurityMitigationsEnabled() has been invoked to indicate that CPU
  // security mitigations are enabled on Mac.
  // On some platforms this may cache the resulting value in its implementation,
  // e.g. on Linux/ChromeOS where this function cannot run in a sandbox and so
  // a cached value must be returned.
  static int NumberOfProcessors();

  // Returns the number of the most efficient logical processors for the current
  // application. This is typically e-cores on Intel hybrid architecture, or
  // LITTLE cores on ARM bit.LITTLE architecture.
  // Returns 0 on symmetric architecture or when it failed to recognize.
  // This function will cache the result value in its implementation.
  static int NumberOfEfficientProcessors();

  // Return the number of bytes of physical memory on the current machine.
  // If low-end device mode is manually enabled via command line flag, this
  // will return the lesser of the actual physical memory, or 512MB.
  static uint64_t AmountOfPhysicalMemory();

  // Return the number of bytes of current available physical memory on the
  // machine.
  // (The amount of memory that can be allocated without any significant
  // impact on the system. It can lead to freeing inactive file-backed
  // and/or speculative file-backed memory).
  static uint64_t AmountOfAvailablePhysicalMemory();

  // Return the number of bytes of virtual memory of this process. A return
  // value of zero means that there is no limit on the available virtual
  // memory.
  static uint64_t AmountOfVirtualMemory();

  // Return the number of megabytes of physical memory on the current machine.
  static int AmountOfPhysicalMemoryMB() {
    return static_cast<int>(AmountOfPhysicalMemory() / 1024 / 1024);
  }

  // Return the number of megabytes of available virtual memory, or zero if it
  // is unlimited.
  static int AmountOfVirtualMemoryMB() {
    return static_cast<int>(AmountOfVirtualMemory() / 1024 / 1024);
  }

  // Return the available disk space in bytes on the volume containing |path|,
  // or -1 on failure.
  static int64_t AmountOfFreeDiskSpace(const FilePath& path);

  // Return the total disk space in bytes on the volume containing |path|, or -1
  // on failure.
  static int64_t AmountOfTotalDiskSpace(const FilePath& path);

#if BUILDFLAG(IS_FUCHSIA)
  // Sets the total amount of disk space to report under the specified |path|.
  // If |bytes| is -ve then any existing entry for |path| is removed.
  static void SetAmountOfTotalDiskSpace(const FilePath& path, int64_t bytes);
#endif

  // Returns system uptime.
  static TimeDelta Uptime();

  // Returns a descriptive string for the current machine model or an empty
  // string if the machine model is unknown or an error occurred.
  // e.g. "MacPro1,1" on Mac, "iPhone9,3" on iOS or "Nexus 5" on Android. Only
  // implemented on macOS, iOS, Android, Chrome OS and Windows. This returns an
  // empty string on other platforms.
  //
  // For macOS, a useful reference of the resulting strings returned by this
  // function and their corresponding hardware can be found at
  // https://everymac.com/systems/by_capability/mac-specs-by-machine-model-machine-id.html
  //
  // For iOS, corresponding hardware can be found at
  // https://deviceatlas.com/resources/clientside/ios-hardware-identification
  static std::string HardwareModelName();

  // Returns the SOC manufacturer's name or an empty string if the manufacturer
  // is unknown or an error occurred.
  // e.g. "Google" on Pixel 8 Pro. Only implemented on Android, returns an
  // empty string on other platforms.
  static std::string SocManufacturer();

#if BUILDFLAG(IS_MAC)
  struct HardwareModelNameSplit {
    std::string category;
    int model = 0;
    int variant = 0;
  };
  // Hardware model names on the Mac are of the shape "Mac𝓍,𝓎" where the
  // prefix is the general category, the 𝓍 is the model, and the 𝓎 is the
  // variant. This function takes the hardware model name as returned by
  // HardwareModelName() above, and returns it split into its constituent parts.
  // Returns nullopt if the value cannot be parsed.
  //
  // /!\ WARNING
  //
  // This is NOT A USEFUL FUNCTION and SHOULD NOT BE USED. While the `model`
  // value does inform as to what generation of hardware it is within the
  // `category`, this is not useful in determining the capabilities of the
  // hardware. Instead of using the `model` value, check the actual capabilities
  // of the hardware to verify what it can do rather than relying on a hardware
  // model name. In addition, while the `category` value used to have meaning
  // and could be used to determine the type of hardware (e.g. desktop vs
  // laptop), in 2022 Apple started using the generic category of "Mac", thus
  // removing its usefulness when used alone. While the entire model string as
  // returned by HardwareModelName() above can be useful for identifying a
  // specific piece of equipment, splitting apart it is not useful.
  //
  // Do not add any further callers! When the aforementioned 2022-era hardware
  // is the minimum requirement for Chromium, remove this function and adjust
  // all callers appropriately.
  static std::optional<HardwareModelNameSplit> SplitHardwareModelNameDoNotUse(
      std::string_view name);
#endif

  struct HardwareInfo {
    std::string manufacturer;
    std::string model;
  };
  // Returns via |callback| a struct containing descriptive UTF-8 strings for
  // the current machine manufacturer and model, or empty strings if the
  // information is unknown or an error occurred. Implemented on Windows, macOS,
  // iOS, Linux, Chrome OS and Android.
  static void GetHardwareInfo(base::OnceCallback<void(HardwareInfo)> callback);

  // Returns the name of the host operating system.
  static std::string OperatingSystemName();

  // Returns the version of the host operating system.
  static std::string OperatingSystemVersion();

  // Retrieves detailed numeric values for the OS version.
  // DON'T USE THIS ON THE MAC OR WINDOWS to determine the current OS release
  // for OS version-specific feature checks and workarounds. If you must use an
  // OS version check instead of a feature check, use
  // base::mac::MacOSVersion()/MacOSMajorVersion() family from
  // base/mac/mac_util.h, or base::win::GetVersion() from
  // base/win/windows_version.h.
  static void OperatingSystemVersionNumbers(int32_t* major_version,
                                            int32_t* minor_version,
                                            int32_t* bugfix_version);

  // Returns the architecture of the running operating system.
  // Exact return value may differ across platforms.
  // e.g. a 32-bit x86 kernel on a 64-bit capable CPU will return "x86",
  //      whereas a x86-64 kernel on the same CPU will return "x86_64"
  static std::string OperatingSystemArchitecture();

  // Returns the architecture of the running process, which might be different
  // than the architecture returned by OperatingSystemArchitecture() (e.g.
  // macOS Rosetta, a 32-bit binary on a 64-bit OS, etc).
  // Will return one of: "x86", "x86_64", "ARM", "ARM_64", or an empty string if
  // none of the above.
  static std::string ProcessCPUArchitecture();

  // Returns the CPU model name of the system. If it can not be figured out,
  // an empty string is returned.
  // More detailed info can be obtained from base/cpu.h.
  static std::string CPUModelName();

  // Return the smallest amount of memory (in bytes) which the VM system will
  // allocate.
  static size_t VMAllocationGranularity();

#if BUILDFLAG(IS_CHROMEOS)
  // Set |value| and return true if LsbRelease contains information about |key|.
  static bool GetLsbReleaseValue(const std::string& key, std::string* value);

  // Convenience function for GetLsbReleaseValue("CHROMEOS_RELEASE_BOARD",...).
  // Returns "unknown" if CHROMEOS_RELEASE_BOARD is not set. Otherwise, returns
  // the full name of the board. Note that the returned value often differs
  // between developers' systems and devices that use official builds. E.g. for
  // a developer-built image, the function could return 'glimmer', while in an
  // official build, it may be something like 'glimmer-signed-mp-v4keys'.
  //
  // NOTE: Strings returned by this function should be treated as opaque values
  // within Chrome (e.g. for reporting metrics elsewhere). If you need to make
  // Chrome behave differently for different Chrome OS devices, either directly
  // check for the hardware feature that you care about (preferred) or add a
  // command-line flag to Chrome and pass it from session_manager (based on
  // whether a USE flag is set or not). See https://goo.gl/BbBkzg for more
  // details.
  static std::string GetLsbReleaseBoard();

  // Returns the creation time of /etc/lsb-release. (Used to get the date and
  // time of the Chrome OS build).
  static Time GetLsbReleaseTime();

  // Returns true when actually running in a Chrome OS environment.
  static bool IsRunningOnChromeOS();

  // Overrides |lsb_release| and |lsb_release_time|. Overrides cannot be nested.
  // Call ResetChromeOSVersionInfoForTest() to restore the previous values.
  // Prefer base::test::ScopedChromeOSVersionInfo to calling this function.
  static void SetChromeOSVersionInfoForTest(const std::string& lsb_release,
                                            const Time& lsb_release_time);

  // Undoes the function above.
  static void ResetChromeOSVersionInfoForTest();

  // Returns the kernel version of the host operating system.
  static std::string KernelVersion();

  // Crashes if running on Chrome OS non-test image. Use only for really
  // sensitive and risky use cases. Only works while running in verified mode,
  // this check an easily be bypassed in dev mode.
  static void CrashIfChromeOSNonTestImage();
#endif  // BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(IS_ANDROID)
  // Returns the Android build's codename.
  static std::string GetAndroidBuildCodename();

  // Returns the Android build ID.
  static std::string GetAndroidBuildID();

  // Returns the Android hardware EGL system property.
  static std::string GetAndroidHardwareEGL();
#endif  // BUILDFLAG(IS_ANDROID)

#if BUILDFLAG(IS_IOS)
  // Returns the iOS build number string which is normally an alphanumeric
  // string like 12E456. This build number can differentiate between different
  // versions of iOS that may have the same major/minor/bugfix version numbers.
  // For example, iOS beta releases have the same version number but different
  // build number strings.
  static std::string GetIOSBuildNumber();

  // Overrides the hardware model name. The overridden value is used instead of
  // `StringSysctl({CTL_HW, HW_MACHINE})`. `name` should not be empty.
  static void OverrideHardwareModelName(std::string name);
#endif  // BUILDFLAG(IS_IOS)

  // Returns true for low-end devices that may require extreme tradeoffs,
  // including user-visible changes, for acceptable performance.
  // For general memory optimizations, consider |AmountOfPhysicalMemoryMB|.
  //
  // On Android this returns:
  //   true when memory <= 1GB on Android O and later.
  //   true when memory <= 512MB on Android N and earlier.
  // This is not the same as "low-memory" and will be false on a large number of
  // <=1GB pre-O Android devices. See: |detectLowEndDevice| in SysUtils.java.
  // On Desktop this returns true when memory <= 2GB.
  static bool IsLowEndDevice();

  // The same as IsLowEndDevice() except on Android.
  //
  // On Android this returns:
  //   true when IsLowEndDevice() returns true.
  //   true when the physical memory of the device is 4gb or 6gb and
  //             the feature: kPartialLowEndModeOnMidEndDevices() is enabled.
  static bool IsLowEndDeviceOrPartialLowEndModeEnabled();
  static bool IsLowEndDeviceOrPartialLowEndModeEnabled(
      const FeatureParam<bool>& param_for_exclusion);

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
  // Returns true for Android devices whose memory is X GB, considering
  // carveouts. The carveouts is memory reserved by the system, e.g.
  // for drivers, MTE, etc. It's very common for querying app to see
  // hundreds MBs less than actual physical memory installed on the system.
  // Addendum: This logic should also work for ChromeOS.
  static bool Is3GbDevice();
  static bool Is4GbDevice();
  static bool Is6GbDevice();
  // Returns true for Android devices whose memory is 4GB or 6GB, considering
  // carveouts.
  static bool Is4GbOr6GbDevice();
#endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(IS_MAC)
  // Indicates that CPU security mitigations are enabled for the current
  // process. This is used to control the behavior of NumberOfProcessors(), see
  // comment on that method.
  static void SetCpuSecurityMitigationsEnabled();

  // Resets all state associated with CPU security mitigations.
  static void ResetCpuSecurityMitigationsEnabledForTesting();
#endif

 private:
  friend class test::ScopedAmountOfPhysicalMemoryOverride;
  FRIEND_TEST_ALL_PREFIXES(SysInfoTest, AmountOfAvailablePhysicalMemory);
  FRIEND_TEST_ALL_PREFIXES(debug::SystemMetricsTest, ParseMeminfo);

  static int NumberOfEfficientProcessorsImpl();
  static uint64_t AmountOfPhysicalMemoryImpl();
  static uint64_t AmountOfAvailablePhysicalMemoryImpl();
  static bool IsLowEndDeviceImpl();
  static HardwareInfo GetHardwareInfoSync();

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
    BUILDFLAG(IS_AIX)
  static uint64_t AmountOfAvailablePhysicalMemory(
      const SystemMemoryInfoKB& meminfo);
#endif

  // Sets the amount of physical memory in MB for testing, thus allowing tests
  // to run irrespective of the host machine's configuration.
  static std::optional<uint64_t> SetAmountOfPhysicalMemoryMbForTesting(
      uint64_t amount_of_memory_mb);
  static void ClearAmountOfPhysicalMemoryMbForTesting();
};

}  // namespace base

#endif  // BASE_SYSTEM_SYS_INFO_H_