1*6777b538SAndroid Build Coastguard Worker // Copyright 2024 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/android/pmf_utils.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <fcntl.h>
8*6777b538SAndroid Build Coastguard Worker #include <inttypes.h>
9*6777b538SAndroid Build Coastguard Worker #include <unistd.h>
10*6777b538SAndroid Build Coastguard Worker
11*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker namespace base::android {
15*6777b538SAndroid Build Coastguard Worker namespace {
CalculateProcessMemoryFootprint(base::File & statm_file,base::File & status_file)16*6777b538SAndroid Build Coastguard Worker std::optional<uint64_t> CalculateProcessMemoryFootprint(
17*6777b538SAndroid Build Coastguard Worker base::File& statm_file,
18*6777b538SAndroid Build Coastguard Worker base::File& status_file) {
19*6777b538SAndroid Build Coastguard Worker // Get total resident and shared sizes from statm file.
20*6777b538SAndroid Build Coastguard Worker static size_t page_size = static_cast<size_t>(getpagesize());
21*6777b538SAndroid Build Coastguard Worker uint64_t resident_pages = 0;
22*6777b538SAndroid Build Coastguard Worker uint64_t shared_pages = 0;
23*6777b538SAndroid Build Coastguard Worker uint64_t vm_size_pages = 0;
24*6777b538SAndroid Build Coastguard Worker uint64_t swap_footprint = 0;
25*6777b538SAndroid Build Coastguard Worker constexpr uint32_t kMaxLineSize = 4096;
26*6777b538SAndroid Build Coastguard Worker char line[kMaxLineSize];
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker int n = statm_file.ReadAtCurrentPos(line, sizeof(line) - 1);
29*6777b538SAndroid Build Coastguard Worker if (n <= 0) {
30*6777b538SAndroid Build Coastguard Worker return std::optional<size_t>();
31*6777b538SAndroid Build Coastguard Worker }
32*6777b538SAndroid Build Coastguard Worker line[n] = '\0';
33*6777b538SAndroid Build Coastguard Worker
34*6777b538SAndroid Build Coastguard Worker int num_scanned = sscanf(line, "%" SCNu64 " %" SCNu64 " %" SCNu64,
35*6777b538SAndroid Build Coastguard Worker &vm_size_pages, &resident_pages, &shared_pages);
36*6777b538SAndroid Build Coastguard Worker if (num_scanned != 3) {
37*6777b538SAndroid Build Coastguard Worker return std::optional<size_t>();
38*6777b538SAndroid Build Coastguard Worker }
39*6777b538SAndroid Build Coastguard Worker
40*6777b538SAndroid Build Coastguard Worker // Get swap size from status file. The format is: VmSwap : 10 kB.
41*6777b538SAndroid Build Coastguard Worker n = status_file.ReadAtCurrentPos(line, sizeof(line) - 1);
42*6777b538SAndroid Build Coastguard Worker if (n <= 0) {
43*6777b538SAndroid Build Coastguard Worker return std::optional<size_t>();
44*6777b538SAndroid Build Coastguard Worker }
45*6777b538SAndroid Build Coastguard Worker line[n] = '\0';
46*6777b538SAndroid Build Coastguard Worker
47*6777b538SAndroid Build Coastguard Worker char* swap_line = strstr(line, "VmSwap");
48*6777b538SAndroid Build Coastguard Worker if (!swap_line) {
49*6777b538SAndroid Build Coastguard Worker return std::optional<size_t>();
50*6777b538SAndroid Build Coastguard Worker }
51*6777b538SAndroid Build Coastguard Worker num_scanned = sscanf(swap_line, "VmSwap: %" SCNu64 " kB", &swap_footprint);
52*6777b538SAndroid Build Coastguard Worker if (num_scanned != 1) {
53*6777b538SAndroid Build Coastguard Worker return std::optional<size_t>();
54*6777b538SAndroid Build Coastguard Worker }
55*6777b538SAndroid Build Coastguard Worker
56*6777b538SAndroid Build Coastguard Worker swap_footprint *= 1024;
57*6777b538SAndroid Build Coastguard Worker return (resident_pages - shared_pages) * page_size + swap_footprint;
58*6777b538SAndroid Build Coastguard Worker }
59*6777b538SAndroid Build Coastguard Worker } // namespace
60*6777b538SAndroid Build Coastguard Worker
61*6777b538SAndroid Build Coastguard Worker // static
CalculatePrivateMemoryFootprintForTesting(base::File & statm_file,base::File & status_file)62*6777b538SAndroid Build Coastguard Worker std::optional<uint64_t> PmfUtils::CalculatePrivateMemoryFootprintForTesting(
63*6777b538SAndroid Build Coastguard Worker base::File& statm_file,
64*6777b538SAndroid Build Coastguard Worker base::File& status_file) {
65*6777b538SAndroid Build Coastguard Worker return CalculateProcessMemoryFootprint(statm_file, status_file);
66*6777b538SAndroid Build Coastguard Worker }
67*6777b538SAndroid Build Coastguard Worker
68*6777b538SAndroid Build Coastguard Worker // static
GetPrivateMemoryFootprintForCurrentProcess()69*6777b538SAndroid Build Coastguard Worker std::optional<uint64_t> PmfUtils::GetPrivateMemoryFootprintForCurrentProcess() {
70*6777b538SAndroid Build Coastguard Worker // ScopedAllowBlocking is required to use base::File, but /proc/{pid}/status
71*6777b538SAndroid Build Coastguard Worker // and /proc/{pid}/statm are not regular files. For example, regarding linux,
72*6777b538SAndroid Build Coastguard Worker // proc_pid_statm() defined in fs/proc/array.c is invoked when reading
73*6777b538SAndroid Build Coastguard Worker // /proc/{pid}/statm. proc_pid_statm() gets task information and directly
74*6777b538SAndroid Build Coastguard Worker // writes the information into the given seq_file. This is different from
75*6777b538SAndroid Build Coastguard Worker // regular file operations.
76*6777b538SAndroid Build Coastguard Worker base::ScopedAllowBlocking allow_blocking;
77*6777b538SAndroid Build Coastguard Worker
78*6777b538SAndroid Build Coastguard Worker base::FilePath proc_self_dir = base::FilePath("/proc/self");
79*6777b538SAndroid Build Coastguard Worker base::File status_file(
80*6777b538SAndroid Build Coastguard Worker proc_self_dir.Append("status"),
81*6777b538SAndroid Build Coastguard Worker base::File::Flags::FLAG_OPEN | base::File::Flags::FLAG_READ);
82*6777b538SAndroid Build Coastguard Worker base::File statm_file(
83*6777b538SAndroid Build Coastguard Worker proc_self_dir.Append("statm"),
84*6777b538SAndroid Build Coastguard Worker base::File::Flags::FLAG_OPEN | base::File::Flags::FLAG_READ);
85*6777b538SAndroid Build Coastguard Worker if (!status_file.IsValid() || !statm_file.IsValid()) {
86*6777b538SAndroid Build Coastguard Worker return std::optional<size_t>();
87*6777b538SAndroid Build Coastguard Worker }
88*6777b538SAndroid Build Coastguard Worker
89*6777b538SAndroid Build Coastguard Worker return CalculateProcessMemoryFootprint(statm_file, status_file);
90*6777b538SAndroid Build Coastguard Worker }
91*6777b538SAndroid Build Coastguard Worker
92*6777b538SAndroid Build Coastguard Worker } // namespace base::android
93