From b6a891913a0cd43870fb870b1f702d734897af0e Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Wed, 26 Apr 2023 18:05:17 +0000 Subject: [PATCH] Properly handle disabled location prefetch. The controller was still registering for location updates when location prefetch was disabled. Now, it skips requesting location updates altogether when location prefetch is disabled. Bug: 279725615 Test: atest DeviceIdleTest Test: atest FrameworksMockingServicesTests:DeviceIdleControllerTest Change-Id: If303d5448acbc4e97132f3713a7795e46eacc5ab --- .../android/server/DeviceIdleController.java | 89 +++++++++++-------- .../server/DeviceIdleControllerTest.java | 83 +++++++++++++++++ 2 files changed, 136 insertions(+), 36 deletions(-) diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java index f779b4d96b45f..b0b3b1f3cb5ea 100644 --- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java +++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java @@ -319,6 +319,8 @@ public class DeviceIdleController extends SystemService private SensorManager mSensorManager; private final boolean mUseMotionSensor; private Sensor mMotionSensor; + private final boolean mIsLocationPrefetchEnabled; + @Nullable private LocationRequest mLocationRequest; private Intent mIdleIntent; private Bundle mIdleIntentOptions; @@ -2460,6 +2462,11 @@ public class DeviceIdleController extends SystemService return null; } + boolean isLocationPrefetchEnabled() { + return mContext.getResources().getBoolean( + com.android.internal.R.bool.config_autoPowerModePrefetchLocation); + } + boolean useMotionSensor() { return mContext.getResources().getBoolean( com.android.internal.R.bool.config_autoPowerModeUseMotionSensor); @@ -2489,6 +2496,7 @@ public class DeviceIdleController extends SystemService mAppStateTracker = mInjector.getAppStateTracker(context, AppSchedulingModuleThread.get().getLooper()); LocalServices.addService(AppStateTracker.class, mAppStateTracker); + mIsLocationPrefetchEnabled = mInjector.isLocationPrefetchEnabled(); mUseMotionSensor = mInjector.useMotionSensor(); } @@ -2602,8 +2610,7 @@ public class DeviceIdleController extends SystemService mMotionSensor = mInjector.getMotionSensor(); } - if (getContext().getResources().getBoolean( - com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) { + if (mIsLocationPrefetchEnabled) { mLocationRequest = new LocationRequest.Builder(/*intervalMillis=*/ 0) .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY) .setMaxUpdates(1) @@ -3779,34 +3786,40 @@ public class DeviceIdleController extends SystemService case STATE_SENSING: cancelSensingTimeoutAlarmLocked(); moveToStateLocked(STATE_LOCATING, reason); - scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT); - LocationManager locationManager = mInjector.getLocationManager(); - if (locationManager != null - && locationManager.getProvider(LocationManager.FUSED_PROVIDER) != null) { - locationManager.requestLocationUpdates(LocationManager.FUSED_PROVIDER, - mLocationRequest, - AppSchedulingModuleThread.getExecutor(), - mGenericLocationListener); - mLocating = true; + if (mIsLocationPrefetchEnabled) { + scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT); + LocationManager locationManager = mInjector.getLocationManager(); + if (locationManager != null + && locationManager.getProvider(LocationManager.FUSED_PROVIDER) + != null) { + locationManager.requestLocationUpdates(LocationManager.FUSED_PROVIDER, + mLocationRequest, + AppSchedulingModuleThread.getExecutor(), + mGenericLocationListener); + mLocating = true; + } else { + mHasFusedLocation = false; + } + if (locationManager != null + && locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { + mHasGps = true; + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, + 1000, 5, mGpsLocationListener, mHandler.getLooper()); + mLocating = true; + } else { + mHasGps = false; + } + // If we have a location provider, we're all set, the listeners will move state + // forward. + if (mLocating) { + break; + } + // Otherwise, we have to move from locating into idle maintenance. } else { - mHasFusedLocation = false; - } - if (locationManager != null - && locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { - mHasGps = true; - locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5, - mGpsLocationListener, mHandler.getLooper()); - mLocating = true; - } else { - mHasGps = false; - } - // If we have a location provider, we're all set, the listeners will move state - // forward. - if (mLocating) { - break; + mLocating = false; } - // Otherwise, we have to move from locating into idle maintenance. + // We're not doing any locating work, so move on to the next state. case STATE_LOCATING: cancelAlarmLocked(); cancelLocatingLocked(); @@ -5303,15 +5316,19 @@ public class DeviceIdleController extends SystemService pw.print(" "); pw.print(mStationaryListeners.size()); pw.println(" stationary listeners registered"); } - pw.print(" mLocating="); pw.print(mLocating); - pw.print(" mHasGps="); pw.print(mHasGps); - pw.print(" mHasFused="); pw.print(mHasFusedLocation); - pw.print(" mLocated="); pw.println(mLocated); - if (mLastGenericLocation != null) { - pw.print(" mLastGenericLocation="); pw.println(mLastGenericLocation); - } - if (mLastGpsLocation != null) { - pw.print(" mLastGpsLocation="); pw.println(mLastGpsLocation); + if (mIsLocationPrefetchEnabled) { + pw.print(" mLocating="); pw.print(mLocating); + pw.print(" mHasGps="); pw.print(mHasGps); + pw.print(" mHasFused="); pw.print(mHasFusedLocation); + pw.print(" mLocated="); pw.println(mLocated); + if (mLastGenericLocation != null) { + pw.print(" mLastGenericLocation="); pw.println(mLastGenericLocation); + } + if (mLastGpsLocation != null) { + pw.print(" mLastGpsLocation="); pw.println(mLastGpsLocation); + } + } else { + pw.println(" Location prefetching disabled"); } pw.print(" mState="); pw.print(stateToString(mState)); pw.print(" mLightState="); diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index 3a47b476a131c..2b57c59276784 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -154,6 +154,7 @@ public class DeviceIdleControllerTest { // Freeze time for testing. long nowElapsed; boolean useMotionSensor = true; + boolean isLocationPrefetchEnabled = true; InjectorForTest(Context ctx) { super(ctx); @@ -222,6 +223,11 @@ public class DeviceIdleControllerTest { return mMotionSensor; } + @Override + boolean isLocationPrefetchEnabled() { + return isLocationPrefetchEnabled; + } + @Override PowerManager getPowerManager() { return mPowerManager; @@ -990,6 +996,43 @@ public class DeviceIdleControllerTest { verifyStateConditions(STATE_IDLE_MAINTENANCE); } + @Test + public void testStepIdleStateLocked_ValidStates_LocationPrefetchDisabled() { + mInjector.locationManager = mLocationManager; + mInjector.isLocationPrefetchEnabled = false; + cleanupDeviceIdleController(); + setupDeviceIdleController(); + doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider(anyString()); + // Make sure the controller doesn't think there's a wake-from-idle alarm coming soon. + setAlarmSoon(false); + // Set state to INACTIVE. + mDeviceIdleController.becomeActiveLocked("testing", 0); + setChargingOn(false); + setScreenOn(false); + verifyStateConditions(STATE_INACTIVE); + + mDeviceIdleController.stepIdleStateLocked("testing"); + verifyStateConditions(STATE_IDLE_PENDING); + + mDeviceIdleController.stepIdleStateLocked("testing"); + verifyStateConditions(STATE_SENSING); + + mDeviceIdleController.stepIdleStateLocked("testing"); + // Prefetch location is off, so SENSING should go straight through to IDLE. + verifyStateConditions(STATE_IDLE); + + // Should just alternate between IDLE and IDLE_MAINTENANCE now. + + mDeviceIdleController.stepIdleStateLocked("testing"); + verifyStateConditions(STATE_IDLE_MAINTENANCE); + + mDeviceIdleController.stepIdleStateLocked("testing"); + verifyStateConditions(STATE_IDLE); + + mDeviceIdleController.stepIdleStateLocked("testing"); + verifyStateConditions(STATE_IDLE_MAINTENANCE); + } + @Test public void testStepIdleStateLocked_ValidStates_WithLocationManager_NoProviders() { // Make sure the controller doesn't think there's a wake-from-idle alarm coming soon. @@ -1023,6 +1066,46 @@ public class DeviceIdleControllerTest { verifyStateConditions(STATE_IDLE_MAINTENANCE); } + @Test + public void testStepIdleStateLocked_ValidStates_WithLocationManager_MissingProviders() { + mInjector.locationManager = mLocationManager; + doReturn(null).when(mLocationManager) + .getProvider(eq(LocationManager.FUSED_PROVIDER)); + doReturn(null).when(mLocationManager) + .getProvider(eq(LocationManager.GPS_PROVIDER)); + doReturn(mock(LocationProvider.class)).when(mLocationManager) + .getProvider(eq(LocationManager.NETWORK_PROVIDER)); + // Make sure the controller doesn't think there's a wake-from-idle alarm coming soon. + setAlarmSoon(false); + // Set state to INACTIVE. + mDeviceIdleController.becomeActiveLocked("testing", 0); + setChargingOn(false); + setScreenOn(false); + verifyStateConditions(STATE_INACTIVE); + + mDeviceIdleController.stepIdleStateLocked("testing"); + verifyStateConditions(STATE_IDLE_PENDING); + + mDeviceIdleController.stepIdleStateLocked("testing"); + verifyStateConditions(STATE_SENSING); + + mDeviceIdleController.stepIdleStateLocked("testing"); + // Location manager exists, but the required providers don't exist, + // so SENSING should go straight through to IDLE. + verifyStateConditions(STATE_IDLE); + + // Should just alternate between IDLE and IDLE_MAINTENANCE now. + + mDeviceIdleController.stepIdleStateLocked("testing"); + verifyStateConditions(STATE_IDLE_MAINTENANCE); + + mDeviceIdleController.stepIdleStateLocked("testing"); + verifyStateConditions(STATE_IDLE); + + mDeviceIdleController.stepIdleStateLocked("testing"); + verifyStateConditions(STATE_IDLE_MAINTENANCE); + } + @Test public void testStepIdleStateLocked_ValidStates_WithLocationManager_WithProviders() { mInjector.locationManager = mLocationManager;