Merge "Add testing for TMS#TemperatureWatcher" into rvc-dev am: f3c2d9c02a am: 952d0f6328 am: a2e8169cb3
Change-Id: Ie22ae414aa02721cf59220873aadcc8464d81631
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user