1 #include <fstream>
2 #include <sstream>
3 #include <regex>
4 #include <vector>
5 #include <algorithm>
6 
7 #include <cerrno>
8 #include <sys/stat.h>
9 
10 #include <hardware/memtrack.h>
11 #include <hardware/exynos/ion.h>
12 
13 #include "memtrack_exynos.h"
14 
15 using namespace std;
16 
17 #define NUM_AVAILABLE_FLAGS 4U
18 static unsigned int available_flags [NUM_AVAILABLE_FLAGS] = {
19     MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_SYSTEM | MEMTRACK_FLAG_NONSECURE,
20     MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_DEDICATED | MEMTRACK_FLAG_NONSECURE,
21     MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_SYSTEM | MEMTRACK_FLAG_SECURE,
22     MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS | MEMTRACK_FLAG_DEDICATED| MEMTRACK_FLAG_SECURE,
23 };
24 
25 struct DmabufBuffer {
26     unsigned int id;
27     unsigned int type;
28     size_t size;
29     size_t pss;
DmabufBufferDmabufBuffer30     DmabufBuffer(unsigned int _id, size_t _size, size_t _pss)
31         : id(_id), type(MEMTRACK_FLAG_SMAPS_UNACCOUNTED | MEMTRACK_FLAG_SHARED_PSS), size(_size), pss(_pss)
32     { }
setPoolTypeDmabufBuffer33     void setPoolType(string _type) { type |= (_type == "carveout") ? MEMTRACK_FLAG_DEDICATED : MEMTRACK_FLAG_SYSTEM; }
setFlagsDmabufBuffer34     void setFlags(unsigned int flags) { type |= (flags & ION_FLAG_PROTECTED) ? MEMTRACK_FLAG_SECURE : MEMTRACK_FLAG_NONSECURE; }
35 };
36 
37 const char DMABUF_FOOTPRINT_PATH[] = "/sys/kernel/debug/dma_buf/footprint/";
build_dmabuf_footprint(vector<DmabufBuffer> & buffers,pid_t pid)38 static bool build_dmabuf_footprint(vector<DmabufBuffer> &buffers, pid_t pid)
39 {
40     ostringstream dmabuf_path;
41     dmabuf_path << DMABUF_FOOTPRINT_PATH << pid;
42 
43     ifstream dmabuf(dmabuf_path.str());
44     if (!dmabuf)
45         return false;
46     //
47     // exp_name      size     share
48     // ion-102   69271552  34635776
49     regex rex("\\s*ion-(\\d+)\\s+(\\d+)\\s+(\\d+).*");
50     smatch mch;
51     // 1-id, 2-size, 3-pss
52     for (string line; getline(dmabuf, line); )
53         if (regex_match(line, mch, rex))
54             buffers.emplace_back(stoul(mch[1], 0, 10), stoul(mch[2], 0, 10), stoul(mch[3], 0, 10));
55 
56     return true;
57 }
58 
59 const char ION_BUFFERS_PATH[] = "/sys/kernel/debug/ion/buffers";
complete_dmabuf_footprint(int type,vector<DmabufBuffer> & buffers)60 static bool complete_dmabuf_footprint(int type, vector<DmabufBuffer> &buffers)
61 {
62     ifstream ion(ION_BUFFERS_PATH);
63     if (!ion)
64         return false;
65 
66     // [  id]            heap heaptype flags size(kb) : iommu_mapped...
67     // [ 106] ion_system_heap   system  0x40    16912 : 19080000.dsim(0)
68     regex rexion("\\[ *(\\d+)\\] +[[:alnum:]\\-_]+ +(\\w+) +([x[:xdigit:]]+) +(\\d+).*");
69     smatch mch;
70     // 1-id, 2-heaptype, 3-flags, 4-size
71     for (string line; getline(ion, line); ) {
72         if (regex_match(line, mch, rexion)) {
73             unsigned int id = stoul(mch[1], 0, 10);
74             unsigned int flags = stoul(mch[3], 0, 16);
75             size_t len = stoul(mch[4], 0, 10) * 1024;
76             auto elem = find_if(begin(buffers), end(buffers), [id, len] (auto &item) {
77                                     return (item.id == id) && (item.size == len);
78                                 });
79             // passes if type = OTHER && not flag & hwrender or type == GRAPHIC && flag & hwrender
80             if ((elem != end(buffers)) && ((type == MEMTRACK_TYPE_OTHER) == !(flags & ION_FLAG_MAY_HWRENDER))) {
81                 elem->setFlags(flags);
82                 elem->setPoolType(mch[2]);
83             }
84         }
85     }
86 
87     return true;
88 }
89 
dmabuf_memtrack_get_memory(pid_t pid,int type,struct memtrack_record * records,size_t * num_records)90 int dmabuf_memtrack_get_memory(pid_t pid, int type, struct memtrack_record *records, size_t *num_records)
91 {
92     if ((type != MEMTRACK_TYPE_OTHER) && (type != MEMTRACK_TYPE_GRAPHICS))
93         return -ENODEV;
94 
95     if (*num_records == 0) {
96         *num_records = NUM_AVAILABLE_FLAGS;
97         return 0;
98     }
99 
100     *num_records = (*num_records < NUM_AVAILABLE_FLAGS) ? *num_records : NUM_AVAILABLE_FLAGS;
101 
102     for (size_t i = 0; i < *num_records; i++) {
103         records[i].size_in_bytes = 0;
104         records[i].flags = available_flags[i];
105     }
106 
107     vector<DmabufBuffer> buffers;
108 
109     if (!build_dmabuf_footprint(buffers, pid))
110         return -ENODEV;
111 
112     if (buffers.size() == 0)
113         return 0;
114 
115     if (!complete_dmabuf_footprint(type, buffers))
116         return -ENODEV;
117 
118     for (auto item: buffers) {
119         for (size_t i = 0; i < *num_records; i++) {
120             if (item.type == available_flags[i]) {
121                 records[i].size_in_bytes += item.pss;
122                 break;
123             }
124         }
125     }
126 
127     return 0;
128 }
129