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