Loading android/app/src/com/android/bluetooth/Utils.java +21 −27 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading android/app/src/com/android/bluetooth/btservice/AdapterService.java +10 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -1017,7 +1020,7 @@ public class AdapterService extends Service { if (service == null) { return false; } return service.startDiscovery(); return service.startDiscovery(callingPackage); } @Override Loading Loading @@ -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(); } Loading android/app/src/com/android/bluetooth/gatt/ContextMap.java +3 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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>(); Loading android/app/src/com/android/bluetooth/gatt/GattService.java +11 −25 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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. Loading Loading @@ -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) { Loading Loading @@ -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); } Loading @@ -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) { Loading android/app/src/com/android/bluetooth/gatt/ScanClient.java +2 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 Loading
android/app/src/com/android/bluetooth/Utils.java +21 −27 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading
android/app/src/com/android/bluetooth/btservice/AdapterService.java +10 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -1017,7 +1020,7 @@ public class AdapterService extends Service { if (service == null) { return false; } return service.startDiscovery(); return service.startDiscovery(callingPackage); } @Override Loading Loading @@ -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(); } Loading
android/app/src/com/android/bluetooth/gatt/ContextMap.java +3 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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>(); Loading
android/app/src/com/android/bluetooth/gatt/GattService.java +11 −25 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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. Loading Loading @@ -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) { Loading Loading @@ -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); } Loading @@ -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) { Loading
android/app/src/com/android/bluetooth/gatt/ScanClient.java +2 −3 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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