Add PowerManager#getThermalHeadroom

Adds getThermalHeadroom, which allows users to determine how close the
device currently is to SEVERE thermal throttling. For intensive
applications which can scale their workloads, this allows them to help
manage the thermal envelope of the device.

Test: Manual, modify Filament test app to call and observe values
Test: PowerManagerTest#testGetThermalHeadroom
Test: atest android.os.cts.PowerManager_ThermalTest
Test: atest com.android.systemui.statusbar.phone.StatusBarTest
Test: atest CachedDeviceStateServiceTest
Test: atest AbstractAccessibilityServiceConnectionTest
Test: atest KeyEventDispatcherTest
Test: atest AttentionManagerServiceTest
Test: atest HdmiControlServiceTest
Test: atest ThermalManagerServiceTest
Test: atest RecoverySystemServiceTest
Bug: 136285293
Change-Id: I26e1c849c4b08cbf7ee0057f555cf0893750da43
This commit is contained in:
Dan Stoza
2019-11-12 16:09:41 -08:00
parent 75088d14f4
commit b04705837a
14 changed files with 419 additions and 74 deletions

View File

@@ -36625,6 +36625,7 @@ package android.os {
method public void addThermalStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.os.PowerManager.OnThermalStatusChangedListener);
method public int getCurrentThermalStatus();
method public int getLocationPowerSaveMode();
method public float getThermalHeadroom(@IntRange(from=0, to=60) int);
method public boolean isDeviceIdleMode();
method public boolean isIgnoringBatteryOptimizations(String);
method public boolean isInteractive();

View File

@@ -148,6 +148,7 @@ import android.os.IHardwarePropertiesManager;
import android.os.IPowerManager;
import android.os.IRecoverySystem;
import android.os.ISystemUpdateManager;
import android.os.IThermalService;
import android.os.IUserManager;
import android.os.IncidentManager;
import android.os.PowerManager;
@@ -576,10 +577,12 @@ public final class SystemServiceRegistry {
new CachedServiceFetcher<PowerManager>() {
@Override
public PowerManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.POWER_SERVICE);
IPowerManager service = IPowerManager.Stub.asInterface(b);
return new PowerManager(ctx.getOuterContext(),
service, ctx.mMainThread.getHandler());
IBinder powerBinder = ServiceManager.getServiceOrThrow(Context.POWER_SERVICE);
IPowerManager powerService = IPowerManager.Stub.asInterface(powerBinder);
IBinder thermalBinder = ServiceManager.getServiceOrThrow(Context.THERMAL_SERVICE);
IThermalService thermalService = IThermalService.Stub.asInterface(thermalBinder);
return new PowerManager(ctx.getOuterContext(), powerService, thermalService,
ctx.mMainThread.getHandler());
}});
registerService(Context.RECOVERY_SERVICE, RecoverySystem.class,

View File

@@ -103,4 +103,11 @@ interface IThermalService {
* {@hide}
*/
List<CoolingDevice> getCurrentCoolingDevicesWithType(in int type);
/**
* @param forecastSeconds how many seconds ahead to forecast the provided headroom
* @return forecasted thermal headroom, normalized such that 1.0 indicates that throttling will
* occur; returns NaN if the headroom or forecast is unavailable
*/
float getThermalHeadroom(int forecastSeconds);
}

View File

@@ -18,7 +18,9 @@ package android.os;
import android.Manifest.permission;
import android.annotation.CallbackExecutor;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -39,6 +41,7 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicLong;
/**
* This class gives you control of the power state of the device.
@@ -916,20 +919,22 @@ public final class PowerManager {
final IPowerManager mService;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
final Handler mHandler;
final IThermalService mThermalService;
/** We lazily initialize it.*/
private DeviceIdleManager mDeviceIdleManager;
IThermalService mThermalService;
private final ArrayMap<OnThermalStatusChangedListener, IThermalStatusListener>
mListenerMap = new ArrayMap<>();
/**
* {@hide}
*/
public PowerManager(Context context, IPowerManager service, Handler handler) {
public PowerManager(Context context, IPowerManager service, IThermalService thermalService,
Handler handler) {
mContext = context;
mService = service;
mThermalService = thermalService;
mHandler = handler;
}
@@ -1877,18 +1882,11 @@ public final class PowerManager {
* thermal throttling.
*/
public @ThermalStatus int getCurrentThermalStatus() {
synchronized (this) {
if (mThermalService == null) {
mThermalService = IThermalService.Stub.asInterface(
ServiceManager.getService(Context.THERMAL_SERVICE));
}
try {
return mThermalService.getCurrentThermalStatus();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
try {
return mThermalService.getCurrentThermalStatus();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
@@ -1915,13 +1913,7 @@ public final class PowerManager {
*/
public void addThermalStatusListener(@NonNull OnThermalStatusChangedListener listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
synchronized (this) {
if (mThermalService == null) {
mThermalService = IThermalService.Stub.asInterface(
ServiceManager.getService(Context.THERMAL_SERVICE));
}
this.addThermalStatusListener(mContext.getMainExecutor(), listener);
}
this.addThermalStatusListener(mContext.getMainExecutor(), listener);
}
/**
@@ -1934,35 +1926,29 @@ public final class PowerManager {
@NonNull OnThermalStatusChangedListener listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
Preconditions.checkNotNull(executor, "executor cannot be null");
synchronized (this) {
if (mThermalService == null) {
mThermalService = IThermalService.Stub.asInterface(
ServiceManager.getService(Context.THERMAL_SERVICE));
}
Preconditions.checkArgument(!mListenerMap.containsKey(listener),
"Listener already registered: " + listener);
IThermalStatusListener internalListener = new IThermalStatusListener.Stub() {
@Override
public void onStatusChange(int status) {
final long token = Binder.clearCallingIdentity();
try {
executor.execute(() -> {
listener.onThermalStatusChanged(status);
});
} finally {
Binder.restoreCallingIdentity(token);
}
Preconditions.checkArgument(!mListenerMap.containsKey(listener),
"Listener already registered: " + listener);
IThermalStatusListener internalListener = new IThermalStatusListener.Stub() {
@Override
public void onStatusChange(int status) {
final long token = Binder.clearCallingIdentity();
try {
executor.execute(() -> {
listener.onThermalStatusChanged(status);
});
} finally {
Binder.restoreCallingIdentity(token);
}
};
try {
if (mThermalService.registerThermalStatusListener(internalListener)) {
mListenerMap.put(listener, internalListener);
} else {
throw new RuntimeException("Listener failed to set");
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
};
try {
if (mThermalService.registerThermalStatusListener(internalListener)) {
mListenerMap.put(listener, internalListener);
} else {
throw new RuntimeException("Listener failed to set");
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@@ -1973,22 +1959,72 @@ public final class PowerManager {
*/
public void removeThermalStatusListener(@NonNull OnThermalStatusChangedListener listener) {
Preconditions.checkNotNull(listener, "listener cannot be null");
synchronized (this) {
if (mThermalService == null) {
mThermalService = IThermalService.Stub.asInterface(
ServiceManager.getService(Context.THERMAL_SERVICE));
}
IThermalStatusListener internalListener = mListenerMap.get(listener);
Preconditions.checkArgument(internalListener != null, "Listener was not added");
try {
if (mThermalService.unregisterThermalStatusListener(internalListener)) {
mListenerMap.remove(listener);
} else {
throw new RuntimeException("Listener failed to remove");
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
IThermalStatusListener internalListener = mListenerMap.get(listener);
Preconditions.checkArgument(internalListener != null, "Listener was not added");
try {
if (mThermalService.unregisterThermalStatusListener(internalListener)) {
mListenerMap.remove(listener);
} else {
throw new RuntimeException("Listener failed to remove");
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@CurrentTimeMillisLong
private final AtomicLong mLastHeadroomUpdate = new AtomicLong(0L);
private static final int MINIMUM_HEADROOM_TIME_MILLIS = 500;
/**
* Provides an estimate of how much thermal headroom the device currently has before hitting
* severe throttling.
*
* Note that this only attempts to track the headroom of slow-moving sensors, such as the skin
* temperature sensor. This means that there is no benefit to calling this function more
* frequently than about once per second, and attempts to call significantly more frequently may
* result in the function returning {@code NaN}.
*
* In addition, in order to be able to provide an accurate forecast, the system does not attempt
* to forecast until it has multiple temperature samples from which to extrapolate. This should
* only take a few seconds from the time of the first call, but during this time, no forecasting
* will occur, and the current headroom will be returned regardless of the value of
* {@code forecastSeconds}.
*
* The value returned is a non-negative float that represents how much of the thermal envelope
* is in use (or is forecasted to be in use). A value of 1.0 indicates that the device is (or
* will be) throttled at {@link #THERMAL_STATUS_SEVERE}. Such throttling can affect the CPU,
* GPU, and other subsystems. Values may exceed 1.0, but there is no implied mapping to specific
* thermal status levels beyond that point. This means that values greater than 1.0 may
* correspond to {@link #THERMAL_STATUS_SEVERE}, but may also represent heavier throttling.
*
* A value of 0.0 corresponds to a fixed distance from 1.0, but does not correspond to any
* particular thermal status or temperature. Values on (0.0, 1.0] may be expected to scale
* linearly with temperature, though temperature changes over time are typically not linear.
* Negative values will be clamped to 0.0 before returning.
*
* @param forecastSeconds how many seconds in the future to forecast. Given that device
* conditions may change at any time, forecasts from further in the
* future will likely be less accurate than forecasts in the near future.
* @return a value greater than or equal to 0.0 where 1.0 indicates the SEVERE throttling
* threshold, as described above. Returns NaN if the device does not support this
* functionality or if this function is called significantly faster than once per
* second.
*/
public float getThermalHeadroom(@IntRange(from = 0, to = 60) int forecastSeconds) {
// Rate-limit calls into the thermal service
long now = SystemClock.elapsedRealtime();
long timeSinceLastUpdate = now - mLastHeadroomUpdate.get();
if (timeSinceLastUpdate < MINIMUM_HEADROOM_TIME_MILLIS) {
return Float.NaN;
}
try {
float forecast = mThermalService.getThermalHeadroom(forecastSeconds);
mLastHeadroomUpdate.set(SystemClock.elapsedRealtime());
return forecast;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

View File

@@ -243,6 +243,28 @@ public class PowerManagerTest extends AndroidTestCase {
.times(1)).onThermalStatusChanged(status);
}
@Test
public void testGetThermalHeadroom() throws Exception {
float headroom = mPm.getThermalHeadroom(0);
// If the device doesn't support thermal headroom, return early
if (Float.isNaN(headroom)) {
return;
}
assertTrue("Expected non-negative headroom", headroom >= 0.0f);
assertTrue("Expected reasonably small headroom", headroom < 10.0f);
// Call again immediately to ensure rate limiting works
headroom = mPm.getThermalHeadroom(0);
assertTrue("Expected NaN because of rate limiting", Float.isNaN(headroom));
// Sleep for a second before attempting to call again so as to not get rate limited
Thread.sleep(1000);
headroom = mPm.getThermalHeadroom(5);
assertFalse("Expected data to still be available", Float.isNaN(headroom));
assertTrue("Expected non-negative headroom", headroom >= 0.0f);
assertTrue("Expected reasonably small headroom", headroom < 10.0f);
}
@Test
public void testUserspaceRebootNotSupported_throwsUnsupportedOperationException() {
// Can't use assumption framework with AndroidTestCase :(

View File

@@ -50,6 +50,7 @@ import android.metrics.LogMaker;
import android.os.Binder;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -256,7 +257,8 @@ public class StatusBarTest extends SysuiTestCase {
mDependency.injectTestDependency(NotificationFilter.class, mNotificationFilter);
IPowerManager powerManagerService = mock(IPowerManager.class);
mPowerManager = new PowerManager(mContext, powerManagerService,
IThermalService thermalService = mock(IThermalService.class);
mPowerManager = new PowerManager(mContext, powerManagerService, thermalService,
Handler.createAsync(Looper.myLooper()));
mNotificationInterruptionStateProvider =

View File

@@ -16,15 +16,18 @@
package com.android.server.power;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.thermal.V1_0.ThermalStatus;
import android.hardware.thermal.V1_0.ThermalStatusCode;
import android.hardware.thermal.V1_1.IThermalCallback;
import android.hardware.thermal.V2_0.IThermalChangedCallback;
import android.hardware.thermal.V2_0.TemperatureThreshold;
import android.hardware.thermal.V2_0.ThrottlingSeverity;
import android.os.Binder;
import android.os.CoolingDevice;
import android.os.Handler;
import android.os.HwBinder;
import android.os.IThermalEventListener;
import android.os.IThermalService;
@@ -36,6 +39,7 @@ import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.Temperature;
import android.util.ArrayMap;
import android.util.EventLog;
@@ -43,6 +47,7 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.server.EventLogTags;
import com.android.server.FgThread;
@@ -54,6 +59,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -100,6 +106,9 @@ public class ThermalManagerService extends SystemService {
/** Hal ready. */
private final AtomicBoolean mHalReady = new AtomicBoolean();
/** Watches temperatures to forecast when throttling will occur */
private final TemperatureWatcher mTemperatureWatcher = new TemperatureWatcher();
/** Invalid throttling status */
private static final int INVALID_THROTTLING = Integer.MIN_VALUE;
@@ -154,6 +163,7 @@ public class ThermalManagerService extends SystemService {
onTemperatureChanged(temperatures.get(i), false);
}
onTemperatureMapChangedLocked();
mTemperatureWatcher.updateSevereThresholds();
mHalReady.set(true);
}
}
@@ -462,6 +472,15 @@ public class ThermalManagerService extends SystemService {
}
}
@Override
public float getThermalHeadroom(int forecastSeconds) {
if (!mHalReady.get()) {
return Float.NaN;
}
return mTemperatureWatcher.getForecast(forecastSeconds);
}
private void dumpItemsLocked(PrintWriter pw, String prefix,
Collection<?> items) {
for (Iterator iterator = items.iterator(); iterator.hasNext();) {
@@ -616,6 +635,10 @@ public class ThermalManagerService extends SystemService {
protected abstract List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
int type);
@NonNull
protected abstract List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
int type);
protected abstract boolean connectToHal();
protected abstract void dump(PrintWriter pw, String prefix);
@@ -727,6 +750,12 @@ public class ThermalManagerService extends SystemService {
}
}
@Override
protected List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
int type) {
return new ArrayList<>();
}
@Override
protected boolean connectToHal() {
synchronized (mHalLock) {
@@ -856,6 +885,12 @@ public class ThermalManagerService extends SystemService {
}
}
@Override
protected List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
int type) {
return new ArrayList<>();
}
@Override
protected boolean connectToHal() {
synchronized (mHalLock) {
@@ -974,6 +1009,32 @@ public class ThermalManagerService extends SystemService {
}
}
@Override
protected List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
int type) {
synchronized (mHalLock) {
List<TemperatureThreshold> ret = new ArrayList<>();
if (mThermalHal20 == null) {
return ret;
}
try {
mThermalHal20.getTemperatureThresholds(shouldFilter, type,
(status, thresholds) -> {
if (ThermalStatusCode.SUCCESS == status.code) {
ret.addAll(thresholds);
} else {
Slog.e(TAG,
"Couldn't get temperature thresholds because of HAL "
+ "error: " + status.debugMessage);
}
});
} catch (RemoteException e) {
Slog.e(TAG, "Couldn't getTemperatureThresholds, reconnecting...", e);
}
return ret;
}
}
@Override
protected boolean connectToHal() {
synchronized (mHalLock) {
@@ -1001,4 +1062,190 @@ public class ThermalManagerService extends SystemService {
}
}
private 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<>();
/** Map of skin temperature sensor name to the corresponding SEVERE temperature threshold */
@GuardedBy("mSamples")
private ArrayMap<String, Float> mSevereThresholds = new ArrayMap<>();
@GuardedBy("mSamples")
private long mLastForecastCallTimeMillis = 0;
void updateSevereThresholds() {
synchronized (mSamples) {
List<TemperatureThreshold> thresholds =
mHalWrapper.getTemperatureThresholds(true, Temperature.TYPE_SKIN);
for (int t = 0; t < thresholds.size(); ++t) {
TemperatureThreshold threshold = thresholds.get(t);
if (threshold.hotThrottlingThresholds.length <= ThrottlingSeverity.SEVERE) {
continue;
}
float temperature =
threshold.hotThrottlingThresholds[ThrottlingSeverity.SEVERE];
if (!Float.isNaN(temperature)) {
mSevereThresholds.put(threshold.name,
threshold.hotThrottlingThresholds[ThrottlingSeverity.SEVERE]);
}
}
}
}
private static final int INACTIVITY_THRESHOLD_MILLIS = 10000;
private static final int RING_BUFFER_SIZE = 30;
private void updateTemperature() {
synchronized (mSamples) {
if (SystemClock.elapsedRealtime() - mLastForecastCallTimeMillis
< INACTIVITY_THRESHOLD_MILLIS) {
// Trigger this again after a second as long as forecast has been called more
// recently than the inactivity timeout
mHandler.postDelayed(this::updateTemperature, 1000);
} else {
// Otherwise, we've been idle for at least 10 seconds, so we should
// shut down
mSamples.clear();
return;
}
long now = SystemClock.elapsedRealtime();
List<Temperature> temperatures = mHalWrapper.getCurrentTemperatures(true,
Temperature.TYPE_SKIN);
for (int t = 0; t < temperatures.size(); ++t) {
Temperature temperature = temperatures.get(t);
// Filter out invalid temperatures. If this results in no values being stored at
// all, the mSamples.empty() check in getForecast() will catch it.
if (Float.isNaN(temperature.getValue())) {
continue;
}
ArrayList<Sample> samples = mSamples.computeIfAbsent(temperature.getName(),
k -> new ArrayList<>(RING_BUFFER_SIZE));
if (samples.size() == RING_BUFFER_SIZE) {
samples.remove(0);
}
samples.add(new Sample(now, temperature.getValue()));
}
}
}
/**
* 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) {
long sumTimes = 0L;
float sumTemperatures = 0.0f;
for (int s = 0; s < samples.size(); ++s) {
Sample sample = samples.get(s);
sumTimes += sample.time;
sumTemperatures += sample.temperature;
}
long meanTime = sumTimes / samples.size();
float meanTemperature = sumTemperatures / samples.size();
long sampleVariance = 0L;
float sampleCovariance = 0.0f;
for (int s = 0; s < samples.size(); ++s) {
Sample sample = samples.get(s);
long timeDelta = sample.time - meanTime;
float temperatureDelta = sample.temperature - meanTemperature;
sampleVariance += timeDelta * timeDelta;
sampleCovariance += timeDelta * temperatureDelta;
}
return sampleCovariance / sampleVariance;
}
/**
* Used to determine the temperature corresponding to 0.0. Given that 1.0 is pinned at the
* temperature corresponding to the SEVERE threshold, we set 0.0 to be that temperature
* minus DEGREES_BETWEEN_ZERO_AND_ONE.
*/
private static final float DEGREES_BETWEEN_ZERO_AND_ONE = 30.0f;
private float normalizeTemperature(float temperature, float severeThreshold) {
synchronized (mSamples) {
float zeroNormalized = severeThreshold - DEGREES_BETWEEN_ZERO_AND_ONE;
if (temperature <= zeroNormalized) {
return 0.0f;
}
float delta = temperature - zeroNormalized;
return delta / DEGREES_BETWEEN_ZERO_AND_ONE;
}
}
private static final int MINIMUM_SAMPLE_COUNT = 3;
float getForecast(int forecastSeconds) {
synchronized (mSamples) {
mLastForecastCallTimeMillis = System.currentTimeMillis();
if (mSamples.isEmpty()) {
updateTemperature();
}
// If somehow things take much longer than expected or there are no temperatures
// to sample, return early
if (mSamples.isEmpty()) {
Slog.e(TAG, "No temperature samples found");
return Float.NaN;
}
// If we don't have any thresholds, we can't normalize the temperatures,
// so return early
if (mSevereThresholds.isEmpty()) {
Slog.e(TAG, "No temperature thresholds found");
return Float.NaN;
}
float maxNormalized = Float.NaN;
for (Map.Entry<String, ArrayList<Sample>> entry : mSamples.entrySet()) {
String name = entry.getKey();
ArrayList<Sample> samples = entry.getValue();
Float threshold = mSevereThresholds.get(name);
if (threshold == null) {
Slog.e(TAG, "No threshold found for " + name);
continue;
}
float currentTemperature = samples.get(0).temperature;
if (samples.size() < MINIMUM_SAMPLE_COUNT) {
// Don't try to forecast, just use the latest one we have
float normalized = normalizeTemperature(currentTemperature, threshold);
if (Float.isNaN(maxNormalized) || normalized > maxNormalized) {
maxNormalized = normalized;
}
continue;
}
float slope = getSlopeOf(samples);
float normalized = normalizeTemperature(
currentTemperature + slope * forecastSeconds * 1000, threshold);
if (Float.isNaN(maxNormalized) || normalized > maxNormalized) {
maxNormalized = normalized;
}
}
return maxNormalized;
}
}
private class Sample {
public long time;
public float temperature;
Sample(long time, float temperature) {
this.time = time;
this.temperature = temperature;
}
}
}
}

View File

@@ -26,6 +26,7 @@ import android.content.Intent;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.OsProtoEnums;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -52,13 +53,14 @@ import org.mockito.MockitoAnnotations;
public class CachedDeviceStateServiceTest {
@Mock private BatteryManagerInternal mBatteryManager;
@Mock private IPowerManager mPowerManager;
@Mock private IThermalService mThermalService;
private BroadcastInterceptingContext mContext;
@Before
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
Context context = InstrumentationRegistry.getContext();
PowerManager powerManager = new PowerManager(context, mPowerManager, null);
PowerManager powerManager = new PowerManager(context, mPowerManager, mThermalService, null);
mContext = new BroadcastInterceptingContext(context) {
@Override
public Object getSystemService(String name) {

View File

@@ -74,6 +74,7 @@ import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallback;
@@ -153,6 +154,7 @@ public class AbstractAccessibilityServiceConnectionTest {
@Mock private Context mMockContext;
@Mock private IPowerManager mMockIPowerManager;
@Mock private IThermalService mMockIThermalService;
@Mock private PackageManager mMockPackageManager;
@Spy private AccessibilityServiceInfo mSpyServiceInfo = new AccessibilityServiceInfo();
@Mock private AccessibilitySecurityPolicy mMockSecurityPolicy;
@@ -180,7 +182,7 @@ public class AbstractAccessibilityServiceConnectionTest {
.thenReturn(mMockMagnificationController);
PowerManager powerManager =
new PowerManager(mMockContext, mMockIPowerManager, mHandler);
new PowerManager(mMockContext, mMockIPowerManager, mMockIThermalService, mHandler);
when(mMockContext.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
when(mMockPackageManager.hasSystemFeature(FEATURE_FINGERPRINT)).thenReturn(true);

View File

@@ -34,6 +34,7 @@ import static org.mockito.hamcrest.MockitoHamcrest.argThat;
import android.content.Context;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
@@ -73,6 +74,7 @@ public class KeyEventDispatcherTest {
private KeyEventFilter mKeyEventFilter1;
private KeyEventFilter mKeyEventFilter2;
private IPowerManager mMockPowerManagerService;
private IThermalService mMockThermalService;
private MessageCapturingHandler mMessageCapturingHandler;
private ArgumentCaptor<Integer> mFilter1SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
private ArgumentCaptor<Integer> mFilter2SequenceCaptor = ArgumentCaptor.forClass(Integer.class);
@@ -82,10 +84,12 @@ public class KeyEventDispatcherTest {
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
mInputEventsHandler = new MessageCapturingHandler(looper, null);
mMockPowerManagerService = mock(IPowerManager.class);
mMockThermalService = mock(IThermalService.class);
// TODO: It would be better to mock PowerManager rather than its binder, but the class is
// final.
PowerManager powerManager =
new PowerManager(mock(Context.class), mMockPowerManagerService, new Handler(looper));
new PowerManager(mock(Context.class), mMockPowerManagerService, mMockThermalService,
new Handler(looper));
mMessageCapturingHandler = new MessageCapturingHandler(looper, null);
mKeyEventDispatcher = new KeyEventDispatcher(mInputEventsHandler, SEND_FRAMEWORK_KEY_EVENT,
mLock, powerManager, mMessageCapturingHandler);

View File

@@ -37,6 +37,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.os.IBinder;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.PowerManager;
import android.os.RemoteException;
import android.provider.DeviceConfig;
@@ -74,6 +75,8 @@ public class AttentionManagerServiceTest {
@Mock
private IPowerManager mMockIPowerManager;
@Mock
private IThermalService mMockIThermalService;
@Mock
Context mContext;
@Before
@@ -84,7 +87,7 @@ public class AttentionManagerServiceTest {
// setup power manager mock
PowerManager mPowerManager;
doReturn(true).when(mMockIPowerManager).isInteractive();
mPowerManager = new PowerManager(mContext, mMockIPowerManager, null);
mPowerManager = new PowerManager(mContext, mMockIPowerManager, mMockIThermalService, null);
Object mLock = new Object();
// setup a spy on attention manager

View File

@@ -34,6 +34,7 @@ import android.content.ContextWrapper;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPortInfo;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -123,6 +124,7 @@ public class HdmiControlServiceTest {
private HdmiPortInfo[] mHdmiPortInfo;
@Mock private IPowerManager mIPowerManagerMock;
@Mock private IThermalService mIThermalServiceMock;
@Before
public void setUp() throws Exception {
@@ -130,7 +132,8 @@ public class HdmiControlServiceTest {
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock, null);
PowerManager powerManager = new PowerManager(mContextSpy, mIPowerManagerMock,
mIThermalServiceMock, null);
when(mContextSpy.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
when(mIPowerManagerMock.isInteractive()).thenReturn(true);

View File

@@ -28,10 +28,12 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.thermal.V2_0.TemperatureThreshold;
import android.os.CoolingDevice;
import android.os.IBinder;
import android.os.IPowerManager;
import android.os.IThermalEventListener;
import android.os.IThermalService;
import android.os.IThermalStatusListener;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -72,6 +74,8 @@ public class ThermalManagerServiceTest {
@Mock
private IPowerManager mIPowerManagerMock;
@Mock
private IThermalService mIThermalServiceMock;
@Mock
private IThermalEventListener mEventListener1;
@Mock
private IThermalEventListener mEventListener2;
@@ -132,6 +136,12 @@ public class ThermalManagerServiceTest {
return ret;
}
@Override
protected List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
int type) {
return new ArrayList<>();
}
@Override
protected boolean connectToHal() {
return true;
@@ -153,7 +163,7 @@ public class ThermalManagerServiceTest {
public void setUp() throws RemoteException {
MockitoAnnotations.initMocks(this);
mFakeHal = new ThermalHalFake();
mPowerManager = new PowerManager(mContext, mIPowerManagerMock, null);
mPowerManager = new PowerManager(mContext, mIPowerManagerMock, mIThermalServiceMock, null);
when(mContext.getSystemServiceName(PowerManager.class)).thenReturn(Context.POWER_SERVICE);
when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
resetListenerMock();

View File

@@ -36,6 +36,7 @@ import android.content.IntentSender;
import android.os.Handler;
import android.os.IPowerManager;
import android.os.IRecoverySystemProgressListener;
import android.os.IThermalService;
import android.os.Looper;
import android.os.PowerManager;
@@ -62,6 +63,7 @@ public class RecoverySystemServiceTest {
private RecoverySystemService.UncryptSocket mUncryptSocket;
private Context mContext;
private IPowerManager mIPowerManager;
private IThermalService mIThermalService;
private FileWriter mUncryptUpdateFileWriter;
private LockSettingsInternal mLockSettingsInternal;
@@ -77,8 +79,9 @@ public class RecoverySystemServiceTest {
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
mIPowerManager = mock(IPowerManager.class);
mIThermalService = mock(IThermalService.class);
PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager,
new Handler(looper));
mIThermalService, new Handler(looper));
mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties,
powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal);