diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index bf26a41c536af..422761c4dca58 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -2503,4 +2503,27 @@ public final class Debug * @hide */ public static native long getZramFreeKb(); + + /** + * Return memory size in kilobytes allocated for ION heaps. + * + * @hide + */ + public static native long getIonHeapsSizeKb(); + + /** + * Return memory size in kilobytes allocated for ION pools. + * + * @hide + */ + public static native long getIonPoolsSizeKb(); + + /** + * Return ION memory mapped by processes in kB. + * Notes: + * * Warning: Might impact performance as it reads /proc//maps files for each process. + * + * @hide + */ + public static native long getIonMappedSizeKb(); } diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java index c1d129b66e7af..362bc92e40ad2 100644 --- a/core/java/com/android/internal/util/MemInfoReader.java +++ b/core/java/com/android/internal/util/MemInfoReader.java @@ -91,7 +91,15 @@ public final class MemInfoReader { * that are mapped in to processes. */ public long getCachedSizeKb() { - return mInfos[Debug.MEMINFO_BUFFERS] + mInfos[Debug.MEMINFO_SLAB_RECLAIMABLE] + long kReclaimable = mInfos[Debug.MEMINFO_KRECLAIMABLE]; + + // Note: MEMINFO_KRECLAIMABLE includes MEMINFO_SLAB_RECLAIMABLE and ION pools. + // Fall back to using MEMINFO_SLAB_RECLAIMABLE in case of older kernels that do + // not include KReclaimable meminfo field. + if (kReclaimable == 0) { + kReclaimable = mInfos[Debug.MEMINFO_SLAB_RECLAIMABLE]; + } + return mInfos[Debug.MEMINFO_BUFFERS] + kReclaimable + mInfos[Debug.MEMINFO_CACHED] - mInfos[Debug.MEMINFO_MAPPED]; } diff --git a/core/jni/Android.bp b/core/jni/Android.bp index 49c029cb75451..f68fd5799cfcf 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -233,6 +233,7 @@ cc_library_shared { static_libs: [ "libasync_safe", + "libdmabufinfo", "libgif", "libseccomp_policy", "libgrallocusage", diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 6aed1e8ffe606..1ff28feb67386 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -43,6 +43,7 @@ #include #include #include "jni.h" +#include #include #include #include @@ -779,6 +780,59 @@ static jlong android_os_Debug_getFreeZramKb(JNIEnv* env, jobject clazz) { return zramFreeKb; } +static jlong android_os_Debug_getIonHeapsSizeKb(JNIEnv* env, jobject clazz) { + jlong heapsSizeKb = 0; + uint64_t size; + + if (meminfo::ReadIonHeapsSizeKb(&size)) { + heapsSizeKb = size; + } + + return heapsSizeKb; +} + +static jlong android_os_Debug_getIonPoolsSizeKb(JNIEnv* env, jobject clazz) { + jlong poolsSizeKb = 0; + uint64_t size; + + if (meminfo::ReadIonPoolsSizeKb(&size)) { + poolsSizeKb = size; + } + + return poolsSizeKb; +} + +static jlong android_os_Debug_getIonMappedSizeKb(JNIEnv* env, jobject clazz) { + jlong ionPss = 0; + std::vector dmabufs; + + std::unique_ptr dir(opendir("/proc"), closedir); + if (!dir) { + LOG(ERROR) << "Failed to open /proc directory"; + return false; + } + + struct dirent* dent; + while ((dent = readdir(dir.get()))) { + if (dent->d_type != DT_DIR) continue; + + int pid = atoi(dent->d_name); + if (pid == 0) { + continue; + } + + if (!AppendDmaBufInfo(pid, &dmabufs, false)) { + LOG(ERROR) << "Failed to read maps for pid " << pid; + } + } + + for (dmabufinfo::DmaBuffer buf : dmabufs) { + ionPss += buf.size() / 1024; + } + + return ionPss; +} + /* * JNI registration. */ @@ -822,6 +876,12 @@ static const JNINativeMethod gMethods[] = { (void*)android_os_Debug_getUnreachableMemory }, { "getZramFreeKb", "()J", (void*)android_os_Debug_getFreeZramKb }, + { "getIonHeapsSizeKb", "()J", + (void*)android_os_Debug_getIonHeapsSizeKb }, + { "getIonPoolsSizeKb", "()J", + (void*)android_os_Debug_getIonPoolsSizeKb }, + { "getIonMappedSizeKb", "()J", + (void*)android_os_Debug_getIonMappedSizeKb }, }; int register_android_os_Debug(JNIEnv *env) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 6cbcd190d152a..d7b716561dc4a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -12799,14 +12799,31 @@ public class ActivityManagerService extends IActivityManager.Stub pw.println(totalPss - cachedPss); } } - long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss) + long kernelUsed = memInfo.getKernelUsedSizeKb(); + final long ionHeap = Debug.getIonHeapsSizeKb(); + if (ionHeap > 0) { + final long ionMapped = Debug.getIonMappedSizeKb(); + final long ionUnmapped = ionHeap - ionMapped; + final long ionPool = Debug.getIonPoolsSizeKb(); + pw.print(" ION: "); + pw.print(stringifyKBSize(ionHeap + ionPool)); + pw.print(" ("); + pw.print(stringifyKBSize(ionMapped)); + pw.print(" mapped + "); + pw.print(stringifyKBSize(ionUnmapped)); + pw.print(" unmapped + "); + pw.print(stringifyKBSize(ionPool)); + pw.println(" pools)"); + kernelUsed += ionUnmapped; + } + final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() - - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb(); + - kernelUsed - memInfo.getZramTotalSizeKb(); if (!opts.isCompact) { pw.print(" Used RAM: "); pw.print(stringifyKBSize(totalPss - cachedPss - + memInfo.getKernelUsedSizeKb())); pw.print(" ("); + + kernelUsed)); pw.print(" ("); pw.print(stringifyKBSize(totalPss - cachedPss)); pw.print(" used pss + "); - pw.print(stringifyKBSize(memInfo.getKernelUsedSizeKb())); pw.print(" kernel)\n"); + pw.print(stringifyKBSize(kernelUsed)); pw.print(" kernel)\n"); pw.print(" Lost RAM: "); pw.println(stringifyKBSize(lostRAM)); } else { pw.print("lostram,"); pw.println(lostRAM); @@ -13525,14 +13542,25 @@ public class ActivityManagerService extends IActivityManager.Stub memInfoBuilder.append(stringifyKBSize(cachedPss + memInfo.getCachedSizeKb() + memInfo.getFreeSizeKb())); memInfoBuilder.append("\n"); + long kernelUsed = memInfo.getKernelUsedSizeKb(); + final long ionHeap = Debug.getIonHeapsSizeKb(); + if (ionHeap > 0) { + final long ionMapped = Debug.getIonMappedSizeKb(); + final long ionUnmapped = ionHeap - ionMapped; + final long ionPool = Debug.getIonPoolsSizeKb(); + memInfoBuilder.append(" ION: "); + memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool)); + memInfoBuilder.append("\n"); + kernelUsed += ionUnmapped; + } memInfoBuilder.append(" Used RAM: "); memInfoBuilder.append(stringifyKBSize( - totalPss - cachedPss + memInfo.getKernelUsedSizeKb())); + totalPss - cachedPss + kernelUsed)); memInfoBuilder.append("\n"); memInfoBuilder.append(" Lost RAM: "); memInfoBuilder.append(stringifyKBSize(memInfo.getTotalSizeKb() - (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() - - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb())); + - kernelUsed - memInfo.getZramTotalSizeKb())); memInfoBuilder.append("\n"); Slog.i(TAG, "Low on memory:"); Slog.i(TAG, shortNativeBuilder.toString());