1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <sys/types.h>
20 
21 #include <string>
22 #include <vector>
23 
24 #include "meminfo.h"
25 
26 namespace android {
27 namespace meminfo {
28 
29 using VmaCallback = std::function<void(const Vma&)>;
30 
31 class ProcMemInfo final {
32     // Per-process memory accounting
33   public:
34     // Reset the working set accounting of the process via /proc/<pid>/clear_refs
35     static bool ResetWorkingSet(pid_t pid);
36 
37     ProcMemInfo(pid_t pid, bool get_wss = false, uint64_t pgflags = 0, uint64_t pgflags_mask = 0);
38 
39     const std::vector<Vma>& Maps();
40     const MemUsage& Usage();
41     const MemUsage& Wss();
42 
43     // Same as Maps() except, only valid for reading working set using CONFIG_IDLE_PAGE_TRACKING
44     // support in kernel. If the kernel support doesn't exist, the function will return an empty
45     // vector.
46     const std::vector<Vma>& MapsWithPageIdle();
47 
48     // Same as Maps() except, do not read the usage stats for each map.
49     const std::vector<Vma>& MapsWithoutUsageStats();
50 
51     // If MapsWithoutUsageStats was called, this function will fill in
52     // usage stats for this single vma.
53     bool FillInVmaStats(Vma& vma);
54 
55     // Collect all 'vma' or 'maps' from /proc/<pid>/smaps and store them in 'maps_'. Returns a
56     // constant reference to the vma vector after the collection is done.
57     //
58     // Each 'struct Vma' is *fully* populated by this method (unlike SmapsOrRollup).
59     const std::vector<Vma>& Smaps(const std::string& path = "");
60 
61     // If 'use_smaps' is 'true' this method reads /proc/<pid>/smaps and calls the callback()
62     // for each vma or map that it finds, else if 'use_smaps' is false /proc/<pid>/maps is
63     // used instead. Each vma or map found, is converted to 'struct Vma' object which is then
64     // passed to the callback.
65     // Returns 'false' if the file is malformed.
66     bool ForEachVma(const VmaCallback& callback, bool use_smaps = true);
67 
68     // Reads all VMAs from /proc/<pid>/maps and calls the callback() for each one of them.
69     // Returns false in case of failure during parsing.
70     bool ForEachVmaFromMaps(const VmaCallback& callback);
71 
72     // Used to parse either of /proc/<pid>/{smaps, smaps_rollup} and record the process's
73     // Pss and Private memory usage in 'stats'.  In particular, the method only populates the fields
74     // of the MemUsage structure that are intended to be used by Android's periodic Pss collection.
75     //
76     // The method populates the following statistics in order to be fast an efficient.
77     //   Pss
78     //   Rss
79     //   Uss
80     //   private_clean
81     //   private_dirty
82     //   SwapPss
83     // All other fields of MemUsage are zeroed.
84     bool SmapsOrRollup(MemUsage* stats) const;
85 
86     // Used to parse either of /proc/<pid>/{smaps, smaps_rollup} and record the process's
87     // Pss.
88     // Returns 'true' on success and the value of Pss in the out parameter.
89     bool SmapsOrRollupPss(uint64_t* pss) const;
90 
91     const std::vector<uint64_t>& SwapOffsets();
92 
93     // Reads /proc/<pid>/pagemap for this process for each page within
94     // the 'vma' and stores that in 'pagemap'. It is assumed that the 'vma'
95     // is obtained by calling Maps() or 'ForEachVma' for the same object. No special checks
96     // are made to see if 'vma' is *valid*.
97     // Returns false if anything goes wrong, 'true' otherwise.
98     bool PageMap(const Vma& vma, std::vector<uint64_t>* pagemap);
99 
100     ~ProcMemInfo() = default;
101 
102   private:
103     bool ReadMaps(bool get_wss, bool use_pageidle = false, bool get_usage_stats = true,
104                   bool swap_only = false);
105     bool ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle, bool swap_only);
106 
107     pid_t pid_;
108     bool get_wss_;
109     uint64_t pgflags_;
110     uint64_t pgflags_mask_;
111 
112     std::vector<Vma> maps_;
113 
114     MemUsage usage_;
115     std::vector<uint64_t> swap_offsets_;
116 };
117 
118 // Makes callback for each 'vma' or 'map' found in file provided.
119 // If 'read_smaps_fields' is 'true', the file is expected to be in the
120 // same format as /proc/<pid>/smaps, else the file is expected to be
121 // formatted as /proc/<pid>/maps.
122 // Returns 'false' if the file is malformed.
123 bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback,
124                         bool read_smaps_fields = true);
125 
126 // Returns if the kernel supports /proc/<pid>/smaps_rollup. Assumes that the
127 // calling process has access to the /proc/<pid>/smaps_rollup.
128 // Returns 'false' if the file doesn't exist.
129 bool IsSmapsRollupSupported();
130 
131 // Same as ProcMemInfo::SmapsOrRollup but reads the statistics directly
132 // from a file. The file MUST be in the same format as /proc/<pid>/smaps
133 // or /proc/<pid>/smaps_rollup
134 bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats);
135 
136 // Same as ProcMemInfo::SmapsOrRollupPss but reads the statistics directly
137 // from a file and returns total Pss in kB. The file MUST be in the same format
138 // as /proc/<pid>/smaps or /proc/<pid>/smaps_rollup
139 bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss);
140 
141 }  // namespace meminfo
142 }  // namespace android
143