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

Commit a74a8643 authored by Ana Krulec's avatar Ana Krulec Committed by Steven Thomas
Browse files

Switch from allowed display configs to refresh rate range

This completes the recent work to switch from a list of allowed display
configs to a default config + min/max frame rate.

Bug: 142507213

Test: Ran on a device with refresh rate switching, confirmed expected
      60/90 switching behavior when touching the screen.
Test: Launched Google Maps on a device with 60/90 switching, confirmed
      the device stays at 60fps.
Test: Checked dumpsys output, confirmed new display config specs
      formatting looks good.
Test: Ran on a device with refresh rate switching disallowed via the
      ro.surface_flinger.refresh_rate_switching sysprop, and confirmed
      we don't do refresh rate switching.
Test: Ran on a device that doesn't support refresh rate switching, and
      confirmed normal behavior.
Test: Tested surface flinger's display config back door, confirmed it
      still works.
Test: Inspected log output, made sure there's nothing weird.
Test: Ran unit tests for DisplayModeDirector, LocalDisplayAdapter, and
      RefreshRateConfigs.
Test: atest FrameworksServicesTests
Test: atest FrameworksMockingServicesTests
Test: adb shell /data/nativetest64/libgui_test/libgui_test
Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest

Change-Id: If1417dbb5723df3386db15b2d968cfd164c2615b
parent b03866ee
Loading
Loading
Loading
Loading
+54 −41
Original line number Diff line number Diff line
@@ -158,11 +158,10 @@ public final class SurfaceControl implements Parcelable {
            IBinder displayToken, long numFrames, long timestamp);
    private static native int nativeGetActiveConfig(IBinder displayToken);
    private static native boolean nativeSetActiveConfig(IBinder displayToken, int id);
    private static native boolean nativeSetAllowedDisplayConfigs(IBinder displayToken,
                                                                 int[] allowedConfigs);
    private static native int[] nativeGetAllowedDisplayConfigs(IBinder displayToken);
    private static native boolean nativeSetDesiredDisplayConfigSpecs(IBinder displayToken,
            SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs);
    private static native SurfaceControl.DesiredDisplayConfigSpecs
            nativeGetDesiredDisplayConfigSpecs(IBinder displayToken);
    private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
    private static native SurfaceControl.DisplayPrimaries nativeGetDisplayNativePrimaries(
            IBinder displayToken);
@@ -1479,71 +1478,85 @@ public final class SurfaceControl implements Parcelable {
    }

    /**
     * Contains information about desired display configuration.
     *
     * @hide
     */
    public static boolean setAllowedDisplayConfigs(IBinder displayToken, int[] allowedConfigs) {
        if (displayToken == null) {
            throw new IllegalArgumentException("displayToken must not be null");
    public static final class DesiredDisplayConfigSpecs {
        public int defaultConfig;
        public float minRefreshRate;
        public float maxRefreshRate;

        public DesiredDisplayConfigSpecs() {}

        public DesiredDisplayConfigSpecs(DesiredDisplayConfigSpecs other) {
            copyFrom(other);
        }
        if (allowedConfigs == null) {
            throw new IllegalArgumentException("allowedConfigs must not be null");

        public DesiredDisplayConfigSpecs(
                int defaultConfig, float minRefreshRate, float maxRefreshRate) {
            this.defaultConfig = defaultConfig;
            this.minRefreshRate = minRefreshRate;
            this.maxRefreshRate = maxRefreshRate;
        }

        return nativeSetAllowedDisplayConfigs(displayToken, allowedConfigs);
        @Override
        public boolean equals(Object o) {
            return o instanceof DesiredDisplayConfigSpecs && equals((DesiredDisplayConfigSpecs) o);
        }

        /**
     * @hide
         * Tests for equality.
         */
    public static int[] getAllowedDisplayConfigs(IBinder displayToken) {
        if (displayToken == null) {
            throw new IllegalArgumentException("displayToken must not be null");
        }
        return nativeGetAllowedDisplayConfigs(displayToken);
        public boolean equals(DesiredDisplayConfigSpecs other) {
            return other != null && defaultConfig == other.defaultConfig
                    && minRefreshRate == other.minRefreshRate
                    && maxRefreshRate == other.maxRefreshRate;
        }

    /**
     * Contains information about desired display configuration.
     *
     * @hide
     */
    public static final class DesiredDisplayConfigSpecs {
        /**
         * @hide
         */
        public int mDefaultModeId;
        @Override
        public int hashCode() {
            return 0; // don't care
        }

        /**
         * @hide
         * Copies the supplied object's values to this object.
         */
        public float mMinRefreshRate;
        public void copyFrom(DesiredDisplayConfigSpecs other) {
            defaultConfig = other.defaultConfig;
            minRefreshRate = other.minRefreshRate;
            maxRefreshRate = other.maxRefreshRate;
        }

        /**
         * @hide
         */
        public float mMaxRefreshRate;
        @Override
        public String toString() {
            return String.format("defaultConfig=%d min=%.0f max=%.0f", defaultConfig,
                    minRefreshRate, maxRefreshRate);
        }
    }

    /**
     * @hide
     */
        public DesiredDisplayConfigSpecs(
                int defaultModeId, float minRefreshRate, float maxRefreshRate) {
            mDefaultModeId = defaultModeId;
            mMinRefreshRate = minRefreshRate;
            mMaxRefreshRate = maxRefreshRate;
    public static boolean setDesiredDisplayConfigSpecs(IBinder displayToken,
            SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs) {
        if (displayToken == null) {
            throw new IllegalArgumentException("displayToken must not be null");
        }

        return nativeSetDesiredDisplayConfigSpecs(displayToken, desiredDisplayConfigSpecs);
    }

    /**
     * @hide
     */
    public static boolean setDesiredDisplayConfigSpecs(IBinder displayToken,
            SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs) {
    public static SurfaceControl.DesiredDisplayConfigSpecs getDesiredDisplayConfigSpecs(
            IBinder displayToken) {
        if (displayToken == null) {
            throw new IllegalArgumentException("displayToken must not be null");
        }

        return nativeSetDesiredDisplayConfigSpecs(displayToken, desiredDisplayConfigSpecs);
        return nativeGetDesiredDisplayConfigSpecs(displayToken);
    }

    /**
+28 −54
Original line number Diff line number Diff line
@@ -141,7 +141,7 @@ static struct {
static struct {
    jclass clazz;
    jmethodID ctor;
    jfieldID defaultModeId;
    jfieldID defaultConfig;
    jfieldID minRefreshRate;
    jfieldID maxRefreshRate;
} gDesiredDisplayConfigSpecsClassInfo;
@@ -776,65 +776,40 @@ static jobjectArray nativeGetDisplayConfigs(JNIEnv* env, jclass clazz,
    return configArray;
}

static jboolean nativeSetAllowedDisplayConfigs(JNIEnv* env, jclass clazz,
        jobject tokenObj, jintArray configArray) {
    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
    if (token == nullptr) return JNI_FALSE;

    std::vector<int32_t> allowedConfigs;
    jsize configArraySize = env->GetArrayLength(configArray);
    allowedConfigs.reserve(configArraySize);

    jint* configArrayElements = env->GetIntArrayElements(configArray, 0);
    for (int i = 0; i < configArraySize; i++) {
        allowedConfigs.push_back(configArrayElements[i]);
    }
    env->ReleaseIntArrayElements(configArray, configArrayElements, 0);

    size_t result = SurfaceComposerClient::setAllowedDisplayConfigs(token, allowedConfigs);
    return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}

static jintArray nativeGetAllowedDisplayConfigs(JNIEnv* env, jclass clazz, jobject tokenObj) {
    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
    if (token == nullptr) return JNI_FALSE;

    std::vector<int32_t> allowedConfigs;
    size_t result = SurfaceComposerClient::getAllowedDisplayConfigs(token, &allowedConfigs);
    if (result != NO_ERROR) {
        return nullptr;
    }

    jintArray allowedConfigsArray = env->NewIntArray(allowedConfigs.size());
    if (allowedConfigsArray == nullptr) {
        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
        return nullptr;
    }
    jint* allowedConfigsArrayValues = env->GetIntArrayElements(allowedConfigsArray, 0);
    for (size_t i = 0; i < allowedConfigs.size(); i++) {
        allowedConfigsArrayValues[i] = static_cast<jint>(allowedConfigs[i]);
    }
    env->ReleaseIntArrayElements(allowedConfigsArray, allowedConfigsArrayValues, 0);
    return allowedConfigsArray;
}

static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, jobject tokenObj,
                                                   jobject desiredDisplayConfigSpecs) {
    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
    if (token == nullptr) return JNI_FALSE;

    jint defaultModeId = env->GetIntField(desiredDisplayConfigSpecs,
                                          gDesiredDisplayConfigSpecsClassInfo.defaultModeId);
    jint defaultConfig = env->GetIntField(desiredDisplayConfigSpecs,
                                          gDesiredDisplayConfigSpecsClassInfo.defaultConfig);
    jfloat minRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
                                               gDesiredDisplayConfigSpecsClassInfo.minRefreshRate);
    jfloat maxRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
                                               gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate);

    size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(
            token, defaultModeId, minRefreshRate, maxRefreshRate);
            token, defaultConfig, minRefreshRate, maxRefreshRate);
    return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}

static jobject nativeGetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, jobject tokenObj) {
    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
    if (token == nullptr) return nullptr;

    int32_t defaultConfig;
    float minRefreshRate;
    float maxRefreshRate;
    if (SurfaceComposerClient::getDesiredDisplayConfigSpecs(token, &defaultConfig, &minRefreshRate,
                                                            &maxRefreshRate) != NO_ERROR) {
        return nullptr;
    }

    return env->NewObject(gDesiredDisplayConfigSpecsClassInfo.clazz,
                          gDesiredDisplayConfigSpecsClassInfo.ctor, defaultConfig, minRefreshRate,
                          maxRefreshRate);
}

static jint nativeGetActiveConfig(JNIEnv* env, jclass clazz, jobject tokenObj) {
    sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
    if (token == NULL) return -1;
@@ -1415,13 +1390,12 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
            (void*)nativeGetActiveConfig },
    {"nativeSetActiveConfig", "(Landroid/os/IBinder;I)Z",
            (void*)nativeSetActiveConfig },
    {"nativeSetAllowedDisplayConfigs", "(Landroid/os/IBinder;[I)Z",
            (void*)nativeSetAllowedDisplayConfigs },
    {"nativeGetAllowedDisplayConfigs", "(Landroid/os/IBinder;)[I",
            (void*)nativeGetAllowedDisplayConfigs },
    {"nativeSetDesiredDisplayConfigSpecs",
            "(Landroid/os/IBinder;Landroid/view/SurfaceControl$DesiredDisplayConfigSpecs;)Z",
            (void*)nativeSetDesiredDisplayConfigSpecs },
    {"nativeGetDesiredDisplayConfigSpecs",
            "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DesiredDisplayConfigSpecs;",
            (void*)nativeGetDesiredDisplayConfigSpecs },
    {"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
            (void*)nativeGetDisplayColorModes},
    {"nativeGetDisplayNativePrimaries", "(Landroid/os/IBinder;)Landroid/view/SurfaceControl$DisplayPrimaries;",
@@ -1605,12 +1579,12 @@ int register_android_view_SurfaceControl(JNIEnv* env)
            MakeGlobalRefOrDie(env, desiredDisplayConfigSpecsClazz);
    gDesiredDisplayConfigSpecsClassInfo.ctor =
            GetMethodIDOrDie(env, gDesiredDisplayConfigSpecsClassInfo.clazz, "<init>", "(IFF)V");
    gDesiredDisplayConfigSpecsClassInfo.defaultModeId =
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "mDefaultModeId", "I");
    gDesiredDisplayConfigSpecsClassInfo.defaultConfig =
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "defaultConfig", "I");
    gDesiredDisplayConfigSpecsClassInfo.minRefreshRate =
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "mMinRefreshRate", "F");
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "minRefreshRate", "F");
    gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate =
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "mMaxRefreshRate", "F");
            GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "maxRefreshRate", "F");

    return err;
}
+4 −9
Original line number Diff line number Diff line
@@ -138,18 +138,13 @@ abstract class DisplayDevice {
    }

    /**
     * Sets the refresh ranges, and display modes that the system is allowed to switch between.
     * Display modes are roughly ordered by preference.
     * Sets the display mode specs.
     *
     * Not all display devices will automatically switch between modes, so it's important that the
     * most-desired modes are at the beginning of the allowed array.
     *
     * @param defaultModeId is used, if the device does not support multiple refresh
     * rates, and to navigate other parameters.
     * default modeId is set correctly.
     */
    public void setDesiredDisplayConfigSpecs(int defaultModeId, float minRefreshRate,
            float maxRefreshRate, int[] modes) {
    }
    public void setDesiredDisplayModeSpecsLocked(
            DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) {}

    /**
     * Sets the requested color mode.
+18 −11
Original line number Diff line number Diff line
@@ -431,7 +431,8 @@ public final class DisplayManagerService extends SystemService {
            recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY));
        }

        mDisplayModeDirector.setDisplayModeListener(new AllowedDisplayModeObserver());
        mDisplayModeDirector.setDesiredDisplayModeSpecsListener(
                new DesiredDisplayModeSpecsObserver());
        mDisplayModeDirector.start(mSensorManager);

        mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
@@ -1347,19 +1348,24 @@ public final class DisplayManagerService extends SystemService {
        return SurfaceControl.getDisplayedContentSample(token, maxFrames, timestamp);
    }

    private void onAllowedDisplayModesChangedInternal() {
    private void onDesiredDisplayModeSpecsChangedInternal() {
        boolean changed = false;
        synchronized (mSyncRoot) {
            final int count = mLogicalDisplays.size();
            for (int i = 0; i < count; i++) {
                LogicalDisplay display = mLogicalDisplays.valueAt(i);
                int displayId = mLogicalDisplays.keyAt(i);
                int[] allowedModes = mDisplayModeDirector.getAllowedModes(displayId);
                // Note that order is important here since not all display devices are capable of
                // automatically switching, so we do actually want to check for equality and not
                // just equivalent contents (regardless of order).
                if (!Arrays.equals(allowedModes, display.getAllowedDisplayModesLocked())) {
                    display.setAllowedDisplayModesLocked(allowedModes);
                DisplayModeDirector.DesiredDisplayModeSpecs desiredDisplayModeSpecs =
                        mDisplayModeDirector.getDesiredDisplayModeSpecs(displayId);
                DisplayModeDirector.DesiredDisplayModeSpecs existingDesiredDisplayModeSpecs =
                        display.getDesiredDisplayModeSpecsLocked();
                if (DEBUG) {
                    Slog.i(TAG,
                            "Comparing display specs: " + desiredDisplayModeSpecs
                                    + ", existing: " + existingDesiredDisplayModeSpecs);
                }
                if (!desiredDisplayModeSpecs.equals(existingDesiredDisplayModeSpecs)) {
                    display.setDesiredDisplayModeSpecsLocked(desiredDisplayModeSpecs);
                    changed = true;
                }
            }
@@ -2510,9 +2516,10 @@ public final class DisplayManagerService extends SystemService {

    }

    class AllowedDisplayModeObserver implements DisplayModeDirector.DisplayModeListener {
        public void onAllowedDisplayModesChanged() {
            onAllowedDisplayModesChangedInternal();
    class DesiredDisplayModeSpecsObserver
            implements DisplayModeDirector.DesiredDisplayModeSpecsListener {
        public void onDesiredDisplayModeSpecsChanged() {
            onDesiredDisplayModeSpecsChangedInternal();
        }
    }
}
+69 −67

File changed.

Preview size limit exceeded, changes collapsed.

Loading