• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.assertTrue;
26 import static org.mockito.AdditionalMatchers.aryEq;
27 import static org.mockito.ArgumentMatchers.any;
28 import static org.mockito.ArgumentMatchers.anyFloat;
29 import static org.mockito.ArgumentMatchers.anyInt;
30 import static org.mockito.ArgumentMatchers.eq;
31 import static org.mockito.Mockito.doReturn;
32 import static org.mockito.Mockito.mock;
33 import static org.mockito.Mockito.reset;
34 import static org.mockito.Mockito.timeout;
35 import static org.mockito.Mockito.times;
36 import static org.mockito.Mockito.verify;
37 import static org.mockito.Mockito.when;
38 
39 import android.content.Context;
40 import android.content.pm.PackageManager;
41 import android.hardware.thermal.TemperatureThreshold;
42 import android.hardware.thermal.ThrottlingSeverity;
43 import android.os.CoolingDevice;
44 import android.os.Flags;
45 import android.os.IBinder;
46 import android.os.IPowerManager;
47 import android.os.IThermalEventListener;
48 import android.os.IThermalHeadroomListener;
49 import android.os.IThermalService;
50 import android.os.IThermalStatusListener;
51 import android.os.PowerManager;
52 import android.os.RemoteException;
53 import android.os.Temperature;
54 import android.platform.test.annotations.DisableFlags;
55 import android.platform.test.annotations.EnableFlags;
56 import android.platform.test.flag.junit.SetFlagsRule;
57 
58 import androidx.test.filters.SmallTest;
59 import androidx.test.runner.AndroidJUnit4;
60 
61 import com.android.server.SystemService;
62 import com.android.server.power.ThermalManagerService.TemperatureWatcher;
63 import com.android.server.power.ThermalManagerService.ThermalHalWrapper;
64 
65 import org.junit.Before;
66 import org.junit.ClassRule;
67 import org.junit.Rule;
68 import org.junit.Test;
69 import org.junit.runner.RunWith;
70 import org.mockito.ArgumentCaptor;
71 import org.mockito.Mock;
72 import org.mockito.MockitoAnnotations;
73 
74 import java.io.FileDescriptor;
75 import java.io.PrintWriter;
76 import java.io.StringWriter;
77 import java.util.ArrayList;
78 import java.util.Arrays;
79 import java.util.HashSet;
80 import java.util.List;
81 import java.util.Map;
82 import java.util.concurrent.atomic.AtomicInteger;
83 
84 /**
85  * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server
86  * /power/ThermalManagerServiceTest.java
87  */
88 @SmallTest
89 @RunWith(AndroidJUnit4.class)
90 public class ThermalManagerServiceTest {
91     @ClassRule
92     public static final SetFlagsRule.ClassRule mSetFlagsClassRule = new SetFlagsRule.ClassRule();
93     @Rule
94     public final SetFlagsRule mSetFlagsRule = mSetFlagsClassRule.createSetFlagsRule();
95 
96     private static final long CALLBACK_TIMEOUT_MILLI_SEC = 5000;
97     private ThermalManagerService mService;
98     private ThermalHalFake mFakeHal;
99     private PowerManager mPowerManager;
100     @Mock
101     private Context mContext;
102     @Mock
103     private IPowerManager mIPowerManagerMock;
104     @Mock
105     private IThermalService mIThermalServiceMock;
106     @Mock
107     private IThermalHeadroomListener mHeadroomListener;
108     @Mock
109     private IThermalEventListener mEventListener1;
110     @Mock
111     private IThermalEventListener mEventListener2;
112     @Mock
113     private IThermalStatusListener mStatusListener1;
114     @Mock
115     private IThermalStatusListener mStatusListener2;
116 
117     /**
118      * Fake Hal class.
119      */
120     private class ThermalHalFake extends ThermalHalWrapper {
121         private static final int INIT_STATUS = Temperature.THROTTLING_NONE;
122         private final List<Temperature> mTemperatureList = new ArrayList<>();
123         private AtomicInteger mGetCurrentTemperaturesCalled = new AtomicInteger();
124         private List<CoolingDevice> mCoolingDeviceList = new ArrayList<>();
125         private List<TemperatureThreshold> mTemperatureThresholdList = initializeThresholds();
126 
127         private Temperature mSkin1 = new Temperature(28, Temperature.TYPE_SKIN, "skin1",
128                 INIT_STATUS);
129         private Temperature mSkin2 = new Temperature(31, Temperature.TYPE_SKIN, "skin2",
130                 INIT_STATUS);
131         private Temperature mBattery = new Temperature(34, Temperature.TYPE_BATTERY, "batt",
132                 INIT_STATUS);
133         private Temperature mUsbPort = new Temperature(37, Temperature.TYPE_USB_PORT, "usbport",
134                 INIT_STATUS);
135         private CoolingDevice mCpu = new CoolingDevice(40, CoolingDevice.TYPE_BATTERY, "cpu");
136         private CoolingDevice mGpu = new CoolingDevice(43, CoolingDevice.TYPE_BATTERY, "gpu");
137         private Map<Integer, Float> mForecastSkinTemperatures = null;
138         private int mForecastSkinTemperaturesCalled = 0;
139         private boolean mForecastSkinTemperaturesError = false;
140 
initializeThresholds()141         private List<TemperatureThreshold> initializeThresholds() {
142             ArrayList<TemperatureThreshold> thresholds = new ArrayList<>();
143 
144             TemperatureThreshold skinThreshold = new TemperatureThreshold();
145             skinThreshold.type = Temperature.TYPE_SKIN;
146             skinThreshold.name = "skin1";
147             skinThreshold.hotThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
148             skinThreshold.coldThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
149             for (int i = 0; i < skinThreshold.hotThrottlingThresholds.length; ++i) {
150                 // Sets NONE to 25.0f, SEVERE to 40.0f, and SHUTDOWN to 55.0f
151                 skinThreshold.hotThrottlingThresholds[i] = 25.0f + 5.0f * i;
152             }
153             thresholds.add(skinThreshold);
154 
155             TemperatureThreshold cpuThreshold = new TemperatureThreshold();
156             cpuThreshold.type = Temperature.TYPE_CPU;
157             cpuThreshold.name = "cpu";
158             cpuThreshold.hotThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
159             cpuThreshold.coldThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
160             for (int i = 0; i < cpuThreshold.hotThrottlingThresholds.length; ++i) {
161                 if (i == ThrottlingSeverity.SEVERE) {
162                     cpuThreshold.hotThrottlingThresholds[i] = 95.0f;
163                 } else {
164                     cpuThreshold.hotThrottlingThresholds[i] = Float.NaN;
165                 }
166             }
167             thresholds.add(cpuThreshold);
168 
169             return thresholds;
170         }
171 
ThermalHalFake()172         ThermalHalFake() {
173             mTemperatureList.add(mSkin1);
174             mTemperatureList.add(mSkin2);
175             mTemperatureList.add(mBattery);
176             mTemperatureList.add(mUsbPort);
177             mCoolingDeviceList.add(mCpu);
178             mCoolingDeviceList.add(mGpu);
179             mGetCurrentTemperaturesCalled.set(0);
180         }
181 
enableForecastSkinTemperature()182         void enableForecastSkinTemperature() {
183             mForecastSkinTemperatures = Map.of(0, 22.0f, 10, 25.0f, 20, 28.0f,
184                     30, 31.0f, 40, 34.0f, 50, 37.0f, 60, 40.0f);
185         }
186 
disableForecastSkinTemperature()187         void disableForecastSkinTemperature() {
188             mForecastSkinTemperatures = null;
189         }
190 
failForecastSkinTemperature()191         void failForecastSkinTemperature() {
192             mForecastSkinTemperaturesError = true;
193         }
194 
updateTemperatureList(Temperature... temperatures)195         void updateTemperatureList(Temperature... temperatures) {
196             synchronized (mTemperatureList) {
197                 mTemperatureList.clear();
198                 mTemperatureList.addAll(Arrays.asList(temperatures));
199             }
200         }
201 
202         @Override
getCurrentTemperatures(boolean shouldFilter, int type)203         protected List<Temperature> getCurrentTemperatures(boolean shouldFilter, int type) {
204             List<Temperature> ret = new ArrayList<>();
205             synchronized (mTemperatureList) {
206                 mGetCurrentTemperaturesCalled.incrementAndGet();
207                 for (Temperature temperature : mTemperatureList) {
208                     if (shouldFilter && type != temperature.getType()) {
209                         continue;
210                     }
211                     ret.add(temperature);
212                 }
213             }
214             return ret;
215         }
216 
217         @Override
getCurrentCoolingDevices(boolean shouldFilter, int type)218         protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter, int type) {
219             List<CoolingDevice> ret = new ArrayList<>();
220             for (CoolingDevice cdev : mCoolingDeviceList) {
221                 if (shouldFilter && type != cdev.getType()) {
222                     continue;
223                 }
224                 ret.add(cdev);
225             }
226             return ret;
227         }
228 
229         @Override
getTemperatureThresholds(boolean shouldFilter, int type)230         protected List<TemperatureThreshold> getTemperatureThresholds(boolean shouldFilter,
231                 int type) {
232             List<TemperatureThreshold> ret = new ArrayList<>();
233             for (TemperatureThreshold threshold : mTemperatureThresholdList) {
234                 if (shouldFilter && type != threshold.type) {
235                     continue;
236                 }
237                 ret.add(threshold);
238             }
239             return ret;
240         }
241 
242         @Override
forecastSkinTemperature(int forecastSeconds)243         protected float forecastSkinTemperature(int forecastSeconds) {
244             mForecastSkinTemperaturesCalled++;
245             if (mForecastSkinTemperaturesError) {
246                 throw new RuntimeException();
247             }
248             if (mForecastSkinTemperatures == null) {
249                 throw new UnsupportedOperationException();
250             }
251             return mForecastSkinTemperatures.get(forecastSeconds);
252         }
253 
254         @Override
connectToHal()255         protected boolean connectToHal() {
256             return true;
257         }
258 
259         @Override
dump(PrintWriter pw, String prefix)260         protected void dump(PrintWriter pw, String prefix) {
261             pw.print(prefix);
262             pw.println("ThermalHAL AIDL 1  connected: yes");
263         }
264     }
265 
assertListEqualsIgnoringOrder(List<?> actual, List<?> expected)266     private void assertListEqualsIgnoringOrder(List<?> actual, List<?> expected) {
267         HashSet<?> actualSet = new HashSet<>(actual);
268         HashSet<?> expectedSet = new HashSet<>(expected);
269         assertEquals(expectedSet, actualSet);
270     }
271 
272     @Before
setUp()273     public void setUp() throws RemoteException {
274         MockitoAnnotations.initMocks(this);
275         mFakeHal = new ThermalHalFake();
276         mPowerManager = new PowerManager(mContext, mIPowerManagerMock, mIThermalServiceMock, null);
277         when(mContext.getSystemServiceName(PowerManager.class)).thenReturn(Context.POWER_SERVICE);
278         when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
279         resetListenerMock();
280         mService = new ThermalManagerService(mContext, mFakeHal);
281         mService.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
282     }
283 
resetListenerMock()284     private void resetListenerMock() {
285         reset(mEventListener1);
286         reset(mStatusListener1);
287         reset(mEventListener2);
288         reset(mStatusListener2);
289         reset(mHeadroomListener);
290         doReturn(mock(IBinder.class)).when(mEventListener1).asBinder();
291         doReturn(mock(IBinder.class)).when(mStatusListener1).asBinder();
292         doReturn(mock(IBinder.class)).when(mEventListener2).asBinder();
293         doReturn(mock(IBinder.class)).when(mStatusListener2).asBinder();
294         doReturn(mock(IBinder.class)).when(mHeadroomListener).asBinder();
295     }
296 
297     @Test
testRegister()298     public void testRegister() throws Exception {
299         mService = new ThermalManagerService(mContext, mFakeHal);
300         // Register callbacks before AMS ready and verify they are called after AMS is ready
301         assertTrue(mService.mService.registerThermalEventListener(mEventListener1));
302         assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1));
303         assertTrue(mService.mService.registerThermalEventListenerWithType(mEventListener2,
304                 Temperature.TYPE_SKIN));
305         assertTrue(mService.mService.registerThermalStatusListener(mStatusListener2));
306         Thread.sleep(CALLBACK_TIMEOUT_MILLI_SEC);
307         resetListenerMock();
308         mService.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
309         assertTrue(mService.mService.registerThermalHeadroomListener(mHeadroomListener));
310 
311         ArgumentCaptor<Temperature> captor = ArgumentCaptor.forClass(Temperature.class);
312         verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
313                 .times(4)).notifyThrottling(captor.capture());
314         assertListEqualsIgnoringOrder(mFakeHal.mTemperatureList, captor.getAllValues());
315         verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
316                 .times(0)).onStatusChange(Temperature.THROTTLING_NONE);
317         captor = ArgumentCaptor.forClass(Temperature.class);
318         verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
319                 .times(2)).notifyThrottling(captor.capture());
320         assertListEqualsIgnoringOrder(
321                 new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
322                 captor.getAllValues());
323         verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
324                 .times(0)).onStatusChange(Temperature.THROTTLING_NONE);
325         resetListenerMock();
326 
327         // Register callbacks after AMS ready and verify they are called
328         assertTrue(mService.mService.registerThermalEventListener(mEventListener1));
329         assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1));
330         captor = ArgumentCaptor.forClass(Temperature.class);
331         verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
332                 .times(4)).notifyThrottling(captor.capture());
333         assertListEqualsIgnoringOrder(mFakeHal.mTemperatureList, captor.getAllValues());
334         verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
335                 .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
336 
337         // Register new callbacks and verify old ones are not called (remained same) while new
338         // ones are called
339         assertTrue(mService.mService.registerThermalEventListenerWithType(mEventListener2,
340                 Temperature.TYPE_SKIN));
341         assertTrue(mService.mService.registerThermalStatusListener(mStatusListener2));
342         verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
343                 .times(4)).notifyThrottling(any(Temperature.class));
344         verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
345                 .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
346         captor = ArgumentCaptor.forClass(Temperature.class);
347         verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
348                 .times(2)).notifyThrottling(captor.capture());
349         assertListEqualsIgnoringOrder(
350                 new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
351                 captor.getAllValues());
352         verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
353                 .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
354     }
355 
356     @Test
testNotifyThrottling()357     public void testNotifyThrottling() throws Exception {
358         assertTrue(mService.mService.registerThermalEventListener(mEventListener1));
359         assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1));
360         assertTrue(mService.mService.registerThermalEventListenerWithType(mEventListener2,
361                 Temperature.TYPE_SKIN));
362         assertTrue(mService.mService.registerThermalStatusListener(mStatusListener2));
363         Thread.sleep(CALLBACK_TIMEOUT_MILLI_SEC);
364         resetListenerMock();
365 
366         int status = Temperature.THROTTLING_SEVERE;
367         // Should only notify event not status
368         Temperature newBattery = new Temperature(50, Temperature.TYPE_BATTERY, "batt", status);
369         mFakeHal.mCallback.onTemperatureChanged(newBattery);
370         verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
371                 .times(1)).notifyThrottling(newBattery);
372         verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
373                 .times(0)).onStatusChange(anyInt());
374         verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
375                 .times(0)).notifyThrottling(newBattery);
376         verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
377                 .times(0)).onStatusChange(anyInt());
378         resetListenerMock();
379         // Notify both event and status
380         Temperature newSkin = new Temperature(50, Temperature.TYPE_SKIN, "skin1", status);
381         mFakeHal.mCallback.onTemperatureChanged(newSkin);
382         verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
383                 .times(1)).notifyThrottling(newSkin);
384         verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
385                 .times(1)).onStatusChange(status);
386         verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
387                 .times(1)).notifyThrottling(newSkin);
388         verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
389                 .times(1)).onStatusChange(status);
390         resetListenerMock();
391         // Back to None, should only notify event not status
392         status = Temperature.THROTTLING_NONE;
393         newBattery = new Temperature(50, Temperature.TYPE_BATTERY, "batt", status);
394         mFakeHal.mCallback.onTemperatureChanged(newBattery);
395         verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
396                 .times(1)).notifyThrottling(newBattery);
397         verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
398                 .times(0)).onStatusChange(anyInt());
399         verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
400                 .times(0)).notifyThrottling(newBattery);
401         verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
402                 .times(0)).onStatusChange(anyInt());
403         resetListenerMock();
404         // Should also notify status
405         newSkin = new Temperature(50, Temperature.TYPE_SKIN, "skin1", status);
406         mFakeHal.mCallback.onTemperatureChanged(newSkin);
407         verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
408                 .times(1)).notifyThrottling(newSkin);
409         verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
410                 .times(1)).onStatusChange(status);
411         verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
412                 .times(1)).notifyThrottling(newSkin);
413         verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
414                 .times(1)).onStatusChange(status);
415     }
416 
417     @Test
418     @EnableFlags({Flags.FLAG_ALLOW_THERMAL_THRESHOLDS_CALLBACK})
testNotifyThrottling_headroomCallback()419     public void testNotifyThrottling_headroomCallback() throws Exception {
420         assertTrue(mService.mService.registerThermalHeadroomListener(mHeadroomListener));
421         Thread.sleep(CALLBACK_TIMEOUT_MILLI_SEC);
422         resetListenerMock();
423         int status = Temperature.THROTTLING_SEVERE;
424         mFakeHal.updateTemperatureList();
425 
426         // Should not notify on non-skin type
427         Temperature newBattery = new Temperature(37, Temperature.TYPE_BATTERY, "batt", status);
428         mFakeHal.mCallback.onTemperatureChanged(newBattery);
429         verify(mHeadroomListener, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
430                 .times(0)).onHeadroomChange(anyFloat(), anyFloat(), anyInt(), any());
431         resetListenerMock();
432 
433         // Notify headroom on skin temperature change
434         Temperature newSkin = new Temperature(37, Temperature.TYPE_SKIN, "skin1", status);
435         mFakeHal.mCallback.onTemperatureChanged(newSkin);
436         verify(mHeadroomListener, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
437                 .times(1)).onHeadroomChange(eq(0.9f), anyFloat(), anyInt(),
438                 eq(new float[]{Float.NaN, 0.6666667f, 0.8333333f, 1.0f, 1.1666666f, 1.3333334f,
439                         1.5f}));
440         resetListenerMock();
441 
442         // Same or similar temperature should not trigger in a short period
443         mFakeHal.mCallback.onTemperatureChanged(newSkin);
444         newSkin = new Temperature(36.9f, Temperature.TYPE_SKIN, "skin1", status);
445         mFakeHal.mCallback.onTemperatureChanged(newSkin);
446         newSkin = new Temperature(37.1f, Temperature.TYPE_SKIN, "skin1", status);
447         mFakeHal.mCallback.onTemperatureChanged(newSkin);
448         verify(mHeadroomListener, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
449                 .times(0)).onHeadroomChange(anyFloat(), anyFloat(), anyInt(), any());
450         resetListenerMock();
451 
452         // Significant temperature should trigger in a short period
453         newSkin = new Temperature(34f, Temperature.TYPE_SKIN, "skin1", status);
454         mFakeHal.mCallback.onTemperatureChanged(newSkin);
455         verify(mHeadroomListener, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
456                 .times(1)).onHeadroomChange(eq(0.8f), anyFloat(), anyInt(),
457                 eq(new float[]{Float.NaN, 0.6666667f, 0.8333333f, 1.0f, 1.1666666f, 1.3333334f,
458                         1.5f}));
459         resetListenerMock();
460         newSkin = new Temperature(40f, Temperature.TYPE_SKIN, "skin1", status);
461         mFakeHal.mCallback.onTemperatureChanged(newSkin);
462         verify(mHeadroomListener, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
463                 .times(1)).onHeadroomChange(eq(1.0f), anyFloat(), anyInt(),
464                 eq(new float[]{Float.NaN, 0.6666667f, 0.8333333f, 1.0f, 1.1666666f, 1.3333334f,
465                         1.5f}));
466     }
467 
468     @Test
testGetCurrentTemperatures()469     public void testGetCurrentTemperatures() throws RemoteException {
470         assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(false, 0),
471                 Arrays.asList(mService.mService.getCurrentTemperatures()));
472         assertListEqualsIgnoringOrder(
473                 mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN),
474                 Arrays.asList(mService.mService.getCurrentTemperaturesWithType(
475                         Temperature.TYPE_SKIN)));
476     }
477 
478     @Test
testGetCurrentStatus()479     public void testGetCurrentStatus() throws RemoteException {
480         int status = Temperature.THROTTLING_SEVERE;
481         Temperature newSkin = new Temperature(100, Temperature.TYPE_SKIN, "skin1", status);
482         mFakeHal.mCallback.onTemperatureChanged(newSkin);
483         assertEquals(status, mService.mService.getCurrentThermalStatus());
484         int battStatus = Temperature.THROTTLING_EMERGENCY;
485         Temperature newBattery = new Temperature(60, Temperature.TYPE_BATTERY, "batt", battStatus);
486         assertEquals(status, mService.mService.getCurrentThermalStatus());
487     }
488 
489     @Test
testThermalShutdown()490     public void testThermalShutdown() throws RemoteException {
491         int status = Temperature.THROTTLING_SHUTDOWN;
492         Temperature newSkin = new Temperature(100, Temperature.TYPE_SKIN, "skin1", status);
493         mFakeHal.mCallback.onTemperatureChanged(newSkin);
494         verify(mIPowerManagerMock, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
495                 .times(1)).shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
496         Temperature newBattery = new Temperature(60, Temperature.TYPE_BATTERY, "batt", status);
497         mFakeHal.mCallback.onTemperatureChanged(newBattery);
498         verify(mIPowerManagerMock, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
499                 .times(1)).shutdown(false, PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE, false);
500     }
501 
502     @Test
testNoHal()503     public void testNoHal() throws RemoteException {
504         mService = new ThermalManagerService(mContext);
505         // Do no call onActivityManagerReady to skip connect HAL
506         assertTrue(mService.mService.registerThermalEventListener(mEventListener1));
507         assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1));
508         assertTrue(mService.mService.registerThermalEventListenerWithType(mEventListener2,
509                 Temperature.TYPE_SKIN));
510         assertFalse(mService.mService.registerThermalHeadroomListener(mHeadroomListener));
511         verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
512                 .times(0)).notifyThrottling(any(Temperature.class));
513         verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
514                 .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
515         verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
516                 .times(0)).notifyThrottling(any(Temperature.class));
517         verify(mHeadroomListener, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
518                 .times(0)).onHeadroomChange(anyFloat(), anyFloat(), anyInt(), any());
519 
520         assertEquals(0, Arrays.asList(mService.mService.getCurrentTemperatures()).size());
521         assertEquals(0, Arrays.asList(mService.mService.getCurrentTemperaturesWithType(
522                 Temperature.TYPE_SKIN)).size());
523         assertEquals(Temperature.THROTTLING_NONE, mService.mService.getCurrentThermalStatus());
524         assertTrue(Float.isNaN(mService.mService.getThermalHeadroom(0)));
525 
526         assertTrue(mService.mService.unregisterThermalEventListener(mEventListener1));
527         assertTrue(mService.mService.unregisterThermalEventListener(mEventListener2));
528         assertTrue(mService.mService.unregisterThermalStatusListener(mStatusListener1));
529         assertFalse(mService.mService.unregisterThermalHeadroomListener(mHeadroomListener));
530     }
531 
532     @Test
testGetCurrentCoolingDevices()533     public void testGetCurrentCoolingDevices() throws RemoteException {
534         assertListEqualsIgnoringOrder(mFakeHal.getCurrentCoolingDevices(false, 0),
535                 Arrays.asList(mService.mService.getCurrentCoolingDevices()));
536         assertListEqualsIgnoringOrder(
537                 mFakeHal.getCurrentCoolingDevices(false, CoolingDevice.TYPE_BATTERY),
538                 Arrays.asList(mService.mService.getCurrentCoolingDevices()));
539         assertListEqualsIgnoringOrder(
540                 mFakeHal.getCurrentCoolingDevices(true, CoolingDevice.TYPE_CPU),
541                 Arrays.asList(mService.mService.getCurrentCoolingDevicesWithType(
542                         CoolingDevice.TYPE_CPU)));
543     }
544 
545     @Test
testGetThermalHeadroomInputRange()546     public void testGetThermalHeadroomInputRange() throws RemoteException {
547         assertTrue(Float.isNaN(mService.mService.getThermalHeadroom(
548                 ThermalManagerService.MIN_FORECAST_SEC - 1)));
549         assertTrue(Float.isNaN(mService.mService.getThermalHeadroom(
550                 ThermalManagerService.MAX_FORECAST_SEC + 1)));
551     }
552 
553     @Test
554     @DisableFlags({Flags.FLAG_ALLOW_THERMAL_HAL_SKIN_FORECAST})
testGetThermalHeadroom_handlerUpdateTemperatures()555     public void testGetThermalHeadroom_handlerUpdateTemperatures()
556             throws RemoteException, InterruptedException {
557         // test that handler will at least enqueue one message to periodically read temperatures
558         // even if there is sample seeded from HAL temperature callback
559         String temperatureName = "skin1";
560         Temperature temperature = new Temperature(100, Temperature.TYPE_SKIN, temperatureName,
561                 Temperature.THROTTLING_NONE);
562         mFakeHal.mCallback.onTemperatureChanged(temperature);
563         float headroom = mService.mService.getThermalHeadroom(0);
564         // the callback temperature 100C (headroom > 1.0f) sample should have been appended by the
565         // immediately scheduled fake HAL current temperatures read (mSkin1, mSkin2), and because
566         // there are less samples for prediction, the latest temperature mSkin1 is used to calculate
567         // headroom (mSkin2 has no threshold), which is 0.6f (28C vs threshold 40C).
568         assertEquals(0.6f, headroom, 0.01f);
569         // one called by service onActivityManagerReady, one called by handler on headroom call
570         assertEquals(2, mFakeHal.mGetCurrentTemperaturesCalled.get());
571         // periodic read should update the samples history, so the headroom should increase 0.1f
572         // as current temperature goes up by 3C every 1100ms.
573         for (int i = 1; i < 5; i++) {
574             Temperature newTemperature = new Temperature(mFakeHal.mSkin1.getValue() + 3 * i,
575                     Temperature.TYPE_SKIN,
576                     temperatureName,
577                     Temperature.THROTTLING_NONE);
578             mFakeHal.updateTemperatureList(newTemperature);
579             // wait for handler to update temperature
580             Thread.sleep(1100);
581             // assert that only one callback was scheduled to query HAL when making multiple
582             // headroom calls
583             assertEquals(2 + i, mFakeHal.mGetCurrentTemperaturesCalled.get());
584             headroom = mService.mService.getThermalHeadroom(0);
585             assertEquals(0.6f + 0.1f * i, headroom, 0.01f);
586         }
587     }
588 
589     @Test
590     @EnableFlags({Flags.FLAG_ALLOW_THERMAL_HAL_SKIN_FORECAST})
testGetThermalHeadroom_halForecast()591     public void testGetThermalHeadroom_halForecast() throws RemoteException {
592         mFakeHal.mForecastSkinTemperaturesCalled = 0;
593         mFakeHal.enableForecastSkinTemperature();
594         mService = new ThermalManagerService(mContext, mFakeHal);
595         mService.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
596         assertTrue(mService.mIsHalSkinForecastSupported.get());
597         assertEquals(1, mFakeHal.mForecastSkinTemperaturesCalled);
598         mFakeHal.mForecastSkinTemperaturesCalled = 0;
599 
600         assertEquals(1.0f, mService.mService.getThermalHeadroom(60), 0.01f);
601         assertEquals(0.9f, mService.mService.getThermalHeadroom(50), 0.01f);
602         assertEquals(0.8f, mService.mService.getThermalHeadroom(40), 0.01f);
603         assertEquals(0.7f, mService.mService.getThermalHeadroom(30), 0.01f);
604         assertEquals(0.6f, mService.mService.getThermalHeadroom(20), 0.01f);
605         assertEquals(0.5f, mService.mService.getThermalHeadroom(10), 0.01f);
606         assertEquals(0.4f, mService.mService.getThermalHeadroom(0), 0.01f);
607         assertEquals(7, mFakeHal.mForecastSkinTemperaturesCalled);
608     }
609 
610     @Test
611     @EnableFlags({Flags.FLAG_ALLOW_THERMAL_HAL_SKIN_FORECAST})
testGetThermalHeadroom_halForecast_disabledOnMultiThresholds()612     public void testGetThermalHeadroom_halForecast_disabledOnMultiThresholds()
613             throws RemoteException {
614         mFakeHal.mForecastSkinTemperaturesCalled = 0;
615         List<TemperatureThreshold> thresholds = mFakeHal.initializeThresholds();
616         TemperatureThreshold skinThreshold = new TemperatureThreshold();
617         skinThreshold.type = Temperature.TYPE_SKIN;
618         skinThreshold.name = "skin2";
619         skinThreshold.hotThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
620         skinThreshold.coldThrottlingThresholds = new float[7 /*ThrottlingSeverity#len*/];
621         for (int i = 0; i < skinThreshold.hotThrottlingThresholds.length; ++i) {
622             // Sets NONE to 45.0f, SEVERE to 60.0f, and SHUTDOWN to 75.0f
623             skinThreshold.hotThrottlingThresholds[i] = 45.0f + 5.0f * i;
624         }
625         thresholds.add(skinThreshold);
626         mFakeHal.mTemperatureThresholdList = thresholds;
627         mFakeHal.enableForecastSkinTemperature();
628         mService = new ThermalManagerService(mContext, mFakeHal);
629         mService.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
630         assertFalse("HAL skin forecast should be disabled on multiple SKIN thresholds",
631                 mService.mIsHalSkinForecastSupported.get());
632         mService.mService.getThermalHeadroom(10);
633         assertEquals(0, mFakeHal.mForecastSkinTemperaturesCalled);
634     }
635 
636     @Test
637     @EnableFlags({Flags.FLAG_ALLOW_THERMAL_HAL_SKIN_FORECAST,
638             Flags.FLAG_ALLOW_THERMAL_THRESHOLDS_CALLBACK})
testGetThermalHeadroom_halForecast_disabledOnMultiThresholdsCallback()639     public void testGetThermalHeadroom_halForecast_disabledOnMultiThresholdsCallback()
640             throws RemoteException {
641         mFakeHal.mForecastSkinTemperaturesCalled = 0;
642         mFakeHal.enableForecastSkinTemperature();
643         mService = new ThermalManagerService(mContext, mFakeHal);
644         mService.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
645         assertTrue(mService.mIsHalSkinForecastSupported.get());
646         assertEquals(1, mFakeHal.mForecastSkinTemperaturesCalled);
647         mFakeHal.mForecastSkinTemperaturesCalled = 0;
648 
649         TemperatureThreshold newThreshold = new TemperatureThreshold();
650         newThreshold.name = "skin2";
651         newThreshold.type = Temperature.TYPE_SKIN;
652         newThreshold.hotThrottlingThresholds = new float[]{
653                 Float.NaN, 43.0f, 46.0f, 49.0f, Float.NaN, Float.NaN, Float.NaN
654         };
655         mFakeHal.mCallback.onThresholdChanged(newThreshold);
656         mService.mService.getThermalHeadroom(10);
657         assertEquals(0, mFakeHal.mForecastSkinTemperaturesCalled);
658     }
659 
660     @Test
661     @EnableFlags({Flags.FLAG_ALLOW_THERMAL_HAL_SKIN_FORECAST})
testGetThermalHeadroom_halForecast_errorOnHal()662     public void testGetThermalHeadroom_halForecast_errorOnHal() throws RemoteException {
663         mFakeHal.mForecastSkinTemperaturesCalled = 0;
664         mFakeHal.enableForecastSkinTemperature();
665         mService = new ThermalManagerService(mContext, mFakeHal);
666         mService.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
667         assertTrue(mService.mIsHalSkinForecastSupported.get());
668         assertEquals(1, mFakeHal.mForecastSkinTemperaturesCalled);
669         mFakeHal.mForecastSkinTemperaturesCalled = 0;
670 
671         mFakeHal.disableForecastSkinTemperature();
672         assertTrue(Float.isNaN(mService.mService.getThermalHeadroom(10)));
673         assertEquals(1, mFakeHal.mForecastSkinTemperaturesCalled);
674         mFakeHal.enableForecastSkinTemperature();
675         assertFalse(Float.isNaN(mService.mService.getThermalHeadroom(10)));
676         assertEquals(2, mFakeHal.mForecastSkinTemperaturesCalled);
677         mFakeHal.failForecastSkinTemperature();
678         assertTrue(Float.isNaN(mService.mService.getThermalHeadroom(10)));
679         assertEquals(3, mFakeHal.mForecastSkinTemperaturesCalled);
680     }
681 
682     @Test
683     @EnableFlags({Flags.FLAG_ALLOW_THERMAL_THRESHOLDS_CALLBACK,
684             Flags.FLAG_ALLOW_THERMAL_HEADROOM_THRESHOLDS})
testTemperatureWatcherUpdateSevereThresholds()685     public void testTemperatureWatcherUpdateSevereThresholds() throws Exception {
686         assertTrue(mService.mService.registerThermalHeadroomListener(mHeadroomListener));
687         verify(mHeadroomListener, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
688                 .times(1)).onHeadroomChange(eq(0.6f), eq(0.6f), anyInt(),
689                 aryEq(new float[]{Float.NaN, 0.6666667f, 0.8333333f, 1.0f, 1.1666666f, 1.3333334f,
690                         1.5f}));
691         resetListenerMock();
692         TemperatureWatcher watcher = mService.mTemperatureWatcher;
693         TemperatureThreshold newThreshold = new TemperatureThreshold();
694         newThreshold.name = "skin1";
695         newThreshold.type = Temperature.TYPE_SKIN;
696         // significant change in threshold (> 0.3C) should trigger a callback
697         newThreshold.hotThrottlingThresholds = new float[]{
698                 Float.NaN, 43.0f, 46.0f, 49.0f, Float.NaN, Float.NaN, Float.NaN
699         };
700         mFakeHal.mCallback.onThresholdChanged(newThreshold);
701         synchronized (watcher.mSamples) {
702             Float threshold = watcher.mSevereThresholds.get("skin1");
703             assertNotNull(threshold);
704             assertEquals(49.0f, threshold, 0.0f);
705             assertArrayEquals("Got" + Arrays.toString(watcher.mHeadroomThresholds),
706                     new float[]{Float.NaN, 0.8f, 0.9f, 1.0f, Float.NaN, Float.NaN, Float.NaN},
707                     watcher.mHeadroomThresholds, 0.01f);
708         }
709         verify(mHeadroomListener, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
710                 .times(1)).onHeadroomChange(eq(0.3f), eq(0.3f), anyInt(),
711                 aryEq(new float[]{Float.NaN, 0.8f, 0.9f, 1.0f, Float.NaN, Float.NaN, Float.NaN}));
712         resetListenerMock();
713 
714         // same or similar threshold callback data within a second should not trigger callback
715         mFakeHal.mCallback.onThresholdChanged(newThreshold);
716         newThreshold.hotThrottlingThresholds = new float[]{
717                 Float.NaN, 43.1f, 45.9f, 49.0f, Float.NaN, Float.NaN, Float.NaN
718         };
719         mFakeHal.mCallback.onThresholdChanged(newThreshold);
720         verify(mHeadroomListener, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
721                 .times(0)).onHeadroomChange(anyFloat(), anyFloat(), anyInt(), any());
722     }
723 
724     @Test
testTemperatureWatcherUpdateHeadroomThreshold()725     public void testTemperatureWatcherUpdateHeadroomThreshold() {
726         TemperatureWatcher watcher = mService.mTemperatureWatcher;
727         synchronized (watcher.mSamples) {
728             Arrays.fill(watcher.mHeadroomThresholds, Float.NaN);
729         }
730         TemperatureThreshold threshold = new TemperatureThreshold();
731         threshold.hotThrottlingThresholds = new float[]{Float.NaN, 40, 46, 49, 64, 70, 79};
732         synchronized (watcher.mSamples) {
733             watcher.updateTemperatureThresholdLocked(threshold, false /*override*/);
734             assertArrayEquals(new float[]{Float.NaN, 0.7f, 0.9f, 1.0f, 1.5f, 1.7f, 2.0f},
735                     watcher.mHeadroomThresholds, 0.01f);
736         }
737 
738         // when another sensor reports different threshold, we expect to see smaller one to be used
739         threshold = new TemperatureThreshold();
740         threshold.hotThrottlingThresholds = new float[]{Float.NaN, 37, 46, 52, 64, 100, 200};
741         synchronized (watcher.mSamples) {
742             watcher.updateTemperatureThresholdLocked(threshold, false /*override*/);
743             assertArrayEquals(new float[]{Float.NaN, 0.5f, 0.8f, 1.0f, 1.4f, 1.7f, 2.0f},
744                     watcher.mHeadroomThresholds, 0.01f);
745         }
746     }
747 
748     @Test
testGetThermalHeadroomThresholds()749     public void testGetThermalHeadroomThresholds() throws Exception {
750         float[] expected = new float[]{Float.NaN, 0.1f, 0.2f, 0.3f, 0.4f, Float.NaN, 0.6f};
751         when(mIThermalServiceMock.getThermalHeadroomThresholds()).thenReturn(expected);
752         Map<Integer, Float> thresholds1 = mPowerManager.getThermalHeadroomThresholds();
753         verify(mIThermalServiceMock, times(1)).getThermalHeadroomThresholds();
754         checkHeadroomThresholds(expected, thresholds1);
755 
756         reset(mIThermalServiceMock);
757         expected = new float[]{Float.NaN, 0.2f, 0.3f, 0.4f, 0.4f, Float.NaN, 0.6f};
758         when(mIThermalServiceMock.getThermalHeadroomThresholds()).thenReturn(expected);
759         Map<Integer, Float> thresholds2 = mPowerManager.getThermalHeadroomThresholds();
760         verify(mIThermalServiceMock, times(1)).getThermalHeadroomThresholds();
761         checkHeadroomThresholds(expected, thresholds2);
762     }
763 
checkHeadroomThresholds(float[] expected, Map<Integer, Float> thresholds)764     private void checkHeadroomThresholds(float[] expected, Map<Integer, Float> thresholds) {
765         for (int status = PowerManager.THERMAL_STATUS_LIGHT;
766                 status <= PowerManager.THERMAL_STATUS_SHUTDOWN; status++) {
767             if (Float.isNaN(expected[status])) {
768                 assertFalse(thresholds.containsKey(status));
769             } else {
770                 assertEquals(expected[status], thresholds.get(status), 0.01f);
771             }
772         }
773     }
774 
775     @Test
testGetThermalHeadroomThresholdsOnDefaultHalResult()776     public void testGetThermalHeadroomThresholdsOnDefaultHalResult() throws Exception {
777         TemperatureWatcher watcher = mService.mTemperatureWatcher;
778         ArrayList<TemperatureThreshold> thresholds = new ArrayList<>();
779         mFakeHal.mTemperatureThresholdList = thresholds;
780         watcher.getAndUpdateThresholds();
781         synchronized (watcher.mSamples) {
782             assertArrayEquals(
783                     new float[]{Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN,
784                             Float.NaN},
785                     watcher.mHeadroomThresholds, 0.01f);
786         }
787         TemperatureThreshold nanThresholds = new TemperatureThreshold();
788         nanThresholds.name = "nan";
789         nanThresholds.type = Temperature.TYPE_SKIN;
790         nanThresholds.hotThrottlingThresholds = new float[ThrottlingSeverity.SHUTDOWN + 1];
791         nanThresholds.coldThrottlingThresholds = new float[ThrottlingSeverity.SHUTDOWN + 1];
792         Arrays.fill(nanThresholds.hotThrottlingThresholds, Float.NaN);
793         Arrays.fill(nanThresholds.coldThrottlingThresholds, Float.NaN);
794         thresholds.add(nanThresholds);
795         watcher.getAndUpdateThresholds();
796         synchronized (watcher.mSamples) {
797             assertArrayEquals(
798                     new float[]{Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN, Float.NaN,
799                             Float.NaN},
800                     watcher.mHeadroomThresholds, 0.01f);
801         }
802     }
803 
804     @Test
testTemperatureWatcherGetSlopeOf()805     public void testTemperatureWatcherGetSlopeOf() throws RemoteException {
806         TemperatureWatcher watcher = mService.mTemperatureWatcher;
807         List<TemperatureWatcher.Sample> samples = new ArrayList<>();
808         for (int i = 0; i < 30; ++i) {
809             samples.add(watcher.createSampleForTesting(i, (float) (i / 2 * 2)));
810         }
811         assertEquals(1.0f, watcher.getSlopeOf(samples), 0.01f);
812     }
813 
814     @Test
testTemperatureWatcherNormalizeTemperature()815     public void testTemperatureWatcherNormalizeTemperature() throws RemoteException {
816         assertEquals(0.5f,
817                 TemperatureWatcher.normalizeTemperature(25.0f, 40.0f), 0.0f);
818 
819         // Temperatures more than 30 degrees below the SEVERE threshold should be clamped to 0.0f
820         assertEquals(0.0f,
821                 TemperatureWatcher.normalizeTemperature(0.0f, 40.0f), 0.0f);
822 
823         // Temperatures above the SEVERE threshold should not be clamped
824         assertEquals(2.0f,
825                 TemperatureWatcher.normalizeTemperature(70.0f, 40.0f), 0.0f);
826     }
827 
828     @Test
testTemperatureWatcherGetForecast()829     public void testTemperatureWatcherGetForecast() throws RemoteException {
830         TemperatureWatcher watcher = mService.mTemperatureWatcher;
831 
832         ArrayList<TemperatureWatcher.Sample> samples = new ArrayList<>();
833 
834         // Add a single sample
835         samples.add(watcher.createSampleForTesting(0, 25.0f));
836         watcher.mSamples.put("skin1", samples);
837 
838         // Because there are not enough samples to compute the linear regression,
839         // no matter how far ahead we forecast, we should receive the same value
840         assertEquals(0.5f, watcher.getForecast(0), 0.0f);
841         assertEquals(0.5f, watcher.getForecast(5), 0.0f);
842 
843         // Add some time-series data
844         for (int i = 1; i < 20; ++i) {
845             samples.add(watcher.createSampleForTesting(1000 * i, 25.0f + 0.5f * i));
846         }
847 
848         // Now the forecast should vary depending on how far ahead we are trying to predict
849         assertEquals(0.9f, watcher.getForecast(4), 0.02f);
850         assertEquals(1.0f, watcher.getForecast(10), 0.02f);
851 
852         // If there are no thresholds, then we shouldn't receive a headroom value
853         watcher.mSevereThresholds.erase();
854         assertTrue(Float.isNaN(watcher.getForecast(0)));
855     }
856 
857     @Test
testTemperatureWatcherGetForecastUpdate()858     public void testTemperatureWatcherGetForecastUpdate() throws Exception {
859         TemperatureWatcher watcher = mService.mTemperatureWatcher;
860 
861         // Reduce the inactivity threshold to speed up testing
862         watcher.mInactivityThresholdMillis = 2000;
863 
864         // Make sure mSamples is empty before updateTemperature
865         assertTrue(isWatcherSamplesEmpty(watcher));
866 
867         // Call getForecast once to trigger updateTemperature
868         watcher.getForecast(0);
869 
870         // After 1 second, the samples should be updated
871         Thread.sleep(1000);
872         assertFalse(isWatcherSamplesEmpty(watcher));
873 
874         // After mInactivityThresholdMillis, the samples should be cleared
875         Thread.sleep(watcher.mInactivityThresholdMillis);
876         assertTrue(isWatcherSamplesEmpty(watcher));
877     }
878 
879     // Helper function to hold mSamples lock, avoid GuardedBy lint errors
isWatcherSamplesEmpty(TemperatureWatcher watcher)880     private boolean isWatcherSamplesEmpty(TemperatureWatcher watcher) {
881         synchronized (watcher.mSamples) {
882             return watcher.mSamples.isEmpty();
883         }
884     }
885 
886     @Test
testDump()887     public void testDump() throws Exception {
888         assertTrue(mService.mService.registerThermalEventListener(mEventListener1));
889         assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1));
890         assertTrue(mService.mService.registerThermalEventListenerWithType(mEventListener2,
891                 Temperature.TYPE_SKIN));
892         assertTrue(mService.mService.registerThermalStatusListener(mStatusListener2));
893 
894         when(mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
895                 .thenReturn(PackageManager.PERMISSION_GRANTED);
896         final StringWriter out = new StringWriter();
897         PrintWriter pw = new PrintWriter(out);
898         mService.dumpInternal(new FileDescriptor(), pw, null);
899         final String dumpStr = out.toString();
900         assertThat(dumpStr).contains("IsStatusOverride: false");
901         assertThat(dumpStr).contains(
902                 "ThermalEventListeners:\n"
903                         + "\tcallbacks: 2\n"
904                         + "\tkilled: false\n"
905                         + "\tbroadcasts count: -1");
906         assertThat(dumpStr).contains(
907                 "ThermalStatusListeners:\n"
908                         + "\tcallbacks: 2\n"
909                         + "\tkilled: false\n"
910                         + "\tbroadcasts count: -1");
911         assertThat(dumpStr).contains("Thermal Status: 0");
912         assertThat(dumpStr).contains(
913                 "Cached temperatures:\n"
914                         + "\tTemperature{mValue=37.0, mType=4, mName=usbport, mStatus=0}\n"
915                         + "\tTemperature{mValue=34.0, mType=2, mName=batt, mStatus=0}\n"
916                         + "\tTemperature{mValue=28.0, mType=3, mName=skin1, mStatus=0}\n"
917                         + "\tTemperature{mValue=31.0, mType=3, mName=skin2, mStatus=0}"
918         );
919         assertThat(dumpStr).contains("HAL Ready: true\n"
920                 + "HAL connection:\n"
921                 + "\tThermalHAL AIDL 1  connected: yes");
922         assertThat(dumpStr).contains("Current temperatures from HAL:\n"
923                 + "\tTemperature{mValue=28.0, mType=3, mName=skin1, mStatus=0}\n"
924                 + "\tTemperature{mValue=31.0, mType=3, mName=skin2, mStatus=0}\n"
925                 + "\tTemperature{mValue=34.0, mType=2, mName=batt, mStatus=0}\n"
926                 + "\tTemperature{mValue=37.0, mType=4, mName=usbport, mStatus=0}\n");
927         assertThat(dumpStr).contains("Current cooling devices from HAL:\n"
928                 + "\tCoolingDevice{mValue=40, mType=1, mName=cpu}\n"
929                 + "\tCoolingDevice{mValue=43, mType=1, mName=gpu}\n");
930         assertThat(dumpStr).contains("Temperature static thresholds from HAL:\n"
931                 + "\tTemperatureThreshold{mType=3, mName=skin1, mHotThrottlingThresholds=[25.0, "
932                 + "30.0, 35.0, 40.0, 45.0, 50.0, 55.0], mColdThrottlingThresholds=[0.0, 0.0, 0.0,"
933                 + " 0.0, 0.0, 0.0, 0.0]}\n"
934                 + "\tTemperatureThreshold{mType=0, mName=cpu, mHotThrottlingThresholds=[NaN, NaN,"
935                 + " NaN, 95.0, NaN, NaN, NaN], mColdThrottlingThresholds=[0.0, 0.0, 0.0, 0.0, 0"
936                 + ".0, 0.0, 0.0]}");
937     }
938 }
939