From 252e17132a189018b0e3ee891ddcc8ef912f0131 Mon Sep 17 00:00:00 2001 From: Alex Johnston Date: Wed, 16 Mar 2022 15:33:52 +0000 Subject: [PATCH] Update lost mode location logic * Send location from the fused, network and gps providers (in order) * Do not loop though all location providers Bug: 223148704 Test: atest android.devicepolicy.cts.LostModeLocationTest atest com.android.server.devicepolicy.DevicePolicyManagerTest Change-Id: I2d73130c304e01e9342c40f4589791f34747f4a5 --- .../DevicePolicyManagerService.java | 65 +++++++++---------- .../devicepolicy/DevicePolicyManagerTest.java | 29 ++++++--- 2 files changed, 52 insertions(+), 42 deletions(-) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 17b44e3c0d647..e7c2a8dd0a5ae 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -278,7 +278,6 @@ import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Build; import android.os.Bundle; -import android.os.CancellationSignal; import android.os.Environment; import android.os.Handler; import android.os.IBinder; @@ -7240,47 +7239,45 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Preconditions.checkState(admin != null, "Lost mode location updates can only be sent on an organization-owned device."); mInjector.binderWithCleanCallingIdentity(() -> { - final List providers = - mInjector.getLocationManager().getAllProviders().stream() - .filter(mInjector.getLocationManager()::isProviderEnabled) - .collect(Collectors.toList()); - if (providers.isEmpty()) { - future.complete(false); - return; - } - - final CancellationSignal cancellationSignal = new CancellationSignal(); - List providersWithNullLocation = new ArrayList(); - for (String provider : providers) { - mInjector.getLocationManager().getCurrentLocation(provider, cancellationSignal, - mContext.getMainExecutor(), location -> { - if (cancellationSignal.isCanceled()) { - return; - } else if (location != null) { - sendLostModeLocationUpdate(admin, location); - cancellationSignal.cancel(); - future.complete(true); - } else { - // location == null, provider wasn't able to get location, see - // if there are more providers - providersWithNullLocation.add(provider); - if (providers.size() == providersWithNullLocation.size()) { - future.complete(false); - } - } - } - ); - } + String[] providers = {LocationManager.FUSED_PROVIDER, + LocationManager.NETWORK_PROVIDER, LocationManager.GPS_PROVIDER}; + tryRetrieveAndSendLocationUpdate(admin, future, providers, /* index= */ 0); }); } } - private void sendLostModeLocationUpdate(ActiveAdmin admin, Location location) { + /** Send lost mode location updates recursively, in order of the list of location providers. */ + private void tryRetrieveAndSendLocationUpdate(ActiveAdmin admin, + AndroidFuture future, String[] providers, int index) { + // None of the providers were able to get location, return false + if (index == providers.length) { + future.complete(false); + return; + } + if (mInjector.getLocationManager().isProviderEnabled(providers[index])) { + mInjector.getLocationManager().getCurrentLocation(providers[index], + /* cancellationSignal= */ null, mContext.getMainExecutor(), location -> { + if (location != null) { + mContext.sendBroadcastAsUser( + newLostModeLocationUpdateIntent(admin, location), + admin.getUserHandle()); + future.complete(true); + } else { + tryRetrieveAndSendLocationUpdate(admin, future, providers, index + 1); + } + } + ); + } else { + tryRetrieveAndSendLocationUpdate(admin, future, providers, index + 1); + } + } + + private Intent newLostModeLocationUpdateIntent(ActiveAdmin admin, Location location) { final Intent intent = new Intent( DevicePolicyManager.ACTION_LOST_MODE_LOCATION_UPDATE); intent.putExtra(DevicePolicyManager.EXTRA_LOST_MODE_LOCATION, location); intent.setPackage(admin.info.getPackageName()); - mContext.sendBroadcastAsUser(intent, admin.getUserHandle()); + return intent; } /** diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 197c21fad74a5..ef7aaca203f77 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -48,6 +48,9 @@ import static android.app.admin.DevicePolicyManager.WIFI_SECURITY_PERSONAL; import static android.app.admin.DevicePolicyManager.WIPE_EUICC; import static android.app.admin.PasswordMetrics.computeForPasswordOrPin; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; +import static android.location.LocationManager.FUSED_PROVIDER; +import static android.location.LocationManager.GPS_PROVIDER; +import static android.location.LocationManager.NETWORK_PROVIDER; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE; import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK; @@ -8462,34 +8465,44 @@ public class DevicePolicyManagerTest extends DpmTestBase { @Test public void testSendLostModeLocationUpdate_asDeviceOwner() throws Exception { - final String TEST_PROVIDER = "network"; mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE); setDeviceOwner(); - when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER)); - when(getServices().locationManager.isProviderEnabled(TEST_PROVIDER)).thenReturn(true); + when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(true); dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {}); verify(getServices().locationManager, times(1)).getCurrentLocation( - eq(TEST_PROVIDER), any(), eq(getServices().executor), any()); + eq(FUSED_PROVIDER), any(), eq(getServices().executor), any()); } @Test public void testSendLostModeLocationUpdate_asProfileOwnerOfOrgOwnedDevice() throws Exception { - final String TEST_PROVIDER = "network"; final int MANAGED_PROFILE_ADMIN_UID = UserHandle.getUid(CALLER_USER_HANDLE, DpmMockContext.SYSTEM_UID); mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID; mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE); addManagedProfile(admin1, MANAGED_PROFILE_ADMIN_UID, admin1); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); - when(getServices().locationManager.getAllProviders()).thenReturn(List.of(TEST_PROVIDER)); - when(getServices().locationManager.isProviderEnabled(TEST_PROVIDER)).thenReturn(true); + when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(true); dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {}); verify(getServices().locationManager, times(1)).getCurrentLocation( - eq(TEST_PROVIDER), any(), eq(getServices().executor), any()); + eq(FUSED_PROVIDER), any(), eq(getServices().executor), any()); + } + + @Test + public void testSendLostModeLocationUpdate_noProviderIsEnabled() throws Exception { + mContext.callerPermissions.add(permission.TRIGGER_LOST_MODE); + setDeviceOwner(); + when(getServices().locationManager.isProviderEnabled(FUSED_PROVIDER)).thenReturn(false); + when(getServices().locationManager.isProviderEnabled(NETWORK_PROVIDER)).thenReturn(false); + when(getServices().locationManager.isProviderEnabled(GPS_PROVIDER)).thenReturn(false); + + dpm.sendLostModeLocationUpdate(getServices().executor, /* empty callback */ result -> {}); + + verify(getServices().locationManager, never()).getCurrentLocation( + eq(FUSED_PROVIDER), any(), eq(getServices().executor), any()); } private void setupVpnAuthorization(String userVpnPackage, int userVpnUid) {