• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 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 #include <algorithm>
8 
9 #include "base/base_switches.h"
10 #include "base/command_line.h"
11 #include "base/features.h"
12 #include "base/functional/bind.h"
13 #include "base/functional/callback.h"
14 #include "base/location.h"
15 #include "base/notreached.h"
16 #include "base/system/sys_info_internal.h"
17 #include "base/task/task_traits.h"
18 #include "base/task/thread_pool.h"
19 #include "base/time/time.h"
20 #include "build/build_config.h"
21 
22 namespace base {
23 namespace {
GetLowMemoryDeviceThresholdMB()24 uint64_t GetLowMemoryDeviceThresholdMB() {
25   static const uint64_t threshold = base::saturated_cast<uint64_t>(
26       features::kLowMemoryDeviceThresholdMB.Get());
27   return threshold;
28 }
29 
30 std::optional<uint64_t> g_amount_of_physical_memory_mb_for_testing;
31 }  // namespace
32 
33 // static
NumberOfEfficientProcessors()34 int SysInfo::NumberOfEfficientProcessors() {
35   static int number_of_efficient_processors = NumberOfEfficientProcessorsImpl();
36   return number_of_efficient_processors;
37 }
38 
39 // static
AmountOfPhysicalMemory()40 uint64_t SysInfo::AmountOfPhysicalMemory() {
41   constexpr uint64_t kMB = 1024 * 1024;
42 
43   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
44           switches::kEnableLowEndDeviceMode)) {
45     // Keep using 512MB as the simulated RAM amount for when users or tests have
46     // manually enabled low-end device mode. Note this value is different from
47     // the threshold used for low end devices.
48     constexpr uint64_t kSimulatedMemoryForEnableLowEndDeviceMode = 512 * kMB;
49     return std::min(kSimulatedMemoryForEnableLowEndDeviceMode,
50                     AmountOfPhysicalMemoryImpl());
51   }
52 
53   if (g_amount_of_physical_memory_mb_for_testing) {
54     return g_amount_of_physical_memory_mb_for_testing.value() * kMB;
55   }
56 
57   return AmountOfPhysicalMemoryImpl();
58 }
59 
60 // static
AmountOfAvailablePhysicalMemory()61 uint64_t SysInfo::AmountOfAvailablePhysicalMemory() {
62   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
63           switches::kEnableLowEndDeviceMode)) {
64     // Estimate the available memory by subtracting our memory used estimate
65     // from the fake |kLowMemoryDeviceThresholdMB| limit.
66     uint64_t memory_used =
67         AmountOfPhysicalMemoryImpl() - AmountOfAvailablePhysicalMemoryImpl();
68     uint64_t memory_limit = GetLowMemoryDeviceThresholdMB() * 1024 * 1024;
69     // std::min ensures no underflow, as |memory_used| can be > |memory_limit|.
70     return memory_limit - std::min(memory_used, memory_limit);
71   }
72 
73   return AmountOfAvailablePhysicalMemoryImpl();
74 }
75 
IsLowEndDevice()76 bool SysInfo::IsLowEndDevice() {
77   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
78           switches::kEnableLowEndDeviceMode)) {
79     return true;
80   }
81 
82   return IsLowEndDeviceImpl();
83 }
84 
85 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
86 
87 namespace {
88 
89 enum class BucketizedSize {
90   k2GbOrLess,
91   k3Gb,
92   k4Gb,
93   k6Gb,
94   k8GbOrHigher,
95 };
96 
GetSystemRamBucketizedSize()97 BucketizedSize GetSystemRamBucketizedSize() {
98   int physical_memory = base::SysInfo::AmountOfPhysicalMemoryMB();
99 
100   // Because of Android carveouts, AmountOfPhysicalMemory() returns smaller
101   // than the actual memory size, So we will use a small lowerbound than "X"GB
102   // to discriminate real "X"GB devices from lower memory ones.
103   // Addendum: This logic should also work for ChromeOS.
104 
105   constexpr int kUpperBound2GB = 2 * 1024;  // inclusive
106   if (physical_memory <= kUpperBound2GB) {
107     return BucketizedSize::k2GbOrLess;
108   }
109 
110   constexpr int kLowerBound3GB = kUpperBound2GB;  // exclusive
111   constexpr int kUpperBound3GB = 3.2 * 1024;      // inclusive
112   if (kLowerBound3GB < physical_memory && physical_memory <= kUpperBound3GB) {
113     return BucketizedSize::k3Gb;
114   }
115 
116   constexpr int kLowerBound4GB = kUpperBound3GB;  // exclusive
117   constexpr int kUpperBound4GB = 4 * 1024;        // inclusive
118   if (kLowerBound4GB < physical_memory && physical_memory <= kUpperBound4GB) {
119     return BucketizedSize::k4Gb;
120   }
121 
122   constexpr int kLowerBound6GB = kUpperBound4GB;  // exclusive
123   constexpr int kUpperBound6GB = 6.5 * 1024 - 1;  // inclusive
124   if (kLowerBound6GB < physical_memory && physical_memory <= kUpperBound6GB) {
125     return BucketizedSize::k6Gb;
126   }
127 
128   return BucketizedSize::k8GbOrHigher;
129 }
130 
GetCachedSystemRamBucketizedSize()131 BucketizedSize GetCachedSystemRamBucketizedSize() {
132   static BucketizedSize s_size = GetSystemRamBucketizedSize();
133   return s_size;
134 }
135 
IsPartialLowEndModeOnMidRangeDevicesEnabled()136 bool IsPartialLowEndModeOnMidRangeDevicesEnabled() {
137   // TODO(crbug.com/40264947): make the feature not enable on 32-bit devices
138   // before launching or going to high Stable %.
139   return SysInfo::Is4GbOr6GbDevice() &&
140          base::FeatureList::IsEnabled(
141              features::kPartialLowEndModeOnMidRangeDevices);
142 }
143 
IsPartialLowEndModeOn3GbDevicesEnabled()144 bool IsPartialLowEndModeOn3GbDevicesEnabled() {
145   return SysInfo::Is3GbDevice() &&
146          base::FeatureList::IsEnabled(features::kPartialLowEndModeOn3GbDevices);
147 }
148 
149 }  // namespace
150 
Is3GbDevice()151 bool SysInfo::Is3GbDevice() {
152   return GetCachedSystemRamBucketizedSize() == BucketizedSize::k3Gb;
153 }
154 
Is4GbDevice()155 bool SysInfo::Is4GbDevice() {
156   return GetCachedSystemRamBucketizedSize() == BucketizedSize::k4Gb;
157 }
158 
Is4GbOr6GbDevice()159 bool SysInfo::Is4GbOr6GbDevice() {
160   return GetCachedSystemRamBucketizedSize() == BucketizedSize::k4Gb ||
161          GetCachedSystemRamBucketizedSize() == BucketizedSize::k6Gb;
162 }
163 
Is6GbDevice()164 bool SysInfo::Is6GbDevice() {
165   return GetCachedSystemRamBucketizedSize() == BucketizedSize::k6Gb;
166 }
167 
168 #endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
169 
170 // TODO(crbug.com/40264947): This method is for chromium native code.
171 // We need to update the java-side code, i.e.
172 // base/android/java/src/org/chromium/base/SysUtils.java,
173 // and to make the selected components in java to see this feature.
IsLowEndDeviceOrPartialLowEndModeEnabled()174 bool SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled() {
175 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
176   return base::SysInfo::IsLowEndDevice() ||
177          IsPartialLowEndModeOnMidRangeDevicesEnabled() ||
178          IsPartialLowEndModeOn3GbDevicesEnabled();
179 #else
180   return base::SysInfo::IsLowEndDevice();
181 #endif
182 }
183 
IsLowEndDeviceOrPartialLowEndModeEnabled(const FeatureParam<bool> & param_for_exclusion)184 bool SysInfo::IsLowEndDeviceOrPartialLowEndModeEnabled(
185     const FeatureParam<bool>& param_for_exclusion) {
186 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
187   return base::SysInfo::IsLowEndDevice() ||
188          ((IsPartialLowEndModeOnMidRangeDevicesEnabled() ||
189            IsPartialLowEndModeOn3GbDevicesEnabled()) &&
190           !param_for_exclusion.Get());
191 #else
192   return base::SysInfo::IsLowEndDevice();
193 #endif
194 }
195 
196 #if !BUILDFLAG(IS_ANDROID)
197 // The Android equivalent of this lives in `detectLowEndDevice()` at:
198 // base/android/java/src/org/chromium/base/SysUtils.java
DetectLowEndDevice()199 bool DetectLowEndDevice() {
200   CommandLine* command_line = CommandLine::ForCurrentProcess();
201   if (command_line->HasSwitch(switches::kEnableLowEndDeviceMode))
202     return true;
203   if (command_line->HasSwitch(switches::kDisableLowEndDeviceMode))
204     return false;
205 
206   int ram_size_mb = SysInfo::AmountOfPhysicalMemoryMB();
207   return ram_size_mb > 0 &&
208          static_cast<uint64_t>(ram_size_mb) <= GetLowMemoryDeviceThresholdMB();
209 }
210 
211 // static
IsLowEndDeviceImpl()212 bool SysInfo::IsLowEndDeviceImpl() {
213   static internal::LazySysInfoValue<bool, DetectLowEndDevice> instance;
214   return instance.value();
215 }
216 #endif
217 
218 #if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_WIN) && \
219     !BUILDFLAG(IS_CHROMEOS)
HardwareModelName()220 std::string SysInfo::HardwareModelName() {
221   return std::string();
222 }
223 #endif
224 
225 #if !BUILDFLAG(IS_ANDROID)
SocManufacturer()226 std::string SysInfo::SocManufacturer() {
227   return std::string();
228 }
229 #endif
230 
GetHardwareInfo(base::OnceCallback<void (HardwareInfo)> callback)231 void SysInfo::GetHardwareInfo(base::OnceCallback<void(HardwareInfo)> callback) {
232 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
233   constexpr base::TaskTraits kTraits = {base::MayBlock()};
234 #else
235   constexpr base::TaskTraits kTraits = {};
236 #endif
237 
238   base::ThreadPool::PostTaskAndReplyWithResult(
239       FROM_HERE, kTraits, base::BindOnce(&GetHardwareInfoSync),
240       std::move(callback));
241 }
242 
243 // static
Uptime()244 base::TimeDelta SysInfo::Uptime() {
245   // This code relies on an implementation detail of TimeTicks::Now() - that
246   // its return value happens to coincide with the system uptime value in
247   // microseconds, on Win/Mac/iOS/Linux/ChromeOS and Android.
248   int64_t uptime_in_microseconds = TimeTicks::Now().ToInternalValue();
249   return base::Microseconds(uptime_in_microseconds);
250 }
251 
252 // static
ProcessCPUArchitecture()253 std::string SysInfo::ProcessCPUArchitecture() {
254 #if defined(ARCH_CPU_X86)
255   return "x86";
256 #elif defined(ARCH_CPU_X86_64)
257   return "x86_64";
258 #elif defined(ARCH_CPU_ARMEL)
259   return "ARM";
260 #elif defined(ARCH_CPU_ARM64)
261   return "ARM_64";
262 #elif defined(ARCH_CPU_RISCV64)
263   return "RISCV_64";
264 #else
265   return std::string();
266 #endif
267 }
268 
269 // static
SetAmountOfPhysicalMemoryMbForTesting(const uint64_t amount_of_memory_mb)270 std::optional<uint64_t> SysInfo::SetAmountOfPhysicalMemoryMbForTesting(
271     const uint64_t amount_of_memory_mb) {
272   std::optional<uint64_t> current = g_amount_of_physical_memory_mb_for_testing;
273   g_amount_of_physical_memory_mb_for_testing.emplace(amount_of_memory_mb);
274   return current;
275 }
276 
277 // static
ClearAmountOfPhysicalMemoryMbForTesting()278 void SysInfo::ClearAmountOfPhysicalMemoryMbForTesting() {
279   g_amount_of_physical_memory_mb_for_testing.reset();
280 }
281 
282 }  // namespace base
283