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

Commit 0c5c1904 authored by Zach Johnson's avatar Zach Johnson
Browse files

Fix location for BLE and classic scan results

Test: manual
Bug: 118347564
Bug: 118347252
Change-Id: I0cb22de5f7214db874b75eba91d5ff6076d959b5
parent 977ad222
Loading
Loading
Loading
Loading
+21 −27
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.location.LocationManager;
import android.os.Binder;
import android.os.Build;
import android.os.ParcelUuid;
@@ -277,41 +278,34 @@ public final class Utils {
    }

    /**
     * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION or
     * android.Manifest.permission.ACCESS_FINE_LOCATION and a corresponding app op is allowed
     * Checks whether location is off and must be on for us to perform some operation
     */
    public static boolean blockedByLocationOff(Context context, UserHandle userHandle) {
        return !context.getSystemService(LocationManager.class)
                .isLocationEnabledForUser(userHandle);
    }

    /**
     * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION and
     * OP_FINE_LOCATION is allowed
     */
    public static boolean checkCallerHasLocationPermission(Context context, AppOpsManager appOps,
            String callingPackage) {
            String callingPackage, UserHandle userHandle) {
        if (context.checkCallingOrSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
                == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(
                != PackageManager.PERMISSION_GRANTED || !isAppOppAllowed(
                        appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) {
            return true;
            Log.e(TAG, "Permission denial: Need ACCESS_FINE_LOCATION "
                    + "permission to get scan results");
            return false;
        }

        if (context.checkCallingOrSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
                == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(
                        appOps, AppOpsManager.OP_COARSE_LOCATION, callingPackage)) {
            return true;
        if (blockedByLocationOff(context, userHandle)) {
            Log.e(TAG, "Permission denial: Location is off.");
            return false;
        }
        // Enforce location permission for apps targeting M and later versions
        if (isMApp(context, callingPackage)) {
            // PEERS_MAC_ADDRESS is another way to get scan results without
            // requiring location permissions, so only throw an exception here
            // if PEERS_MAC_ADDRESS permission is missing as well
            if (!checkCallerHasPeersMacAddressPermission(context)) {
                throw new SecurityException("Need ACCESS_COARSE_LOCATION or "
                        + "ACCESS_FINE_LOCATION permission to get scan results");
            }
        } else {
            // Pre-M apps running in the foreground should continue getting scan results
            if (isForegroundApp(context, callingPackage)) {

        return true;
    }
            Log.e(TAG, "Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION "
                    + "permission to get scan results");
        }
        return false;
    }

    /**
     * Returns true if the caller holds PEERS_MAC_ADDRESS.
+10 −3
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.bluetooth.btservice;

import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothActivityEnergyInfo;
@@ -183,6 +184,7 @@ public class AdapterService extends Service {
    private ProfileObserver mProfileObserver;
    private PhonePolicy mPhonePolicy;
    private ActiveDeviceManager mActiveDeviceManager;
    private AppOpsManager mAppOps;

    /**
     * Register a {@link ProfileService} with AdapterService.
@@ -382,6 +384,7 @@ public class AdapterService extends Service {
        initNative();
        mNativeAvailable = true;
        mCallbacks = new RemoteCallbackList<IBluetoothCallback>();
        mAppOps = getSystemService(AppOpsManager.class);
        //Load the name and address
        getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDADDR);
        getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDNAME);
@@ -1007,7 +1010,7 @@ public class AdapterService extends Service {
        }

        @Override
        public boolean startDiscovery() {
        public boolean startDiscovery(String callingPackage) {
            if (!Utils.checkCaller()) {
                Log.w(TAG, "startDiscovery() - Not allowed for non-active user");
                return false;
@@ -1017,7 +1020,7 @@ public class AdapterService extends Service {
            if (service == null) {
                return false;
            }
            return service.startDiscovery();
            return service.startDiscovery(callingPackage);
        }

        @Override
@@ -1811,9 +1814,13 @@ public class AdapterService extends Service {
        return mAdapterProperties.setDiscoverableTimeout(timeout);
    }

    boolean startDiscovery() {
    boolean startDiscovery(String callingPackage) {
        UserHandle callingUser = UserHandle.of(UserHandle.getCallingUserId());
        debugLog("startDiscovery");
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
        if (!Utils.checkCallerHasLocationPermission(this, mAppOps, callingPackage, callingUser)) {
            return false;
        }

        return startDiscoveryNative();
    }
+3 −2
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.util.Log;

@@ -88,8 +89,8 @@ import java.util.UUID;
        /** Whether the calling app has location permission */
        boolean hasLocationPermisson;

        /** Whether the calling app has peers mac address permission */
        boolean hasPeersMacAddressPermission;
        /** The user handle of the app that started the scan */
        UserHandle mUserHandle;

        /** Internal callback info queue, waiting to be send on congestion clear */
        private List<CallbackInfo> mCongestionQueue = new ArrayList<CallbackInfo>();
+11 −25
Original line number Diff line number Diff line
@@ -50,8 +50,8 @@ import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.Log;

import com.android.bluetooth.BluetoothMetricsProto;
@@ -1000,8 +1000,7 @@ public class GattService extends ProfileService {
                            txPower, rssi, periodicAdvInt,
                            ScanRecord.parseFromBytes(scanRecordData),
                            SystemClock.elapsedRealtimeNanos());
            // Do no report if location mode is OFF or the client has no location permission
            // PEERS_MAC_ADDRESS permission holders always get results
            // Do not report if location mode is OFF or the client has no location permission
            if (!hasScanResultPermission(client) || !matchesFilters(client, result)) {
                continue;
            }
@@ -1088,15 +1087,7 @@ public class GattService extends ProfileService {

    /** Determines if the given scan client has the appropriate permissions to receive callbacks. */
    private boolean hasScanResultPermission(final ScanClient client) {
        final boolean requiresLocationEnabled =
                getResources().getBoolean(R.bool.strict_location_check);
        final boolean locationEnabledSetting =
                Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE,
                        Settings.Secure.LOCATION_MODE_OFF) != Settings.Secure.LOCATION_MODE_OFF;
        final boolean locationEnabled =
                !requiresLocationEnabled || locationEnabledSetting || client.legacyForegroundApp;
        return (client.hasPeersMacAddressPermission || (client.hasLocationPermission
                && locationEnabled));
        return client.hasLocationPermission && !Utils.blockedByLocationOff(this, client.userHandle);
    }

    // Check if a scan record matches a specific filters.
@@ -1917,16 +1908,16 @@ public class GattService extends ProfileService {
        if (DBG) {
            Log.d(TAG, "start scan with filters");
        }
        UserHandle callingUser = UserHandle.of(UserHandle.getCallingUserId());
        enforceAdminPermission();
        if (needsPrivilegedPermissionForScan(settings)) {
            enforcePrivilegedPermission();
        }
        final ScanClient scanClient = new ScanClient(scannerId, settings, filters, storages);
        scanClient.userHandle = UserHandle.of(UserHandle.getCallingUserId());
        scanClient.hasLocationPermission =
                Utils.checkCallerHasLocationPermission(this, mAppOps, callingPackage);
        scanClient.hasPeersMacAddressPermission =
                Utils.checkCallerHasPeersMacAddressPermission(this);
        scanClient.legacyForegroundApp = Utils.isLegacyForegroundApp(this, callingPackage);
                Utils.checkCallerHasLocationPermission(
                        this, mAppOps, callingPackage, scanClient.userHandle);

        AppScanStats app = mScannerMap.getAppScanStatsById(scannerId);
        if (app != null) {
@@ -1958,19 +1949,15 @@ public class GattService extends ProfileService {
        piInfo.filters = filters;
        piInfo.callingPackage = callingPackage;
        ScannerMap.App app = mScannerMap.add(uuid, null, null, piInfo, this);
        app.mUserHandle = UserHandle.of(UserHandle.getCallingUserId());
        try {
            app.hasLocationPermisson =
                    Utils.checkCallerHasLocationPermission(this, mAppOps, callingPackage);
                    Utils.checkCallerHasLocationPermission(
                            this, mAppOps, callingPackage, app.mUserHandle);
        } catch (SecurityException se) {
            // No need to throw here. Just mark as not granted.
            app.hasLocationPermisson = false;
        }
        try {
            app.hasPeersMacAddressPermission = Utils.checkCallerHasPeersMacAddressPermission(this);
        } catch (SecurityException se) {
            // No need to throw here. Just mark as not granted.
            app.hasPeersMacAddressPermission = false;
        }
        mScanManager.registerScanner(uuid);
    }

@@ -1979,8 +1966,7 @@ public class GattService extends ProfileService {
        final ScanClient scanClient =
                new ScanClient(scannerId, piInfo.settings, piInfo.filters, null);
        scanClient.hasLocationPermission = app.hasLocationPermisson;
        scanClient.hasPeersMacAddressPermission = app.hasPeersMacAddressPermission;
        scanClient.legacyForegroundApp = Utils.isLegacyForegroundApp(this, piInfo.callingPackage);
        scanClient.userHandle = app.mUserHandle;

        AppScanStats scanStats = mScannerMap.getAppScanStatsById(scannerId);
        if (scanStats != null) {
+2 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import android.bluetooth.le.ResultStorageDescriptor;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanSettings;
import android.os.Binder;
import android.os.UserHandle;

import java.util.List;
import java.util.Objects;
@@ -41,9 +42,7 @@ import java.util.UUID;
    // App associated with the scan client died.
    public boolean appDied;
    public boolean hasLocationPermission;
    public boolean hasPeersMacAddressPermission;
    // Pre-M apps are allowed to get scan results even if location is disabled
    public boolean legacyForegroundApp;
    public UserHandle userHandle;

    public AppScanStats stats = null;

Loading