Merge "Add IActivityManager.getUidLastIdleElapsedTime()" into main
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 5e6b54b..84bc6ce 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -962,4 +962,12 @@
      */
     oneway void frozenBinderTransactionDetected(int debugPid, int code, int flags, int err);
     int getBindingUidProcessState(int uid, in String callingPackage);
+
+    /**
+     * Return the timestampe (in the elapsed timebase) when the UID became idle from active
+     * last time (regardless of if the UID is still idle, or became active again).
+     * This is useful when trying to detect whether an UID has ever became idle since a certain
+     * time in the past.
+     */
+    long getUidLastIdleElapsedTime(int uid, in String callingPackage);
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b00676a..5941fd7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -8015,6 +8015,18 @@
         return uidRecord != null && !uidRecord.isSetIdle();
     }
 
+    @Override
+    public long getUidLastIdleElapsedTime(int uid, String callingPackage) {
+        if (!hasUsageStatsPermission(callingPackage)) {
+            enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+                    "getUidLastIdleElapsedTime");
+        }
+        synchronized (mProcLock) {
+            final UidRecord uidRecord = mProcessList.getUidRecordLOSP(uid);
+            return uidRecord != null ? uidRecord.getRealLastIdleTime() : 0;
+        }
+    }
+
     @GuardedBy("mUidFrozenStateChangedCallbackList")
     private final RemoteCallbackList<IUidFrozenStateChangedCallback>
             mUidFrozenStateChangedCallbackList = new RemoteCallbackList<>();
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index df6481d..9c1ce66 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -3681,7 +3681,7 @@
         for (int i = N - 1; i >= 0; i--) {
             final UidRecord uidRec = mActiveUids.valueAt(i);
             final long bgTime = uidRec.getLastBackgroundTime();
-            final long idleTime = uidRec.getLastIdleTime();
+            final long idleTime = uidRec.getLastIdleTimeIfStillIdle();
             if (bgTime > 0 && (!uidRec.isIdle() || idleTime == 0)) {
                 if (bgTime <= maxBgTime) {
                     EventLogTags.writeAmUidIdle(uidRec.getUid());
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index 45fd470..86fa0fc 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -17,6 +17,7 @@
 package com.android.server.am;
 
 import android.Manifest;
+import android.annotation.ElapsedRealtimeLong;
 import android.app.ActivityManager;
 import android.content.pm.PackageManager;
 import android.os.SystemClock;
@@ -65,8 +66,19 @@
     @CompositeRWLock({"mService", "mProcLock"})
     private long mLastBackgroundTime;
 
+    /**
+     * Last time the UID became idle. This is set to 0, once the UID becomes active.
+     */
+    @ElapsedRealtimeLong
     @CompositeRWLock({"mService", "mProcLock"})
-    private long mLastIdleTime;
+    private long mLastIdleTimeIfStillIdle;
+
+    /**
+     * Last time the UID became idle. Unlike {@link #mLastIdleTimeIfStillIdle}, we never clear it.
+     */
+    @ElapsedRealtimeLong
+    @CompositeRWLock({"mService", "mProcLock"})
+    private long mRealLastIdleTime;
 
     @CompositeRWLock({"mService", "mProcLock"})
     private boolean mEphemeral;
@@ -257,14 +269,28 @@
         mLastBackgroundTime = lastBackgroundTime;
     }
 
+    /**
+     * Last time the UID became idle. This is set to 0, once the UID becomes active.
+     */
     @GuardedBy(anyOf = {"mService", "mProcLock"})
-    long getLastIdleTime() {
-        return mLastIdleTime;
+    long getLastIdleTimeIfStillIdle() {
+        return mLastIdleTimeIfStillIdle;
+    }
+
+    /**
+     * Last time the UID became idle. Unlike {@link #getLastIdleTimeIfStillIdle}, we never clear it.
+     */
+    @GuardedBy(anyOf = {"mService", "mProcLock"})
+    long getRealLastIdleTime() {
+        return mRealLastIdleTime;
     }
 
     @GuardedBy({"mService", "mProcLock"})
-    void setLastIdleTime(long lastActiveTime) {
-        mLastIdleTime = lastActiveTime;
+    void setLastIdleTime(@ElapsedRealtimeLong long lastIdleTime) {
+        mLastIdleTimeIfStillIdle = lastIdleTime;
+        if (lastIdleTime > 0) {
+            mRealLastIdleTime = lastIdleTime;
+        }
     }
 
     @GuardedBy(anyOf = {"mService", "mProcLock"})