1 // Copyright 2017 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 <fidl/fuchsia.buildinfo/cpp/fidl.h>
8 #include <fidl/fuchsia.hwinfo/cpp/fidl.h>
9 #include <sys/statvfs.h>
10 #include <zircon/syscalls.h>
11
12 #include <string>
13
14 #include "base/containers/flat_map.h"
15 #include "base/files/file_util.h"
16 #include "base/fuchsia/fuchsia_logging.h"
17 #include "base/fuchsia/system_info.h"
18 #include "base/logging.h"
19 #include "base/no_destructor.h"
20 #include "base/notimplemented.h"
21 #include "base/numerics/clamped_math.h"
22 #include "base/synchronization/lock.h"
23 #include "base/threading/scoped_blocking_call.h"
24 #include "build/build_config.h"
25
26 namespace base {
27
28 namespace {
29
GetDiskSpaceInfo(const FilePath & path,int64_t * available_bytes,int64_t * total_bytes)30 bool GetDiskSpaceInfo(const FilePath& path,
31 int64_t* available_bytes,
32 int64_t* total_bytes) {
33 struct statvfs stats;
34 if (statvfs(path.value().c_str(), &stats) != 0) {
35 PLOG(ERROR) << "statvfs() for path:" << path;
36 return false;
37 }
38
39 if (available_bytes) {
40 ClampedNumeric<int64_t> available_blocks(stats.f_bavail);
41 *available_bytes = available_blocks * stats.f_frsize;
42 }
43
44 if (total_bytes) {
45 ClampedNumeric<int64_t> total_blocks(stats.f_blocks);
46 *total_bytes = total_blocks * stats.f_frsize;
47 }
48
49 return true;
50 }
51
52 struct TotalDiskSpace {
53 Lock lock;
54 flat_map<FilePath, int64_t> space_map GUARDED_BY(lock);
55 };
56
GetTotalDiskSpace()57 TotalDiskSpace& GetTotalDiskSpace() {
58 static NoDestructor<TotalDiskSpace> total_disk_space;
59 return *total_disk_space;
60 }
61
62 // Returns the total-disk-space set for the volume containing |path|. If
63 // |volume_path| is non-null then it receives the path to the relevant volume.
64 // Returns -1, and does not modify |volume_path|, if no match is found. Also
65 // returns -1 if |path| is not absolute.
GetAmountOfTotalDiskSpaceAndVolumePath(const FilePath & path,FilePath * volume_path)66 int64_t GetAmountOfTotalDiskSpaceAndVolumePath(const FilePath& path,
67 FilePath* volume_path) {
68 if (!path.IsAbsolute()) {
69 return -1;
70 }
71 TotalDiskSpace& total_disk_space = GetTotalDiskSpace();
72
73 AutoLock l(total_disk_space.lock);
74 int64_t result = -1;
75 FilePath matched_path;
76 for (const auto& path_and_size : total_disk_space.space_map) {
77 if (path_and_size.first == path || path_and_size.first.IsParent(path)) {
78 // If a deeper path was already matched then ignore this entry.
79 if (!matched_path.empty() && !matched_path.IsParent(path_and_size.first))
80 continue;
81 matched_path = path_and_size.first;
82 result = path_and_size.second;
83 }
84 }
85
86 if (volume_path)
87 *volume_path = matched_path;
88 return result;
89 }
90
91 } // namespace
92
93 // static
AmountOfPhysicalMemoryImpl()94 uint64_t SysInfo::AmountOfPhysicalMemoryImpl() {
95 return zx_system_get_physmem();
96 }
97
98 // static
AmountOfAvailablePhysicalMemoryImpl()99 uint64_t SysInfo::AmountOfAvailablePhysicalMemoryImpl() {
100 // TODO(crbug.com/42050649): Implement this when Fuchsia supports it.
101 NOTIMPLEMENTED_LOG_ONCE();
102 return 0;
103 }
104
105 // static
NumberOfProcessors()106 int SysInfo::NumberOfProcessors() {
107 return static_cast<int>(zx_system_get_num_cpus());
108 }
109
110 // static
AmountOfVirtualMemory()111 uint64_t SysInfo::AmountOfVirtualMemory() {
112 // Fuchsia does not provide this type of information.
113 // Return zero to indicate that there is unlimited available virtual memory.
114 return 0;
115 }
116
117 // static
OperatingSystemName()118 std::string SysInfo::OperatingSystemName() {
119 return "Fuchsia";
120 }
121
122 // static
AmountOfFreeDiskSpace(const FilePath & path)123 int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
124 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
125
126 // First check whether there is a soft-quota that applies to |path|.
127 FilePath volume_path;
128 const int64_t total_space =
129 GetAmountOfTotalDiskSpaceAndVolumePath(path, &volume_path);
130 if (total_space >= 0) {
131 // TODO(crbug.com/42050202): Replace this with an efficient implementation.
132 const int64_t used_space = ComputeDirectorySize(volume_path);
133 return std::max(0l, total_space - used_space);
134 }
135
136 // Report the actual amount of free space in |path|'s filesystem.
137 int64_t available;
138 if (GetDiskSpaceInfo(path, &available, nullptr))
139 return available;
140
141 return -1;
142 }
143
144 // static
AmountOfTotalDiskSpace(const FilePath & path)145 int64_t SysInfo::AmountOfTotalDiskSpace(const FilePath& path) {
146 ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
147
148 if (path.empty())
149 return -1;
150
151 // Return the soft-quota that applies to |path|, if one is configured.
152 int64_t total_space = GetAmountOfTotalDiskSpaceAndVolumePath(path, nullptr);
153 if (total_space >= 0)
154 return total_space;
155
156 // Report the actual space in |path|'s filesystem.
157 if (GetDiskSpaceInfo(path, nullptr, &total_space))
158 return total_space;
159
160 return -1;
161 }
162
163 // static
SetAmountOfTotalDiskSpace(const FilePath & path,int64_t bytes)164 void SysInfo::SetAmountOfTotalDiskSpace(const FilePath& path, int64_t bytes) {
165 DCHECK(path.IsAbsolute());
166 TotalDiskSpace& total_disk_space = GetTotalDiskSpace();
167 AutoLock l(total_disk_space.lock);
168 if (bytes >= 0)
169 total_disk_space.space_map[path] = bytes;
170 else
171 total_disk_space.space_map.erase(path);
172 }
173
174 // static
OperatingSystemVersion()175 std::string SysInfo::OperatingSystemVersion() {
176 const auto& build_info = GetCachedBuildInfo();
177 return build_info.version().value_or("");
178 }
179
180 // static
OperatingSystemVersionNumbers(int32_t * major_version,int32_t * minor_version,int32_t * bugfix_version)181 void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
182 int32_t* minor_version,
183 int32_t* bugfix_version) {
184 // TODO(crbug.com/42050501): Implement this when Fuchsia supports it.
185 NOTIMPLEMENTED_LOG_ONCE();
186 *major_version = 0;
187 *minor_version = 0;
188 *bugfix_version = 0;
189 }
190
191 // static
OperatingSystemArchitecture()192 std::string SysInfo::OperatingSystemArchitecture() {
193 #if defined(ARCH_CPU_X86_64)
194 return "x86_64";
195 #elif defined(ARCH_CPU_ARM64)
196 return "aarch64";
197 #else
198 #error Unsupported architecture.
199 #endif
200 }
201
202 // static
CPUModelName()203 std::string SysInfo::CPUModelName() {
204 // TODO(crbug.com/40191727): Implement this when Fuchsia supports it.
205 NOTIMPLEMENTED_LOG_ONCE();
206 return std::string();
207 }
208
209 // static
VMAllocationGranularity()210 size_t SysInfo::VMAllocationGranularity() {
211 return static_cast<size_t>(getpagesize());
212 }
213
214 // static
NumberOfEfficientProcessorsImpl()215 int SysInfo::NumberOfEfficientProcessorsImpl() {
216 NOTIMPLEMENTED();
217 return 0;
218 }
219
GetHardwareInfoSync()220 SysInfo::HardwareInfo SysInfo::GetHardwareInfoSync() {
221 const auto product_info = GetProductInfo();
222
223 return {
224 .manufacturer = product_info.manufacturer().value_or(""),
225 .model = product_info.model().value_or(""),
226 };
227 }
228
229 } // namespace base
230