Merge "Limit refresh rates if skin temperature is high" into sc-qpr1-dev am: a2276a43e3
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15741890 Change-Id: Ic9bb379bd89fd244a425b38653b926d58a630e3a
This commit is contained in:
@@ -36,9 +36,14 @@ import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
|
|||||||
import android.hardware.fingerprint.IUdfpsHbmListener;
|
import android.hardware.fingerprint.IUdfpsHbmListener;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.IThermalEventListener;
|
||||||
|
import android.os.IThermalService;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceManager;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
|
import android.os.Temperature;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -108,6 +113,7 @@ public class DisplayModeDirector {
|
|||||||
private final UdfpsObserver mUdfpsObserver;
|
private final UdfpsObserver mUdfpsObserver;
|
||||||
private final SensorObserver mSensorObserver;
|
private final SensorObserver mSensorObserver;
|
||||||
private final HbmObserver mHbmObserver;
|
private final HbmObserver mHbmObserver;
|
||||||
|
private final SkinThermalStatusObserver mSkinThermalStatusObserver;
|
||||||
private final DeviceConfigInterface mDeviceConfig;
|
private final DeviceConfigInterface mDeviceConfig;
|
||||||
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
|
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
|
||||||
|
|
||||||
@@ -156,6 +162,7 @@ public class DisplayModeDirector {
|
|||||||
};
|
};
|
||||||
mSensorObserver = new SensorObserver(context, ballotBox, injector);
|
mSensorObserver = new SensorObserver(context, ballotBox, injector);
|
||||||
mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
|
mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
|
||||||
|
mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox);
|
||||||
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
|
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
|
||||||
mDeviceConfig = injector.getDeviceConfig();
|
mDeviceConfig = injector.getDeviceConfig();
|
||||||
mAlwaysRespectAppRequest = false;
|
mAlwaysRespectAppRequest = false;
|
||||||
@@ -174,6 +181,7 @@ public class DisplayModeDirector {
|
|||||||
mBrightnessObserver.observe(sensorManager);
|
mBrightnessObserver.observe(sensorManager);
|
||||||
mSensorObserver.observe();
|
mSensorObserver.observe();
|
||||||
mHbmObserver.observe();
|
mHbmObserver.observe();
|
||||||
|
mSkinThermalStatusObserver.observe();
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
// We may have a listener already registered before the call to start, so go ahead and
|
// We may have a listener already registered before the call to start, so go ahead and
|
||||||
// notify them to pick up our newly initialized state.
|
// notify them to pick up our newly initialized state.
|
||||||
@@ -606,6 +614,7 @@ public class DisplayModeDirector {
|
|||||||
mUdfpsObserver.dumpLocked(pw);
|
mUdfpsObserver.dumpLocked(pw);
|
||||||
mSensorObserver.dumpLocked(pw);
|
mSensorObserver.dumpLocked(pw);
|
||||||
mHbmObserver.dumpLocked(pw);
|
mHbmObserver.dumpLocked(pw);
|
||||||
|
mSkinThermalStatusObserver.dumpLocked(pw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,7 +723,6 @@ public class DisplayModeDirector {
|
|||||||
return mUdfpsObserver;
|
return mUdfpsObserver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
|
DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
|
||||||
float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
|
float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
|
||||||
@@ -950,16 +958,19 @@ public class DisplayModeDirector {
|
|||||||
// user seeing the display flickering when the switches occur.
|
// user seeing the display flickering when the switches occur.
|
||||||
public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
|
public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
|
||||||
|
|
||||||
|
// Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
|
||||||
|
public static final int PRIORITY_SKIN_TEMPERATURE = 9;
|
||||||
|
|
||||||
// High-brightness-mode may need a specific range of refresh-rates to function properly.
|
// High-brightness-mode may need a specific range of refresh-rates to function properly.
|
||||||
public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9;
|
public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 10;
|
||||||
|
|
||||||
// The proximity sensor needs the refresh rate to be locked in order to function, so this is
|
// The proximity sensor needs the refresh rate to be locked in order to function, so this is
|
||||||
// set to a high priority.
|
// set to a high priority.
|
||||||
public static final int PRIORITY_PROXIMITY = 10;
|
public static final int PRIORITY_PROXIMITY = 11;
|
||||||
|
|
||||||
// The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
|
// The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
|
||||||
// to function, so this needs to be the highest priority of all votes.
|
// to function, so this needs to be the highest priority of all votes.
|
||||||
public static final int PRIORITY_UDFPS = 11;
|
public static final int PRIORITY_UDFPS = 12;
|
||||||
|
|
||||||
// Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
|
// Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
|
||||||
// APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
|
// APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
|
||||||
@@ -1054,6 +1065,8 @@ public class DisplayModeDirector {
|
|||||||
return "PRIORITY_PROXIMITY";
|
return "PRIORITY_PROXIMITY";
|
||||||
case PRIORITY_LOW_POWER_MODE:
|
case PRIORITY_LOW_POWER_MODE:
|
||||||
return "PRIORITY_LOW_POWER_MODE";
|
return "PRIORITY_LOW_POWER_MODE";
|
||||||
|
case PRIORITY_SKIN_TEMPERATURE:
|
||||||
|
return "PRIORITY_SKIN_TEMPERATURE";
|
||||||
case PRIORITY_UDFPS:
|
case PRIORITY_UDFPS:
|
||||||
return "PRIORITY_UDFPS";
|
return "PRIORITY_UDFPS";
|
||||||
case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
|
case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
|
||||||
@@ -2309,6 +2322,52 @@ public class DisplayModeDirector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
|
||||||
|
private final BallotBox mBallotBox;
|
||||||
|
private final Injector mInjector;
|
||||||
|
|
||||||
|
private @Temperature.ThrottlingStatus int mStatus = -1;
|
||||||
|
|
||||||
|
SkinThermalStatusObserver(Injector injector, BallotBox ballotBox) {
|
||||||
|
mInjector = injector;
|
||||||
|
mBallotBox = ballotBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyThrottling(Temperature temp) {
|
||||||
|
mStatus = temp.getStatus();
|
||||||
|
if (mLoggingEnabled) {
|
||||||
|
Slog.d(TAG, "New thermal throttling status "
|
||||||
|
+ ", current thermal status = " + mStatus);
|
||||||
|
}
|
||||||
|
final Vote vote;
|
||||||
|
if (mStatus >= Temperature.THROTTLING_CRITICAL) {
|
||||||
|
vote = Vote.forRefreshRates(0f, 60f);
|
||||||
|
} else {
|
||||||
|
vote = null;
|
||||||
|
}
|
||||||
|
mBallotBox.vote(GLOBAL_ID, Vote.PRIORITY_SKIN_TEMPERATURE, vote);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void observe() {
|
||||||
|
IThermalService thermalService = mInjector.getThermalService();
|
||||||
|
if (thermalService == null) {
|
||||||
|
Slog.w(TAG, "Could not observe thermal status. Service not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
thermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Slog.e(TAG, "Failed to register thermal status listener", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dumpLocked(PrintWriter writer) {
|
||||||
|
writer.println(" SkinThermalStatusObserver:");
|
||||||
|
writer.println(" mStatus: " + mStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
|
private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
|
||||||
public DeviceConfigDisplaySettings() {
|
public DeviceConfigDisplaySettings() {
|
||||||
}
|
}
|
||||||
@@ -2470,6 +2529,8 @@ public class DisplayModeDirector {
|
|||||||
BrightnessInfo getBrightnessInfo(int displayId);
|
BrightnessInfo getBrightnessInfo(int displayId);
|
||||||
|
|
||||||
boolean isDozeState(Display d);
|
boolean isDozeState(Display d);
|
||||||
|
|
||||||
|
IThermalService getThermalService();
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -2530,6 +2591,12 @@ public class DisplayModeDirector {
|
|||||||
return Display.isDozeState(d.getState());
|
return Display.isDozeState(d.getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IThermalService getThermalService() {
|
||||||
|
return IThermalService.Stub.asInterface(
|
||||||
|
ServiceManager.getService(Context.THERMAL_SERVICE));
|
||||||
|
}
|
||||||
|
|
||||||
private DisplayManager getDisplayManager() {
|
private DisplayManager getDisplayManager() {
|
||||||
if (mDisplayManager == null) {
|
if (mDisplayManager == null) {
|
||||||
mDisplayManager = mContext.getSystemService(DisplayManager.class);
|
mDisplayManager = mContext.getSystemService(DisplayManager.class);
|
||||||
|
|||||||
@@ -56,7 +56,11 @@ import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation;
|
|||||||
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
|
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
|
||||||
import android.hardware.fingerprint.IUdfpsHbmListener;
|
import android.hardware.fingerprint.IUdfpsHbmListener;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.IThermalEventListener;
|
||||||
|
import android.os.IThermalService;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.Temperature;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.test.mock.MockContentResolver;
|
import android.test.mock.MockContentResolver;
|
||||||
@@ -116,6 +120,8 @@ public class DisplayModeDirectorTest {
|
|||||||
public SensorManagerInternal mSensorManagerInternalMock;
|
public SensorManagerInternal mSensorManagerInternalMock;
|
||||||
@Mock
|
@Mock
|
||||||
public DisplayManagerInternal mDisplayManagerInternalMock;
|
public DisplayManagerInternal mDisplayManagerInternalMock;
|
||||||
|
@Mock
|
||||||
|
public IThermalService mThermalServiceMock;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@@ -124,6 +130,7 @@ public class DisplayModeDirectorTest {
|
|||||||
final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
|
final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
|
||||||
when(mContext.getContentResolver()).thenReturn(resolver);
|
when(mContext.getContentResolver()).thenReturn(resolver);
|
||||||
mInjector = spy(new FakesInjector());
|
mInjector = spy(new FakesInjector());
|
||||||
|
when(mInjector.getThermalService()).thenReturn(mThermalServiceMock);
|
||||||
mHandler = new Handler(Looper.getMainLooper());
|
mHandler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
|
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
|
||||||
@@ -1547,12 +1554,52 @@ public class DisplayModeDirectorTest {
|
|||||||
assertNull(vote);
|
assertNull(vote);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSkinTemperature() throws RemoteException {
|
||||||
|
DisplayModeDirector director =
|
||||||
|
createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
|
||||||
|
director.start(createMockSensorManager());
|
||||||
|
|
||||||
|
ArgumentCaptor<IThermalEventListener> thermalEventListener =
|
||||||
|
ArgumentCaptor.forClass(IThermalEventListener.class);
|
||||||
|
|
||||||
|
verify(mThermalServiceMock).registerThermalEventListenerWithType(
|
||||||
|
thermalEventListener.capture(), eq(Temperature.TYPE_SKIN));
|
||||||
|
final IThermalEventListener listener = thermalEventListener.getValue();
|
||||||
|
|
||||||
|
// Verify that there is no skin temperature vote initially.
|
||||||
|
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
|
||||||
|
assertNull(vote);
|
||||||
|
|
||||||
|
// Set the skin temperature to critical and verify that we added a vote.
|
||||||
|
listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL));
|
||||||
|
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
|
||||||
|
assertVoteForRefreshRateRange(vote, 0f, 60.f);
|
||||||
|
|
||||||
|
// Set the skin temperature to severe and verify that the vote is gone.
|
||||||
|
listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_SEVERE));
|
||||||
|
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
|
||||||
|
assertNull(vote);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Temperature getSkinTemp(@Temperature.ThrottlingStatus int status) {
|
||||||
|
return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status);
|
||||||
|
}
|
||||||
|
|
||||||
private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
|
private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
|
||||||
assertThat(vote).isNotNull();
|
assertThat(vote).isNotNull();
|
||||||
final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
|
final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
|
||||||
assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
|
assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertVoteForRefreshRateRange(
|
||||||
|
Vote vote, float refreshRateLow, float refreshRateHigh) {
|
||||||
|
assertThat(vote).isNotNull();
|
||||||
|
final RefreshRateRange expectedRange =
|
||||||
|
new RefreshRateRange(refreshRateLow, refreshRateHigh);
|
||||||
|
assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
|
||||||
|
}
|
||||||
|
|
||||||
public static class FakeDeviceConfig extends FakeDeviceConfigInterface {
|
public static class FakeDeviceConfig extends FakeDeviceConfigInterface {
|
||||||
@Override
|
@Override
|
||||||
public String getProperty(String namespace, String name) {
|
public String getProperty(String namespace, String name) {
|
||||||
@@ -1748,6 +1795,11 @@ public class DisplayModeDirectorTest {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IThermalService getThermalService() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
void notifyPeakRefreshRateChanged() {
|
void notifyPeakRefreshRateChanged() {
|
||||||
if (mPeakRefreshRateObserver != null) {
|
if (mPeakRefreshRateObserver != null) {
|
||||||
mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
|
mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
|
||||||
|
|||||||
Reference in New Issue
Block a user