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