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

Commit 88c1665d authored by Long Ling's avatar Long Ling Committed by Automerger Merge Worker
Browse files

Limit refresh rates if skin temperature is high am: 7e783bb0

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15911112

Change-Id: Ifd8bb967063b918b4661da3d44d9ceb67c2e8abc
parents 62681b5f 7e783bb0
Loading
Loading
Loading
Loading
+71 −4
Original line number Original line Diff line number Diff line
@@ -36,9 +36,14 @@ import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.net.Uri;
import android.net.Uri;
import android.os.Handler;
import android.os.Handler;
import android.os.IThermalEventListener;
import android.os.IThermalService;
import android.os.Looper;
import android.os.Looper;
import android.os.Message;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemClock;
import android.os.Temperature;
import android.os.UserHandle;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings;
@@ -108,6 +113,7 @@ public class DisplayModeDirector {
    private final UdfpsObserver mUdfpsObserver;
    private final UdfpsObserver mUdfpsObserver;
    private final SensorObserver mSensorObserver;
    private final SensorObserver mSensorObserver;
    private final HbmObserver mHbmObserver;
    private final HbmObserver mHbmObserver;
    private final SkinThermalStatusObserver mSkinThermalStatusObserver;
    private final DeviceConfigInterface mDeviceConfig;
    private final DeviceConfigInterface mDeviceConfig;
    private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
    private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;


@@ -156,6 +162,7 @@ public class DisplayModeDirector {
        };
        };
        mSensorObserver = new SensorObserver(context, ballotBox, injector);
        mSensorObserver = new SensorObserver(context, ballotBox, injector);
        mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
        mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
        mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox);
        mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
        mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
        mDeviceConfig = injector.getDeviceConfig();
        mDeviceConfig = injector.getDeviceConfig();
        mAlwaysRespectAppRequest = false;
        mAlwaysRespectAppRequest = false;
@@ -174,6 +181,7 @@ public class DisplayModeDirector {
        mBrightnessObserver.observe(sensorManager);
        mBrightnessObserver.observe(sensorManager);
        mSensorObserver.observe();
        mSensorObserver.observe();
        mHbmObserver.observe();
        mHbmObserver.observe();
        mSkinThermalStatusObserver.observe();
        synchronized (mLock) {
        synchronized (mLock) {
            // We may have a listener already registered before the call to start, so go ahead and
            // We may have a listener already registered before the call to start, so go ahead and
            // notify them to pick up our newly initialized state.
            // notify them to pick up our newly initialized state.
@@ -606,6 +614,7 @@ public class DisplayModeDirector {
            mUdfpsObserver.dumpLocked(pw);
            mUdfpsObserver.dumpLocked(pw);
            mSensorObserver.dumpLocked(pw);
            mSensorObserver.dumpLocked(pw);
            mHbmObserver.dumpLocked(pw);
            mHbmObserver.dumpLocked(pw);
            mSkinThermalStatusObserver.dumpLocked(pw);
        }
        }
    }
    }


@@ -714,7 +723,6 @@ public class DisplayModeDirector {
        return mUdfpsObserver;
        return mUdfpsObserver;
    }
    }



    @VisibleForTesting
    @VisibleForTesting
    DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
    DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
            float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
            float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
@@ -950,16 +958,19 @@ public class DisplayModeDirector {
        // user seeing the display flickering when the switches occur.
        // user seeing the display flickering when the switches occur.
        public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
        public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;


        // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
        public static final int PRIORITY_SKIN_TEMPERATURE = 9;

        // High-brightness-mode may need a specific range of refresh-rates to function properly.
        // High-brightness-mode may need a specific range of refresh-rates to function properly.
        public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9;
        public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 10;


        // The proximity sensor needs the refresh rate to be locked in order to function, so this is
        // The proximity sensor needs the refresh rate to be locked in order to function, so this is
        // set to a high priority.
        // set to a high priority.
        public static final int PRIORITY_PROXIMITY = 10;
        public static final int PRIORITY_PROXIMITY = 11;


        // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
        // The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
        // to function, so this needs to be the highest priority of all votes.
        // to function, so this needs to be the highest priority of all votes.
        public static final int PRIORITY_UDFPS = 11;
        public static final int PRIORITY_UDFPS = 12;


        // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
        // Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
        // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
        // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
@@ -1054,6 +1065,8 @@ public class DisplayModeDirector {
                    return "PRIORITY_PROXIMITY";
                    return "PRIORITY_PROXIMITY";
                case PRIORITY_LOW_POWER_MODE:
                case PRIORITY_LOW_POWER_MODE:
                    return "PRIORITY_LOW_POWER_MODE";
                    return "PRIORITY_LOW_POWER_MODE";
                case PRIORITY_SKIN_TEMPERATURE:
                    return "PRIORITY_SKIN_TEMPERATURE";
                case PRIORITY_UDFPS:
                case PRIORITY_UDFPS:
                    return "PRIORITY_UDFPS";
                    return "PRIORITY_UDFPS";
                case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
                case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
@@ -2309,6 +2322,52 @@ public class DisplayModeDirector {
        }
        }
    }
    }


    private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
        private final BallotBox mBallotBox;
        private final Injector mInjector;

        private @Temperature.ThrottlingStatus int mStatus = -1;

        SkinThermalStatusObserver(Injector injector, BallotBox ballotBox) {
            mInjector = injector;
            mBallotBox = ballotBox;
        }

        @Override
        public void notifyThrottling(Temperature temp) {
            mStatus = temp.getStatus();
            if (mLoggingEnabled) {
                Slog.d(TAG, "New thermal throttling status "
                        + ", current thermal status = " + mStatus);
            }
            final Vote vote;
            if (mStatus >= Temperature.THROTTLING_CRITICAL) {
                vote = Vote.forRefreshRates(0f, 60f);
            } else {
                vote = null;
            }
            mBallotBox.vote(GLOBAL_ID, Vote.PRIORITY_SKIN_TEMPERATURE, vote);
        }

        public void observe() {
            IThermalService thermalService = mInjector.getThermalService();
            if (thermalService == null) {
                Slog.w(TAG, "Could not observe thermal status. Service not available");
                return;
            }
            try {
                thermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN);
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to register thermal status listener", e);
            }
        }

        void dumpLocked(PrintWriter writer) {
            writer.println("  SkinThermalStatusObserver:");
            writer.println("    mStatus: " + mStatus);
        }
    }

    private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
    private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
        public DeviceConfigDisplaySettings() {
        public DeviceConfigDisplaySettings() {
        }
        }
@@ -2470,6 +2529,8 @@ public class DisplayModeDirector {
        BrightnessInfo getBrightnessInfo(int displayId);
        BrightnessInfo getBrightnessInfo(int displayId);


        boolean isDozeState(Display d);
        boolean isDozeState(Display d);

        IThermalService getThermalService();
    }
    }


    @VisibleForTesting
    @VisibleForTesting
@@ -2530,6 +2591,12 @@ public class DisplayModeDirector {
            return Display.isDozeState(d.getState());
            return Display.isDozeState(d.getState());
        }
        }


        @Override
        public IThermalService getThermalService() {
            return IThermalService.Stub.asInterface(
                    ServiceManager.getService(Context.THERMAL_SERVICE));
        }

        private DisplayManager getDisplayManager() {
        private DisplayManager getDisplayManager() {
            if (mDisplayManager == null) {
            if (mDisplayManager == null) {
                mDisplayManager = mContext.getSystemService(DisplayManager.class);
                mDisplayManager = mContext.getSystemService(DisplayManager.class);
+52 −0
Original line number Original line Diff line number Diff line
@@ -56,7 +56,11 @@ import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Handler;
import android.os.Handler;
import android.os.IThermalEventListener;
import android.os.IThermalService;
import android.os.Looper;
import android.os.Looper;
import android.os.RemoteException;
import android.os.Temperature;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
import android.test.mock.MockContentResolver;
@@ -116,6 +120,8 @@ public class DisplayModeDirectorTest {
    public SensorManagerInternal mSensorManagerInternalMock;
    public SensorManagerInternal mSensorManagerInternalMock;
    @Mock
    @Mock
    public DisplayManagerInternal mDisplayManagerInternalMock;
    public DisplayManagerInternal mDisplayManagerInternalMock;
    @Mock
    public IThermalService mThermalServiceMock;


    @Before
    @Before
    public void setUp() throws Exception {
    public void setUp() throws Exception {
@@ -124,6 +130,7 @@ public class DisplayModeDirectorTest {
        final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
        final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
        when(mContext.getContentResolver()).thenReturn(resolver);
        when(mContext.getContentResolver()).thenReturn(resolver);
        mInjector = spy(new FakesInjector());
        mInjector = spy(new FakesInjector());
        when(mInjector.getThermalService()).thenReturn(mThermalServiceMock);
        mHandler = new Handler(Looper.getMainLooper());
        mHandler = new Handler(Looper.getMainLooper());


        LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
        LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
@@ -1547,12 +1554,52 @@ public class DisplayModeDirectorTest {
        assertNull(vote);
        assertNull(vote);
    }
    }


    @Test
    public void testSkinTemperature() throws RemoteException {
        DisplayModeDirector director =
                createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
        director.start(createMockSensorManager());

        ArgumentCaptor<IThermalEventListener> thermalEventListener =
                ArgumentCaptor.forClass(IThermalEventListener.class);

        verify(mThermalServiceMock).registerThermalEventListenerWithType(
            thermalEventListener.capture(), eq(Temperature.TYPE_SKIN));
        final IThermalEventListener listener = thermalEventListener.getValue();

        // Verify that there is no skin temperature vote initially.
        Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
        assertNull(vote);

        // Set the skin temperature to critical and verify that we added a vote.
        listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL));
        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
        assertVoteForRefreshRateRange(vote, 0f, 60.f);

        // Set the skin temperature to severe and verify that the vote is gone.
        listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_SEVERE));
        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
        assertNull(vote);
    }

    private Temperature getSkinTemp(@Temperature.ThrottlingStatus int status) {
        return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status);
    }

    private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
    private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
        assertThat(vote).isNotNull();
        assertThat(vote).isNotNull();
        final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
        final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
        assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
        assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
    }
    }


    private void assertVoteForRefreshRateRange(
            Vote vote, float refreshRateLow, float refreshRateHigh) {
        assertThat(vote).isNotNull();
        final RefreshRateRange expectedRange =
                new RefreshRateRange(refreshRateLow, refreshRateHigh);
        assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
    }

    public static class FakeDeviceConfig extends FakeDeviceConfigInterface {
    public static class FakeDeviceConfig extends FakeDeviceConfigInterface {
        @Override
        @Override
        public String getProperty(String namespace, String name) {
        public String getProperty(String namespace, String name) {
@@ -1748,6 +1795,11 @@ public class DisplayModeDirectorTest {
            return false;
            return false;
        }
        }


        @Override
        public IThermalService getThermalService() {
            return null;
        }

        void notifyPeakRefreshRateChanged() {
        void notifyPeakRefreshRateChanged() {
            if (mPeakRefreshRateObserver != null) {
            if (mPeakRefreshRateObserver != null) {
                mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
                mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,