VRR: Use appId to replace uid mapping

Uid is combination of user id and app id. Because the allowlist
is recored by pkg for each users. We could ignore the user id part
and it also could solve the issue we didn't update the mapping
when user added case.

Bug: 298722189
Test: atest SmallAreaDetectionAllowMappingsTest
Test: atest SmallAreaDetectionControllerTest
Test: Add new user and open Youtube short to check refresh rate
Change-Id: I46867b097bf824bfb0654e3179c15182515a461a
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 0689478..9bfe3be 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -757,7 +757,8 @@
 
         mContext.registerReceiver(mIdleModeReceiver, filter);
 
-        mSmallAreaDetectionController = SmallAreaDetectionController.create(mContext);
+        mSmallAreaDetectionController = (mFlags.isSmallAreaDetectionEnabled())
+                ? SmallAreaDetectionController.create(mContext) : null;
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/display/SmallAreaDetectionController.java b/services/core/java/com/android/server/display/SmallAreaDetectionController.java
index adaa539..bf384b0 100644
--- a/services/core/java/com/android/server/display/SmallAreaDetectionController.java
+++ b/services/core/java/com/android/server/display/SmallAreaDetectionController.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.PackageManagerInternal;
+import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.provider.DeviceConfigInterface;
 import android.util.ArrayMap;
@@ -30,15 +31,14 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.BackgroundThread;
 import com.android.server.LocalServices;
-import com.android.server.pm.UserManagerInternal;
+import com.android.server.pm.pkg.PackageStateInternal;
 
 import java.io.PrintWriter;
-import java.util.Arrays;
 import java.util.Map;
 
 final class SmallAreaDetectionController {
-    private static native void nativeUpdateSmallAreaDetection(int[] uids, float[] thresholds);
-    private static native void nativeSetSmallAreaDetectionThreshold(int uid, float threshold);
+    private static native void nativeUpdateSmallAreaDetection(int[] appIds, float[] thresholds);
+    private static native void nativeSetSmallAreaDetectionThreshold(int appId, float threshold);
 
     // TODO(b/281720315): Move this to DeviceConfig once server side ready.
     private static final String KEY_SMALL_AREA_DETECTION_ALLOWLIST =
@@ -47,12 +47,8 @@
     private final Object mLock = new Object();
     private final Context mContext;
     private final PackageManagerInternal mPackageManager;
-    private final UserManagerInternal mUserManager;
     @GuardedBy("mLock")
     private final Map<String, Float> mAllowPkgMap = new ArrayMap<>();
-    // TODO(b/298722189): Update allowlist when user changes
-    @GuardedBy("mLock")
-    private int[] mUserIds;
 
     static SmallAreaDetectionController create(@NonNull Context context) {
         final SmallAreaDetectionController controller =
@@ -67,7 +63,6 @@
     SmallAreaDetectionController(Context context, DeviceConfigInterface deviceConfig) {
         mContext = context;
         mPackageManager = LocalServices.getService(PackageManagerInternal.class);
-        mUserManager = LocalServices.getService(UserManagerInternal.class);
         deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                 BackgroundThread.getExecutor(),
                 new SmallAreaDetectionController.OnPropertiesChangedListener());
@@ -76,6 +71,7 @@
 
     @VisibleForTesting
     void updateAllowlist(@Nullable String property) {
+        final Map<String, Float> allowPkgMap = new ArrayMap<>();
         synchronized (mLock) {
             mAllowPkgMap.clear();
             if (property != null) {
@@ -86,8 +82,11 @@
                         .getStringArray(R.array.config_smallAreaDetectionAllowlist);
                 for (String defaultMapString : defaultMapStrings) putToAllowlist(defaultMapString);
             }
-            updateSmallAreaDetection();
+
+            if (mAllowPkgMap.isEmpty()) return;
+            allowPkgMap.putAll(mAllowPkgMap);
         }
+        updateSmallAreaDetection(allowPkgMap);
     }
 
     @GuardedBy("mLock")
@@ -105,43 +104,32 @@
         }
     }
 
-    @GuardedBy("mLock")
-    private void updateUidListForAllUsers(SparseArray<Float> list, String pkg, float threshold) {
-        for (int i = 0; i < mUserIds.length; i++) {
-            final int userId = mUserIds[i];
-            final int uid = mPackageManager.getPackageUid(pkg, 0, userId);
-            if (uid > 0) list.put(uid, threshold);
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void updateSmallAreaDetection() {
-        if (mAllowPkgMap.isEmpty()) return;
-
-        mUserIds = mUserManager.getUserIds();
-
-        final SparseArray<Float> uidThresholdList = new SparseArray<>();
-        for (String pkg : mAllowPkgMap.keySet()) {
-            final float threshold = mAllowPkgMap.get(pkg);
-            updateUidListForAllUsers(uidThresholdList, pkg, threshold);
+    private void updateSmallAreaDetection(Map<String, Float> allowPkgMap) {
+        final SparseArray<Float> appIdThresholdList = new SparseArray(allowPkgMap.size());
+        for (String pkg : allowPkgMap.keySet()) {
+            final float threshold = allowPkgMap.get(pkg);
+            final PackageStateInternal stage = mPackageManager.getPackageStateInternal(pkg);
+            if (stage != null) {
+                appIdThresholdList.put(stage.getAppId(), threshold);
+            }
         }
 
-        final int[] uids = new int[uidThresholdList.size()];
-        final float[] thresholds = new float[uidThresholdList.size()];
-        for (int i = 0; i < uidThresholdList.size();  i++) {
-            uids[i] = uidThresholdList.keyAt(i);
-            thresholds[i] = uidThresholdList.valueAt(i);
+        final int[] appIds = new int[appIdThresholdList.size()];
+        final float[] thresholds = new float[appIdThresholdList.size()];
+        for (int i = 0; i < appIdThresholdList.size();  i++) {
+            appIds[i] = appIdThresholdList.keyAt(i);
+            thresholds[i] = appIdThresholdList.valueAt(i);
         }
-        updateSmallAreaDetection(uids, thresholds);
+        updateSmallAreaDetection(appIds, thresholds);
     }
 
     @VisibleForTesting
-    void updateSmallAreaDetection(int[] uids, float[] thresholds) {
-        nativeUpdateSmallAreaDetection(uids, thresholds);
+    void updateSmallAreaDetection(int[] appIds, float[] thresholds) {
+        nativeUpdateSmallAreaDetection(appIds, thresholds);
     }
 
-    void setSmallAreaDetectionThreshold(int uid, float threshold) {
-        nativeSetSmallAreaDetectionThreshold(uid, threshold);
+    void setSmallAreaDetectionThreshold(int appId, float threshold) {
+        nativeSetSmallAreaDetectionThreshold(appId, threshold);
     }
 
     void dump(PrintWriter pw) {
@@ -151,7 +139,6 @@
             for (String pkg : mAllowPkgMap.keySet()) {
                 pw.println("    " + pkg + " threshold = " + mAllowPkgMap.get(pkg));
             }
-            pw.println("  mUserIds=" + Arrays.toString(mUserIds));
         }
     }
 
@@ -167,11 +154,15 @@
     private final class PackageReceiver implements PackageManagerInternal.PackageListObserver {
         @Override
         public void onPackageAdded(@NonNull String packageName, int uid) {
+            float threshold = 0.0f;
             synchronized (mLock) {
                 if (mAllowPkgMap.containsKey(packageName)) {
-                    setSmallAreaDetectionThreshold(uid, mAllowPkgMap.get(packageName));
+                    threshold = mAllowPkgMap.get(packageName);
                 }
             }
+            if (threshold > 0.0f) {
+                setSmallAreaDetectionThreshold(UserHandle.getAppId(uid), threshold);
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index fae8383..d953e8e 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -71,6 +71,10 @@
             Flags.FLAG_ENABLE_POWER_THROTTLING_CLAMPER,
             Flags::enablePowerThrottlingClamper);
 
+    private final FlagState mSmallAreaDetectionFlagState = new FlagState(
+            Flags.FLAG_ENABLE_SMALL_AREA_DETECTION,
+            Flags::enableSmallAreaDetection);
+
     /** Returns whether connected display management is enabled or not. */
     public boolean isConnectedDisplayManagementEnabled() {
         return mConnectedDisplayManagementFlagState.isEnabled();
@@ -147,6 +151,10 @@
         return mBackUpSmoothDisplayAndForcePeakRefreshRateFlagState.isEnabled();
     }
 
+    public boolean isSmallAreaDetectionEnabled() {
+        return mSmallAreaDetectionFlagState.isEnabled();
+    }
+
     private static class FlagState {
 
         private final String mName;
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 9ab9c9d..9141814 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -104,3 +104,12 @@
     bug: "211737588"
     is_fixed_read_only: true
 }
+
+flag {
+    name: "enable_small_area_detection"
+    namespace: "display_manager"
+    description: "Feature flag for SmallAreaDetection"
+    bug: "298722189"
+    is_fixed_read_only: true
+}
+
diff --git a/services/core/jni/com_android_server_display_SmallAreaDetectionController.cpp b/services/core/jni/com_android_server_display_SmallAreaDetectionController.cpp
index b256f16..1844d30 100644
--- a/services/core/jni/com_android_server_display_SmallAreaDetectionController.cpp
+++ b/services/core/jni/com_android_server_display_SmallAreaDetectionController.cpp
@@ -24,33 +24,33 @@
 #include "utils/Log.h"
 
 namespace android {
-static void nativeUpdateSmallAreaDetection(JNIEnv* env, jclass clazz, jintArray juids,
+static void nativeUpdateSmallAreaDetection(JNIEnv* env, jclass clazz, jintArray jappIds,
                                            jfloatArray jthresholds) {
-    if (juids == nullptr || jthresholds == nullptr) return;
+    if (jappIds == nullptr || jthresholds == nullptr) return;
 
-    ScopedIntArrayRO uids(env, juids);
+    ScopedIntArrayRO appIds(env, jappIds);
     ScopedFloatArrayRO thresholds(env, jthresholds);
 
-    if (uids.size() != thresholds.size()) {
-        ALOGE("uids size exceeds thresholds size!");
+    if (appIds.size() != thresholds.size()) {
+        ALOGE("appIds size exceeds thresholds size!");
         return;
     }
 
-    std::vector<int32_t> uidVector;
+    std::vector<int32_t> appIdVector;
     std::vector<float> thresholdVector;
-    size_t size = uids.size();
-    uidVector.reserve(size);
+    size_t size = appIds.size();
+    appIdVector.reserve(size);
     thresholdVector.reserve(size);
     for (int i = 0; i < size; i++) {
-        uidVector.push_back(static_cast<int32_t>(uids[i]));
+        appIdVector.push_back(static_cast<int32_t>(appIds[i]));
         thresholdVector.push_back(static_cast<float>(thresholds[i]));
     }
-    SurfaceComposerClient::updateSmallAreaDetection(uidVector, thresholdVector);
+    SurfaceComposerClient::updateSmallAreaDetection(appIdVector, thresholdVector);
 }
 
-static void nativeSetSmallAreaDetectionThreshold(JNIEnv* env, jclass clazz, jint uid,
+static void nativeSetSmallAreaDetectionThreshold(JNIEnv* env, jclass clazz, jint appId,
                                                  jfloat threshold) {
-    SurfaceComposerClient::setSmallAreaDetectionThreshold(uid, threshold);
+    SurfaceComposerClient::setSmallAreaDetectionThreshold(appId, threshold);
 }
 
 static const JNINativeMethod gMethods[] = {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index d021f1d..16d72e4 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -117,7 +117,6 @@
 import com.android.server.display.notifications.DisplayNotificationManager;
 import com.android.server.input.InputManagerInternal;
 import com.android.server.lights.LightsManager;
-import com.android.server.pm.UserManagerInternal;
 import com.android.server.sensors.SensorManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -312,7 +311,6 @@
     @Mock SensorManager mSensorManager;
     @Mock DisplayDeviceConfig mMockDisplayDeviceConfig;
     @Mock PackageManagerInternal mMockPackageManagerInternal;
-    @Mock UserManagerInternal mMockUserManagerInternal;
 
 
     @Captor ArgumentCaptor<ContentRecordingSession> mContentRecordingSessionCaptor;
@@ -336,8 +334,6 @@
                 VirtualDeviceManagerInternal.class, mMockVirtualDeviceManagerInternal);
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
-        LocalServices.removeServiceForTest(UserManagerInternal.class);
-        LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal);
         // TODO: b/287945043
         mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
         mResources = Mockito.spy(mContext.getResources());
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/SmallAreaDetectionControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/SmallAreaDetectionControllerTest.java
index 1ce79a5..05ac5b5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/SmallAreaDetectionControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/SmallAreaDetectionControllerTest.java
@@ -16,8 +16,6 @@
 
 package com.android.server.display;
 
-import static android.os.Process.INVALID_UID;
-
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doNothing;
@@ -35,7 +33,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.LocalServices;
-import com.android.server.pm.UserManagerInternal;
+import com.android.server.pm.pkg.PackageStateInternal;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -55,7 +53,10 @@
     @Mock
     private PackageManagerInternal mMockPackageManagerInternal;
     @Mock
-    private UserManagerInternal mMockUserManagerInternal;
+    private PackageStateInternal mMockPkgStateA;
+    @Mock
+    private PackageStateInternal mMockPkgStateB;
+
 
     private SmallAreaDetectionController mSmallAreaDetectionController;
 
@@ -64,29 +65,18 @@
     private static final String PKG_NOT_INSTALLED = "com.not.installed";
     private static final float THRESHOLD_A = 0.05f;
     private static final float THRESHOLD_B = 0.07f;
-    private static final int USER_1 = 110;
-    private static final int USER_2 = 111;
-    private static final int UID_A_1 = 11011111;
-    private static final int UID_A_2 = 11111111;
-    private static final int UID_B_1 = 11022222;
-    private static final int UID_B_2 = 11122222;
+    private static final int APP_ID_A = 11111;
+    private static final int APP_ID_B = 22222;
 
     @Before
     public void setup() {
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
-        LocalServices.removeServiceForTest(UserManagerInternal.class);
-        LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal);
 
-        when(mMockUserManagerInternal.getUserIds()).thenReturn(new int[]{USER_1, USER_2});
-        when(mMockPackageManagerInternal.getPackageUid(PKG_A, 0, USER_1)).thenReturn(UID_A_1);
-        when(mMockPackageManagerInternal.getPackageUid(PKG_A, 0, USER_2)).thenReturn(UID_A_2);
-        when(mMockPackageManagerInternal.getPackageUid(PKG_B, 0, USER_1)).thenReturn(UID_B_1);
-        when(mMockPackageManagerInternal.getPackageUid(PKG_B, 0, USER_2)).thenReturn(UID_B_2);
-        when(mMockPackageManagerInternal.getPackageUid(PKG_NOT_INSTALLED, 0, USER_1)).thenReturn(
-                INVALID_UID);
-        when(mMockPackageManagerInternal.getPackageUid(PKG_NOT_INSTALLED, 0, USER_2)).thenReturn(
-                INVALID_UID);
+        when(mMockPackageManagerInternal.getPackageStateInternal(PKG_A)).thenReturn(mMockPkgStateA);
+        when(mMockPackageManagerInternal.getPackageStateInternal(PKG_B)).thenReturn(mMockPkgStateB);
+        when(mMockPkgStateA.getAppId()).thenReturn(APP_ID_A);
+        when(mMockPkgStateB.getAppId()).thenReturn(APP_ID_B);
 
         mSmallAreaDetectionController = spy(new SmallAreaDetectionController(
                 new ContextWrapper(ApplicationProvider.getApplicationContext()),
@@ -99,9 +89,9 @@
         final String property = PKG_A + ":" + THRESHOLD_A + "," + PKG_B + ":" + THRESHOLD_B;
         mSmallAreaDetectionController.updateAllowlist(property);
 
-        final int[] resultUidArray = {UID_A_1, UID_B_1, UID_A_2, UID_B_2};
-        final float[] resultThresholdArray = {THRESHOLD_A, THRESHOLD_B, THRESHOLD_A, THRESHOLD_B};
-        verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultUidArray),
+        final int[] resultAppIdArray = {APP_ID_A, APP_ID_B};
+        final float[] resultThresholdArray = {THRESHOLD_A, THRESHOLD_B};
+        verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultAppIdArray),
                 eq(resultThresholdArray));
     }
 
@@ -110,9 +100,9 @@
         final String property = PKG_A + "," + PKG_B + ":" + THRESHOLD_B;
         mSmallAreaDetectionController.updateAllowlist(property);
 
-        final int[] resultUidArray = {UID_B_1, UID_B_2};
-        final float[] resultThresholdArray = {THRESHOLD_B, THRESHOLD_B};
-        verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultUidArray),
+        final int[] resultAppIdArray = {APP_ID_B};
+        final float[] resultThresholdArray = {THRESHOLD_B};
+        verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultAppIdArray),
                 eq(resultThresholdArray));
     }
 
@@ -122,9 +112,9 @@
                 PKG_A + ":" + THRESHOLD_A + "," + PKG_NOT_INSTALLED + ":" + THRESHOLD_B;
         mSmallAreaDetectionController.updateAllowlist(property);
 
-        final int[] resultUidArray = {UID_A_1, UID_A_2};
-        final float[] resultThresholdArray = {THRESHOLD_A, THRESHOLD_A};
-        verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultUidArray),
+        final int[] resultAppIdArray = {APP_ID_A};
+        final float[] resultThresholdArray = {THRESHOLD_A};
+        verify(mSmallAreaDetectionController).updateSmallAreaDetection(eq(resultAppIdArray),
                 eq(resultThresholdArray));
     }