blob: 3689cf5ce99cc238587965d0fc31bb1ef07be869
1 | /* |
2 | * Copyright (C) 2014 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 | #define LOG_TAG "memtrack_aml" |
18 | #include <errno.h> |
19 | #include <stdio.h> |
20 | #include <stdlib.h> |
21 | #include <ctype.h> |
22 | |
23 | #include <hardware/memtrack.h> |
24 | #include <log/log.h> |
25 | |
26 | #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) |
27 | |
28 | static struct hw_module_methods_t memtrack_module_methods = { |
29 | .open = NULL, |
30 | }; |
31 | |
32 | struct memtrack_record record_templates[] = { |
33 | { |
34 | .flags = MEMTRACK_FLAG_SMAPS_UNACCOUNTED | |
35 | MEMTRACK_FLAG_PRIVATE | |
36 | MEMTRACK_FLAG_NONSECURE, |
37 | }, |
38 | |
39 | /* |
40 | { |
41 | .flags = MEMTRACK_FLAG_SMAPS_ACCOUNTED | |
42 | MEMTRACK_FLAG_PRIVATE | |
43 | MEMTRACK_FLAG_NONSECURE, |
44 | }, |
45 | */ |
46 | }; |
47 | |
48 | // just return 0 |
49 | int aml_memtrack_init(const struct memtrack_module *module) |
50 | { |
51 | return 0; |
52 | } |
53 | |
54 | /* |
55 | * find the userid of process @pid |
56 | * return the userid if success, or return -1 if not |
57 | */ |
58 | static int memtrack_find_userid(int pid) |
59 | { |
60 | FILE *fp; |
61 | char line[1024]; |
62 | char tmp[128]; |
63 | int userid; |
64 | |
65 | sprintf(tmp, "/proc/%d/status", pid); |
66 | if ((fp=fopen(tmp, "r")) == NULL) { |
67 | ALOGD("open file %s error %s", tmp, strerror(errno)); |
68 | return -1; |
69 | } |
70 | |
71 | while (fgets(line, sizeof(line), fp) != NULL) { |
72 | if (sscanf(line, "Uid: %d", &userid) == 1) { |
73 | fclose(fp); |
74 | return userid; |
75 | } |
76 | } |
77 | |
78 | // should never reach here |
79 | fclose(fp); |
80 | return -1; |
81 | } |
82 | |
83 | static unsigned int memtrack_read_smaps(FILE *fp) |
84 | { |
85 | char line[1024]; |
86 | unsigned int size, sum = 0; |
87 | int skip, done = 0; |
88 | |
89 | unsigned long int start, end; |
90 | int len; |
91 | char *name; |
92 | int nameLen, name_pos; |
93 | |
94 | if(fgets(line, sizeof(line), fp) == 0) { |
95 | return 0; |
96 | } |
97 | |
98 | while (!done) { |
99 | skip = 0; |
100 | |
101 | len = strlen(line); |
102 | if (len < 1) |
103 | return 0; |
104 | |
105 | line[--len] = 0; |
106 | |
107 | if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) { |
108 | skip = 1; |
109 | } else { |
110 | while (isspace(line[name_pos])) { |
111 | name_pos += 1; |
112 | } |
113 | name = line + name_pos; |
114 | nameLen = strlen(name); |
115 | |
116 | if (nameLen >= 8 && |
117 | (!strncmp(name, "/dev/mali", 6) || !strncmp(name, "/dev/ump", 6))) { |
118 | skip = 0; |
119 | } else { |
120 | skip = 1; |
121 | } |
122 | |
123 | } |
124 | |
125 | while (1) { |
126 | if (fgets(line, 1024, fp) == 0) { |
127 | done = 1; |
128 | break; |
129 | } |
130 | |
131 | if(!skip) { |
132 | if (line[0] == 'S' && sscanf(line, "Size: %d kB", &size) == 1) { |
133 | sum += size; |
134 | } |
135 | } |
136 | |
137 | if (strlen(line) > 30 && line[8] == '-' && line[17] == ' ') { |
138 | // looks like a new mapping |
139 | // example: "10000000-10001000 ---p 10000000 00:00 0" |
140 | break; |
141 | } |
142 | } |
143 | |
144 | } |
145 | |
146 | // converted into Bytes |
147 | return (sum * 1024); |
148 | } |
149 | |
150 | static unsigned int memtrack_get_gpuMem(int pid) |
151 | { |
152 | FILE *fp; |
153 | char tmp[128]; |
154 | unsigned int result; |
155 | |
156 | sprintf(tmp, "/proc/%d/smaps", pid); |
157 | fp = fopen(tmp, "r"); |
158 | if (fp == NULL) { |
159 | ALOGD("open file %s error %s", tmp, strerror(errno)); |
160 | return 0; |
161 | } |
162 | |
163 | result = memtrack_read_smaps(fp); |
164 | |
165 | fclose(fp); |
166 | return result; |
167 | } |
168 | |
169 | static int memtrack_get_memory(pid_t pid, enum memtrack_type type, |
170 | struct memtrack_record *records, |
171 | size_t *num_records) |
172 | { |
173 | FILE *fp; |
174 | FILE *ion_fp; |
175 | char line[1024]; |
176 | char tmp[128]; |
177 | unsigned int mali_inuse = 0; |
178 | unsigned int size; |
179 | size_t unaccounted_size = 0; |
180 | |
181 | char ion_name[128]; |
182 | int ion_pid; |
183 | unsigned int ion_size; |
184 | unsigned int gpu_size; |
185 | |
186 | |
187 | // ALOGD("type is %d, pid is %d\n", type, pid); |
188 | size_t allocated_records = ARRAY_SIZE(record_templates); |
189 | *num_records = ARRAY_SIZE(record_templates); |
190 | |
191 | if (records == NULL) { |
192 | return 0; |
193 | } |
194 | |
195 | memcpy(records, record_templates, sizeof(struct memtrack_record) * allocated_records); |
196 | |
197 | if (type == MEMTRACK_TYPE_GL) { |
198 | // find the user id of the process, only support calculate the non root process |
199 | int ret = memtrack_find_userid(pid); |
200 | if (ret <= 0) { |
201 | return -1; |
202 | } |
203 | gpu_size = memtrack_get_gpuMem(pid); |
204 | unaccounted_size += gpu_size; |
205 | } else if (type == MEMTRACK_TYPE_GRAPHICS) { |
206 | sprintf(tmp, "/proc/ion/vmalloc_ion"); |
207 | // sprintf(tmp, "/sys/kernel/debug/ion/vmalloc_ion"); |
208 | if ((ion_fp = fopen(tmp, "r")) == NULL) { |
209 | ALOGD("open file %s error %s", tmp, strerror(errno)); |
210 | return -errno; |
211 | } |
212 | |
213 | while(fgets(line, sizeof(line), ion_fp) != NULL) { |
214 | if (sscanf(line, "%s%d%u", ion_name, &ion_pid, &ion_size) != 3) { |
215 | continue; |
216 | } else { |
217 | if (ion_pid == pid) { |
218 | unaccounted_size += ion_size; |
219 | } |
220 | } |
221 | |
222 | } |
223 | |
224 | fclose(ion_fp); |
225 | } |
226 | |
227 | if (allocated_records > 0) { |
228 | records[0].size_in_bytes = unaccounted_size; |
229 | // ALOGD("graphic %u\n", unaccounted_size); |
230 | } |
231 | |
232 | return 0; |
233 | } |
234 | |
235 | int aml_memtrack_get_memory(const struct memtrack_module *module, |
236 | pid_t pid, |
237 | int type, |
238 | struct memtrack_record *records, |
239 | size_t *num_records) |
240 | { |
241 | if (type == MEMTRACK_TYPE_GL || type == MEMTRACK_TYPE_GRAPHICS) { |
242 | return memtrack_get_memory(pid, type, records, num_records); |
243 | |
244 | } else { |
245 | return -EINVAL; |
246 | } |
247 | } |
248 | |
249 | |
250 | struct memtrack_module HAL_MODULE_INFO_SYM = { |
251 | common: { |
252 | tag: HARDWARE_MODULE_TAG, |
253 | module_api_version: MEMTRACK_MODULE_API_VERSION_0_1, |
254 | hal_api_version: HARDWARE_HAL_API_VERSION, |
255 | id: MEMTRACK_HARDWARE_MODULE_ID, |
256 | name: "aml Memory Tracker HAL", |
257 | author: "amlogic", |
258 | methods: &memtrack_module_methods, |
259 | }, |
260 | |
261 | init: aml_memtrack_init, |
262 | getMemory: aml_memtrack_get_memory, |
263 | }; |
264 |