• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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;
18 
19 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
20 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
21 
22 import static org.junit.Assert.assertThrows;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25 import static org.mockito.ArgumentMatchers.any;
26 import static org.mockito.ArgumentMatchers.anyInt;
27 import static org.mockito.ArgumentMatchers.anyLong;
28 import static org.mockito.ArgumentMatchers.anyString;
29 import static org.mockito.ArgumentMatchers.eq;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.times;
32 import static org.mockito.Mockito.when;
33 
34 import android.app.ActivityManager;
35 import android.app.ActivityManagerInternal;
36 import android.app.AppOpsManager;
37 import android.content.Context;
38 import android.hardware.health.HealthInfo;
39 import android.os.HandlerThread;
40 import android.os.SystemClock;
41 import android.os.SystemProperties;
42 import android.os.UserHandle;
43 import android.platform.test.annotations.DisableFlags;
44 import android.platform.test.annotations.EnableFlags;
45 import android.platform.test.flag.junit.SetFlagsRule;
46 
47 import androidx.test.ext.junit.runners.AndroidJUnit4;
48 import androidx.test.platform.app.InstrumentationRegistry;
49 
50 import com.android.dx.mockito.inline.extended.ExtendedMockito;
51 import com.android.internal.R;
52 import com.android.internal.app.IBatteryStats;
53 import com.android.modules.utils.testing.ExtendedMockitoRule;
54 import com.android.server.am.BatteryStatsService;
55 import com.android.server.flags.Flags;
56 import com.android.server.lights.LightsManager;
57 import com.android.server.lights.LogicalLight;
58 
59 import org.junit.Before;
60 import org.junit.Rule;
61 import org.junit.Test;
62 import org.junit.runner.RunWith;
63 import org.mockito.Mock;
64 import org.mockito.MockitoAnnotations;
65 
66 import java.util.concurrent.CountDownLatch;
67 import java.util.concurrent.TimeUnit;
68 
69 @RunWith(AndroidJUnit4.class)
70 public class BatteryServiceTest {
71 
72     private static final int CURRENT_BATTERY_VOLTAGE = 3000;
73     private static final int VOLTAGE_LESS_THEN_ONE_PERCENT = 3029;
74     private static final int VOLTAGE_MORE_THEN_ONE_PERCENT = 3030;
75     private static final int CURRENT_BATTERY_TEMP = 300;
76     private static final int TEMP_LESS_THEN_ONE_DEGREE_CELSIUS = 305;
77     private static final int TEMP_MORE_THEN_ONE_DEGREE_CELSIUS = 310;
78     private static final int CURRENT_BATTERY_HEALTH = 2;
79     private static final int UPDATED_BATTERY_HEALTH = 3;
80     private static final int CURRENT_CHARGE_COUNTER = 4680000;
81     private static final int UPDATED_CHARGE_COUNTER = 4218000;
82     private static final int CURRENT_MAX_CHARGING_CURRENT = 298125;
83     private static final int UPDATED_MAX_CHARGING_CURRENT = 398125;
84     private static final int HANDLER_IDLE_TIME_MS = 5000;
85     @Rule
86     public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this)
87             .mockStatic(SystemProperties.class)
88             .mockStatic(ActivityManager.class)
89             .mockStatic(BatteryStatsService.class)
90             .build();
91     @Rule
92     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
93     @Mock
94     private Context mContextMock;
95     @Mock
96     private LightsManager mLightsManagerMock;
97     @Mock
98     private ActivityManagerInternal mActivityManagerInternalMock;
99     @Mock
100     private IBatteryStats mIBatteryStatsMock;
101 
102     private BatteryService mBatteryService;
103     private String mSystemUiPackage;
104 
105     /**
106      * Creates a mock and registers it to {@link LocalServices}.
107      */
addLocalServiceMock(Class<T> clazz, T mock)108     private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
109         LocalServices.removeServiceForTest(clazz);
110         LocalServices.addService(clazz, mock);
111     }
112 
113     @Before
setUp()114     public void setUp() throws Exception {
115         MockitoAnnotations.initMocks(this);
116 
117         mSystemUiPackage = InstrumentationRegistry.getInstrumentation().getTargetContext()
118                 .getResources().getString(R.string.config_systemUi);
119 
120         when(mLightsManagerMock.getLight(anyInt())).thenReturn(mock(LogicalLight.class));
121         when(mActivityManagerInternalMock.isSystemReady()).thenReturn(true);
122         when(mContextMock.getResources()).thenReturn(
123                 InstrumentationRegistry.getInstrumentation().getTargetContext().getResources());
124         ExtendedMockito.when(BatteryStatsService.getService()).thenReturn(mIBatteryStatsMock);
125 
126         doNothing().when(mIBatteryStatsMock).setBatteryState(anyInt(), anyInt(), anyInt(), anyInt(),
127                 anyInt(), anyInt(), anyInt(), anyInt(), anyLong());
128         doNothing().when(() -> SystemProperties.set(anyString(), anyString()));
129         doNothing().when(() -> ActivityManager.broadcastStickyIntent(any(),
130                 eq(new String[]{mSystemUiPackage}), eq(AppOpsManager.OP_NONE),
131                 eq(BatteryService.BATTERY_CHANGED_OPTIONS), eq(UserHandle.USER_ALL)));
132 
133         addLocalServiceMock(LightsManager.class, mLightsManagerMock);
134         addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock);
135 
136         createBatteryService();
137     }
138 
139     @Test
createBatteryService_withNullLooper_throwsNullPointerException()140     public void createBatteryService_withNullLooper_throwsNullPointerException() {
141         assertThrows(NullPointerException.class, () -> new BatteryService(mContextMock));
142     }
143 
144     @Test
145     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
onlyVoltageUpdated_lessThenOnePercent_broadcastNotSent()146     public void onlyVoltageUpdated_lessThenOnePercent_broadcastNotSent() {
147         mBatteryService.update(createHealthInfo(VOLTAGE_LESS_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
148                 CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
149 
150         waitForHandlerToExecute();
151 
152         verifyNumberOfTimesBroadcastSent(0);
153     }
154 
155     @Test
156     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
onlyVoltageUpdated_beforeTwentySeconds_broadcastNotSent()157     public void onlyVoltageUpdated_beforeTwentySeconds_broadcastNotSent() {
158         mBatteryService.update(
159                 createHealthInfo(VOLTAGE_MORE_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
160                         CURRENT_CHARGE_COUNTER,
161                         CURRENT_BATTERY_HEALTH,
162                         CURRENT_MAX_CHARGING_CURRENT));
163 
164         waitForHandlerToExecute();
165 
166         verifyNumberOfTimesBroadcastSent(0);
167     }
168 
169     @Test
170     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
voltageUpdated_withUpdateInChargingCurrent_broadcastSent()171     public void voltageUpdated_withUpdateInChargingCurrent_broadcastSent() {
172         mBatteryService.mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime() - 20000;
173         long lastChargingCurrentUpdateTime =
174                 mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime;
175         mBatteryService.update(createHealthInfo(VOLTAGE_MORE_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
176                 CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH, UPDATED_MAX_CHARGING_CURRENT));
177 
178         waitForHandlerToExecute();
179 
180         assertTrue(lastChargingCurrentUpdateTime
181                 < mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime);
182         verifyNumberOfTimesBroadcastSent(1);
183     }
184 
185     @Test
186     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
187     public void onlyTempUpdated_lessThenOneDegreeCelsius_broadcastNotSent() {
188         mBatteryService.update(
189                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, TEMP_LESS_THEN_ONE_DEGREE_CELSIUS,
190                         CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH,
191                         CURRENT_MAX_CHARGING_CURRENT));
192 
193         waitForHandlerToExecute();
194 
195         verifyNumberOfTimesBroadcastSent(0);
196     }
197 
198     @Test
199     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
200     public void tempUpdated_broadcastSent() {
201         long lastVoltageUpdateTime = mBatteryService.mLastBroadcastVoltageUpdateTime;
202         long lastChargingCurrentUpdateTime =
203                 mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime;
204         mBatteryService.update(
205                 createHealthInfo(VOLTAGE_LESS_THEN_ONE_PERCENT, TEMP_MORE_THEN_ONE_DEGREE_CELSIUS,
206                         UPDATED_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH,
207                         UPDATED_MAX_CHARGING_CURRENT));
208 
209         waitForHandlerToExecute();
210 
211         assertTrue(lastVoltageUpdateTime < mBatteryService.mLastBroadcastVoltageUpdateTime);
212         assertTrue(lastChargingCurrentUpdateTime
213                 < mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime);
214         verifyNumberOfTimesBroadcastSent(1);
215     }
216 
217     @Test
218     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
219     public void batteryHealthUpdated_withOtherExtrasConstant_broadcastSent() {
220         long lastVoltageUpdateTime = mBatteryService.mLastBroadcastVoltageUpdateTime;
221         long lastChargingCurrentUpdateTime =
222                 mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime;
223         mBatteryService.update(
224                 createHealthInfo(VOLTAGE_LESS_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
225                         CURRENT_CHARGE_COUNTER,
226                         UPDATED_BATTERY_HEALTH, UPDATED_MAX_CHARGING_CURRENT));
227 
228         waitForHandlerToExecute();
229 
230         verifyNumberOfTimesBroadcastSent(1);
231 
232         // updating counter just after the health update does not triggers broadcast.
233         mBatteryService.update(
234                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP,
235                         UPDATED_CHARGE_COUNTER,
236                         UPDATED_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
237 
238         waitForHandlerToExecute();
239 
240         assertTrue(lastVoltageUpdateTime < mBatteryService.mLastBroadcastVoltageUpdateTime);
241         assertTrue(lastChargingCurrentUpdateTime
242                 < mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime);
243         verifyNumberOfTimesBroadcastSent(1);
244     }
245 
246     @Test
247     @DisableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
248     public void voltageUpdated_lessThanOnePercent_flagDisabled_broadcastSent() {
249         mBatteryService.update(createHealthInfo(VOLTAGE_LESS_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
250                 CURRENT_CHARGE_COUNTER, CURRENT_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
251 
252         waitForHandlerToExecute();
253 
254         verifyNumberOfTimesBroadcastSent(1);
255     }
256 
257     @Test
258     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
259     public void onlyChargeCounterUpdated_broadcastNotSent() {
260         mBatteryService.update(
261                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP,
262                         UPDATED_CHARGE_COUNTER,
263                         CURRENT_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
264 
265         waitForHandlerToExecute();
266 
267         verifyNumberOfTimesBroadcastSent(0);
268     }
269 
270     @Test
271     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
272     public void chargeCounterUpdated_tempUpdatedLessThanOneDegree_broadcastNotSent() {
273         mBatteryService.update(
274                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, TEMP_LESS_THEN_ONE_DEGREE_CELSIUS,
275                         UPDATED_CHARGE_COUNTER,
276                         CURRENT_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
277 
278         waitForHandlerToExecute();
279 
280         verifyNumberOfTimesBroadcastSent(0);
281     }
282 
283     @Test
284     @DisableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
285     public void onlyChargeCounterUpdated_broadcastSent() {
286         mBatteryService.update(
287                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP,
288                         UPDATED_CHARGE_COUNTER,
289                         CURRENT_BATTERY_HEALTH, CURRENT_MAX_CHARGING_CURRENT));
290 
291         waitForHandlerToExecute();
292 
293         verifyNumberOfTimesBroadcastSent(1);
294     }
295 
296     @Test
297     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
298     public void onlyMaxChargingCurrentUpdated_beforeFiveSeconds_broadcastNotSent() {
299         mBatteryService.update(
300                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP,
301                         CURRENT_CHARGE_COUNTER,
302                         CURRENT_BATTERY_HEALTH,
303                         UPDATED_MAX_CHARGING_CURRENT));
304 
305         waitForHandlerToExecute();
306 
307         verifyNumberOfTimesBroadcastSent(0);
308     }
309 
310     @Test
311     @EnableFlags(Flags.FLAG_RATE_LIMIT_BATTERY_CHANGED_BROADCAST)
312     public void maxChargingCurrentUpdated_afterFiveSeconds_broadcastSent() {
313         mBatteryService.mLastBroadcastMaxChargingCurrentUpdateTime =
314                 SystemClock.elapsedRealtime() - 5000;
315         long lastVoltageUpdateTime = mBatteryService.mLastBroadcastVoltageUpdateTime;
316         mBatteryService.update(
317                 createHealthInfo(VOLTAGE_MORE_THEN_ONE_PERCENT, CURRENT_BATTERY_TEMP,
318                         CURRENT_CHARGE_COUNTER,
319                         CURRENT_BATTERY_HEALTH,
320                         UPDATED_MAX_CHARGING_CURRENT));
321 
322         waitForHandlerToExecute();
323 
324         assertTrue(lastVoltageUpdateTime < mBatteryService.mLastBroadcastVoltageUpdateTime);
325         verifyNumberOfTimesBroadcastSent(1);
326     }
327 
328     private HealthInfo createHealthInfo(
329             int batteryVoltage,
330             int batteryTemperature,
331             int batteryChargeCounter,
332             int batteryHealth,
333             int maxChargingCurrent) {
334         HealthInfo h = new HealthInfo();
335         h.batteryVoltageMillivolts = batteryVoltage;
336         h.batteryTemperatureTenthsCelsius = batteryTemperature;
337         h.batteryChargeCounterUah = batteryChargeCounter;
338         h.batteryStatus = 5;
339         h.batteryHealth = batteryHealth;
340         h.batteryPresent = true;
341         h.batteryLevel = 100;
342         h.maxChargingCurrentMicroamps = maxChargingCurrent;
343         h.batteryCurrentAverageMicroamps = -2812;
344         h.batteryCurrentMicroamps = 298125;
345         h.maxChargingVoltageMicrovolts = 3000;
346         h.batteryCycleCount = 50;
347         h.chargingState = 4;
348         h.batteryCapacityLevel = 100;
349         return h;
350     }
351 
352     // Creates a new battery service objects and sets the initial values.
353     private void createBatteryService() throws InterruptedException {
354         final HandlerThread handlerThread = new HandlerThread("BatteryServiceTest");
355         handlerThread.start();
356 
357         mBatteryService = new BatteryService(mContextMock, handlerThread.getLooper());
358 
359         // trigger the update to set the initial values.
360         mBatteryService.update(
361                 createHealthInfo(CURRENT_BATTERY_VOLTAGE, CURRENT_BATTERY_TEMP,
362                         CURRENT_CHARGE_COUNTER,
363                         CURRENT_BATTERY_HEALTH,
364                         CURRENT_MAX_CHARGING_CURRENT));
365 
366         waitForHandlerToExecute();
367     }
368 
369     private void waitForHandlerToExecute() {
370         final CountDownLatch latch = new CountDownLatch(1);
371         mBatteryService.getHandlerForTest().post(latch::countDown);
372         boolean isExecutionComplete = false;
373 
374         try {
375             isExecutionComplete = latch.await(HANDLER_IDLE_TIME_MS, TimeUnit.MILLISECONDS);
376         } catch (InterruptedException e) {
377             fail("Handler interrupted before executing the message " + e);
378         }
379 
380         assertTrue("Timed out while waiting for Handler to execute.", isExecutionComplete);
381     }
382 
383     private void verifyNumberOfTimesBroadcastSent(int numberOfTimes) {
384         // Increase the numberOfTimes by 1 as one broadcast was sent initially during the test
385         // setUp.
386         verify(() -> ActivityManager.broadcastStickyIntent(any(),
387                         eq(new String[]{mSystemUiPackage}), eq(AppOpsManager.OP_NONE),
388                         eq(BatteryService.BATTERY_CHANGED_OPTIONS), eq(UserHandle.USER_ALL)),
389                 times(++numberOfTimes));
390     }
391 }
392