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

Commit 6d3c5ab3 authored by Long Ling's avatar Long Ling Committed by Automerger Merge Worker
Browse files

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

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

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

@@ -156,6 +162,7 @@ public class DisplayModeDirector {
        };
        mSensorObserver = new SensorObserver(context, ballotBox, injector);
        mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
        mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox);
        mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
        mDeviceConfig = injector.getDeviceConfig();
        mAlwaysRespectAppRequest = false;
@@ -174,6 +181,7 @@ public class DisplayModeDirector {
        mBrightnessObserver.observe(sensorManager);
        mSensorObserver.observe();
        mHbmObserver.observe();
        mSkinThermalStatusObserver.observe();
        synchronized (mLock) {
            // 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.
@@ -606,6 +614,7 @@ public class DisplayModeDirector {
            mUdfpsObserver.dumpLocked(pw);
            mSensorObserver.dumpLocked(pw);
            mHbmObserver.dumpLocked(pw);
            mSkinThermalStatusObserver.dumpLocked(pw);
        }
    }

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


    @VisibleForTesting
    DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
            float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
@@ -950,16 +958,19 @@ public class DisplayModeDirector {
        // user seeing the display flickering when the switches occur.
        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.
        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
        // 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
        // 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
        // APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
@@ -1054,6 +1065,8 @@ public class DisplayModeDirector {
                    return "PRIORITY_PROXIMITY";
                case PRIORITY_LOW_POWER_MODE:
                    return "PRIORITY_LOW_POWER_MODE";
                case PRIORITY_SKIN_TEMPERATURE:
                    return "PRIORITY_SKIN_TEMPERATURE";
                case PRIORITY_UDFPS:
                    return "PRIORITY_UDFPS";
                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 {
        public DeviceConfigDisplaySettings() {
        }
@@ -2470,6 +2529,8 @@ public class DisplayModeDirector {
        BrightnessInfo getBrightnessInfo(int displayId);

        boolean isDozeState(Display d);

        IThermalService getThermalService();
    }

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

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

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

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

        LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
@@ -1547,12 +1554,52 @@ public class DisplayModeDirectorTest {
        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) {
        assertThat(vote).isNotNull();
        final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
        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 {
        @Override
        public String getProperty(String namespace, String name) {
@@ -1748,6 +1795,11 @@ public class DisplayModeDirectorTest {
            return false;
        }

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

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