Loading src/com/android/bluetooth/Utils.java +86 −11 Original line number Diff line number Diff line Loading @@ -286,32 +286,98 @@ public final class Utils { } /** * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION and * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION and * OP_COARSE_LOCATION is allowed */ public static boolean checkCallerHasCoarseLocation(Context context, AppOpsManager appOps, String callingPackage, UserHandle userHandle) { if (blockedByLocationOff(context, userHandle)) { Log.e(TAG, "Permission denial: Location is off."); return false; } // Check coarse, but note fine if (context.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) { return true; } Log.e(TAG, "Permission denial: Need ACCESS_COARSE_LOCATION " + "permission to get scan results"); return false; } /** * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION and * OP_COARSE_LOCATION is allowed or android.Manifest.permission.ACCESS_FINE_LOCATION and * OP_FINE_LOCATION is allowed */ public static boolean checkCallerHasLocationPermission(Context context, AppOpsManager appOps, public static boolean checkCallerHasCoarseOrFineLocation(Context context, AppOpsManager appOps, String callingPackage, UserHandle userHandle) { if (context.checkCallingOrSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || !isAppOppAllowed( appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) { Log.e(TAG, "Permission denial: Need ACCESS_FINE_LOCATION " if (blockedByLocationOff(context, userHandle)) { Log.e(TAG, "Permission denial: Location is off."); return false; } if (context.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) { return true; } // Check coarse, but note fine if (context.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) { return true; } Log.e(TAG, "Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION" + "permission to get scan results"); return false; } /** * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION and * OP_FINE_LOCATION is allowed */ public static boolean checkCallerHasFineLocation(Context context, AppOpsManager appOps, String callingPackage, UserHandle userHandle) { if (blockedByLocationOff(context, userHandle)) { Log.e(TAG, "Permission denial: Location is off."); return false; } if (context.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_FINE_LOCATION) == 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; } /** * Returns true if the caller holds NETWORK_SETTINGS */ public static boolean checkCallerHasNetworkSettingsPermission(Context context) { return context.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS) == PackageManager.PERMISSION_GRANTED; } /** * Returns true if the caller holds PEERS_MAC_ADDRESS. * Returns true if the caller holds NETWORK_SETUP_WIZARD */ public static boolean checkCallerHasPeersMacAddressPermission(Context context) { return context.checkCallingOrSelfPermission(android.Manifest.permission.PEERS_MAC_ADDRESS) public static boolean checkCallerHasNetworkSetupWizardPermission(Context context) { return context.checkCallingOrSelfPermission( android.Manifest.permission.NETWORK_SETUP_WIZARD) == PackageManager.PERMISSION_GRANTED; } Loading @@ -329,6 +395,15 @@ public final class Utils { return true; } public static boolean isQApp(Context context, String pkgName) { try { return context.getPackageManager().getApplicationInfo(pkgName, 0).targetSdkVersion >= Build.VERSION_CODES.Q; } catch (PackageManager.NameNotFoundException e) { // In case of exception, assume Q app } return true; } /** * Return true if the specified package name is a foreground app. * Loading src/com/android/bluetooth/btservice/AdapterProperties.java +1 −0 Original line number Diff line number Diff line Loading @@ -923,6 +923,7 @@ class AdapterProperties { Intent intent; if (state == AbstractionLayer.BT_DISCOVERY_STOPPED) { mDiscovering = false; mService.clearDiscoveringPackages(); mDiscoveryEndMs = System.currentTimeMillis(); intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM); Loading src/com/android/bluetooth/btservice/AdapterService.java +33 −2 Original line number Diff line number Diff line Loading @@ -136,6 +136,8 @@ public class AdapterService extends Service { private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30; private final ArrayList<DiscoveringPackage> mDiscoveringPackages = new ArrayList<>(); static { classInitNative(); } Loading Loading @@ -386,6 +388,7 @@ public class AdapterService extends Service { debugLog("onCreate()"); mRemoteDevices = new RemoteDevices(this, Looper.getMainLooper()); mRemoteDevices.init(); clearDiscoveringPackages(); mBinder = new AdapterServiceBinder(this); mAdapterProperties = new AdapterProperties(this); mAdapterStateMachine = AdapterState.make(this); Loading Loading @@ -1905,14 +1908,42 @@ public class AdapterService extends Service { return mAdapterProperties.setDiscoverableTimeout(timeout); } ArrayList<DiscoveringPackage> getDiscoveringPackages() { return mDiscoveringPackages; } void clearDiscoveringPackages() { synchronized (mDiscoveringPackages) { mDiscoveringPackages.clear(); } } 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)) { mAppOps.checkPackage(callingUser.getIdentifier(), callingPackage); boolean isQApp = Utils.isQApp(this, callingPackage); String permission = null; if (Utils.checkCallerHasNetworkSettingsPermission(this)) { permission = android.Manifest.permission.NETWORK_SETTINGS; } else if (Utils.checkCallerHasNetworkSetupWizardPermission(this)) { permission = android.Manifest.permission.NETWORK_SETUP_WIZARD; } else if (isQApp) { if (!Utils.checkCallerHasFineLocation(this, mAppOps, callingPackage, callingUser)) { return false; } permission = android.Manifest.permission.ACCESS_FINE_LOCATION; } else { if (!Utils.checkCallerHasCoarseLocation(this, mAppOps, callingPackage, callingUser)) { return false; } permission = android.Manifest.permission.ACCESS_COARSE_LOCATION; } synchronized (mDiscoveringPackages) { mDiscoveringPackages.add(new DiscoveringPackage(callingPackage, permission)); } return startDiscoveryNative(); } Loading src/com/android/bluetooth/btservice/DiscoveringPackage.java 0 → 100644 +35 −0 Original line number Diff line number Diff line /* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth.btservice; final class DiscoveringPackage { private String mPackageName; private String mPermission; DiscoveringPackage(String packageName, String permission) { mPackageName = packageName; mPermission = permission; } public String getPackageName() { return mPackageName; } public String getPermission() { return mPermission; } } src/com/android/bluetooth/btservice/RemoteDevices.java +9 −3 Original line number Diff line number Diff line Loading @@ -582,10 +582,16 @@ final class RemoteDevices { intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi); intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName); final ArrayList<DiscoveringPackage> packages = sAdapterService.getDiscoveringPackages(); synchronized (packages) { for (DiscoveringPackage pkg : packages) { intent.setPackage(pkg.getPackageName()); sAdapterService.sendBroadcastMultiplePermissions(intent, new String[]{ AdapterService.BLUETOOTH_PERM, android.Manifest.permission.ACCESS_COARSE_LOCATION AdapterService.BLUETOOTH_PERM, pkg.getPermission() }); } } } void aclStateChangeCallback(int status, byte[] address, int newState) { BluetoothDevice device = getDevice(address); Loading Loading
src/com/android/bluetooth/Utils.java +86 −11 Original line number Diff line number Diff line Loading @@ -286,32 +286,98 @@ public final class Utils { } /** * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION and * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION and * OP_COARSE_LOCATION is allowed */ public static boolean checkCallerHasCoarseLocation(Context context, AppOpsManager appOps, String callingPackage, UserHandle userHandle) { if (blockedByLocationOff(context, userHandle)) { Log.e(TAG, "Permission denial: Location is off."); return false; } // Check coarse, but note fine if (context.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) { return true; } Log.e(TAG, "Permission denial: Need ACCESS_COARSE_LOCATION " + "permission to get scan results"); return false; } /** * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION and * OP_COARSE_LOCATION is allowed or android.Manifest.permission.ACCESS_FINE_LOCATION and * OP_FINE_LOCATION is allowed */ public static boolean checkCallerHasLocationPermission(Context context, AppOpsManager appOps, public static boolean checkCallerHasCoarseOrFineLocation(Context context, AppOpsManager appOps, String callingPackage, UserHandle userHandle) { if (context.checkCallingOrSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || !isAppOppAllowed( appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) { Log.e(TAG, "Permission denial: Need ACCESS_FINE_LOCATION " if (blockedByLocationOff(context, userHandle)) { Log.e(TAG, "Permission denial: Location is off."); return false; } if (context.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) { return true; } // Check coarse, but note fine if (context.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && isAppOppAllowed(appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) { return true; } Log.e(TAG, "Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION" + "permission to get scan results"); return false; } /** * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION and * OP_FINE_LOCATION is allowed */ public static boolean checkCallerHasFineLocation(Context context, AppOpsManager appOps, String callingPackage, UserHandle userHandle) { if (blockedByLocationOff(context, userHandle)) { Log.e(TAG, "Permission denial: Location is off."); return false; } if (context.checkCallingOrSelfPermission( android.Manifest.permission.ACCESS_FINE_LOCATION) == 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; } /** * Returns true if the caller holds NETWORK_SETTINGS */ public static boolean checkCallerHasNetworkSettingsPermission(Context context) { return context.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS) == PackageManager.PERMISSION_GRANTED; } /** * Returns true if the caller holds PEERS_MAC_ADDRESS. * Returns true if the caller holds NETWORK_SETUP_WIZARD */ public static boolean checkCallerHasPeersMacAddressPermission(Context context) { return context.checkCallingOrSelfPermission(android.Manifest.permission.PEERS_MAC_ADDRESS) public static boolean checkCallerHasNetworkSetupWizardPermission(Context context) { return context.checkCallingOrSelfPermission( android.Manifest.permission.NETWORK_SETUP_WIZARD) == PackageManager.PERMISSION_GRANTED; } Loading @@ -329,6 +395,15 @@ public final class Utils { return true; } public static boolean isQApp(Context context, String pkgName) { try { return context.getPackageManager().getApplicationInfo(pkgName, 0).targetSdkVersion >= Build.VERSION_CODES.Q; } catch (PackageManager.NameNotFoundException e) { // In case of exception, assume Q app } return true; } /** * Return true if the specified package name is a foreground app. * Loading
src/com/android/bluetooth/btservice/AdapterProperties.java +1 −0 Original line number Diff line number Diff line Loading @@ -923,6 +923,7 @@ class AdapterProperties { Intent intent; if (state == AbstractionLayer.BT_DISCOVERY_STOPPED) { mDiscovering = false; mService.clearDiscoveringPackages(); mDiscoveryEndMs = System.currentTimeMillis(); intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM); Loading
src/com/android/bluetooth/btservice/AdapterService.java +33 −2 Original line number Diff line number Diff line Loading @@ -136,6 +136,8 @@ public class AdapterService extends Service { private static final int CONTROLLER_ENERGY_UPDATE_TIMEOUT_MILLIS = 30; private final ArrayList<DiscoveringPackage> mDiscoveringPackages = new ArrayList<>(); static { classInitNative(); } Loading Loading @@ -386,6 +388,7 @@ public class AdapterService extends Service { debugLog("onCreate()"); mRemoteDevices = new RemoteDevices(this, Looper.getMainLooper()); mRemoteDevices.init(); clearDiscoveringPackages(); mBinder = new AdapterServiceBinder(this); mAdapterProperties = new AdapterProperties(this); mAdapterStateMachine = AdapterState.make(this); Loading Loading @@ -1905,14 +1908,42 @@ public class AdapterService extends Service { return mAdapterProperties.setDiscoverableTimeout(timeout); } ArrayList<DiscoveringPackage> getDiscoveringPackages() { return mDiscoveringPackages; } void clearDiscoveringPackages() { synchronized (mDiscoveringPackages) { mDiscoveringPackages.clear(); } } 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)) { mAppOps.checkPackage(callingUser.getIdentifier(), callingPackage); boolean isQApp = Utils.isQApp(this, callingPackage); String permission = null; if (Utils.checkCallerHasNetworkSettingsPermission(this)) { permission = android.Manifest.permission.NETWORK_SETTINGS; } else if (Utils.checkCallerHasNetworkSetupWizardPermission(this)) { permission = android.Manifest.permission.NETWORK_SETUP_WIZARD; } else if (isQApp) { if (!Utils.checkCallerHasFineLocation(this, mAppOps, callingPackage, callingUser)) { return false; } permission = android.Manifest.permission.ACCESS_FINE_LOCATION; } else { if (!Utils.checkCallerHasCoarseLocation(this, mAppOps, callingPackage, callingUser)) { return false; } permission = android.Manifest.permission.ACCESS_COARSE_LOCATION; } synchronized (mDiscoveringPackages) { mDiscoveringPackages.add(new DiscoveringPackage(callingPackage, permission)); } return startDiscoveryNative(); } Loading
src/com/android/bluetooth/btservice/DiscoveringPackage.java 0 → 100644 +35 −0 Original line number Diff line number Diff line /* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.bluetooth.btservice; final class DiscoveringPackage { private String mPackageName; private String mPermission; DiscoveringPackage(String packageName, String permission) { mPackageName = packageName; mPermission = permission; } public String getPackageName() { return mPackageName; } public String getPermission() { return mPermission; } }
src/com/android/bluetooth/btservice/RemoteDevices.java +9 −3 Original line number Diff line number Diff line Loading @@ -582,10 +582,16 @@ final class RemoteDevices { intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi); intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName); final ArrayList<DiscoveringPackage> packages = sAdapterService.getDiscoveringPackages(); synchronized (packages) { for (DiscoveringPackage pkg : packages) { intent.setPackage(pkg.getPackageName()); sAdapterService.sendBroadcastMultiplePermissions(intent, new String[]{ AdapterService.BLUETOOTH_PERM, android.Manifest.permission.ACCESS_COARSE_LOCATION AdapterService.BLUETOOTH_PERM, pkg.getPermission() }); } } } void aclStateChangeCallback(int status, byte[] address, int newState) { BluetoothDevice device = getDevice(address); Loading