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:
Long Ling
2021-09-02 17:01:04 +00:00
committed by Automerger Merge Worker
2 changed files with 123 additions and 4 deletions

View File

@@ -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);

View File

@@ -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*/,