Merge "Per process DMA-BUF stats" into sc-dev
diff --git a/core/java/com/android/internal/os/DmabufInfoReader.java b/core/java/com/android/internal/os/DmabufInfoReader.java
new file mode 100644
index 0000000..786a6ee
--- /dev/null
+++ b/core/java/com/android/internal/os/DmabufInfoReader.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.annotation.Nullable;
+
+/** Wrapper around libdmabufinfo. */
+public final class DmabufInfoReader {
+    private DmabufInfoReader() {}
+
+    /** Process dma-buf stats. */
+    public static final class ProcessDmabuf {
+        /** Size of buffers retained by the process. */
+        public final int retainedSizeKb;
+        /** Number of buffers retained by the process. */
+        public final int retainedBuffersCount;
+        /** Size of buffers mapped to the address space. */
+        public final int mappedSizeKb;
+        /** Count of buffers mapped to the address space. */
+        public final int mappedBuffersCount;
+
+        ProcessDmabuf(int retainedSizeKb, int retainedBuffersCount,
+                int mappedSizeKb, int mappedBuffersCount) {
+            this.retainedSizeKb = retainedSizeKb;
+            this.retainedBuffersCount = retainedBuffersCount;
+            this.mappedSizeKb = mappedSizeKb;
+            this.mappedBuffersCount = mappedBuffersCount;
+        }
+    }
+
+    /**
+     * Return stats for DMA-BUFs retained by process pid or null if the DMA-BUF
+     * stats could not be read.
+     */
+    @Nullable
+    public static native ProcessDmabuf getProcessStats(int pid);
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 20d257e..de85ff9 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -202,6 +202,7 @@
                 "com_android_internal_content_om_OverlayConfig.cpp",
                 "com_android_internal_net_NetworkUtilsInternal.cpp",
                 "com_android_internal_os_ClassLoaderFactory.cpp",
+                "com_android_internal_os_DmabufInfoReader.cpp",
                 "com_android_internal_os_FuseAppLoop.cpp",
                 "com_android_internal_os_KernelCpuBpfTracking.cpp",
                 "com_android_internal_os_KernelCpuTotalBpfMapReader.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 0c3f265..6636b1f 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -191,6 +191,7 @@
 extern int register_com_android_internal_content_om_OverlayConfig(JNIEnv *env);
 extern int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv* env);
 extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
+extern int register_com_android_internal_os_DmabufInfoReader(JNIEnv* env);
 extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
 extern int register_com_android_internal_os_KernelCpuBpfTracking(JNIEnv* env);
 extern int register_com_android_internal_os_KernelCpuTotalBpfMapReader(JNIEnv* env);
@@ -1616,6 +1617,7 @@
         REG_JNI(register_android_animation_PropertyValuesHolder),
         REG_JNI(register_android_security_Scrypt),
         REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
+        REG_JNI(register_com_android_internal_os_DmabufInfoReader),
         REG_JNI(register_com_android_internal_os_FuseAppLoop),
         REG_JNI(register_com_android_internal_os_KernelCpuBpfTracking),
         REG_JNI(register_com_android_internal_os_KernelCpuTotalBpfMapReader),
diff --git a/core/jni/com_android_internal_os_DmabufInfoReader.cpp b/core/jni/com_android_internal_os_DmabufInfoReader.cpp
new file mode 100644
index 0000000..4b0a6ac
--- /dev/null
+++ b/core/jni/com_android_internal_os_DmabufInfoReader.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dmabufinfo/dmabufinfo.h>
+#include "core_jni_helpers.h"
+
+namespace android {
+
+static jobject DmabufInfoReader_getProcessStats(JNIEnv *env, jobject, jint pid) {
+    std::vector<dmabufinfo::DmaBuffer> buffers;
+    if (!dmabufinfo::ReadDmaBufMapRefs(pid, &buffers)) {
+        return nullptr;
+    }
+    jint mappedSize = 0;
+    jint mappedCount = buffers.size();
+    for (const auto &buffer : buffers) {
+        mappedSize += buffer.size();
+    }
+    mappedSize /= 1024;
+
+    jint retainedSize = -1;
+    jint retainedCount = -1;
+    if (dmabufinfo::ReadDmaBufFdRefs(pid, &buffers)) {
+        retainedCount = buffers.size();
+        retainedSize = 0;
+        for (const auto &buffer : buffers) {
+            retainedSize += buffer.size();
+        }
+        retainedSize /= 1024;
+    }
+
+    jclass clazz = FindClassOrDie(env, "com/android/internal/os/DmabufInfoReader$ProcessDmabuf");
+    jmethodID constructID = GetMethodIDOrDie(env, clazz, "<init>", "(IIII)V");
+    return env->NewObject(clazz, constructID, retainedSize, retainedCount, mappedSize, mappedCount);
+}
+
+static const JNINativeMethod methods[] = {
+        {"getProcessStats", "(I)Lcom/android/internal/os/DmabufInfoReader$ProcessDmabuf;",
+         (void *)DmabufInfoReader_getProcessStats},
+};
+
+int register_com_android_internal_os_DmabufInfoReader(JNIEnv *env) {
+    return RegisterMethodsOrDie(env, "com/android/internal/os/DmabufInfoReader", methods,
+                                NELEM(methods));
+}
+
+} // namespace android
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index a7b9e95..91231c3 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -111,6 +111,7 @@
 import android.os.OutcomeReceiver;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StatFs;
@@ -148,6 +149,7 @@
 import com.android.internal.os.BatterySipper;
 import com.android.internal.os.BatteryStatsHelper;
 import com.android.internal.os.BinderCallsStats.ExportedCallStat;
+import com.android.internal.os.DmabufInfoReader;
 import com.android.internal.os.KernelCpuBpfTracking;
 import com.android.internal.os.KernelCpuThreadReader;
 import com.android.internal.os.KernelCpuThreadReaderDiff;
@@ -198,6 +200,7 @@
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -528,6 +531,8 @@
                         synchronized (mProcessSystemIonHeapSizeLock) {
                             return pullProcessSystemIonHeapSizeLocked(atomTag, data);
                         }
+                    case FrameworkStatsLog.PROCESS_DMABUF_MEMORY:
+                        return pullProcessDmabufMemory(atomTag, data);
                     case FrameworkStatsLog.SYSTEM_MEMORY:
                         return pullSystemMemory(atomTag, data);
                     case FrameworkStatsLog.TEMPERATURE:
@@ -818,6 +823,7 @@
         registerIonHeapSize();
         registerProcessSystemIonHeapSize();
         registerSystemMemory();
+        registerProcessDmabufMemory();
         registerTemperature();
         registerCoolingDevice();
         registerBinderCallsStats();
@@ -2183,6 +2189,43 @@
         return StatsManager.PULL_SUCCESS;
     }
 
+    private void registerProcessDmabufMemory() {
+        int tagId = FrameworkStatsLog.PROCESS_DMABUF_MEMORY;
+        mStatsManager.setPullAtomCallback(
+                tagId,
+                null, // use default PullAtomMetadata values
+                DIRECT_EXECUTOR,
+                mStatsCallbackImpl
+        );
+    }
+
+    int pullProcessDmabufMemory(int atomTag, List<StatsEvent> pulledData) {
+        List<ProcessMemoryState> managedProcessList =
+                LocalServices.getService(ActivityManagerInternal.class)
+                        .getMemoryStateForProcesses();
+        managedProcessList.sort(Comparator.comparingInt(x -> x.oomScore));
+        for (ProcessMemoryState process : managedProcessList) {
+            if (process.uid == Process.SYSTEM_UID) {
+                continue;
+            }
+            DmabufInfoReader.ProcessDmabuf proc = DmabufInfoReader.getProcessStats(process.pid);
+            if (proc == null || (proc.retainedBuffersCount <= 0 && proc.mappedBuffersCount <= 0)) {
+                continue;
+            }
+            pulledData.add(
+                    FrameworkStatsLog.buildStatsEvent(
+                            atomTag,
+                            process.uid,
+                            process.processName,
+                            process.oomScore,
+                            proc.retainedSizeKb,
+                            proc.retainedBuffersCount,
+                            proc.mappedSizeKb,
+                            proc.mappedBuffersCount));
+        }
+        return StatsManager.PULL_SUCCESS;
+    }
+
     private void registerSystemMemory() {
         int tagId = FrameworkStatsLog.SYSTEM_MEMORY;
         mStatsManager.setPullAtomCallback(