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

Commit 0b2490de authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Add testing for TMS#TemperatureWatcher" into rvc-dev am: f3c2d9c0

Change-Id: Ia9839cebe74def6ff82a44abe33d660db52046c2
parents a8cf86f0 f3c2d9c0
Loading
Loading
Loading
Loading
+21 −7
Original line number Diff line number Diff line
@@ -107,7 +107,8 @@ public class ThermalManagerService extends SystemService {
    private final AtomicBoolean mHalReady = new AtomicBoolean();

    /** Watches temperatures to forecast when throttling will occur */
    private final TemperatureWatcher mTemperatureWatcher = new TemperatureWatcher();
    @VisibleForTesting
    final TemperatureWatcher mTemperatureWatcher = new TemperatureWatcher();

    /** Invalid throttling status */
    private static final int INVALID_THROTTLING = Integer.MIN_VALUE;
@@ -1069,16 +1070,19 @@ public class ThermalManagerService extends SystemService {
        }
    }

    private class TemperatureWatcher {
    @VisibleForTesting
    class TemperatureWatcher {
        private final Handler mHandler = BackgroundThread.getHandler();

        /** Map of skin temperature sensor name to a corresponding list of samples */
        @GuardedBy("mSamples")
        private final ArrayMap<String, ArrayList<Sample>> mSamples = new ArrayMap<>();
        @VisibleForTesting
        final ArrayMap<String, ArrayList<Sample>> mSamples = new ArrayMap<>();

        /** Map of skin temperature sensor name to the corresponding SEVERE temperature threshold */
        @GuardedBy("mSamples")
        private ArrayMap<String, Float> mSevereThresholds = new ArrayMap<>();
        @VisibleForTesting
        ArrayMap<String, Float> mSevereThresholds = new ArrayMap<>();

        @GuardedBy("mSamples")
        private long mLastForecastCallTimeMillis = 0;
@@ -1146,7 +1150,8 @@ public class ThermalManagerService extends SystemService {
         * Calculates the trend using a linear regression. As the samples are degrees Celsius with
         * associated timestamps in milliseconds, the slope is in degrees Celsius per millisecond.
         */
        private float getSlopeOf(List<Sample> samples) {
        @VisibleForTesting
        float getSlopeOf(List<Sample> samples) {
            long sumTimes = 0L;
            float sumTemperatures = 0.0f;
            for (int s = 0; s < samples.size(); ++s) {
@@ -1177,7 +1182,8 @@ public class ThermalManagerService extends SystemService {
         */
        private static final float DEGREES_BETWEEN_ZERO_AND_ONE = 30.0f;

        private float normalizeTemperature(float temperature, float severeThreshold) {
        @VisibleForTesting
        float normalizeTemperature(float temperature, float severeThreshold) {
            synchronized (mSamples) {
                float zeroNormalized = severeThreshold - DEGREES_BETWEEN_ZERO_AND_ONE;
                if (temperature <= zeroNormalized) {
@@ -1245,7 +1251,15 @@ public class ThermalManagerService extends SystemService {
            }
        }

        private class Sample {
        @VisibleForTesting
        // Since Sample is inside an inner class, we can't make it static
        // This allows test code to create Sample objects via ThermalManagerService
        Sample createSampleForTesting(long time, float temperature) {
            return new Sample(time, temperature);
        }

        @VisibleForTesting
        class Sample {
            public long time;
            public float temperature;

+103 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.power;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -29,6 +30,7 @@ import static org.mockito.Mockito.when;

import android.content.Context;
import android.hardware.thermal.V2_0.TemperatureThreshold;
import android.hardware.thermal.V2_0.ThrottlingSeverity;
import android.os.CoolingDevice;
import android.os.IBinder;
import android.os.IPowerManager;
@@ -91,6 +93,7 @@ public class ThermalManagerServiceTest {
        private static final int INIT_STATUS = Temperature.THROTTLING_NONE;
        private ArrayList<Temperature> mTemperatureList = new ArrayList<>();
        private ArrayList<CoolingDevice> mCoolingDeviceList = new ArrayList<>();
        private ArrayList<TemperatureThreshold> mTemperatureThresholdList = initializeThresholds();

        private Temperature mSkin1 = new Temperature(0, Temperature.TYPE_SKIN, "skin1",
                INIT_STATUS);
@@ -103,6 +106,35 @@ public class ThermalManagerServiceTest {
        private CoolingDevice mCpu = new CoolingDevice(0, CoolingDevice.TYPE_BATTERY, "cpu");
        private CoolingDevice mGpu = new CoolingDevice(0, CoolingDevice.TYPE_BATTERY, "gpu");

        private ArrayList<TemperatureThreshold> initializeThresholds() {
            ArrayList<TemperatureThreshold> thresholds = new ArrayList<>();

            TemperatureThreshold skinThreshold = new TemperatureThreshold();
            skinThreshold.type = Temperature.TYPE_SKIN;
            skinThreshold.name = "skin1";
            skinThreshold.hotThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
            for (int i = 0; i < skinThreshold.hotThrottlingThresholds.length; ++i) {
                // Sets NONE to 25.0f, SEVERE to 40.0f, and SHUTDOWN to 55.0f
                skinThreshold.hotThrottlingThresholds[i] = 25.0f + 5.0f * i;
            }
            thresholds.add(skinThreshold);

            TemperatureThreshold cpuThreshold = new TemperatureThreshold();
            cpuThreshold.type = Temperature.TYPE_CPU;
            cpuThreshold.name = "cpu";
            cpuThreshold.hotThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
            for (int i = 0; i < cpuThreshold.hotThrottlingThresholds.length; ++i) {
                if (i == ThrottlingSeverity.SEVERE) {
                    cpuThreshold.hotThrottlingThresholds[i] = 95.0f;
                } else {
                    cpuThreshold.hotThrottlingThresholds[i] = Float.NaN;
                }
            }
            thresholds.add(cpuThreshold);

            return thresholds;
        }

        ThermalHalFake() {
            mTemperatureList.add(mSkin1);
            mTemperatureList.add(mSkin2);
@@ -139,7 +171,14 @@ public class ThermalManagerServiceTest {
        @Override
        protected List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
                int type) {
            return new ArrayList<>();
            List<TemperatureThreshold> ret = new ArrayList<>();
            for (TemperatureThreshold threshold : mTemperatureThresholdList) {
                if (shouldFilter && type != threshold.type) {
                    continue;
                }
                ret.add(threshold);
            }
            return ret;
        }

        @Override
@@ -351,4 +390,67 @@ public class ThermalManagerServiceTest {
                Arrays.asList(mService.mService.getCurrentCoolingDevicesWithType(
                        CoolingDevice.TYPE_CPU)));
    }

    @Test
    public void testTemperatureWatcherUpdateSevereThresholds() throws RemoteException {
        ThermalManagerService.TemperatureWatcher watcher = mService.mTemperatureWatcher;
        watcher.mSevereThresholds.erase();
        watcher.updateSevereThresholds();
        assertEquals(1, watcher.mSevereThresholds.size());
        assertEquals("skin1", watcher.mSevereThresholds.keyAt(0));
        Float threshold = watcher.mSevereThresholds.get("skin1");
        assertNotNull(threshold);
        assertEquals(40.0f, threshold, 0.0f);
    }

    @Test
    public void testTemperatureWatcherGetSlopeOf() throws RemoteException {
        ThermalManagerService.TemperatureWatcher watcher = mService.mTemperatureWatcher;
        List<ThermalManagerService.TemperatureWatcher.Sample> samples = new ArrayList<>();
        for (int i = 0; i < 30; ++i) {
            samples.add(watcher.createSampleForTesting(i, (float) (i / 2 * 2)));
        }
        assertEquals(1.0f, watcher.getSlopeOf(samples), 0.01f);
    }

    @Test
    public void testTemperatureWatcherNormalizeTemperature() throws RemoteException {
        ThermalManagerService.TemperatureWatcher watcher = mService.mTemperatureWatcher;
        assertEquals(0.5f, watcher.normalizeTemperature(25.0f, 40.0f), 0.0f);

        // Temperatures more than 30 degrees below the SEVERE threshold should be clamped to 0.0f
        assertEquals(0.0f, watcher.normalizeTemperature(0.0f, 40.0f), 0.0f);

        // Temperatures above the SEVERE threshold should not be clamped
        assertEquals(2.0f, watcher.normalizeTemperature(70.0f, 40.0f), 0.0f);
    }

    @Test
    public void testTemperatureWatcherGetForecast() throws RemoteException {
        ThermalManagerService.TemperatureWatcher watcher = mService.mTemperatureWatcher;

        ArrayList<ThermalManagerService.TemperatureWatcher.Sample> samples = new ArrayList<>();

        // Add a single sample
        samples.add(watcher.createSampleForTesting(0, 25.0f));
        watcher.mSamples.put("skin1", samples);

        // Because there are not enough samples to compute the linear regression,
        // no matter how far ahead we forecast, we should receive the same value
        assertEquals(0.5f, watcher.getForecast(0), 0.0f);
        assertEquals(0.5f, watcher.getForecast(5), 0.0f);

        // Add some time-series data
        for (int i = 1; i < 20; ++i) {
            samples.add(0, watcher.createSampleForTesting(1000 * i, 25.0f + 0.5f * i));
        }

        // Now the forecast should vary depending on how far ahead we are trying to predict
        assertEquals(0.9f, watcher.getForecast(4), 0.02f);
        assertEquals(1.0f, watcher.getForecast(10), 0.02f);

        // If there are no thresholds, then we shouldn't receive a headroom value
        watcher.mSevereThresholds.erase();
        assertTrue(Float.isNaN(watcher.getForecast(0)));
    }
}