1 /*
2  * Copyright (C) 2013 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 #include <errno.h>
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/mman.h>
22 #include <log/log.h>
23 
24 #include <hardware/memtrack.h>
25 
26 #include "memtrack_exynos.h"
27 
28 /* Following includes added for directory parsing. */
29 #include <sys/types.h>
30 #include <dirent.h>
31 
32 /* Some general defines. */
33 #define MALI_DEBUG_FS_PATH 		"/d/mali/mem/"
34 #define MALI_DEBUG_MEM_FILE		"/mem_profile"
35 
36 #define MAX_FILES_PER_PID 		8
37 #define MAX_FILES_PER_NAME		32
38 static int libmemtrack_gbl_input_filename_counter = 	0;
39 static char libmemtrack_gbl_input_filename[MAX_FILES_PER_PID][MAX_FILES_PER_NAME];
40 
41 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
42 #define min(x, y) ((x) < (y) ? (x) : (y))
43 
44 struct memtrack_record record_templates[] = {
45     {
46         .flags = MEMTRACK_FLAG_SMAPS_ACCOUNTED |
47                  MEMTRACK_FLAG_PRIVATE |
48                  MEMTRACK_FLAG_NONSECURE,
49     },
50     {
51         .flags = MEMTRACK_FLAG_SMAPS_UNACCOUNTED |
52                  MEMTRACK_FLAG_PRIVATE |
53                  MEMTRACK_FLAG_NONSECURE,
54     },
55 };
56 
scan_directory_for_filenames(pid_t pid)57 static void scan_directory_for_filenames(pid_t pid)
58 {
59     /* As per ARM, there can be multiple files */
60     DIR *directory;
61     struct dirent *entries;
62     char pid_string[12] = {0};
63     int pid_index = 0;
64 
65     /* Open directory. */
66     directory = opendir(MALI_DEBUG_FS_PATH);
67 
68     sprintf(pid_string, "%d", pid);
69     for (pid_index = 0; pid_index < 12; pid_index++) {
70         if (pid_string[pid_index] == 0) {
71             pid_string[pid_index] = '_';
72             break;
73         }
74     }
75 
76     libmemtrack_gbl_input_filename_counter = 0;
77 
78     if (directory != NULL) {
79         /* Keep reading the directory. */
80         while ((entries = readdir(directory))) {
81             /* Check if the PID is present in the direcotry entry.
82              * If it is present, then keep the filename for reading
83              * contents. Also concatenate the directory path, so that
84              * file can be opened.
85              * */
86             if (!strncmp(entries->d_name, pid_string, strlen(pid_string))) {
87                 snprintf(&libmemtrack_gbl_input_filename[libmemtrack_gbl_input_filename_counter][0], MAX_FILES_PER_NAME, "%s%s%s", MALI_DEBUG_FS_PATH, entries->d_name, MALI_DEBUG_MEM_FILE);
88                 libmemtrack_gbl_input_filename_counter++;
89             }
90         }
91         /* Close directory before leaving. */
92         (void) closedir(directory);
93     } else {
94         ALOGE("libmemtrack-hw -- Couldn't open the directory - %s \r\n", MALI_DEBUG_FS_PATH);
95     }
96 
97     return;
98 }
99 
mali_memtrack_get_memory(pid_t pid,int __unused type,struct memtrack_record * records,size_t * num_records)100 int mali_memtrack_get_memory(pid_t pid, int __unused type,
101                              struct memtrack_record *records,
102                              size_t *num_records)
103 {
104     size_t allocated_records = min(*num_records, ARRAY_SIZE(record_templates));
105     FILE *fp;
106     int local_count;
107     long long int temp_val = 0, total_memory_size = 0, native_buf_mem_size = 0;
108     bool native_buffer_read = false;
109     char line[1024] = {0};
110 
111     *num_records = ARRAY_SIZE(record_templates);
112 
113     /* fastpath to return the necessary number of records */
114     if (allocated_records == 0) {
115         return 0;
116     }
117 
118     memcpy(records, record_templates,
119            sizeof(struct memtrack_record) * allocated_records);
120 
121     /* First, scan the directoy. */
122     scan_directory_for_filenames(pid);
123 
124     local_count = 0;
125     total_memory_size = 0;
126     native_buf_mem_size = 0;
127 
128     while (local_count < libmemtrack_gbl_input_filename_counter) {
129         fp = fopen(&libmemtrack_gbl_input_filename[local_count][0], "r");
130 
131         if (fp == NULL) {
132             /* Unable to open the file. Either move to next file, or
133              * return to caller. */
134             local_count++;
135             continue;
136         }
137 
138         while (1) {
139             char memory_type[16] = {0};
140             char memory_type_2[16] = {0};
141             int ret = 0;
142 
143             if (native_buffer_read == false) {
144                 if (fgets(line, sizeof(line), fp) == NULL) {
145                     if (native_buffer_read == false) {
146                         /* Unable to read Native buffer.
147                          * Probably DDK doesn't support Native Buffer.
148                          * Reset to start of file and look for Total
149                          * Memory. */
150                         fseek(fp, 0, SEEK_SET);
151 
152                         /* Also, set Native buffer flag and memory sizes. */
153                         native_buffer_read = true;
154                         continue;
155                     }
156                 }
157 
158                 /* Search for Total memory. */
159                 /* Format:
160                  *
161                  * Channel: Native Buffer (Total memory: 44285952)
162                  *
163                  */
164                 ret = sscanf(line, "%*s %15s %15s %*s %*s %lld \n", memory_type, memory_type_2, &temp_val);
165 
166                 if (ret != 3)
167                     continue;
168 
169                 if ((strcmp(memory_type, "Native") == 0) &&
170                         (strcmp(memory_type_2, "Buffer") == 0)) {
171                     /* Set native buffer memory read flag to true. */
172                     native_buffer_read = true;
173                     if ((INT64_MAX - temp_val) > native_buf_mem_size)
174                         native_buf_mem_size += temp_val;
175                     else
176                         native_buf_mem_size = INT64_MAX;
177                 } else {
178                     /* Ignore case. Nothing to do here. */
179                     /* Continue reading file until NativeBuffer is found. */
180                 }
181             } else {
182                 if (fgets(line, sizeof(line), fp) == NULL) {
183                     /* Unable to find, so break the loop here.*/
184                     break;
185                 }
186 
187                 /* Search for Total memory. */
188                 /* Format:
189                  *
190                  * Total allocated memory: 36146960
191                  *
192                  */
193                 ret = sscanf(line, "%15s %*s %*s %lld \n", memory_type, &temp_val);
194 
195                 if (ret != 2)
196                     continue;
197 
198                 if (strcmp(memory_type, "Total") == 0) {
199                     /* Store total memory. */
200                     if ((INT64_MAX - temp_val) > total_memory_size)
201                         total_memory_size += temp_val;
202                     else
203                         total_memory_size = INT64_MAX;
204                 } else {
205                     /* Ignore case. Nothing to do here. */
206                 }
207             } /* end if (native_buffer_read == false) */
208 
209         } /* End while(1) */
210 
211         if (fp != NULL) {
212             /* Close the opened file. */
213             fclose(fp);
214 
215             /* Reset some of the local variables here. */
216             fp = NULL;
217             native_buffer_read = false;
218         }
219 
220         /* Manage local variables and counters. */
221         local_count++;
222 
223     } /* while (local_count <= libmemtrack_gbl_input_filename_counter) */
224 
225     /* Arrange and return memory size details. */
226     if (allocated_records > 0)
227         records[0].size_in_bytes = 0;
228 
229     if (allocated_records > 1)
230     {
231         if (native_buf_mem_size >= 0 && total_memory_size > native_buf_mem_size)
232             records[1].size_in_bytes = total_memory_size - native_buf_mem_size;
233         else
234             records[1].size_in_bytes = 0;
235     }
236 
237     return 0;
238 }
239