Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 68ef5685 authored by Tony Huang's avatar Tony Huang Committed by Saul Su
Browse files

VRR: Allowlist for small area detection

Add a allowlist mechanism for suppress frame rate when small area.

In this patch, we will keep a array list to record pkg name which
want to apply the small area detection for suppressing frame rate
and its threshold value of small area ratio.

In framework, we will check all pkg uid by pkg name from
package manager and call a native function which include uid and
threshold.

In SF native, it get the threshold of uid and we will save them
as a map, and it will used to check should it apply small area
detection and what threshold it should use.

Bug: 281720315
Bug: 283055450
Test: atest SmallAreaDetectionMappingsTest
Test: atest LayerHistoryTest
Change-Id: Iacb4ad25f3476d047b08b9f0c1f46e85597c6c68
parent 15e79656
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -5377,6 +5377,13 @@
         of known compatibility issues. -->
    <string-array name="config_highRefreshRateBlacklist"></string-array>

    <!-- The list of packages to automatically opt in to refresh rate suppressing by small area
    detection. Format of this array should be packageName:threshold and threshold value should
     be between 0 to 1-->
    <string-array name="config_smallAreaDetectionAllowlist" translatable="false">
        <!-- Add packages:threshold here -->
    </string-array>

    <!-- The list of packages to force slowJpegMode for Apps using Camera API1 -->
    <string-array name="config_forceSlowJpegModeList" translatable="false">
        <!-- Add packages here -->
+2 −0
Original line number Diff line number Diff line
@@ -4239,6 +4239,8 @@
  <java-symbol type="array" name="config_highRefreshRateBlacklist" />
  <java-symbol type="array" name="config_forceSlowJpegModeList" />

  <java-symbol type="array" name="config_smallAreaDetectionAllowlist" />

  <java-symbol type="layout" name="chooser_dialog" />
  <java-symbol type="layout" name="chooser_dialog_item" />
  <java-symbol type="drawable" name="chooser_dialog_background" />
+7 −0
Original line number Diff line number Diff line
@@ -468,6 +468,8 @@ public final class DisplayManagerService extends SystemService {
    private SensorManager mSensorManager;
    private BrightnessTracker mBrightnessTracker;

    private SmallAreaDetectionController mSmallAreaDetectionController;


    // Whether minimal post processing is allowed by the user.
    @GuardedBy("mSyncRoot")
@@ -731,6 +733,8 @@ public final class DisplayManagerService extends SystemService {
        filter.addAction(Intent.ACTION_DOCK_EVENT);

        mContext.registerReceiver(mIdleModeReceiver, filter);

        mSmallAreaDetectionController = SmallAreaDetectionController.create(mContext);
    }

    @VisibleForTesting
@@ -3046,6 +3050,9 @@ public final class DisplayManagerService extends SystemService {
        pw.println();
        mDisplayModeDirector.dump(pw);
        mBrightnessSynchronizer.dump(pw);
        if (mSmallAreaDetectionController != null) {
            mSmallAreaDetectionController.dump(pw);
        }
    }

    private static float[] getFloatArray(TypedArray array) {
+177 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.server.display;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
import android.provider.DeviceConfig;
import android.provider.DeviceConfigInterface;
import android.util.ArrayMap;
import android.util.SparseArray;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;

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);

    // TODO(b/281720315): Move this to DeviceConfig once server side ready.
    private static final String KEY_SMALL_AREA_DETECTION_ALLOWLIST =
            "small_area_detection_allowlist";

    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 =
                new SmallAreaDetectionController(context, DeviceConfigInterface.REAL);
        final String property = DeviceConfigInterface.REAL.getProperty(
                DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_SMALL_AREA_DETECTION_ALLOWLIST);
        controller.updateAllowlist(property);
        return controller;
    }

    @VisibleForTesting
    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());
        mPackageManager.getPackageList(new PackageReceiver());
    }

    @VisibleForTesting
    void updateAllowlist(@Nullable String property) {
        synchronized (mLock) {
            mAllowPkgMap.clear();
            if (property != null) {
                final String[] mapStrings = property.split(",");
                for (String mapString : mapStrings) putToAllowlist(mapString);
            } else {
                final String[] defaultMapStrings = mContext.getResources()
                        .getStringArray(R.array.config_smallAreaDetectionAllowlist);
                for (String defaultMapString : defaultMapStrings) putToAllowlist(defaultMapString);
            }
            updateSmallAreaDetection();
        }
    }

    @GuardedBy("mLock")
    private void putToAllowlist(String rowData) {
        // Data format: package:threshold - e.g. "com.abc.music:0.05"
        final String[] items = rowData.split(":");
        if (items.length == 2) {
            try {
                final String pkg = items[0];
                final float threshold = Float.valueOf(items[1]);
                mAllowPkgMap.put(pkg, threshold);
            } catch (Exception e) {
                // Just skip if items[1] - the threshold is not parsable number
            }
        }
    }

    @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);
        }

        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);
        }
        updateSmallAreaDetection(uids, thresholds);
    }

    @VisibleForTesting
    void updateSmallAreaDetection(int[] uids, float[] thresholds) {
        nativeUpdateSmallAreaDetection(uids, thresholds);
    }

    void setSmallAreaDetectionThreshold(int uid, float threshold) {
        nativeSetSmallAreaDetectionThreshold(uid, threshold);
    }

    void dump(PrintWriter pw) {
        pw.println("Small area detection allowlist");
        pw.println("  Packages:");
        synchronized (mLock) {
            for (String pkg : mAllowPkgMap.keySet()) {
                pw.println("    " + pkg + " threshold = " + mAllowPkgMap.get(pkg));
            }
            pw.println("  mUserIds=" + Arrays.toString(mUserIds));
        }
    }

    private class OnPropertiesChangedListener implements DeviceConfig.OnPropertiesChangedListener {
        public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
            if (properties.getKeyset().contains(KEY_SMALL_AREA_DETECTION_ALLOWLIST)) {
                updateAllowlist(
                        properties.getString(KEY_SMALL_AREA_DETECTION_ALLOWLIST, null /*default*/));
            }
        }
    }

    private final class PackageReceiver implements PackageManagerInternal.PackageListObserver {
        @Override
        public void onPackageAdded(@NonNull String packageName, int uid) {
            synchronized (mLock) {
                if (mAllowPkgMap.containsKey(packageName)) {
                    setSmallAreaDetectionThreshold(uid, mAllowPkgMap.get(packageName));
                }
            }
        }
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ cc_library_static {
        "com_android_server_companion_virtual_InputController.cpp",
        "com_android_server_devicepolicy_CryptoTestHelper.cpp",
        "com_android_server_display_DisplayControl.cpp",
        "com_android_server_display_SmallAreaDetectionController.cpp",
        "com_android_server_connectivity_Vpn.cpp",
        "com_android_server_gpu_GpuService.cpp",
        "com_android_server_HardwarePropertiesManagerService.cpp",
Loading