diff options
3 files changed, 281 insertions, 34 deletions
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 26421a2acb66..0b30ff5cc398 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -242,11 +242,9 @@ public class DeviceIdleController extends SystemService private ActivityTaskManagerInternal mLocalActivityTaskManager; private PowerManagerInternal mLocalPowerManager; private PowerManager mPowerManager; - private ConnectivityService mConnectivityService; private INetworkPolicyManager mNetworkPolicyManager; private SensorManager mSensorManager; private Sensor mMotionSensor; - private LocationManager mLocationManager; private LocationRequest mLocationRequest; private Intent mIdleIntent; private Intent mLightIdleIntent; @@ -1508,6 +1506,8 @@ public class DeviceIdleController extends SystemService static class Injector { private final Context mContext; + private ConnectivityService mConnectivityService; + private LocationManager mLocationManager; Injector(Context ctx) { mContext = ctx; @@ -1527,7 +1527,11 @@ public class DeviceIdleController extends SystemService } ConnectivityService getConnectivityService() { - return (ConnectivityService) ServiceManager.getService(Context.CONNECTIVITY_SERVICE); + if (mConnectivityService == null) { + mConnectivityService = (ConnectivityService) ServiceManager.getService( + Context.CONNECTIVITY_SERVICE); + } + return mConnectivityService; } Constants getConstants(DeviceIdleController controller, Handler handler, @@ -1536,7 +1540,10 @@ public class DeviceIdleController extends SystemService } LocationManager getLocationManager() { - return mContext.getSystemService(LocationManager.class); + if (mLocationManager == null) { + mLocationManager = mContext.getSystemService(LocationManager.class); + } + return mLocationManager; } MyHandler getHandler(DeviceIdleController controller) { @@ -1666,7 +1673,6 @@ public class DeviceIdleController extends SystemService mGoingIdleWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "deviceidle_going_idle"); mGoingIdleWakeLock.setReferenceCounted(true); - mConnectivityService = mInjector.getConnectivityService(); mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface( ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)); mNetworkPolicyManagerInternal = getLocalService(NetworkPolicyManagerInternal.class); @@ -1689,7 +1695,6 @@ public class DeviceIdleController extends SystemService if (getContext().getResources().getBoolean( com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) { - mLocationManager = mInjector.getLocationManager(); mLocationRequest = new LocationRequest() .setQuality(LocationRequest.ACCURACY_FINE) .setInterval(0) @@ -2160,10 +2165,17 @@ public class DeviceIdleController extends SystemService } } + @VisibleForTesting + boolean isNetworkConnected() { + synchronized (this) { + return mNetworkConnected; + } + } + void updateConnectivityState(Intent connIntent) { ConnectivityService cm; synchronized (this) { - cm = mConnectivityService; + cm = mInjector.getConnectivityService(); } if (cm == null) { return; @@ -2276,13 +2288,17 @@ public class DeviceIdleController extends SystemService /** Must only be used in tests. */ @VisibleForTesting void setDeepEnabledForTest(boolean enabled) { - mDeepEnabled = enabled; + synchronized (this) { + mDeepEnabled = enabled; + } } /** Must only be used in tests. */ @VisibleForTesting void setLightEnabledForTest(boolean enabled) { - mLightEnabled = enabled; + synchronized (this) { + mLightEnabled = enabled; + } } void becomeInactiveIfAppropriateLocked() { @@ -2338,7 +2354,9 @@ public class DeviceIdleController extends SystemService */ @VisibleForTesting void setLightStateForTest(int lightState) { - mLightState = lightState; + synchronized (this) { + mLightState = lightState; + } } @VisibleForTesting @@ -2429,12 +2447,6 @@ public class DeviceIdleController extends SystemService } } - /** Must only be used in tests. */ - @VisibleForTesting - void setLocationManagerForTest(LocationManager lm) { - mLocationManager = lm; - } - @VisibleForTesting int getState() { return mState; @@ -2486,18 +2498,19 @@ public class DeviceIdleController extends SystemService if (DEBUG) Slog.d(TAG, "Moved from STATE_SENSING to STATE_LOCATING."); EventLogTags.writeDeviceIdle(mState, reason); scheduleAlarmLocked(mConstants.LOCATING_TIMEOUT, false); - if (mLocationManager != null - && mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) { - mLocationManager.requestLocationUpdates(mLocationRequest, + LocationManager locationManager = mInjector.getLocationManager(); + if (locationManager != null + && locationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) { + locationManager.requestLocationUpdates(mLocationRequest, mGenericLocationListener, mHandler.getLooper()); mLocating = true; } else { mHasNetworkLocation = false; } - if (mLocationManager != null - && mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { + if (locationManager != null + && locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { mHasGps = true; - mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5, + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5, mGpsLocationListener, mHandler.getLooper()); mLocating = true; } else { @@ -2575,7 +2588,9 @@ public class DeviceIdleController extends SystemService /** Must only be used in tests. */ @VisibleForTesting void setActiveIdleOpsForTest(int count) { - mActiveIdleOpCount = count; + synchronized (this) { + mActiveIdleOpCount = count; + } } void setJobsActive(boolean active) { @@ -2751,8 +2766,9 @@ public class DeviceIdleController extends SystemService void cancelLocatingLocked() { if (mLocating) { - mLocationManager.removeUpdates(mGenericLocationListener); - mLocationManager.removeUpdates(mGpsLocationListener); + LocationManager locationManager = mInjector.getLocationManager(); + locationManager.removeUpdates(mGenericLocationListener); + locationManager.removeUpdates(mGpsLocationListener); mLocating = false; } } diff --git a/services/tests/mockingservicestests/Android.mk b/services/tests/mockingservicestests/Android.mk index 8c0283318419..b83a79fc232c 100644 --- a/services/tests/mockingservicestests/Android.mk +++ b/services/tests/mockingservicestests/Android.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := \ frameworks-base-testutils \ services.core \ + services.net \ androidx-test \ mockito-target-extended-minus-junit4 \ platform-test-annotations \ diff --git a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java index 95ed00f3ad5b..7e7b1436a912 100644 --- a/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/DeviceIdleControllerTest.java @@ -41,6 +41,9 @@ import static com.android.server.DeviceIdleController.lightStateToString; import static com.android.server.DeviceIdleController.stateToString; import static org.junit.Assert.assertEquals; + +import android.net.NetworkInfo; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -50,6 +53,8 @@ import static org.mockito.ArgumentMatchers.anyString; import android.app.ActivityManagerInternal; import android.app.AlarmManager; +import android.net.ConnectivityManager; +import android.content.Intent; import android.app.IActivityManager; import android.content.ContentResolver; import android.content.Context; @@ -83,11 +88,14 @@ public class DeviceIdleControllerTest { private DeviceIdleController mDeviceIdleController; private AnyMotionDetectorForTest mAnyMotionDetector; private AppStateTrackerForTest mAppStateTracker; + private InjectorForTest mInjector; private MockitoSession mMockingSession; @Mock private AlarmManager mAlarmManager; @Mock + private ConnectivityService mConnectivityService; + @Mock private DeviceIdleController.Constants mConstants; @Mock private IActivityManager mIActivityManager; @@ -99,6 +107,8 @@ public class DeviceIdleControllerTest { private PowerManager.WakeLock mWakeLock; class InjectorForTest extends DeviceIdleController.Injector { + ConnectivityService connectivityService; + LocationManager locationManager; InjectorForTest(Context ctx) { super(ctx); @@ -122,18 +132,19 @@ public class DeviceIdleControllerTest { @Override ConnectivityService getConnectivityService() { - return null; + return connectivityService; } @Override - DeviceIdleController.Constants getConstants(DeviceIdleController controller, Handler handler, + DeviceIdleController.Constants getConstants(DeviceIdleController controller, + Handler handler, ContentResolver resolver) { return mConstants; } @Override LocationManager getLocationManager() { - return mLocationManager; + return locationManager; } @Override @@ -201,8 +212,8 @@ public class DeviceIdleControllerTest { doNothing().when(mWakeLock).acquire(); mAppStateTracker = new AppStateTrackerForTest(getContext(), Looper.getMainLooper()); mAnyMotionDetector = new AnyMotionDetectorForTest(); - mDeviceIdleController = new DeviceIdleController(getContext(), - new InjectorForTest(getContext())); + mInjector = new InjectorForTest(getContext()); + mDeviceIdleController = new DeviceIdleController(getContext(), mInjector); spyOn(mDeviceIdleController); doNothing().when(mDeviceIdleController).publishBinderService(any(), any()); mDeviceIdleController.onStart(); @@ -271,6 +282,60 @@ public class DeviceIdleControllerTest { } @Test + public void testUpdateConnectivityState() { + // No connectivity service + final boolean isConnected = mDeviceIdleController.isNetworkConnected(); + mInjector.connectivityService = null; + mDeviceIdleController.updateConnectivityState(null); + assertEquals(isConnected, mDeviceIdleController.isNetworkConnected()); + + // No active network info + mInjector.connectivityService = mConnectivityService; + doReturn(null).when(mConnectivityService).getActiveNetworkInfo(); + mDeviceIdleController.updateConnectivityState(null); + assertFalse(mDeviceIdleController.isNetworkConnected()); + + // Active network info says connected. + final NetworkInfo ani = mock(NetworkInfo.class); + doReturn(ani).when(mConnectivityService).getActiveNetworkInfo(); + doReturn(true).when(ani).isConnected(); + mDeviceIdleController.updateConnectivityState(null); + assertTrue(mDeviceIdleController.isNetworkConnected()); + + // Active network info says not connected. + doReturn(false).when(ani).isConnected(); + mDeviceIdleController.updateConnectivityState(null); + assertFalse(mDeviceIdleController.isNetworkConnected()); + + // Wrong intent passed (false). + Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 3); + doReturn(true).when(ani).isConnected(); + doReturn(1).when(ani).getType(); + mDeviceIdleController.updateConnectivityState(intent); + // Wrong intent means we shouldn't update the connected state. + assertFalse(mDeviceIdleController.isNetworkConnected()); + + // Intent says connected. + doReturn(1).when(ani).getType(); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 1); + intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); + mDeviceIdleController.updateConnectivityState(intent); + assertTrue(mDeviceIdleController.isNetworkConnected()); + + // Wrong intent passed (true). + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 3); + // Wrong intent means we shouldn't update the connected state. + assertTrue(mDeviceIdleController.isNetworkConnected()); + + // Intent says not connected. + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 1); + intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); + mDeviceIdleController.updateConnectivityState(intent); + assertFalse(mDeviceIdleController.isNetworkConnected()); + } + + @Test public void testStateActiveToStateInactive_ConditionsNotMet() { mDeviceIdleController.becomeActiveLocked("testing", 0); verifyStateConditions(STATE_ACTIVE); @@ -361,7 +426,7 @@ public class DeviceIdleControllerTest { @Test public void testStepIdleStateLocked_ValidStates_NoLocationManager() { - mDeviceIdleController.setLocationManagerForTest(null); + mInjector.locationManager = null; // Make sure the controller doesn't think there's a wake-from-idle alarm coming soon. doReturn(Long.MAX_VALUE).when(mAlarmManager).getNextWakeFromIdleTime(); // Set state to INACTIVE. @@ -427,6 +492,7 @@ public class DeviceIdleControllerTest { @Test public void testStepIdleStateLocked_ValidStates_WithLocationManager_WithProviders() { + mInjector.locationManager = mLocationManager; doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider(anyString()); // Make sure the controller doesn't think there's a wake-from-idle alarm coming soon. // TODO: add tests for when there's a wake-from-idle alarm coming soon. @@ -463,6 +529,160 @@ public class DeviceIdleControllerTest { } @Test + public void testLightStepIdleStateLocked_InvalidStates() { + mDeviceIdleController.becomeActiveLocked("testing", 0); + mDeviceIdleController.stepLightIdleStateLocked("testing"); + // stepLightIdleStateLocked doesn't handle the ACTIVE case, so the state + // should stay as ACTIVE. + verifyLightStateConditions(LIGHT_STATE_ACTIVE); + } + + /** + * Make sure stepLightIdleStateLocked doesn't change state when the state is + * LIGHT_STATE_OVERRIDE. + */ + @Test + public void testLightStepIdleStateLocked_Overriden() { + enterLightState(LIGHT_STATE_OVERRIDE); + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_OVERRIDE); + } + + @Test + public void testLightStepIdleStateLocked_ValidStates_NoActiveOps_NetworkConnected() { + setNetworkConnected(true); + mDeviceIdleController.setJobsActive(false); + mDeviceIdleController.setAlarmsActive(false); + mDeviceIdleController.setActiveIdleOpsForTest(0); + + // Set state to INACTIVE. + mDeviceIdleController.becomeActiveLocked("testing", 0); + setChargingOn(false); + setScreenOn(false); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + + // No active ops means INACTIVE should go straight to IDLE. + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE); + + // Should just alternate between IDLE and IDLE_MAINTENANCE now. + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); + } + + @Test + public void testLightStepIdleStateLocked_ValidStates_ActiveOps_NetworkConnected() { + setNetworkConnected(true); + // Set state to INACTIVE. + mDeviceIdleController.becomeActiveLocked("testing", 0); + setChargingOn(false); + setScreenOn(false); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + + // Active ops means INACTIVE should go to PRE_IDLE to wait. + mDeviceIdleController.setJobsActive(true); + mDeviceIdleController.setAlarmsActive(true); + mDeviceIdleController.setActiveIdleOpsForTest(1); + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_PRE_IDLE); + + // Even with active ops, PRE_IDLE should go to IDLE. + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE); + + // Should just alternate between IDLE and IDLE_MAINTENANCE now. + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); + } + + @Test + public void testLightStepIdleStateLocked_ValidStates_NoActiveOps_NoNetworkConnected() { + setNetworkConnected(false); + mDeviceIdleController.setJobsActive(false); + mDeviceIdleController.setAlarmsActive(false); + mDeviceIdleController.setActiveIdleOpsForTest(0); + + // Set state to INACTIVE. + mDeviceIdleController.becomeActiveLocked("testing", 0); + setChargingOn(false); + setScreenOn(false); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + + // No active ops means INACTIVE should go straight to IDLE. + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE); + + // Should cycle between IDLE, WAITING_FOR_NETWORK, and IDLE_MAINTENANCE now. + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); + } + + @Test + public void testLightStepIdleStateLocked_ValidStates_ActiveOps_NoNetworkConnected() { + setNetworkConnected(false); + // Set state to INACTIVE. + mDeviceIdleController.becomeActiveLocked("testing", 0); + setChargingOn(false); + setScreenOn(false); + verifyLightStateConditions(LIGHT_STATE_INACTIVE); + + // Active ops means INACTIVE should go to PRE_IDLE to wait. + mDeviceIdleController.setJobsActive(true); + mDeviceIdleController.setAlarmsActive(true); + mDeviceIdleController.setActiveIdleOpsForTest(1); + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_PRE_IDLE); + + // Even with active ops, PRE_IDLE should go to IDLE. + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE); + + // Should cycle between IDLE, WAITING_FOR_NETWORK, and IDLE_MAINTENANCE now. + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_WAITING_FOR_NETWORK); + + mDeviceIdleController.stepLightIdleStateLocked("testing"); + verifyLightStateConditions(LIGHT_STATE_IDLE_MAINTENANCE); + } + + @Test public void testExitMaintenanceEarlyIfNeededLocked_deep_noActiveOps() { mDeviceIdleController.setJobsActive(false); mDeviceIdleController.setAlarmsActive(false); @@ -903,6 +1123,7 @@ public class DeviceIdleControllerTest { mDeviceIdleController.becomeActiveLocked("testing", 0); break; case STATE_LOCATING: + mInjector.locationManager = mLocationManager; doReturn(mock(LocationProvider.class)).when(mLocationManager).getProvider( anyString()); // Fallthrough to step loop. @@ -917,7 +1138,6 @@ public class DeviceIdleControllerTest { setScreenOn(false); setChargingOn(false); mDeviceIdleController.becomeInactiveIfAppropriateLocked(); - //fail(stateToString(mDeviceIdleController.getState())); int count = 0; while (mDeviceIdleController.getState() != state) { // Stepping through each state ensures that the proper features are turned @@ -925,7 +1145,8 @@ public class DeviceIdleControllerTest { mDeviceIdleController.stepIdleStateLocked("testing"); count++; if (count > 10) { - fail(stateToString(mDeviceIdleController.getState())); + fail("Infinite loop. Check test configuration. Currently at " + + stateToString(mDeviceIdleController.getState())); } } break; @@ -954,7 +1175,8 @@ public class DeviceIdleControllerTest { count++; if (count > 10) { - fail(lightStateToString(mDeviceIdleController.getLightState())); + fail("Infinite loop. Check test configuration. Currently at " + + lightStateToString(mDeviceIdleController.getLightState())); } } break; @@ -979,6 +1201,14 @@ public class DeviceIdleControllerTest { mDeviceIdleController.updateInteractivityLocked(); } + private void setNetworkConnected(boolean connected) { + mInjector.connectivityService = mConnectivityService; + final NetworkInfo ani = mock(NetworkInfo.class); + doReturn(connected).when(ani).isConnected(); + doReturn(ani).when(mConnectivityService).getActiveNetworkInfo(); + mDeviceIdleController.updateConnectivityState(null); + } + private void verifyStateConditions(int expectedState) { int curState = mDeviceIdleController.getState(); assertEquals( |