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

Commit a2276a43 authored by Long Ling's avatar Long Ling Committed by Android (Google) Code Review
Browse files

Merge "Limit refresh rates if skin temperature is high" into sc-qpr1-dev

parents 9a9516dc f1b1ef1c
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*/,