Merge "Add PowerManager#getThermalHeadroom"

This commit is contained in:
Dan Stoza
2020-02-19 18:18:31 +00:00
committed by Android (Google) Code Review
14 changed files with 419 additions and 74 deletions

View File

@@ -36633,6 +36633,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;
@@ -147,6 +148,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;
@@ -174,7 +176,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);