Loading framework/api/current.txt +2 −2 Original line number Diff line number Diff line Loading @@ -17,8 +17,8 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean cancelDiscovery(); method public static boolean checkBluetoothAddress(String); method public void closeProfileProxy(int, android.bluetooth.BluetoothProfile); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disable(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enable(); method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disable(); method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enable(); method public String getAddress(); method public android.bluetooth.le.BluetoothLeAdvertiser getBluetoothLeAdvertiser(); method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner(); Loading framework/java/android/bluetooth/BluetoothAdapter.java +26 −0 Original line number Diff line number Diff line Loading @@ -1282,7 +1282,20 @@ public final class BluetoothAdapter { * such as Airplane mode, or the adapter is already turned on. * * @return true to indicate adapter startup has begun, or false on immediate error * * @deprecated Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, applications * are not allowed to enable/disable Bluetooth. * <b>Compatibility Note:</b> For applications targeting * {@link android.os.Build.VERSION_CODES#TIRAMISU} or above, this API will always fail and return * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#S} * or below), they can continue to use this API. * <p> * Deprecation Exemptions: * <ul> * <li>Device Owner (DO), Profile Owner (PO) and system apps. * </ul> */ @Deprecated @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) Loading Loading @@ -1321,7 +1334,20 @@ public final class BluetoothAdapter { * such as the adapter already being turned off. * * @return true to indicate adapter shutdown has begun, or false on immediate error * * @deprecated Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, applications * are not allowed to enable/disable Bluetooth. * <b>Compatibility Note:</b> For applications targeting * {@link android.os.Build.VERSION_CODES#TIRAMISU} or above, this API will always fail and return * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#S} * or below), they can continue to use this API. * <p> * Deprecation Exemptions: * <ul> * <li>Device Owner (DO), Profile Owner (PO) and system apps. * </ul> */ @Deprecated @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) Loading service/Android.bp +7 −1 Original line number Diff line number Diff line Loading @@ -61,10 +61,12 @@ java_library { libs: [ "framework-annotations-lib", "framework-bluetooth-pre-jarjar", "app-compat-annotations", ], static_libs: [ "androidx.annotation_annotation", "androidx.appcompat_appcompat", ], apex_available: [ Loading @@ -78,10 +80,14 @@ java_library { name: "service-bluetooth", defaults: ["service-bluetooth-common-defaults"], installable: true, static_libs: ["service-bluetooth-pre-jarjar"], static_libs: [ "service-bluetooth-pre-jarjar", "androidx.appcompat_appcompat", ], libs: [ "framework-bluetooth.impl", "app-compat-annotations", ], sdk_version: "system_server_current", Loading service/java/com/android/server/bluetooth/BluetoothManagerService.java +78 −48 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.admin.DevicePolicyManager; import android.app.compat.CompatChanges; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothHearingAid; Loading @@ -43,7 +45,8 @@ import android.bluetooth.IBluetoothManager; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; import android.bluetooth.IBluetoothStateChangeCallback; import android.content.ActivityNotFoundException; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.AttributionSource; import android.content.BroadcastReceiver; import android.content.ComponentName; Loading Loading @@ -79,6 +82,7 @@ import android.provider.Settings.SettingNotFoundException; import android.sysprop.BluetoothProperties; import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -177,6 +181,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int SERVICE_IBLUETOOTH = 1; private static final int SERVICE_IBLUETOOTHGATT = 2; private static final int FLAGS_SYSTEM_APP = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; /** * Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, applications are * not allowed to enable/disable Bluetooth. */ @ChangeId @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU) static final long RESTRICT_ENABLE_DISABLE = 218493289L; private final Context mContext; private final UserManager mUserManager; Loading Loading @@ -272,8 +287,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { // bluetooth profile services private final Map<Integer, ProfileServiceConnections> mProfileServices = new HashMap<>(); private final boolean mWirelessConsentRequired; private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { @Override public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { Loading Loading @@ -482,10 +495,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mContext = context; mWirelessConsentRequired = context.getResources() .getBoolean(Resources.getSystem().getIdentifier( "config_wirelessConsentRequired", "bool", "android")); mCrashes = 0; mBluetooth = null; mBluetoothBinder = null; Loading Loading @@ -1229,10 +1238,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } final int callingUid = Binder.getCallingUid(); final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; if (!callerSystem && !isEnabled() && mWirelessConsentRequired && startConsentUiIfNeeded(packageName, callingUid, BluetoothAdapter.ACTION_REQUEST_ENABLE)) { final int callingPid = Binder.getCallingPid(); if (!isPrivileged(callingPid, callingUid) && !isDeviceOwner(callingUid, packageName) && !CompatChanges.isChangeEnabled(RESTRICT_ENABLE_DISABLE, callingUid) && !isSystem(packageName, callingUid)) { return false; } Loading Loading @@ -1270,10 +1279,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } final int callingUid = Binder.getCallingUid(); final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; if (!callerSystem && isEnabled() && mWirelessConsentRequired && startConsentUiIfNeeded(packageName, callingUid, BluetoothAdapter.ACTION_REQUEST_DISABLE)) { final int callingPid = Binder.getCallingPid(); if (!isPrivileged(callingPid, callingUid) && !isDeviceOwner(callingUid, packageName) && CompatChanges.isChangeEnabled(RESTRICT_ENABLE_DISABLE, callingUid) && !isSystem(packageName, callingUid)) { return false; } Loading @@ -1294,39 +1303,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } private boolean startConsentUiIfNeeded(String packageName, int callingUid, String intentAction) throws RemoteException { if (checkBluetoothPermissionWhenWirelessConsentRequired()) { return false; } try { // Validate the package only if we are going to use it ApplicationInfo applicationInfo = mContext.getPackageManager() .getApplicationInfoAsUser(packageName, PackageManager.MATCH_DIRECT_BOOT_AUTO, UserHandle.getUserHandleForUid(callingUid)); if (applicationInfo.uid != callingUid) { throw new SecurityException("Package " + packageName + " not in uid " + callingUid); } Intent intent = new Intent(intentAction); intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); try { mContext.startActivity(intent); } catch (ActivityNotFoundException e) { // Shouldn't happen Log.e(TAG, "Intent to handle action " + intentAction + " missing"); return false; } return true; } catch (PackageManager.NameNotFoundException e) { throw new RemoteException(e.getMessage()); } } /** * Check if AppOpsManager is available and the packageName belongs to uid * Loading Loading @@ -3082,4 +3058,58 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } return comp; } private boolean isPrivileged(int pid, int uid) { return (mContext.checkPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED, pid, uid) == PackageManager.PERMISSION_GRANTED) || (mContext.getPackageManager().checkSignatures(uid, Process.SYSTEM_UID) == PackageManager.SIGNATURE_MATCH); } private Pair<UserHandle, ComponentName> getDeviceOwner() { DevicePolicyManager devicePolicyManager = mContext.getSystemService(DevicePolicyManager.class); if (devicePolicyManager == null) return null; long ident = Binder.clearCallingIdentity(); UserHandle deviceOwnerUser = null; ComponentName deviceOwnerComponent = null; try { deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser(); deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser(); } finally { Binder.restoreCallingIdentity(ident); } if (deviceOwnerUser == null || deviceOwnerComponent == null || deviceOwnerComponent.getPackageName() == null) { return null; } return new Pair<>(deviceOwnerUser, deviceOwnerComponent); } private boolean isDeviceOwner(int uid, String packageName) { if (packageName == null) { Log.e(TAG, "isDeviceOwner: packageName is null, returning false"); return false; } Pair<UserHandle, ComponentName> deviceOwner = getDeviceOwner(); // no device owner if (deviceOwner == null) return false; return deviceOwner.first.equals(UserHandle.getUserHandleForUid(uid)) && deviceOwner.second.getPackageName().equals(packageName); } public boolean isSystem(String packageName, int uid) { long ident = Binder.clearCallingIdentity(); try { ApplicationInfo info = mContext.getPackageManager().getApplicationInfoAsUser( packageName, 0, UserHandle.getUserHandleForUid(uid)); return (info.flags & FLAGS_SYSTEM_APP) != 0; } catch (PackageManager.NameNotFoundException e) { return false; } finally { Binder.restoreCallingIdentity(ident); } } } Loading
framework/api/current.txt +2 −2 Original line number Diff line number Diff line Loading @@ -17,8 +17,8 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN) public boolean cancelDiscovery(); method public static boolean checkBluetoothAddress(String); method public void closeProfileProxy(int, android.bluetooth.BluetoothProfile); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disable(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enable(); method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean disable(); method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) public boolean enable(); method public String getAddress(); method public android.bluetooth.le.BluetoothLeAdvertiser getBluetoothLeAdvertiser(); method public android.bluetooth.le.BluetoothLeScanner getBluetoothLeScanner(); Loading
framework/java/android/bluetooth/BluetoothAdapter.java +26 −0 Original line number Diff line number Diff line Loading @@ -1282,7 +1282,20 @@ public final class BluetoothAdapter { * such as Airplane mode, or the adapter is already turned on. * * @return true to indicate adapter startup has begun, or false on immediate error * * @deprecated Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, applications * are not allowed to enable/disable Bluetooth. * <b>Compatibility Note:</b> For applications targeting * {@link android.os.Build.VERSION_CODES#TIRAMISU} or above, this API will always fail and return * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#S} * or below), they can continue to use this API. * <p> * Deprecation Exemptions: * <ul> * <li>Device Owner (DO), Profile Owner (PO) and system apps. * </ul> */ @Deprecated @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) Loading Loading @@ -1321,7 +1334,20 @@ public final class BluetoothAdapter { * such as the adapter already being turned off. * * @return true to indicate adapter shutdown has begun, or false on immediate error * * @deprecated Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, applications * are not allowed to enable/disable Bluetooth. * <b>Compatibility Note:</b> For applications targeting * {@link android.os.Build.VERSION_CODES#TIRAMISU} or above, this API will always fail and return * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#S} * or below), they can continue to use this API. * <p> * Deprecation Exemptions: * <ul> * <li>Device Owner (DO), Profile Owner (PO) and system apps. * </ul> */ @Deprecated @RequiresLegacyBluetoothAdminPermission @RequiresBluetoothConnectPermission @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT) Loading
service/Android.bp +7 −1 Original line number Diff line number Diff line Loading @@ -61,10 +61,12 @@ java_library { libs: [ "framework-annotations-lib", "framework-bluetooth-pre-jarjar", "app-compat-annotations", ], static_libs: [ "androidx.annotation_annotation", "androidx.appcompat_appcompat", ], apex_available: [ Loading @@ -78,10 +80,14 @@ java_library { name: "service-bluetooth", defaults: ["service-bluetooth-common-defaults"], installable: true, static_libs: ["service-bluetooth-pre-jarjar"], static_libs: [ "service-bluetooth-pre-jarjar", "androidx.appcompat_appcompat", ], libs: [ "framework-bluetooth.impl", "app-compat-annotations", ], sdk_version: "system_server_current", Loading
service/java/com/android/server/bluetooth/BluetoothManagerService.java +78 −48 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ import android.annotation.SuppressLint; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.admin.DevicePolicyManager; import android.app.compat.CompatChanges; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothHearingAid; Loading @@ -43,7 +45,8 @@ import android.bluetooth.IBluetoothManager; import android.bluetooth.IBluetoothManagerCallback; import android.bluetooth.IBluetoothProfileServiceConnection; import android.bluetooth.IBluetoothStateChangeCallback; import android.content.ActivityNotFoundException; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.AttributionSource; import android.content.BroadcastReceiver; import android.content.ComponentName; Loading Loading @@ -79,6 +82,7 @@ import android.provider.Settings.SettingNotFoundException; import android.sysprop.BluetoothProperties; import android.text.TextUtils; import android.util.Log; import android.util.Pair; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -177,6 +181,17 @@ class BluetoothManagerService extends IBluetoothManager.Stub { private static final int SERVICE_IBLUETOOTH = 1; private static final int SERVICE_IBLUETOOTHGATT = 2; private static final int FLAGS_SYSTEM_APP = ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; /** * Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, applications are * not allowed to enable/disable Bluetooth. */ @ChangeId @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.TIRAMISU) static final long RESTRICT_ENABLE_DISABLE = 218493289L; private final Context mContext; private final UserManager mUserManager; Loading Loading @@ -272,8 +287,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { // bluetooth profile services private final Map<Integer, ProfileServiceConnections> mProfileServices = new HashMap<>(); private final boolean mWirelessConsentRequired; private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() { @Override public void onBluetoothStateChange(int prevState, int newState) throws RemoteException { Loading Loading @@ -482,10 +495,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mContext = context; mWirelessConsentRequired = context.getResources() .getBoolean(Resources.getSystem().getIdentifier( "config_wirelessConsentRequired", "bool", "android")); mCrashes = 0; mBluetooth = null; mBluetoothBinder = null; Loading Loading @@ -1229,10 +1238,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } final int callingUid = Binder.getCallingUid(); final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; if (!callerSystem && !isEnabled() && mWirelessConsentRequired && startConsentUiIfNeeded(packageName, callingUid, BluetoothAdapter.ACTION_REQUEST_ENABLE)) { final int callingPid = Binder.getCallingPid(); if (!isPrivileged(callingPid, callingUid) && !isDeviceOwner(callingUid, packageName) && !CompatChanges.isChangeEnabled(RESTRICT_ENABLE_DISABLE, callingUid) && !isSystem(packageName, callingUid)) { return false; } Loading Loading @@ -1270,10 +1279,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } final int callingUid = Binder.getCallingUid(); final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID; if (!callerSystem && isEnabled() && mWirelessConsentRequired && startConsentUiIfNeeded(packageName, callingUid, BluetoothAdapter.ACTION_REQUEST_DISABLE)) { final int callingPid = Binder.getCallingPid(); if (!isPrivileged(callingPid, callingUid) && !isDeviceOwner(callingUid, packageName) && CompatChanges.isChangeEnabled(RESTRICT_ENABLE_DISABLE, callingUid) && !isSystem(packageName, callingUid)) { return false; } Loading @@ -1294,39 +1303,6 @@ class BluetoothManagerService extends IBluetoothManager.Stub { return true; } private boolean startConsentUiIfNeeded(String packageName, int callingUid, String intentAction) throws RemoteException { if (checkBluetoothPermissionWhenWirelessConsentRequired()) { return false; } try { // Validate the package only if we are going to use it ApplicationInfo applicationInfo = mContext.getPackageManager() .getApplicationInfoAsUser(packageName, PackageManager.MATCH_DIRECT_BOOT_AUTO, UserHandle.getUserHandleForUid(callingUid)); if (applicationInfo.uid != callingUid) { throw new SecurityException("Package " + packageName + " not in uid " + callingUid); } Intent intent = new Intent(intentAction); intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); try { mContext.startActivity(intent); } catch (ActivityNotFoundException e) { // Shouldn't happen Log.e(TAG, "Intent to handle action " + intentAction + " missing"); return false; } return true; } catch (PackageManager.NameNotFoundException e) { throw new RemoteException(e.getMessage()); } } /** * Check if AppOpsManager is available and the packageName belongs to uid * Loading Loading @@ -3082,4 +3058,58 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } return comp; } private boolean isPrivileged(int pid, int uid) { return (mContext.checkPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED, pid, uid) == PackageManager.PERMISSION_GRANTED) || (mContext.getPackageManager().checkSignatures(uid, Process.SYSTEM_UID) == PackageManager.SIGNATURE_MATCH); } private Pair<UserHandle, ComponentName> getDeviceOwner() { DevicePolicyManager devicePolicyManager = mContext.getSystemService(DevicePolicyManager.class); if (devicePolicyManager == null) return null; long ident = Binder.clearCallingIdentity(); UserHandle deviceOwnerUser = null; ComponentName deviceOwnerComponent = null; try { deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser(); deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser(); } finally { Binder.restoreCallingIdentity(ident); } if (deviceOwnerUser == null || deviceOwnerComponent == null || deviceOwnerComponent.getPackageName() == null) { return null; } return new Pair<>(deviceOwnerUser, deviceOwnerComponent); } private boolean isDeviceOwner(int uid, String packageName) { if (packageName == null) { Log.e(TAG, "isDeviceOwner: packageName is null, returning false"); return false; } Pair<UserHandle, ComponentName> deviceOwner = getDeviceOwner(); // no device owner if (deviceOwner == null) return false; return deviceOwner.first.equals(UserHandle.getUserHandleForUid(uid)) && deviceOwner.second.getPackageName().equals(packageName); } public boolean isSystem(String packageName, int uid) { long ident = Binder.clearCallingIdentity(); try { ApplicationInfo info = mContext.getPackageManager().getApplicationInfoAsUser( packageName, 0, UserHandle.getUserHandleForUid(uid)); return (info.flags & FLAGS_SYSTEM_APP) != 0; } catch (PackageManager.NameNotFoundException e) { return false; } finally { Binder.restoreCallingIdentity(ident); } } }