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

Commit 54b9f5fa authored by sashwinbalaji's avatar sashwinbalaji
Browse files

display: brightnessThermalClamper to support sensor based throttling

Update ThermalStatusObserver in thermal clamper to use sensorType and
sensorName passed via displayconfig

If ThermalBrightnessThrottlingData null, default back to SKIN type.

Bug: 279114539
Test: atest BrightnessThermalClamperTest
Test: local build and use emul temp to check display logs
Change-Id: I6471a87bdd5b380445ace33f030809719962c1ba
parent bdd55137
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import com.android.server.display.DisplayDeviceConfig.PowerThrottlingConfigData;
import com.android.server.display.DisplayDeviceConfig.PowerThrottlingData;
import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData;
import com.android.server.display.brightness.BrightnessReason;
import com.android.server.display.config.SensorData;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.display.feature.DisplayManagerFlags;

@@ -336,5 +337,10 @@ public class BrightnessClamperController {
        public float getBrightnessWearBedtimeModeCap() {
            return mDisplayDeviceConfig.getBrightnessCapForWearBedtimeMode();
        }

        @NonNull
        public SensorData getTempSensor() {
            return mDisplayDeviceConfig.getTempSensor();
        }
    }
}
+95 −41
Original line number Diff line number Diff line
@@ -35,8 +35,10 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData;
import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel;
import com.android.server.display.config.SensorData;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.display.utils.DeviceConfigParsingUtils;
import com.android.server.display.utils.SensorUtils;

import java.io.PrintWriter;
import java.util.List;
@@ -49,9 +51,8 @@ class BrightnessThermalClamper extends
        BrightnessClamper<BrightnessThermalClamper.ThermalData> {

    private static final String TAG = "BrightnessThermalClamper";

    @Nullable
    private final IThermalService mThermalService;
    @NonNull
    private final ThermalStatusObserver mThermalStatusObserver;
    @NonNull
    private final DeviceConfigParameterProvider mConfigParameterProvider;
    // data from DeviceConfig, for all displays, for all dataSets
@@ -66,7 +67,6 @@ class BrightnessThermalClamper extends
    // otherwise mDataFromDeviceConfig
    @Nullable
    private ThermalBrightnessThrottlingData mThermalThrottlingDataActive = null;
    private boolean mStarted = false;
    @Nullable
    private String mUniqueDisplayId = null;
    @Nullable
@@ -74,14 +74,6 @@ class BrightnessThermalClamper extends
    @Temperature.ThrottlingStatus
    private int mThrottlingStatus = Temperature.THROTTLING_NONE;

    private final IThermalEventListener mThermalEventListener = new IThermalEventListener.Stub() {
        @Override
        public void notifyThrottling(Temperature temperature) {
            @Temperature.ThrottlingStatus int status = temperature.getStatus();
            mHandler.post(() -> thermalStatusChanged(status));
        }
    };

    private final BiFunction<String, String, ThrottlingLevel> mDataPointMapper = (key, value) -> {
        try {
            int status = DeviceConfigParsingUtils.parseThermalStatus(key);
@@ -105,12 +97,11 @@ class BrightnessThermalClamper extends
    BrightnessThermalClamper(Injector injector, Handler handler,
            ClamperChangeListener listener, ThermalData thermalData) {
        super(handler, listener);
        mThermalService = injector.getThermalService();
        mConfigParameterProvider = injector.getDeviceConfigParameterProvider();
        mThermalStatusObserver = new ThermalStatusObserver(injector, handler);
        mHandler.post(() -> {
            setDisplayData(thermalData);
            loadOverrideData();
            start();
        });

    }
@@ -139,32 +130,19 @@ class BrightnessThermalClamper extends

    @Override
    void stop() {
        if (!mStarted) {
            return;
        }
        try {
            mThermalService.unregisterThermalEventListener(mThermalEventListener);
        } catch (RemoteException e) {
            Slog.e(TAG, "Failed to unregister thermal status listener", e);
        }
        mStarted = false;
        mThermalStatusObserver.stopObserving();
    }

    @Override
    void dump(PrintWriter writer) {
        writer.println("BrightnessThermalClamper:");
        writer.println("  mStarted: " + mStarted);
        if (mThermalService != null) {
            writer.println("  ThermalService available");
        } else {
            writer.println("  ThermalService not available");
        }
        writer.println("  mThrottlingStatus: " + mThrottlingStatus);
        writer.println("  mUniqueDisplayId: " + mUniqueDisplayId);
        writer.println("  mDataId: " + mDataId);
        writer.println("  mDataOverride: " + mThermalThrottlingDataOverride);
        writer.println("  mDataFromDeviceConfig: " + mThermalThrottlingDataFromDeviceConfig);
        writer.println("  mDataActive: " + mThermalThrottlingDataActive);
        mThermalStatusObserver.dump(writer);
        super.dump(writer);
    }

@@ -193,6 +171,7 @@ class BrightnessThermalClamper extends
            Slog.wtf(TAG,
                    "Thermal throttling data is missing for thermalThrottlingDataId=" + mDataId);
        }
        mThermalStatusObserver.registerSensor(data.getTempSensor());
    }

    private void recalculateBrightnessCap() {
@@ -226,22 +205,94 @@ class BrightnessThermalClamper extends
        }
    }

    private void start() {

    private final class ThermalStatusObserver extends IThermalEventListener.Stub {
        private final Injector mInjector;
        private final Handler mHandler;
        private IThermalService mThermalService;
        private boolean mStarted;
        private SensorData mObserverTempSensor;

        ThermalStatusObserver(Injector injector, Handler handler) {
            mInjector = injector;
            mHandler = handler;
            mStarted = false;
        }

        void registerSensor(SensorData tempSensor) {
            if (!mStarted || mObserverTempSensor == null) {
                mObserverTempSensor = tempSensor;
                registerThermalListener();
                return;
            }

            String curType = mObserverTempSensor.type;
            mObserverTempSensor = tempSensor;
            if (curType.equals(tempSensor.type)) {
                Slog.d(TAG, "Thermal status observer already started");
                return;
            }
            stopObserving();
            registerThermalListener();
        }

        void registerThermalListener() {
            mThermalService = mInjector.getThermalService();
            if (mThermalService == null) {
                Slog.e(TAG, "Could not observe thermal status. Service not available");
                return;
            }
            int temperatureType = SensorUtils.getSensorTemperatureType(mObserverTempSensor);
            try {
                // We get a callback immediately upon registering so there's no need to query
                // for the current value.
            mThermalService.registerThermalEventListenerWithType(mThermalEventListener,
                    Temperature.TYPE_SKIN);
                mThermalService.registerThermalEventListenerWithType(this, temperatureType);
                mStarted = true;
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to register thermal status listener", e);
            }
        }

        @Override
        public void notifyThrottling(Temperature temp) {
            Slog.d(TAG, "New thermal throttling status = " + temp.getStatus());
            if (mObserverTempSensor.name != null
                    && !mObserverTempSensor.name.equals(temp.getName())) {
                Slog.i(TAG, "Skipping thermal throttling notification as monitored sensor: "
                            + mObserverTempSensor.name
                            + " != notified sensor: "
                            + temp.getName());
                return;
            }
            @Temperature.ThrottlingStatus int status = temp.getStatus();
            mHandler.post(() -> thermalStatusChanged(status));
        }

        void stopObserving() {
            if (!mStarted) {
                return;
            }
            try {
                mThermalService.unregisterThermalEventListener(this);
                mStarted = false;
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to unregister thermal status listener", e);
            }
            mThermalService = null;
        }

        void dump(PrintWriter writer) {
            writer.println("  ThermalStatusObserver:");
            writer.println("    mStarted: " + mStarted);
            writer.println("    mObserverTempSensor: " + mObserverTempSensor);
            if (mThermalService != null) {
                writer.println("    ThermalService available");
            } else {
                writer.println("    ThermalService not available");
            }
        }
    }

    interface ThermalData {
        @NonNull
        String getUniqueDisplayId();
@@ -251,6 +302,9 @@ class BrightnessThermalClamper extends

        @Nullable
        ThermalBrightnessThrottlingData getThermalBrightnessThrottlingData();

        @NonNull
        SensorData getTempSensor();
    }

    @VisibleForTesting
+75 −16
Original line number Diff line number Diff line
@@ -37,10 +37,14 @@ import com.android.internal.annotations.Keep;
import com.android.server.display.DisplayDeviceConfig;
import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData;
import com.android.server.display.DisplayDeviceConfig.ThermalBrightnessThrottlingData.ThrottlingLevel;
import com.android.server.display.config.SensorData;
import com.android.server.display.feature.DeviceConfigParameterProvider;
import com.android.server.testutils.FakeDeviceConfigInterface;
import com.android.server.testutils.TestHandler;

import junitparams.JUnitParamsRunner;
import junitparams.Parameters;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,9 +54,6 @@ import org.mockito.MockitoAnnotations;

import java.util.List;

import junitparams.JUnitParamsRunner;
import junitparams.Parameters;

@RunWith(JUnitParamsRunner.class)
public class BrightnessThermalClamperTest {

@@ -125,13 +126,13 @@ public class BrightnessThermalClamperTest {
    public void testNotifyThrottlingAfterOnDisplayChange(List<ThrottlingLevel> throttlingLevels,
            @Temperature.ThrottlingStatus int throttlingStatus,
            boolean expectedActive, float expectedBrightness) throws RemoteException {
        IThermalEventListener thermalEventListener = captureThermalEventListener();
        IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
        mClamper.onDisplayChanged(new TestThermalData(throttlingLevels));
        mTestHandler.flush();
        assertFalse(mClamper.isActive());
        assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);

        thermalEventListener.notifyThrottling(createTemperature(throttlingStatus));
        thermalEventListener.notifyThrottling(createSkinTemperature(throttlingStatus));
        mTestHandler.flush();
        assertEquals(expectedActive, mClamper.isActive());
        assertEquals(expectedBrightness, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
@@ -139,11 +140,11 @@ public class BrightnessThermalClamperTest {

    @Test
    @Parameters(method = "testThrottlingData")
    public void testOnDisplayChangeAfterNotifyThrottlng(List<ThrottlingLevel> throttlingLevels,
    public void testOnDisplayChangeAfterNotifyThrottling(List<ThrottlingLevel> throttlingLevels,
            @Temperature.ThrottlingStatus int throttlingStatus,
            boolean expectedActive, float expectedBrightness) throws RemoteException {
        IThermalEventListener thermalEventListener = captureThermalEventListener();
        thermalEventListener.notifyThrottling(createTemperature(throttlingStatus));
        IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
        thermalEventListener.notifyThrottling(createSkinTemperature(throttlingStatus));
        mTestHandler.flush();
        assertFalse(mClamper.isActive());
        assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
@@ -156,8 +157,8 @@ public class BrightnessThermalClamperTest {

    @Test
    public void testOverrideData() throws RemoteException {
        IThermalEventListener thermalEventListener = captureThermalEventListener();
        thermalEventListener.notifyThrottling(createTemperature(Temperature.THROTTLING_SEVERE));
        IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
        thermalEventListener.notifyThrottling(createSkinTemperature(Temperature.THROTTLING_SEVERE));
        mTestHandler.flush();
        assertFalse(mClamper.isActive());
        assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
@@ -183,15 +184,60 @@ public class BrightnessThermalClamperTest {
        assertEquals(0.4f, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
    }

    private IThermalEventListener captureThermalEventListener() throws RemoteException {
    @Test
    public void testDisplaySensorBasedThrottling() throws RemoteException {
        final int severity = PowerManager.THERMAL_STATUS_SEVERE;
        IThermalEventListener thermalEventListener = captureSkinThermalEventListener();
        // Update config to listen to display type sensor.
        final SensorData tempSensor = new SensorData("DISPLAY", "VIRTUAL-SKIN-DISPLAY");
        final TestThermalData thermalData =
                    new TestThermalData(
                        DISPLAY_ID,
                        DisplayDeviceConfig.DEFAULT_ID,
                        List.of(new ThrottlingLevel(severity, 0.5f)),
                        tempSensor);
        mClamper.onDisplayChanged(thermalData);
        mTestHandler.flush();
        verify(mMockThermalService).unregisterThermalEventListener(thermalEventListener);
        thermalEventListener = captureThermalEventListener(Temperature.TYPE_DISPLAY);
        assertFalse(mClamper.isActive());

        // Verify no throttling triggered when any other sensor notification received.
        thermalEventListener.notifyThrottling(createSkinTemperature(severity));
        mTestHandler.flush();
        assertFalse(mClamper.isActive());

        thermalEventListener.notifyThrottling(createDisplayTemperature("OTHER-SENSOR", severity));
        mTestHandler.flush();
        assertFalse(mClamper.isActive());

        assertEquals(PowerManager.BRIGHTNESS_MAX, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);

        // Verify throttling triggered when display sensor of given name throttled.
        thermalEventListener.notifyThrottling(createDisplayTemperature(tempSensor.name, severity));
        mTestHandler.flush();
        assertTrue(mClamper.isActive());
        assertEquals(0.5f, mClamper.getBrightnessCap(), FLOAT_TOLERANCE);
    }

    private IThermalEventListener captureSkinThermalEventListener() throws RemoteException {
        return captureThermalEventListener(Temperature.TYPE_SKIN);
    }

    private IThermalEventListener captureThermalEventListener(int type) throws RemoteException {
        ArgumentCaptor<IThermalEventListener> captor = ArgumentCaptor.forClass(
                IThermalEventListener.class);
        verify(mMockThermalService).registerThermalEventListenerWithType(captor.capture(), eq(
                Temperature.TYPE_SKIN));
                type));
        return captor.getValue();
    }

    private Temperature createTemperature(@Temperature.ThrottlingStatus int status) {
    private Temperature createDisplayTemperature(
                @NonNull String sensorName, @Temperature.ThrottlingStatus int status) {
        return new Temperature(100, Temperature.TYPE_DISPLAY, sensorName, status);
    }

    private Temperature createSkinTemperature(@Temperature.ThrottlingStatus int status) {
        return new Temperature(100, Temperature.TYPE_SKIN, "test_temperature", status);
    }

@@ -217,19 +263,26 @@ public class BrightnessThermalClamperTest {
        private final String mUniqueDisplayId;
        private final String mDataId;
        private final ThermalBrightnessThrottlingData mData;
        private final SensorData mTempSensor;

        private TestThermalData() {
            this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, null);
            this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, null,
                    SensorData.loadTempSensorUnspecifiedConfig());
        }

        private TestThermalData(List<ThrottlingLevel> data) {
            this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, data);
            this(DISPLAY_ID, DisplayDeviceConfig.DEFAULT_ID, data,
                    SensorData.loadTempSensorUnspecifiedConfig());
        }
        private TestThermalData(String uniqueDisplayId, String dataId, List<ThrottlingLevel> data) {

        private TestThermalData(String uniqueDisplayId, String dataId, List<ThrottlingLevel> data,
                    SensorData tempSensor) {
            mUniqueDisplayId = uniqueDisplayId;
            mDataId = dataId;
            mData = ThermalBrightnessThrottlingData.create(data);
            mTempSensor = tempSensor;
        }

        @NonNull
        @Override
        public String getUniqueDisplayId() {
@@ -247,5 +300,11 @@ public class BrightnessThermalClamperTest {
        public ThermalBrightnessThrottlingData getThermalBrightnessThrottlingData() {
            return mData;
        }

        @NonNull
        @Override
        public SensorData getTempSensor() {
            return mTempSensor;
        }
    }
}