1 /*
2 * Copyright (C) 2007 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 "android.os.Debug"
18
19 #include "android_os_Debug.h"
20
21 #include <android-base/file.h>
22 #include <android-base/logging.h>
23 #include <android-base/properties.h>
24 #include <android-base/strings.h>
25 #include <assert.h>
26 #include <binderdebug/BinderDebug.h>
27 #include <bionic/malloc.h>
28 #include <ctype.h>
29 #include <debuggerd/client.h>
30 #include <dmabufinfo/dmabuf_sysfs_stats.h>
31 #include <dmabufinfo/dmabufinfo.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <inttypes.h>
35 #include <log/log.h>
36 #include <malloc.h>
37 #include <meminfo/androidprocheaps.h>
38 #include <meminfo/procmeminfo.h>
39 #include <meminfo/sysmeminfo.h>
40 #include <memtrack/memtrack.h>
41 #include <memunreachable/memunreachable.h>
42 #include <nativehelper/JNIPlatformHelp.h>
43 #include <nativehelper/ScopedUtfChars.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <sys/time.h>
48 #include <time.h>
49 #include <unistd.h>
50 #include <utils/String8.h>
51 #include <utils/misc.h>
52 #include <vintf/KernelConfigs.h>
53
54 #include <iomanip>
55 #include <string>
56 #include <vector>
57
58 #include "jni.h"
59
60 namespace android
61 {
62
63 using namespace android::meminfo;
64
65 struct stat_fields {
66 jfieldID pss_field;
67 jfieldID pssSwappable_field;
68 jfieldID rss_field;
69 jfieldID privateDirty_field;
70 jfieldID sharedDirty_field;
71 jfieldID privateClean_field;
72 jfieldID sharedClean_field;
73 jfieldID swappedOut_field;
74 jfieldID swappedOutPss_field;
75 };
76
77 struct stat_field_names {
78 const char* pss_name;
79 const char* pssSwappable_name;
80 const char* rss_name;
81 const char* privateDirty_name;
82 const char* sharedDirty_name;
83 const char* privateClean_name;
84 const char* sharedClean_name;
85 const char* swappedOut_name;
86 const char* swappedOutPss_name;
87 };
88
89 static stat_fields stat_fields[_NUM_CORE_HEAP];
90
91 static stat_field_names stat_field_names[_NUM_CORE_HEAP] = {
92 { "otherPss", "otherSwappablePss", "otherRss", "otherPrivateDirty", "otherSharedDirty",
93 "otherPrivateClean", "otherSharedClean", "otherSwappedOut", "otherSwappedOutPss" },
94 { "dalvikPss", "dalvikSwappablePss", "dalvikRss", "dalvikPrivateDirty", "dalvikSharedDirty",
95 "dalvikPrivateClean", "dalvikSharedClean", "dalvikSwappedOut", "dalvikSwappedOutPss" },
96 { "nativePss", "nativeSwappablePss", "nativeRss", "nativePrivateDirty", "nativeSharedDirty",
97 "nativePrivateClean", "nativeSharedClean", "nativeSwappedOut", "nativeSwappedOutPss" }
98 };
99
100 static jfieldID otherStats_field;
101 static jfieldID hasSwappedOutPss_field;
102
103 #define BINDER_STATS "/proc/binder/stats"
104
android_os_Debug_getNativeHeapSize(JNIEnv * env,jobject clazz)105 static jlong android_os_Debug_getNativeHeapSize(JNIEnv *env, jobject clazz)
106 {
107 struct mallinfo info = mallinfo();
108 return (jlong) info.usmblks;
109 }
110
android_os_Debug_getNativeHeapAllocatedSize(JNIEnv * env,jobject clazz)111 static jlong android_os_Debug_getNativeHeapAllocatedSize(JNIEnv *env, jobject clazz)
112 {
113 struct mallinfo info = mallinfo();
114 return (jlong) info.uordblks;
115 }
116
android_os_Debug_getNativeHeapFreeSize(JNIEnv * env,jobject clazz)117 static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz)
118 {
119 struct mallinfo info = mallinfo();
120 return (jlong) info.fordblks;
121 }
122
123 // Container used to retrieve graphics memory pss
124 struct graphics_memory_pss
125 {
126 int graphics;
127 int gl;
128 int other;
129 };
130
131 /*
132 * Uses libmemtrack to retrieve graphics memory that the process is using.
133 * Any graphics memory reported in /proc/pid/smaps is not included here.
134 */
read_memtrack_memory(struct memtrack_proc * p,int pid,struct graphics_memory_pss * graphics_mem)135 static int read_memtrack_memory(struct memtrack_proc* p, int pid,
136 struct graphics_memory_pss* graphics_mem)
137 {
138 int err = memtrack_proc_get(p, pid);
139 if (err != 0) {
140 // The memtrack HAL may not be available, do not log to avoid flooding
141 // logcat.
142 return err;
143 }
144
145 ssize_t pss = memtrack_proc_graphics_pss(p);
146 if (pss < 0) {
147 ALOGW("failed to get graphics pss: %zd", pss);
148 return pss;
149 }
150 graphics_mem->graphics = pss / 1024;
151
152 pss = memtrack_proc_gl_pss(p);
153 if (pss < 0) {
154 ALOGW("failed to get gl pss: %zd", pss);
155 return pss;
156 }
157 graphics_mem->gl = pss / 1024;
158
159 pss = memtrack_proc_other_pss(p);
160 if (pss < 0) {
161 ALOGW("failed to get other pss: %zd", pss);
162 return pss;
163 }
164 graphics_mem->other = pss / 1024;
165
166 return 0;
167 }
168
169 /*
170 * Retrieves the graphics memory that is unaccounted for in /proc/pid/smaps.
171 */
read_memtrack_memory(int pid,struct graphics_memory_pss * graphics_mem)172 static int read_memtrack_memory(int pid, struct graphics_memory_pss* graphics_mem)
173 {
174 struct memtrack_proc* p = memtrack_proc_new();
175 if (p == NULL) {
176 ALOGW("failed to create memtrack_proc");
177 return -1;
178 }
179
180 int err = read_memtrack_memory(p, pid, graphics_mem);
181 memtrack_proc_destroy(p);
182 return err;
183 }
184
android_os_Debug_getDirtyPagesPid(JNIEnv * env,jobject clazz,jint pid,jobject object)185 static jboolean android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
186 jint pid, jobject object)
187 {
188 bool foundSwapPss;
189 AndroidHeapStats stats[_NUM_HEAP];
190 memset(&stats, 0, sizeof(stats));
191
192 if (!ExtractAndroidHeapStats(pid, stats, &foundSwapPss)) {
193 return JNI_FALSE;
194 }
195
196 struct graphics_memory_pss graphics_mem;
197 if (read_memtrack_memory(pid, &graphics_mem) == 0) {
198 stats[HEAP_GRAPHICS].pss = graphics_mem.graphics;
199 stats[HEAP_GRAPHICS].privateDirty = graphics_mem.graphics;
200 stats[HEAP_GRAPHICS].rss = graphics_mem.graphics;
201 stats[HEAP_GL].pss = graphics_mem.gl;
202 stats[HEAP_GL].privateDirty = graphics_mem.gl;
203 stats[HEAP_GL].rss = graphics_mem.gl;
204 stats[HEAP_OTHER_MEMTRACK].pss = graphics_mem.other;
205 stats[HEAP_OTHER_MEMTRACK].privateDirty = graphics_mem.other;
206 stats[HEAP_OTHER_MEMTRACK].rss = graphics_mem.other;
207 }
208
209 for (int i=_NUM_CORE_HEAP; i<_NUM_EXCLUSIVE_HEAP; i++) {
210 stats[HEAP_UNKNOWN].pss += stats[i].pss;
211 stats[HEAP_UNKNOWN].swappablePss += stats[i].swappablePss;
212 stats[HEAP_UNKNOWN].rss += stats[i].rss;
213 stats[HEAP_UNKNOWN].privateDirty += stats[i].privateDirty;
214 stats[HEAP_UNKNOWN].sharedDirty += stats[i].sharedDirty;
215 stats[HEAP_UNKNOWN].privateClean += stats[i].privateClean;
216 stats[HEAP_UNKNOWN].sharedClean += stats[i].sharedClean;
217 stats[HEAP_UNKNOWN].swappedOut += stats[i].swappedOut;
218 stats[HEAP_UNKNOWN].swappedOutPss += stats[i].swappedOutPss;
219 }
220
221 for (int i=0; i<_NUM_CORE_HEAP; i++) {
222 env->SetIntField(object, stat_fields[i].pss_field, stats[i].pss);
223 env->SetIntField(object, stat_fields[i].pssSwappable_field, stats[i].swappablePss);
224 env->SetIntField(object, stat_fields[i].rss_field, stats[i].rss);
225 env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty);
226 env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty);
227 env->SetIntField(object, stat_fields[i].privateClean_field, stats[i].privateClean);
228 env->SetIntField(object, stat_fields[i].sharedClean_field, stats[i].sharedClean);
229 env->SetIntField(object, stat_fields[i].swappedOut_field, stats[i].swappedOut);
230 env->SetIntField(object, stat_fields[i].swappedOutPss_field, stats[i].swappedOutPss);
231 }
232
233
234 env->SetBooleanField(object, hasSwappedOutPss_field, foundSwapPss);
235 jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field);
236
237 jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0);
238 if (otherArray == NULL) {
239 return JNI_FALSE;
240 }
241
242 int j=0;
243 for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) {
244 otherArray[j++] = stats[i].pss;
245 otherArray[j++] = stats[i].swappablePss;
246 otherArray[j++] = stats[i].rss;
247 otherArray[j++] = stats[i].privateDirty;
248 otherArray[j++] = stats[i].sharedDirty;
249 otherArray[j++] = stats[i].privateClean;
250 otherArray[j++] = stats[i].sharedClean;
251 otherArray[j++] = stats[i].swappedOut;
252 otherArray[j++] = stats[i].swappedOutPss;
253 }
254
255 env->ReleasePrimitiveArrayCritical(otherIntArray, otherArray, 0);
256 return JNI_TRUE;
257 }
258
android_os_Debug_getDirtyPages(JNIEnv * env,jobject clazz,jobject object)259 static void android_os_Debug_getDirtyPages(JNIEnv *env, jobject clazz, jobject object)
260 {
261 android_os_Debug_getDirtyPagesPid(env, clazz, getpid(), object);
262 }
263
android_os_Debug_getPssPid(JNIEnv * env,jobject clazz,jint pid,jlongArray outUssSwapPssRss,jlongArray outMemtrack)264 static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid,
265 jlongArray outUssSwapPssRss, jlongArray outMemtrack)
266 {
267 jlong pss = 0;
268 jlong rss = 0;
269 jlong swapPss = 0;
270 jlong uss = 0;
271 jlong memtrack = 0;
272
273 struct graphics_memory_pss graphics_mem;
274 if (read_memtrack_memory(pid, &graphics_mem) == 0) {
275 pss = uss = rss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
276 }
277
278 ::android::meminfo::ProcMemInfo proc_mem(pid);
279 ::android::meminfo::MemUsage stats;
280 if (proc_mem.SmapsOrRollup(&stats)) {
281 pss += stats.pss;
282 uss += stats.uss;
283 rss += stats.rss;
284 swapPss = stats.swap_pss;
285 pss += swapPss; // Also in swap, those pages would be accounted as Pss without SWAP
286 } else {
287 return 0;
288 }
289
290 if (outUssSwapPssRss != NULL) {
291 int outLen = env->GetArrayLength(outUssSwapPssRss);
292 if (outLen >= 1) {
293 jlong* outUssSwapPssRssArray = env->GetLongArrayElements(outUssSwapPssRss, 0);
294 if (outUssSwapPssRssArray != NULL) {
295 outUssSwapPssRssArray[0] = uss;
296 if (outLen >= 2) {
297 outUssSwapPssRssArray[1] = swapPss;
298 }
299 if (outLen >= 3) {
300 outUssSwapPssRssArray[2] = rss;
301 }
302 }
303 env->ReleaseLongArrayElements(outUssSwapPssRss, outUssSwapPssRssArray, 0);
304 }
305 }
306
307 if (outMemtrack != NULL) {
308 int outLen = env->GetArrayLength(outMemtrack);
309 if (outLen >= 1) {
310 jlong* outMemtrackArray = env->GetLongArrayElements(outMemtrack, 0);
311 if (outMemtrackArray != NULL) {
312 outMemtrackArray[0] = memtrack;
313 if (outLen >= 2) {
314 outMemtrackArray[1] = graphics_mem.graphics;
315 }
316 if (outLen >= 3) {
317 outMemtrackArray[2] = graphics_mem.gl;
318 }
319 if (outLen >= 4) {
320 outMemtrackArray[3] = graphics_mem.other;
321 }
322 }
323 env->ReleaseLongArrayElements(outMemtrack, outMemtrackArray, 0);
324 }
325 }
326
327 return pss;
328 }
329
android_os_Debug_getPss(JNIEnv * env,jobject clazz)330 static jlong android_os_Debug_getPss(JNIEnv *env, jobject clazz)
331 {
332 return android_os_Debug_getPssPid(env, clazz, getpid(), NULL, NULL);
333 }
334
android_os_Debug_getRssPid(JNIEnv * env,jobject clazz,jint pid,jlongArray outMemtrack)335 static jlong android_os_Debug_getRssPid(JNIEnv* env, jobject clazz, jint pid,
336 jlongArray outMemtrack) {
337 jlong rss = 0;
338 jlong memtrack = 0;
339
340 struct graphics_memory_pss graphics_mem;
341 if (read_memtrack_memory(pid, &graphics_mem) == 0) {
342 rss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
343 }
344
345 ::android::meminfo::ProcMemInfo proc_mem(pid);
346 uint64_t status_rss;
347 if (proc_mem.StatusVmRSS(&status_rss)) {
348 rss += status_rss;
349 } else {
350 return 0;
351 }
352
353 if (outMemtrack != NULL) {
354 int outLen = env->GetArrayLength(outMemtrack);
355 if (outLen >= 1) {
356 jlong* outMemtrackArray = env->GetLongArrayElements(outMemtrack, 0);
357 if (outMemtrackArray != NULL) {
358 outMemtrackArray[0] = memtrack;
359 if (outLen >= 2) {
360 outMemtrackArray[1] = graphics_mem.graphics;
361 }
362 if (outLen >= 3) {
363 outMemtrackArray[2] = graphics_mem.gl;
364 }
365 if (outLen >= 4) {
366 outMemtrackArray[3] = graphics_mem.other;
367 }
368 }
369 env->ReleaseLongArrayElements(outMemtrack, outMemtrackArray, 0);
370 }
371 }
372
373 return rss;
374 }
375
android_os_Debug_getRss(JNIEnv * env,jobject clazz)376 static jlong android_os_Debug_getRss(JNIEnv* env, jobject clazz) {
377 return android_os_Debug_getRssPid(env, clazz, getpid(), NULL);
378 }
379
380 // The 1:1 mapping of MEMINFO_* enums here must match with the constants from
381 // Debug.java.
382 enum {
383 MEMINFO_TOTAL,
384 MEMINFO_FREE,
385 MEMINFO_BUFFERS,
386 MEMINFO_CACHED,
387 MEMINFO_SHMEM,
388 MEMINFO_SLAB,
389 MEMINFO_SLAB_RECLAIMABLE,
390 MEMINFO_SLAB_UNRECLAIMABLE,
391 MEMINFO_SWAP_TOTAL,
392 MEMINFO_SWAP_FREE,
393 MEMINFO_ZRAM_TOTAL,
394 MEMINFO_MAPPED,
395 MEMINFO_VMALLOC_USED,
396 MEMINFO_PAGE_TABLES,
397 MEMINFO_KERNEL_STACK,
398 MEMINFO_KERNEL_RECLAIMABLE,
399 MEMINFO_ACTIVE,
400 MEMINFO_INACTIVE,
401 MEMINFO_UNEVICTABLE,
402 MEMINFO_AVAILABLE,
403 MEMINFO_ACTIVE_ANON,
404 MEMINFO_INACTIVE_ANON,
405 MEMINFO_ACTIVE_FILE,
406 MEMINFO_INACTIVE_FILE,
407 MEMINFO_CMA_TOTAL,
408 MEMINFO_CMA_FREE,
409 MEMINFO_COUNT
410 };
411
android_os_Debug_getMemInfo(JNIEnv * env,jobject clazz,jlongArray out)412 static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
413 {
414 if (out == NULL) {
415 jniThrowNullPointerException(env, "out == null");
416 return;
417 }
418
419 int outLen = env->GetArrayLength(out);
420 if (outLen < MEMINFO_COUNT) {
421 jniThrowRuntimeException(env, "outLen < MEMINFO_COUNT");
422 return;
423 }
424
425 // Read system memory info including ZRAM. The values are stored in the vector
426 // in the same order as MEMINFO_* enum
427 std::vector<std::string_view> tags(
428 ::android::meminfo::SysMemInfo::kDefaultSysMemInfoTags.begin(),
429 ::android::meminfo::SysMemInfo::kDefaultSysMemInfoTags.end());
430 tags.insert(tags.begin() + MEMINFO_ZRAM_TOTAL, "Zram:");
431 std::vector<uint64_t> mem(tags.size());
432 ::android::meminfo::SysMemInfo smi;
433 if (!smi.ReadMemInfo(tags.size(), tags.data(), mem.data())) {
434 jniThrowRuntimeException(env, "SysMemInfo read failed");
435 return;
436 }
437
438 jlong* outArray = env->GetLongArrayElements(out, 0);
439 if (outArray != NULL) {
440 outLen = MEMINFO_COUNT;
441 for (int i = 0; i < outLen; i++) {
442 if (i == MEMINFO_VMALLOC_USED && mem[i] == 0) {
443 outArray[i] = smi.ReadVmallocInfo() / 1024;
444 continue;
445 }
446 outArray[i] = mem[i];
447 }
448 }
449
450 env->ReleaseLongArrayElements(out, outArray, 0);
451 }
452
read_binder_stat(const char * stat)453 static jint read_binder_stat(const char* stat)
454 {
455 UniqueFile fp = MakeUniqueFile(BINDER_STATS, "re");
456 if (fp == nullptr) {
457 return -1;
458 }
459
460 char line[1024];
461
462 char compare[128];
463 int len = snprintf(compare, 128, "proc %d", getpid());
464
465 // loop until we have the block that represents this process
466 do {
467 if (fgets(line, 1024, fp.get()) == 0) {
468 return -1;
469 }
470 } while (strncmp(compare, line, len));
471
472 // now that we have this process, read until we find the stat that we are looking for
473 len = snprintf(compare, 128, " %s: ", stat);
474
475 do {
476 if (fgets(line, 1024, fp.get()) == 0) {
477 return -1;
478 }
479 } while (strncmp(compare, line, len));
480
481 // we have the line, now increment the line ptr to the value
482 char* ptr = line + len;
483 jint result = atoi(ptr);
484 return result;
485 }
486
android_os_Debug_getBinderSentTransactions(JNIEnv * env,jobject clazz)487 static jint android_os_Debug_getBinderSentTransactions(JNIEnv *env, jobject clazz)
488 {
489 return read_binder_stat("bcTRANSACTION");
490 }
491
android_os_getBinderReceivedTransactions(JNIEnv * env,jobject clazz)492 static jint android_os_getBinderReceivedTransactions(JNIEnv *env, jobject clazz)
493 {
494 return read_binder_stat("brTRANSACTION");
495 }
496
497 // these are implemented in android_util_Binder.cpp
498 jint android_os_Debug_getLocalObjectCount(JNIEnv* env, jobject clazz);
499 jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz);
500 jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz);
501
openFile(JNIEnv * env,jobject fileDescriptor,UniqueFile & fp)502 static bool openFile(JNIEnv* env, jobject fileDescriptor, UniqueFile& fp)
503 {
504 if (fileDescriptor == NULL) {
505 jniThrowNullPointerException(env, "fd == null");
506 return false;
507 }
508 int origFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
509 if (origFd < 0) {
510 jniThrowRuntimeException(env, "Invalid file descriptor");
511 return false;
512 }
513
514 /* dup() the descriptor so we don't close the original with fclose() */
515 int fd = fcntl(origFd, F_DUPFD_CLOEXEC, 0);
516 if (fd < 0) {
517 ALOGW("dup(%d) failed: %s\n", origFd, strerror(errno));
518 jniThrowRuntimeException(env, "dup() failed");
519 return false;
520 }
521
522 fp.reset(fdopen(fd, "w"));
523 if (fp == nullptr) {
524 ALOGW("fdopen(%d) failed: %s\n", fd, strerror(errno));
525 close(fd);
526 jniThrowRuntimeException(env, "fdopen() failed");
527 return false;
528 }
529 return true;
530 }
531
532 /*
533 * Dump the native heap, writing human-readable output to the specified
534 * file descriptor.
535 */
android_os_Debug_dumpNativeHeap(JNIEnv * env,jobject,jobject fileDescriptor)536 static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject,
537 jobject fileDescriptor)
538 {
539 UniqueFile fp(nullptr, safeFclose);
540 if (!openFile(env, fileDescriptor, fp)) {
541 return;
542 }
543
544 ALOGD("Native heap dump starting...\n");
545 // Formatting of the native heap dump is handled by malloc debug itself.
546 // See https://android.googlesource.com/platform/bionic/+/master/libc/malloc_debug/README.md#backtrace-heap-dump-format
547 if (android_mallopt(M_WRITE_MALLOC_LEAK_INFO_TO_FILE, fp.get(), sizeof(FILE*))) {
548 ALOGD("Native heap dump complete.\n");
549 } else {
550 PLOG(ERROR) << "Failed to write native heap dump to file";
551 }
552 }
553
554 /*
555 * Dump the native malloc info, writing xml output to the specified
556 * file descriptor.
557 */
android_os_Debug_dumpNativeMallocInfo(JNIEnv * env,jobject,jobject fileDescriptor)558 static void android_os_Debug_dumpNativeMallocInfo(JNIEnv* env, jobject,
559 jobject fileDescriptor)
560 {
561 UniqueFile fp(nullptr, safeFclose);
562 if (!openFile(env, fileDescriptor, fp)) {
563 return;
564 }
565
566 malloc_info(0, fp.get());
567 }
568
dumpTraces(JNIEnv * env,jint pid,jstring fileName,jint timeoutSecs,DebuggerdDumpType dumpType)569 static bool dumpTraces(JNIEnv* env, jint pid, jstring fileName, jint timeoutSecs,
570 DebuggerdDumpType dumpType) {
571 const ScopedUtfChars fileNameChars(env, fileName);
572 if (fileNameChars.c_str() == nullptr) {
573 return false;
574 }
575
576 android::base::unique_fd fd(open(fileNameChars.c_str(),
577 O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_APPEND,
578 0666));
579 if (fd < 0) {
580 PLOG(ERROR) << "Can't open " << fileNameChars.c_str();
581 return false;
582 }
583
584 std::string binderState;
585 android::status_t status = android::getBinderTransactions(pid, binderState);
586 if (status == android::OK) {
587 if (!android::base::WriteStringToFd(binderState, fd)) {
588 PLOG(ERROR) << "Failed to dump binder state info for pid: " << pid;
589 }
590 } else {
591 PLOG(ERROR) << "Failed to get binder state info for pid: " << pid << " status: " << status;
592 }
593 int res = dump_backtrace_to_file_timeout(pid, dumpType, timeoutSecs, fd);
594 if (fdatasync(fd.get()) != 0) {
595 PLOG(ERROR) << "Failed flushing trace.";
596 }
597 return res == 0;
598 }
599
android_os_Debug_dumpJavaBacktraceToFileTimeout(JNIEnv * env,jobject clazz,jint pid,jstring fileName,jint timeoutSecs)600 static jboolean android_os_Debug_dumpJavaBacktraceToFileTimeout(JNIEnv* env, jobject clazz,
601 jint pid, jstring fileName, jint timeoutSecs) {
602 const bool ret = dumpTraces(env, pid, fileName, timeoutSecs, kDebuggerdJavaBacktrace);
603 return ret ? JNI_TRUE : JNI_FALSE;
604 }
605
android_os_Debug_dumpNativeBacktraceToFileTimeout(JNIEnv * env,jobject clazz,jint pid,jstring fileName,jint timeoutSecs)606 static jboolean android_os_Debug_dumpNativeBacktraceToFileTimeout(JNIEnv* env, jobject clazz,
607 jint pid, jstring fileName, jint timeoutSecs) {
608 const bool ret = dumpTraces(env, pid, fileName, timeoutSecs, kDebuggerdNativeBacktrace);
609 return ret ? JNI_TRUE : JNI_FALSE;
610 }
611
android_os_Debug_getUnreachableMemory(JNIEnv * env,jobject clazz,jint limit,jboolean contents)612 static jstring android_os_Debug_getUnreachableMemory(JNIEnv* env, jobject clazz,
613 jint limit, jboolean contents)
614 {
615 std::string s = GetUnreachableMemoryString(contents, limit);
616 return env->NewStringUTF(s.c_str());
617 }
618
android_os_Debug_getFreeZramKb(JNIEnv * env,jobject clazz)619 static jlong android_os_Debug_getFreeZramKb(JNIEnv* env, jobject clazz) {
620
621 jlong zramFreeKb = 0;
622
623 std::string status_path = android::base::StringPrintf("/proc/meminfo");
624 UniqueFile file = MakeUniqueFile(status_path.c_str(), "re");
625
626 char line[256];
627 while (file != nullptr && fgets(line, sizeof(line), file.get())) {
628 jlong v;
629 if (sscanf(line, "SwapFree: %" SCNd64 " kB", &v) == 1) {
630 zramFreeKb = v;
631 break;
632 }
633 }
634
635 return zramFreeKb;
636 }
637
android_os_Debug_getIonHeapsSizeKb(JNIEnv * env,jobject clazz)638 static jlong android_os_Debug_getIonHeapsSizeKb(JNIEnv* env, jobject clazz) {
639 jlong heapsSizeKb = -1;
640 uint64_t size;
641
642 if (meminfo::ReadIonHeapsSizeKb(&size)) {
643 heapsSizeKb = size;
644 }
645
646 return heapsSizeKb;
647 }
648
android_os_Debug_getDmabufTotalExportedKb(JNIEnv * env,jobject clazz)649 static jlong android_os_Debug_getDmabufTotalExportedKb(JNIEnv* env, jobject clazz) {
650 jlong dmabufTotalSizeKb = -1;
651 uint64_t size;
652
653 if (dmabufinfo::GetDmabufTotalExportedKb(&size)) {
654 dmabufTotalSizeKb = size;
655 }
656 return dmabufTotalSizeKb;
657 }
658
android_os_Debug_getDmabufHeapTotalExportedKb(JNIEnv * env,jobject clazz)659 static jlong android_os_Debug_getDmabufHeapTotalExportedKb(JNIEnv* env, jobject clazz) {
660 jlong dmabufHeapTotalSizeKb = -1;
661 uint64_t size;
662
663 if (meminfo::ReadDmabufHeapTotalExportedKb(&size)) {
664 dmabufHeapTotalSizeKb = size;
665 }
666 return dmabufHeapTotalSizeKb;
667 }
668
android_os_Debug_getIonPoolsSizeKb(JNIEnv * env,jobject clazz)669 static jlong android_os_Debug_getIonPoolsSizeKb(JNIEnv* env, jobject clazz) {
670 jlong poolsSizeKb = -1;
671 uint64_t size;
672
673 if (meminfo::ReadIonPoolsSizeKb(&size)) {
674 poolsSizeKb = size;
675 }
676
677 return poolsSizeKb;
678 }
679
android_os_Debug_getDmabufHeapPoolsSizeKb(JNIEnv * env,jobject clazz)680 static jlong android_os_Debug_getDmabufHeapPoolsSizeKb(JNIEnv* env, jobject clazz) {
681 jlong poolsSizeKb = -1;
682 uint64_t size;
683
684 if (meminfo::ReadDmabufHeapPoolsSizeKb(&size)) {
685 poolsSizeKb = size;
686 }
687
688 return poolsSizeKb;
689 }
690
halSupportsGpuPrivateMemory()691 static bool halSupportsGpuPrivateMemory() {
692 int productApiLevel =
693 android::base::GetIntProperty("ro.product.first_api_level",
694 android::base::GetIntProperty("ro.build.version.sdk",
695 __ANDROID_API_FUTURE__));
696 int boardApiLevel =
697 android::base::GetIntProperty("ro.board.api_level",
698 android::base::GetIntProperty("ro.board.first_api_level",
699 __ANDROID_API_FUTURE__));
700
701 return std::min(productApiLevel, boardApiLevel) >= __ANDROID_API_S__;
702 }
703
android_os_Debug_getGpuPrivateMemoryKb(JNIEnv * env,jobject clazz)704 static jlong android_os_Debug_getGpuPrivateMemoryKb(JNIEnv* env, jobject clazz) {
705 static bool gpuPrivateMemorySupported = halSupportsGpuPrivateMemory();
706
707 struct memtrack_proc* p = memtrack_proc_new();
708 if (p == nullptr) {
709 LOG(ERROR) << "getGpuPrivateMemoryKb: Failed to create memtrack_proc";
710 return -1;
711 }
712
713 // Memtrack hal defines PID 0 as global total for GPU-private (GL) memory.
714 if (memtrack_proc_get(p, 0) != 0) {
715 // The memtrack HAL may not be available, avoid flooding the log.
716 memtrack_proc_destroy(p);
717 return -1;
718 }
719
720 ssize_t gpuPrivateMem = memtrack_proc_gl_pss(p);
721
722 memtrack_proc_destroy(p);
723
724 // Old HAL implementations may return 0 for GPU private memory if not supported
725 if (gpuPrivateMem == 0 && !gpuPrivateMemorySupported) {
726 return -1;
727 }
728
729 return gpuPrivateMem / 1024;
730 }
731
android_os_Debug_getDmabufMappedSizeKb(JNIEnv * env,jobject clazz)732 static jlong android_os_Debug_getDmabufMappedSizeKb(JNIEnv* env, jobject clazz) {
733 jlong dmabufPss = 0;
734 std::vector<dmabufinfo::DmaBuffer> dmabufs;
735
736 std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir);
737 if (!dir) {
738 LOG(ERROR) << "Failed to open /proc directory";
739 return false;
740 }
741
742 struct dirent* dent;
743 while ((dent = readdir(dir.get()))) {
744 if (dent->d_type != DT_DIR) continue;
745
746 int pid = atoi(dent->d_name);
747 if (pid == 0) {
748 continue;
749 }
750
751 if (!ReadDmaBufMapRefs(pid, &dmabufs)) {
752 LOG(ERROR) << "Failed to read maps for pid " << pid;
753 }
754 }
755
756 for (const dmabufinfo::DmaBuffer& buf : dmabufs) {
757 dmabufPss += buf.size() / 1024;
758 }
759
760 return dmabufPss;
761 }
762
android_os_Debug_getGpuTotalUsageKb(JNIEnv * env,jobject clazz)763 static jlong android_os_Debug_getGpuTotalUsageKb(JNIEnv* env, jobject clazz) {
764 jlong sizeKb = -1;
765 uint64_t size;
766
767 if (meminfo::ReadGpuTotalUsageKb(&size)) {
768 sizeKb = size;
769 }
770
771 return sizeKb;
772 }
773
android_os_Debug_isVmapStack(JNIEnv * env,jobject clazz)774 static jboolean android_os_Debug_isVmapStack(JNIEnv *env, jobject clazz)
775 {
776 static enum {
777 CONFIG_UNKNOWN,
778 CONFIG_SET,
779 CONFIG_UNSET,
780 } cfg_state = CONFIG_UNKNOWN;
781
782 if (cfg_state == CONFIG_UNKNOWN) {
783 std::map<std::string, std::string> configs;
784 const status_t result = android::kernelconfigs::LoadKernelConfigs(&configs);
785 CHECK(result == OK) << "Kernel configs could not be fetched. b/151092221";
786 std::map<std::string, std::string>::const_iterator it = configs.find("CONFIG_VMAP_STACK");
787 cfg_state = (it != configs.end() && it->second == "y") ? CONFIG_SET : CONFIG_UNSET;
788 }
789 return cfg_state == CONFIG_SET;
790 }
791
android_os_Debug_logAllocatorStats(JNIEnv *,jobject)792 static jboolean android_os_Debug_logAllocatorStats(JNIEnv*, jobject) {
793 return mallopt(M_LOG_STATS, 0) == 1 ? JNI_TRUE : JNI_FALSE;
794 }
795
796 /*
797 * JNI registration.
798 */
799
800 static const JNINativeMethod gMethods[] = {
801 {"getNativeHeapSize", "()J", (void*)android_os_Debug_getNativeHeapSize},
802 {"getNativeHeapAllocatedSize", "()J", (void*)android_os_Debug_getNativeHeapAllocatedSize},
803 {"getNativeHeapFreeSize", "()J", (void*)android_os_Debug_getNativeHeapFreeSize},
804 {"getMemoryInfo", "(Landroid/os/Debug$MemoryInfo;)V",
805 (void*)android_os_Debug_getDirtyPages},
806 {"getMemoryInfo", "(ILandroid/os/Debug$MemoryInfo;)Z",
807 (void*)android_os_Debug_getDirtyPagesPid},
808 {"getPss", "()J", (void*)android_os_Debug_getPss},
809 {"getPss", "(I[J[J)J", (void*)android_os_Debug_getPssPid},
810 {"getRss", "()J", (void*)android_os_Debug_getRss},
811 {"getRss", "(I[J)J", (void*)android_os_Debug_getRssPid},
812 {"getMemInfo", "([J)V", (void*)android_os_Debug_getMemInfo},
813 {"dumpNativeHeap", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Debug_dumpNativeHeap},
814 {"dumpNativeMallocInfo", "(Ljava/io/FileDescriptor;)V",
815 (void*)android_os_Debug_dumpNativeMallocInfo},
816 {"getBinderSentTransactions", "()I", (void*)android_os_Debug_getBinderSentTransactions},
817 {"getBinderReceivedTransactions", "()I", (void*)android_os_getBinderReceivedTransactions},
818 {"getBinderLocalObjectCount", "()I", (void*)android_os_Debug_getLocalObjectCount},
819 {"getBinderProxyObjectCount", "()I", (void*)android_os_Debug_getProxyObjectCount},
820 {"getBinderDeathObjectCount", "()I", (void*)android_os_Debug_getDeathObjectCount},
821 {"dumpJavaBacktraceToFileTimeout", "(ILjava/lang/String;I)Z",
822 (void*)android_os_Debug_dumpJavaBacktraceToFileTimeout},
823 {"dumpNativeBacktraceToFileTimeout", "(ILjava/lang/String;I)Z",
824 (void*)android_os_Debug_dumpNativeBacktraceToFileTimeout},
825 {"getUnreachableMemory", "(IZ)Ljava/lang/String;",
826 (void*)android_os_Debug_getUnreachableMemory},
827 {"getZramFreeKb", "()J", (void*)android_os_Debug_getFreeZramKb},
828 {"getIonHeapsSizeKb", "()J", (void*)android_os_Debug_getIonHeapsSizeKb},
829 {"getDmabufTotalExportedKb", "()J", (void*)android_os_Debug_getDmabufTotalExportedKb},
830 {"getGpuPrivateMemoryKb", "()J", (void*)android_os_Debug_getGpuPrivateMemoryKb},
831 {"getDmabufHeapTotalExportedKb", "()J",
832 (void*)android_os_Debug_getDmabufHeapTotalExportedKb},
833 {"getIonPoolsSizeKb", "()J", (void*)android_os_Debug_getIonPoolsSizeKb},
834 {"getDmabufMappedSizeKb", "()J", (void*)android_os_Debug_getDmabufMappedSizeKb},
835 {"getDmabufHeapPoolsSizeKb", "()J", (void*)android_os_Debug_getDmabufHeapPoolsSizeKb},
836 {"getGpuTotalUsageKb", "()J", (void*)android_os_Debug_getGpuTotalUsageKb},
837 {"isVmapStack", "()Z", (void*)android_os_Debug_isVmapStack},
838 {"logAllocatorStats", "()Z", (void*)android_os_Debug_logAllocatorStats},
839 };
840
register_android_os_Debug(JNIEnv * env)841 int register_android_os_Debug(JNIEnv *env)
842 {
843 jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
844
845 // Check the number of other statistics expected in Java matches here.
846 jfieldID numOtherStats_field = env->GetStaticFieldID(clazz, "NUM_OTHER_STATS", "I");
847 jint numOtherStats = env->GetStaticIntField(clazz, numOtherStats_field);
848 jfieldID numDvkStats_field = env->GetStaticFieldID(clazz, "NUM_DVK_STATS", "I");
849 jint numDvkStats = env->GetStaticIntField(clazz, numDvkStats_field);
850 int expectedNumOtherStats = _NUM_HEAP - _NUM_CORE_HEAP;
851 if ((numOtherStats + numDvkStats) != expectedNumOtherStats) {
852 jniThrowExceptionFmt(env, "java/lang/RuntimeException",
853 "android.os.Debug.Meminfo.NUM_OTHER_STATS+android.os.Debug.Meminfo.NUM_DVK_STATS=%d expected %d",
854 numOtherStats+numDvkStats, expectedNumOtherStats);
855 return JNI_ERR;
856 }
857
858 otherStats_field = env->GetFieldID(clazz, "otherStats", "[I");
859 hasSwappedOutPss_field = env->GetFieldID(clazz, "hasSwappedOutPss", "Z");
860
861 for (int i=0; i<_NUM_CORE_HEAP; i++) {
862 stat_fields[i].pss_field =
863 env->GetFieldID(clazz, stat_field_names[i].pss_name, "I");
864 stat_fields[i].pssSwappable_field =
865 env->GetFieldID(clazz, stat_field_names[i].pssSwappable_name, "I");
866 stat_fields[i].rss_field =
867 env->GetFieldID(clazz, stat_field_names[i].rss_name, "I");
868 stat_fields[i].privateDirty_field =
869 env->GetFieldID(clazz, stat_field_names[i].privateDirty_name, "I");
870 stat_fields[i].sharedDirty_field =
871 env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I");
872 stat_fields[i].privateClean_field =
873 env->GetFieldID(clazz, stat_field_names[i].privateClean_name, "I");
874 stat_fields[i].sharedClean_field =
875 env->GetFieldID(clazz, stat_field_names[i].sharedClean_name, "I");
876 stat_fields[i].swappedOut_field =
877 env->GetFieldID(clazz, stat_field_names[i].swappedOut_name, "I");
878 stat_fields[i].swappedOutPss_field =
879 env->GetFieldID(clazz, stat_field_names[i].swappedOutPss_name, "I");
880 }
881
882 return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods));
883 }
884
885 }; // namespace android
886