1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.power; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assert.assertArrayEquals; 22 import static org.junit.Assert.assertEquals; 23 import static org.junit.Assert.assertFalse; 24 import static org.junit.Assert.assertNotNull; 25 import static org.junit.Assert.assertNotSame; 26 import static org.junit.Assert.assertTrue; 27 import static org.mockito.ArgumentMatchers.any; 28 import static org.mockito.ArgumentMatchers.anyInt; 29 import static org.mockito.Mockito.doReturn; 30 import static org.mockito.Mockito.mock; 31 import static org.mockito.Mockito.reset; 32 import static org.mockito.Mockito.timeout; 33 import static org.mockito.Mockito.times; 34 import static org.mockito.Mockito.verify; 35 import static org.mockito.Mockito.when; 36 37 import android.content.Context; 38 import android.content.pm.PackageManager; 39 import android.hardware.thermal.TemperatureThreshold; 40 import android.hardware.thermal.ThrottlingSeverity; 41 import android.os.CoolingDevice; 42 import android.os.IBinder; 43 import android.os.IPowerManager; 44 import android.os.IThermalEventListener; 45 import android.os.IThermalService; 46 import android.os.IThermalStatusListener; 47 import android.os.PowerManager; 48 import android.os.RemoteException; 49 import android.os.Temperature; 50 51 import androidx.test.filters.SmallTest; 52 import androidx.test.runner.AndroidJUnit4; 53 54 import com.android.server.SystemService; 55 import com.android.server.power.ThermalManagerService.TemperatureWatcher; 56 import com.android.server.power.ThermalManagerService.ThermalHalWrapper; 57 58 import org.junit.Before; 59 import org.junit.Test; 60 import org.junit.runner.RunWith; 61 import org.mockito.ArgumentCaptor; 62 import org.mockito.Mock; 63 import org.mockito.MockitoAnnotations; 64 65 import java.io.FileDescriptor; 66 import java.io.PrintWriter; 67 import java.io.StringWriter; 68 import java.util.ArrayList; 69 import java.util.Arrays; 70 import java.util.HashSet; 71 import java.util.List; 72 import java.util.Map; 73 74 /** 75 * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server 76 * /power/ThermalManagerServiceTest.java 77 */ 78 @SmallTest 79 @RunWith(AndroidJUnit4.class) 80 public class ThermalManagerServiceTest { 81 private static final long CALLBACK_TIMEOUT_MILLI_SEC = 5000; 82 private ThermalManagerService mService; 83 private ThermalHalFake mFakeHal; 84 private PowerManager mPowerManager; 85 @Mock 86 private Context mContext; 87 @Mock 88 private IPowerManager mIPowerManagerMock; 89 @Mock 90 private IThermalService mIThermalServiceMock; 91 @Mock 92 private IThermalEventListener mEventListener1; 93 @Mock 94 private IThermalEventListener mEventListener2; 95 @Mock 96 private IThermalStatusListener mStatusListener1; 97 @Mock 98 private IThermalStatusListener mStatusListener2; 99 100 /** 101 * Fake Hal class. 102 */ 103 private class ThermalHalFake extends ThermalHalWrapper { 104 private static final int INIT_STATUS = Temperature.THROTTLING_NONE; 105 private ArrayList<Temperature> mTemperatureList = new ArrayList<>(); 106 private ArrayList<CoolingDevice> mCoolingDeviceList = new ArrayList<>(); 107 private ArrayList<TemperatureThreshold> mTemperatureThresholdList = initializeThresholds(); 108 109 private Temperature mSkin1 = new Temperature(0, Temperature.TYPE_SKIN, "skin1", 110 INIT_STATUS); 111 private Temperature mSkin2 = new Temperature(0, Temperature.TYPE_SKIN, "skin2", 112 INIT_STATUS); 113 private Temperature mBattery = new Temperature(0, Temperature.TYPE_BATTERY, "batt", 114 INIT_STATUS); 115 private Temperature mUsbPort = new Temperature(0, Temperature.TYPE_USB_PORT, "usbport", 116 INIT_STATUS); 117 private CoolingDevice mCpu = new CoolingDevice(0, CoolingDevice.TYPE_BATTERY, "cpu"); 118 private CoolingDevice mGpu = new CoolingDevice(0, CoolingDevice.TYPE_BATTERY, "gpu"); 119 initializeThresholds()120 private ArrayList<TemperatureThreshold> initializeThresholds() { 121 ArrayList<TemperatureThreshold> thresholds = new ArrayList<>(); 122 123 TemperatureThreshold skinThreshold = new TemperatureThreshold(); 124 skinThreshold.type = Temperature.TYPE_SKIN; 125 skinThreshold.name = "skin1"; 126 skinThreshold.hotThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/]; 127 skinThreshold.coldThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/]; 128 for (int i = 0; i < skinThreshold.hotThrottlingThresholds.length; ++i) { 129 // Sets NONE to 25.0f, SEVERE to 40.0f, and SHUTDOWN to 55.0f 130 skinThreshold.hotThrottlingThresholds[i] = 25.0f + 5.0f * i; 131 } 132 thresholds.add(skinThreshold); 133 134 TemperatureThreshold cpuThreshold = new TemperatureThreshold(); 135 cpuThreshold.type = Temperature.TYPE_CPU; 136 cpuThreshold.name = "cpu"; 137 cpuThreshold.hotThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/]; 138 cpuThreshold.coldThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/]; 139 for (int i = 0; i < cpuThreshold.hotThrottlingThresholds.length; ++i) { 140 if (i == ThrottlingSeverity.SEVERE) { 141 cpuThreshold.hotThrottlingThresholds[i] = 95.0f; 142 } else { 143 cpuThreshold.hotThrottlingThresholds[i] = Float.NaN; 144 } 145 } 146 thresholds.add(cpuThreshold); 147 148 return thresholds; 149 } 150 ThermalHalFake()151 ThermalHalFake() { 152 mTemperatureList.add(mSkin1); 153 mTemperatureList.add(mSkin2); 154 mTemperatureList.add(mBattery); 155 mTemperatureList.add(mUsbPort); 156 mCoolingDeviceList.add(mCpu); 157 mCoolingDeviceList.add(mGpu); 158 } 159 160 @Override getCurrentTemperatures(boolean shouldFilter, int type)161 protected List<Temperature> getCurrentTemperatures(boolean shouldFilter, int type) { 162 List<Temperature> ret = new ArrayList<>(); 163 for (Temperature temperature : mTemperatureList) { 164 if (shouldFilter && type != temperature.getType()) { 165 continue; 166 } 167 ret.add(temperature); 168 } 169 return ret; 170 } 171 172 @Override getCurrentCoolingDevices(boolean shouldFilter, int type)173 protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter, int type) { 174 List<CoolingDevice> ret = new ArrayList<>(); 175 for (CoolingDevice cdev : mCoolingDeviceList) { 176 if (shouldFilter && type != cdev.getType()) { 177 continue; 178 } 179 ret.add(cdev); 180 } 181 return ret; 182 } 183 184 @Override getTemperatureThresholds(boolean shouldFilter, int type)185 protected List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter, 186 int type) { 187 List<TemperatureThreshold> ret = new ArrayList<>(); 188 for (TemperatureThreshold threshold : mTemperatureThresholdList) { 189 if (shouldFilter && type != threshold.type) { 190 continue; 191 } 192 ret.add(threshold); 193 } 194 return ret; 195 } 196 197 @Override connectToHal()198 protected boolean connectToHal() { 199 return true; 200 } 201 202 @Override dump(PrintWriter pw, String prefix)203 protected void dump(PrintWriter pw, String prefix) { 204 pw.print(prefix); 205 pw.println("ThermalHAL AIDL 1 connected: yes"); 206 } 207 } 208 assertListEqualsIgnoringOrder(List<?> actual, List<?> expected)209 private void assertListEqualsIgnoringOrder(List<?> actual, List<?> expected) { 210 HashSet<?> actualSet = new HashSet<>(actual); 211 HashSet<?> expectedSet = new HashSet<>(expected); 212 assertEquals(expectedSet, actualSet); 213 } 214 215 @Before setUp()216 public void setUp() throws RemoteException { 217 MockitoAnnotations.initMocks(this); 218 mFakeHal = new ThermalHalFake(); 219 mPowerManager = new PowerManager(mContext, mIPowerManagerMock, mIThermalServiceMock, null); 220 when(mContext.getSystemServiceName(PowerManager.class)).thenReturn(Context.POWER_SERVICE); 221 when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager); 222 resetListenerMock(); 223 mService = new ThermalManagerService(mContext, mFakeHal); 224 // Register callbacks before AMS ready and no callback sent 225 assertTrue(mService.mService.registerThermalEventListener(mEventListener1)); 226 assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1)); 227 assertTrue(mService.mService.registerThermalEventListenerWithType(mEventListener2, 228 Temperature.TYPE_SKIN)); 229 assertTrue(mService.mService.registerThermalStatusListener(mStatusListener2)); 230 verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 231 .times(0)).notifyThrottling(any(Temperature.class)); 232 verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 233 .times(1)).onStatusChange(Temperature.THROTTLING_NONE); 234 verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 235 .times(0)).notifyThrottling(any(Temperature.class)); 236 verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 237 .times(1)).onStatusChange(Temperature.THROTTLING_NONE); 238 resetListenerMock(); 239 mService.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY); 240 ArgumentCaptor<Temperature> captor = ArgumentCaptor.forClass(Temperature.class); 241 verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 242 .times(4)).notifyThrottling(captor.capture()); 243 assertListEqualsIgnoringOrder(mFakeHal.mTemperatureList, captor.getAllValues()); 244 verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 245 .times(0)).onStatusChange(Temperature.THROTTLING_NONE); 246 captor = ArgumentCaptor.forClass(Temperature.class); 247 verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 248 .times(2)).notifyThrottling(captor.capture()); 249 assertListEqualsIgnoringOrder( 250 new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)), 251 captor.getAllValues()); 252 verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 253 .times(0)).onStatusChange(Temperature.THROTTLING_NONE); 254 } 255 resetListenerMock()256 private void resetListenerMock() { 257 reset(mEventListener1); 258 reset(mStatusListener1); 259 reset(mEventListener2); 260 reset(mStatusListener2); 261 doReturn(mock(IBinder.class)).when(mEventListener1).asBinder(); 262 doReturn(mock(IBinder.class)).when(mStatusListener1).asBinder(); 263 doReturn(mock(IBinder.class)).when(mEventListener2).asBinder(); 264 doReturn(mock(IBinder.class)).when(mStatusListener2).asBinder(); 265 } 266 267 @Test testRegister()268 public void testRegister() throws RemoteException { 269 resetListenerMock(); 270 // Register callbacks and verify they are called 271 assertTrue(mService.mService.registerThermalEventListener(mEventListener1)); 272 assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1)); 273 ArgumentCaptor<Temperature> captor = ArgumentCaptor.forClass(Temperature.class); 274 verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 275 .times(4)).notifyThrottling(captor.capture()); 276 assertListEqualsIgnoringOrder(mFakeHal.mTemperatureList, captor.getAllValues()); 277 verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 278 .times(1)).onStatusChange(Temperature.THROTTLING_NONE); 279 // Register new callbacks and verify old ones are not called (remained same) while new 280 // ones are called 281 assertTrue(mService.mService.registerThermalEventListenerWithType(mEventListener2, 282 Temperature.TYPE_SKIN)); 283 assertTrue(mService.mService.registerThermalStatusListener(mStatusListener2)); 284 verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 285 .times(4)).notifyThrottling(any(Temperature.class)); 286 verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 287 .times(1)).onStatusChange(Temperature.THROTTLING_NONE); 288 captor = ArgumentCaptor.forClass(Temperature.class); 289 verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 290 .times(2)).notifyThrottling(captor.capture()); 291 assertListEqualsIgnoringOrder( 292 new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)), 293 captor.getAllValues()); 294 verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 295 .times(1)).onStatusChange(Temperature.THROTTLING_NONE); 296 } 297 298 @Test testNotify()299 public void testNotify() throws RemoteException { 300 int status = Temperature.THROTTLING_SEVERE; 301 // Should only notify event not status 302 Temperature newBattery = new Temperature(50, Temperature.TYPE_BATTERY, "batt", status); 303 mFakeHal.mCallback.onValues(newBattery); 304 verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 305 .times(1)).notifyThrottling(newBattery); 306 verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 307 .times(0)).onStatusChange(anyInt()); 308 verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 309 .times(0)).notifyThrottling(newBattery); 310 verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 311 .times(0)).onStatusChange(anyInt()); 312 resetListenerMock(); 313 // Notify both event and status 314 Temperature newSkin = new Temperature(50, Temperature.TYPE_SKIN, "skin1", status); 315 mFakeHal.mCallback.onValues(newSkin); 316 verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 317 .times(1)).notifyThrottling(newSkin); 318 verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 319 .times(1)).onStatusChange(status); 320 verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 321 .times(1)).notifyThrottling(newSkin); 322 verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 323 .times(1)).onStatusChange(status); 324 resetListenerMock(); 325 // Back to None, should only notify event not status 326 status = Temperature.THROTTLING_NONE; 327 newBattery = new Temperature(50, Temperature.TYPE_BATTERY, "batt", status); 328 mFakeHal.mCallback.onValues(newBattery); 329 verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 330 .times(1)).notifyThrottling(newBattery); 331 verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 332 .times(0)).onStatusChange(anyInt()); 333 verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 334 .times(0)).notifyThrottling(newBattery); 335 verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 336 .times(0)).onStatusChange(anyInt()); 337 resetListenerMock(); 338 // Should also notify status 339 newSkin = new Temperature(50, Temperature.TYPE_SKIN, "skin1", status); 340 mFakeHal.mCallback.onValues(newSkin); 341 verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 342 .times(1)).notifyThrottling(newSkin); 343 verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 344 .times(1)).onStatusChange(status); 345 verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 346 .times(1)).notifyThrottling(newSkin); 347 verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 348 .times(1)).onStatusChange(status); 349 } 350 351 @Test testGetCurrentTemperatures()352 public void testGetCurrentTemperatures() throws RemoteException { 353 assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(false, 0), 354 Arrays.asList(mService.mService.getCurrentTemperatures())); 355 assertListEqualsIgnoringOrder( 356 mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN), 357 Arrays.asList(mService.mService.getCurrentTemperaturesWithType( 358 Temperature.TYPE_SKIN))); 359 } 360 361 @Test testGetCurrentStatus()362 public void testGetCurrentStatus() throws RemoteException { 363 int status = Temperature.THROTTLING_SEVERE; 364 Temperature newSkin = new Temperature(100, Temperature.TYPE_SKIN, "skin1", status); 365 mFakeHal.mCallback.onValues(newSkin); 366 assertEquals(status, mService.mService.getCurrentThermalStatus()); 367 int battStatus = Temperature.THROTTLING_EMERGENCY; 368 Temperature newBattery = new Temperature(60, Temperature.TYPE_BATTERY, "batt", battStatus); 369 assertEquals(status, mService.mService.getCurrentThermalStatus()); 370 } 371 372 @Test testThermalShutdown()373 public void testThermalShutdown() throws RemoteException { 374 int status = Temperature.THROTTLING_SHUTDOWN; 375 Temperature newSkin = new Temperature(100, Temperature.TYPE_SKIN, "skin1", status); 376 mFakeHal.mCallback.onValues(newSkin); 377 verify(mIPowerManagerMock, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 378 .times(1)).shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false); 379 Temperature newBattery = new Temperature(60, Temperature.TYPE_BATTERY, "batt", status); 380 mFakeHal.mCallback.onValues(newBattery); 381 verify(mIPowerManagerMock, timeout(CALLBACK_TIMEOUT_MILLI_SEC) 382 .times(1)).shutdown(false, PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE, false); 383 } 384 385 @Test testNoHal()386 public void testNoHal() throws RemoteException { 387 mService = new ThermalManagerService(mContext); 388 // Do no call onActivityManagerReady to skip connect HAL 389 assertTrue(mService.mService.registerThermalEventListener(mEventListener1)); 390 assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1)); 391 assertTrue(mService.mService.unregisterThermalEventListener(mEventListener1)); 392 assertTrue(mService.mService.unregisterThermalStatusListener(mStatusListener1)); 393 assertEquals(0, Arrays.asList(mService.mService.getCurrentTemperatures()).size()); 394 assertEquals(0, Arrays.asList(mService.mService.getCurrentTemperaturesWithType( 395 Temperature.TYPE_SKIN)).size()); 396 assertEquals(Temperature.THROTTLING_NONE, mService.mService.getCurrentThermalStatus()); 397 assertTrue(Float.isNaN(mService.mService.getThermalHeadroom(0))); 398 } 399 400 @Test testGetCurrentCoolingDevices()401 public void testGetCurrentCoolingDevices() throws RemoteException { 402 assertListEqualsIgnoringOrder(mFakeHal.getCurrentCoolingDevices(false, 0), 403 Arrays.asList(mService.mService.getCurrentCoolingDevices())); 404 assertListEqualsIgnoringOrder( 405 mFakeHal.getCurrentCoolingDevices(false, CoolingDevice.TYPE_BATTERY), 406 Arrays.asList(mService.mService.getCurrentCoolingDevices())); 407 assertListEqualsIgnoringOrder( 408 mFakeHal.getCurrentCoolingDevices(true, CoolingDevice.TYPE_CPU), 409 Arrays.asList(mService.mService.getCurrentCoolingDevicesWithType( 410 CoolingDevice.TYPE_CPU))); 411 } 412 413 @Test testGetThermalHeadroomInputRange()414 public void testGetThermalHeadroomInputRange() throws RemoteException { 415 assertTrue(Float.isNaN(mService.mService.getThermalHeadroom( 416 ThermalManagerService.MIN_FORECAST_SEC - 1))); 417 assertTrue(Float.isNaN(mService.mService.getThermalHeadroom( 418 ThermalManagerService.MAX_FORECAST_SEC + 1))); 419 } 420 421 @Test testTemperatureWatcherUpdateSevereThresholds()422 public void testTemperatureWatcherUpdateSevereThresholds() throws RemoteException { 423 TemperatureWatcher watcher = mService.mTemperatureWatcher; 424 watcher.mSevereThresholds.erase(); 425 watcher.updateThresholds(); 426 assertEquals(1, watcher.mSevereThresholds.size()); 427 assertEquals("skin1", watcher.mSevereThresholds.keyAt(0)); 428 Float threshold = watcher.mSevereThresholds.get("skin1"); 429 assertNotNull(threshold); 430 assertEquals(40.0f, threshold, 0.0f); 431 } 432 433 @Test testTemperatureWatcherUpdateHeadroomThreshold()434 public void testTemperatureWatcherUpdateHeadroomThreshold() { 435 TemperatureWatcher watcher = mService.mTemperatureWatcher; 436 synchronized (watcher.mSamples) { 437 Arrays.fill(watcher.mHeadroomThresholds, Float.NaN); 438 } 439 watcher.updateHeadroomThreshold(ThrottlingSeverity.LIGHT, 40, 49); 440 watcher.updateHeadroomThreshold(ThrottlingSeverity.MODERATE, 46, 49); 441 watcher.updateHeadroomThreshold(ThrottlingSeverity.SEVERE, 49, 49); 442 watcher.updateHeadroomThreshold(ThrottlingSeverity.CRITICAL, 64, 49); 443 watcher.updateHeadroomThreshold(ThrottlingSeverity.EMERGENCY, 70, 49); 444 watcher.updateHeadroomThreshold(ThrottlingSeverity.SHUTDOWN, 79, 49); 445 synchronized (watcher.mSamples) { 446 assertArrayEquals(new float[]{Float.NaN, 0.7f, 0.9f, 1.0f, 1.5f, 1.7f, 2.0f}, 447 watcher.mHeadroomThresholds, 0.01f); 448 } 449 450 // when another sensor reports different threshold, we expect to see smaller one to be used 451 watcher.updateHeadroomThreshold(ThrottlingSeverity.LIGHT, 37, 52); 452 watcher.updateHeadroomThreshold(ThrottlingSeverity.MODERATE, 46, 52); 453 watcher.updateHeadroomThreshold(ThrottlingSeverity.SEVERE, 52, 52); 454 watcher.updateHeadroomThreshold(ThrottlingSeverity.CRITICAL, 64, 52); 455 watcher.updateHeadroomThreshold(ThrottlingSeverity.EMERGENCY, 100, 52); 456 watcher.updateHeadroomThreshold(ThrottlingSeverity.SHUTDOWN, 200, 52); 457 synchronized (watcher.mSamples) { 458 assertArrayEquals(new float[]{Float.NaN, 0.5f, 0.8f, 1.0f, 1.4f, 1.7f, 2.0f}, 459 watcher.mHeadroomThresholds, 0.01f); 460 } 461 } 462 463 @Test testGetThermalHeadroomThresholdsOnlyReadOnce()464 public void testGetThermalHeadroomThresholdsOnlyReadOnce() throws Exception { 465 float[] expected = new float[]{Float.NaN, 0.1f, 0.2f, 0.3f, 0.4f, Float.NaN, 0.6f}; 466 when(mIThermalServiceMock.getThermalHeadroomThresholds()).thenReturn(expected); 467 Map<Integer, Float> thresholds1 = mPowerManager.getThermalHeadroomThresholds(); 468 verify(mIThermalServiceMock, times(1)).getThermalHeadroomThresholds(); 469 for (int status = PowerManager.THERMAL_STATUS_LIGHT; 470 status <= PowerManager.THERMAL_STATUS_SHUTDOWN; status++) { 471 if (Float.isNaN(expected[status])) { 472 assertFalse(thresholds1.containsKey(status)); 473 } else { 474 assertEquals(expected[status], thresholds1.get(status), 0.01f); 475 } 476 } 477 reset(mIThermalServiceMock); 478 Map<Integer, Float> thresholds2 = mPowerManager.getThermalHeadroomThresholds(); 479 verify(mIThermalServiceMock, times(0)).getThermalHeadroomThresholds(); 480 assertNotSame(thresholds1, thresholds2); 481 assertEquals(thresholds1, thresholds2); 482 } 483 484 @Test testGetThermalHeadroomThresholdsOnDefaultHalResult()485 public void testGetThermalHeadroomThresholdsOnDefaultHalResult() throws Exception { 486 TemperatureWatcher watcher = mService.mTemperatureWatcher; 487 ArrayList<TemperatureThreshold> thresholds = new ArrayList<>(); 488 mFakeHal.mTemperatureThresholdList = thresholds; 489 watcher.updateThresholds(); 490 synchronized (watcher.mSamples) { 491 assertArrayEquals( 492 new float[]{Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, 493 Float.NaN}, 494 watcher.mHeadroomThresholds, 0.01f); 495 } 496 TemperatureThreshold nanThresholds = new TemperatureThreshold(); 497 nanThresholds.name = "nan"; 498 nanThresholds.type = Temperature.TYPE_SKIN; 499 nanThresholds.hotThrottlingThresholds = new float[ThrottlingSeverity.SHUTDOWN + 1]; 500 nanThresholds.coldThrottlingThresholds = new float[ThrottlingSeverity.SHUTDOWN + 1]; 501 Arrays.fill(nanThresholds.hotThrottlingThresholds, Float.NaN); 502 Arrays.fill(nanThresholds.coldThrottlingThresholds, Float.NaN); 503 thresholds.add(nanThresholds); 504 watcher.updateThresholds(); 505 synchronized (watcher.mSamples) { 506 assertArrayEquals( 507 new float[]{Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, 508 Float.NaN}, 509 watcher.mHeadroomThresholds, 0.01f); 510 } 511 } 512 513 @Test testTemperatureWatcherGetSlopeOf()514 public void testTemperatureWatcherGetSlopeOf() throws RemoteException { 515 TemperatureWatcher watcher = mService.mTemperatureWatcher; 516 List<TemperatureWatcher.Sample> samples = new ArrayList<>(); 517 for (int i = 0; i < 30; ++i) { 518 samples.add(watcher.createSampleForTesting(i, (float) (i / 2 * 2))); 519 } 520 assertEquals(1.0f, watcher.getSlopeOf(samples), 0.01f); 521 } 522 523 @Test testTemperatureWatcherNormalizeTemperature()524 public void testTemperatureWatcherNormalizeTemperature() throws RemoteException { 525 assertEquals(0.5f, 526 TemperatureWatcher.normalizeTemperature(25.0f, 40.0f), 0.0f); 527 528 // Temperatures more than 30 degrees below the SEVERE threshold should be clamped to 0.0f 529 assertEquals(0.0f, 530 TemperatureWatcher.normalizeTemperature(0.0f, 40.0f), 0.0f); 531 532 // Temperatures above the SEVERE threshold should not be clamped 533 assertEquals(2.0f, 534 TemperatureWatcher.normalizeTemperature(70.0f, 40.0f), 0.0f); 535 } 536 537 @Test testTemperatureWatcherGetForecast()538 public void testTemperatureWatcherGetForecast() throws RemoteException { 539 TemperatureWatcher watcher = mService.mTemperatureWatcher; 540 541 ArrayList<TemperatureWatcher.Sample> samples = new ArrayList<>(); 542 543 // Add a single sample 544 samples.add(watcher.createSampleForTesting(0, 25.0f)); 545 watcher.mSamples.put("skin1", samples); 546 547 // Because there are not enough samples to compute the linear regression, 548 // no matter how far ahead we forecast, we should receive the same value 549 assertEquals(0.5f, watcher.getForecast(0), 0.0f); 550 assertEquals(0.5f, watcher.getForecast(5), 0.0f); 551 552 // Add some time-series data 553 for (int i = 1; i < 20; ++i) { 554 samples.add(watcher.createSampleForTesting(1000 * i, 25.0f + 0.5f * i)); 555 } 556 557 // Now the forecast should vary depending on how far ahead we are trying to predict 558 assertEquals(0.9f, watcher.getForecast(4), 0.02f); 559 assertEquals(1.0f, watcher.getForecast(10), 0.02f); 560 561 // If there are no thresholds, then we shouldn't receive a headroom value 562 watcher.mSevereThresholds.erase(); 563 assertTrue(Float.isNaN(watcher.getForecast(0))); 564 } 565 566 @Test testTemperatureWatcherGetForecastUpdate()567 public void testTemperatureWatcherGetForecastUpdate() throws Exception { 568 TemperatureWatcher watcher = mService.mTemperatureWatcher; 569 570 // Reduce the inactivity threshold to speed up testing 571 watcher.mInactivityThresholdMillis = 2000; 572 573 // Make sure mSamples is empty before updateTemperature 574 assertTrue(isWatcherSamplesEmpty(watcher)); 575 576 // Call getForecast once to trigger updateTemperature 577 watcher.getForecast(0); 578 579 // After 1 second, the samples should be updated 580 Thread.sleep(1000); 581 assertFalse(isWatcherSamplesEmpty(watcher)); 582 583 // After mInactivityThresholdMillis, the samples should be cleared 584 Thread.sleep(watcher.mInactivityThresholdMillis); 585 assertTrue(isWatcherSamplesEmpty(watcher)); 586 } 587 588 // Helper function to hold mSamples lock, avoid GuardedBy lint errors isWatcherSamplesEmpty(TemperatureWatcher watcher)589 private boolean isWatcherSamplesEmpty(TemperatureWatcher watcher) { 590 synchronized (watcher.mSamples) { 591 return watcher.mSamples.isEmpty(); 592 } 593 } 594 595 @Test testDump()596 public void testDump() { 597 when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)) 598 .thenReturn(PackageManager.PERMISSION_GRANTED); 599 final StringWriter out = new StringWriter(); 600 PrintWriter pw = new PrintWriter(out); 601 mService.dumpInternal(new FileDescriptor(), pw, null); 602 final String dumpStr = out.toString(); 603 assertThat(dumpStr).contains("IsStatusOverride: false"); 604 assertThat(dumpStr).contains( 605 "ThermalEventListeners:\n" 606 + "\tcallbacks: 2\n" 607 + "\tkilled: false\n" 608 + "\tbroadcasts count: -1"); 609 assertThat(dumpStr).contains( 610 "ThermalStatusListeners:\n" 611 + "\tcallbacks: 2\n" 612 + "\tkilled: false\n" 613 + "\tbroadcasts count: -1"); 614 assertThat(dumpStr).contains("Thermal Status: 0"); 615 assertThat(dumpStr).contains( 616 "Cached temperatures:\n" 617 + "\tTemperature{mValue=0.0, mType=4, mName=usbport, mStatus=0}\n" 618 + "\tTemperature{mValue=0.0, mType=2, mName=batt, mStatus=0}\n" 619 + "\tTemperature{mValue=0.0, mType=3, mName=skin1, mStatus=0}\n" 620 + "\tTemperature{mValue=0.0, mType=3, mName=skin2, mStatus=0}" 621 ); 622 assertThat(dumpStr).contains("HAL Ready: true\n" 623 + "HAL connection:\n" 624 + "\tThermalHAL AIDL 1 connected: yes"); 625 assertThat(dumpStr).contains("Current temperatures from HAL:\n" 626 + "\tTemperature{mValue=0.0, mType=3, mName=skin1, mStatus=0}\n" 627 + "\tTemperature{mValue=0.0, mType=3, mName=skin2, mStatus=0}\n" 628 + "\tTemperature{mValue=0.0, mType=2, mName=batt, mStatus=0}\n" 629 + "\tTemperature{mValue=0.0, mType=4, mName=usbport, mStatus=0}\n"); 630 assertThat(dumpStr).contains("Current cooling devices from HAL:\n" 631 + "\tCoolingDevice{mValue=0, mType=1, mName=cpu}\n" 632 + "\tCoolingDevice{mValue=0, mType=1, mName=gpu}\n"); 633 assertThat(dumpStr).contains("Temperature static thresholds from HAL:\n" 634 + "\tTemperatureThreshold{mType=3, mName=skin1, mHotThrottlingThresholds=[25.0, " 635 + "30.0, 35.0, 40.0, 45.0, 50.0, 55.0], mColdThrottlingThresholds=[0.0, 0.0, 0.0," 636 + " 0.0, 0.0, 0.0, 0.0]}\n" 637 + "\tTemperatureThreshold{mType=0, mName=cpu, mHotThrottlingThresholds=[NaN, NaN," 638 + " NaN, 95.0, NaN, NaN, NaN], mColdThrottlingThresholds=[0.0, 0.0, 0.0, 0.0, 0" 639 + ".0, 0.0, 0.0]}"); 640 } 641 } 642