Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 252e1713 authored by Alex Johnston's avatar Alex Johnston
Browse files

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
parent 404e0450
Loading
Loading
Loading
Loading
+31 −34
Original line number Diff line number Diff line
@@ -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<String> providers =
                        mInjector.getLocationManager().getAllProviders().stream()
                                .filter(mInjector.getLocationManager()::isProviderEnabled)
                                .collect(Collectors.toList());
                if (providers.isEmpty()) {
                    future.complete(false);
                    return;
                String[] providers = {LocationManager.FUSED_PROVIDER,
                        LocationManager.NETWORK_PROVIDER, LocationManager.GPS_PROVIDER};
                tryRetrieveAndSendLocationUpdate(admin, future, providers, /* index= */ 0);
            });
        }
    }
                final CancellationSignal cancellationSignal = new CancellationSignal();
                List<String> providersWithNullLocation = new ArrayList<String>();
                for (String provider : providers) {
                    mInjector.getLocationManager().getCurrentLocation(provider, cancellationSignal,
                            mContext.getMainExecutor(), location -> {
                                if (cancellationSignal.isCanceled()) {
    /** Send lost mode location updates recursively, in order of the list of location providers. */
    private void tryRetrieveAndSendLocationUpdate(ActiveAdmin admin,
            AndroidFuture<Boolean> future, String[] providers, int index) {
        // None of the providers were able to get location, return false
        if (index == providers.length) {
            future.complete(false);
            return;
                                } else if (location != null) {
                                    sendLostModeLocationUpdate(admin, location);
                                    cancellationSignal.cancel();
        }
        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 {
                                    // 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);
                                    }
                            tryRetrieveAndSendLocationUpdate(admin, future, providers, index + 1);
                        }
                    }
            );
                }
            });
        } else {
           tryRetrieveAndSendLocationUpdate(admin, future, providers, index + 1);
        }
    }
    private void sendLostModeLocationUpdate(ActiveAdmin admin, Location location) {
    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;
    }
    /**
+21 −8
Original line number Diff line number Diff line
@@ -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) {