Merge "Register IBluetoothManagerCallback per-process." into sc-dev am: 01034e6e61 am: 512bc4c6ec
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15523353 Change-Id: I644808e3a34b21d66d5eafa6ca506f00c0464137
This commit is contained in:
@@ -64,6 +64,8 @@ import android.os.SystemProperties;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
@@ -78,6 +80,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
@@ -715,10 +718,21 @@ public final class BluetoothAdapter {
|
|||||||
private final IBluetoothManager mManagerService;
|
private final IBluetoothManager mManagerService;
|
||||||
private final AttributionSource mAttributionSource;
|
private final AttributionSource mAttributionSource;
|
||||||
|
|
||||||
|
// Yeah, keeping both mService and sService isn't pretty, but it's too late
|
||||||
|
// in the current release for a major refactoring, so we leave them both
|
||||||
|
// intact until this can be cleaned up in a future release
|
||||||
|
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
|
@GuardedBy("mServiceLock")
|
||||||
private IBluetooth mService;
|
private IBluetooth mService;
|
||||||
private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
|
private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
|
||||||
|
|
||||||
|
@GuardedBy("sServiceLock")
|
||||||
|
private static boolean sServiceRegistered;
|
||||||
|
@GuardedBy("sServiceLock")
|
||||||
|
private static IBluetooth sService;
|
||||||
|
private static final Object sServiceLock = new Object();
|
||||||
|
|
||||||
private final Object mLock = new Object();
|
private final Object mLock = new Object();
|
||||||
private final Map<LeScanCallback, ScanCallback> mLeScanClients;
|
private final Map<LeScanCallback, ScanCallback> mLeScanClients;
|
||||||
private final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
|
private final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
|
||||||
@@ -792,19 +806,11 @@ public final class BluetoothAdapter {
|
|||||||
* Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
|
* Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
|
||||||
*/
|
*/
|
||||||
BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) {
|
BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) {
|
||||||
if (managerService == null) {
|
|
||||||
throw new IllegalArgumentException("bluetooth manager service is null");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
mServiceLock.writeLock().lock();
|
|
||||||
mService = managerService.registerAdapter(mManagerCallback);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
} finally {
|
|
||||||
mServiceLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
mManagerService = Objects.requireNonNull(managerService);
|
mManagerService = Objects.requireNonNull(managerService);
|
||||||
mAttributionSource = Objects.requireNonNull(attributionSource);
|
mAttributionSource = Objects.requireNonNull(attributionSource);
|
||||||
|
synchronized (mServiceLock.writeLock()) {
|
||||||
|
mService = getBluetoothService(mManagerCallback);
|
||||||
|
}
|
||||||
mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
|
mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
|
||||||
mToken = new Binder(DESCRIPTOR);
|
mToken = new Binder(DESCRIPTOR);
|
||||||
}
|
}
|
||||||
@@ -3162,21 +3168,16 @@ public final class BluetoothAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("AndroidFrameworkBluetoothPermission")
|
private static final IBluetoothManagerCallback sManagerCallback =
|
||||||
private final IBluetoothManagerCallback mManagerCallback =
|
|
||||||
new IBluetoothManagerCallback.Stub() {
|
new IBluetoothManagerCallback.Stub() {
|
||||||
@SuppressLint("AndroidFrameworkRequiresPermission")
|
|
||||||
public void onBluetoothServiceUp(IBluetooth bluetoothService) {
|
public void onBluetoothServiceUp(IBluetooth bluetoothService) {
|
||||||
if (DBG) {
|
if (DBG) {
|
||||||
Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
|
Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
|
||||||
}
|
}
|
||||||
|
|
||||||
mServiceLock.writeLock().lock();
|
synchronized (sServiceLock) {
|
||||||
mService = bluetoothService;
|
sService = bluetoothService;
|
||||||
mServiceLock.writeLock().unlock();
|
for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
|
||||||
|
|
||||||
synchronized (mProxyServiceStateCallbacks) {
|
|
||||||
for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) {
|
|
||||||
try {
|
try {
|
||||||
if (cb != null) {
|
if (cb != null) {
|
||||||
cb.onBluetoothServiceUp(bluetoothService);
|
cb.onBluetoothServiceUp(bluetoothService);
|
||||||
@@ -3188,6 +3189,56 @@ public final class BluetoothAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onBluetoothServiceDown() {
|
||||||
|
if (DBG) {
|
||||||
|
Log.d(TAG, "onBluetoothServiceDown");
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (sServiceLock) {
|
||||||
|
sService = null;
|
||||||
|
for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
|
||||||
|
try {
|
||||||
|
if (cb != null) {
|
||||||
|
cb.onBluetoothServiceDown();
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "onBluetoothServiceDown: cb is null!");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onBrEdrDown() {
|
||||||
|
if (VDBG) {
|
||||||
|
Log.i(TAG, "onBrEdrDown");
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (sServiceLock) {
|
||||||
|
for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
|
||||||
|
try {
|
||||||
|
if (cb != null) {
|
||||||
|
cb.onBrEdrDown();
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "onBrEdrDown: cb is null!");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final IBluetoothManagerCallback mManagerCallback =
|
||||||
|
new IBluetoothManagerCallback.Stub() {
|
||||||
|
public void onBluetoothServiceUp(IBluetooth bluetoothService) {
|
||||||
|
synchronized (mServiceLock.writeLock()) {
|
||||||
|
mService = bluetoothService;
|
||||||
|
}
|
||||||
synchronized (mMetadataListeners) {
|
synchronized (mMetadataListeners) {
|
||||||
mMetadataListeners.forEach((device, pair) -> {
|
mMetadataListeners.forEach((device, pair) -> {
|
||||||
try {
|
try {
|
||||||
@@ -3212,12 +3263,7 @@ public final class BluetoothAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onBluetoothServiceDown() {
|
public void onBluetoothServiceDown() {
|
||||||
if (DBG) {
|
synchronized (mServiceLock.writeLock()) {
|
||||||
Log.d(TAG, "onBluetoothServiceDown: " + mService);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
mServiceLock.writeLock().lock();
|
|
||||||
mService = null;
|
mService = null;
|
||||||
if (mLeScanClients != null) {
|
if (mLeScanClients != null) {
|
||||||
mLeScanClients.clear();
|
mLeScanClients.clear();
|
||||||
@@ -3228,29 +3274,10 @@ public final class BluetoothAdapter {
|
|||||||
if (mBluetoothLeScanner != null) {
|
if (mBluetoothLeScanner != null) {
|
||||||
mBluetoothLeScanner.cleanup();
|
mBluetoothLeScanner.cleanup();
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
mServiceLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronized (mProxyServiceStateCallbacks) {
|
|
||||||
for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) {
|
|
||||||
try {
|
|
||||||
if (cb != null) {
|
|
||||||
cb.onBluetoothServiceDown();
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "onBluetoothServiceDown: cb is null!");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBrEdrDown() {
|
public void onBrEdrDown() {
|
||||||
if (VDBG) {
|
|
||||||
Log.i(TAG, "onBrEdrDown: " + mService);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3485,15 +3512,12 @@ public final class BluetoothAdapter {
|
|||||||
|
|
||||||
protected void finalize() throws Throwable {
|
protected void finalize() throws Throwable {
|
||||||
try {
|
try {
|
||||||
mManagerService.unregisterAdapter(mManagerCallback);
|
removeServiceStateCallback(mManagerCallback);
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
} finally {
|
} finally {
|
||||||
super.finalize();
|
super.finalize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
|
* Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
|
||||||
* <p>Alphabetic characters must be uppercase to be valid.
|
* <p>Alphabetic characters must be uppercase to be valid.
|
||||||
@@ -3557,24 +3581,64 @@ public final class BluetoothAdapter {
|
|||||||
return mAttributionSource;
|
return mAttributionSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks =
|
@GuardedBy("sServiceLock")
|
||||||
new ArrayList<IBluetoothManagerCallback>();
|
private static final WeakHashMap<IBluetoothManagerCallback, Void> sProxyServiceStateCallbacks =
|
||||||
|
new WeakHashMap<>();
|
||||||
|
|
||||||
|
/*package*/ IBluetooth getBluetoothService() {
|
||||||
|
synchronized (sServiceLock) {
|
||||||
|
if (sProxyServiceStateCallbacks.isEmpty()) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Anonymous service access requires at least one lifecycle in process");
|
||||||
|
}
|
||||||
|
return sService;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
/*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
|
/*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
|
||||||
synchronized (mProxyServiceStateCallbacks) {
|
Objects.requireNonNull(cb);
|
||||||
if (cb == null) {
|
synchronized (sServiceLock) {
|
||||||
Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
|
sProxyServiceStateCallbacks.put(cb, null);
|
||||||
} else if (!mProxyServiceStateCallbacks.contains(cb)) {
|
registerOrUnregisterAdapterLocked();
|
||||||
mProxyServiceStateCallbacks.add(cb);
|
return sService;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return mService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
|
/*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
|
||||||
synchronized (mProxyServiceStateCallbacks) {
|
Objects.requireNonNull(cb);
|
||||||
mProxyServiceStateCallbacks.remove(cb);
|
synchronized (sServiceLock) {
|
||||||
|
sProxyServiceStateCallbacks.remove(cb);
|
||||||
|
registerOrUnregisterAdapterLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle registering (or unregistering) a single process-wide
|
||||||
|
* {@link IBluetoothManagerCallback} based on the presence of local
|
||||||
|
* {@link #sProxyServiceStateCallbacks} clients.
|
||||||
|
*/
|
||||||
|
@GuardedBy("sServiceLock")
|
||||||
|
private void registerOrUnregisterAdapterLocked() {
|
||||||
|
final boolean isRegistered = sServiceRegistered;
|
||||||
|
final boolean wantRegistered = !sProxyServiceStateCallbacks.isEmpty();
|
||||||
|
|
||||||
|
if (isRegistered != wantRegistered) {
|
||||||
|
if (wantRegistered) {
|
||||||
|
try {
|
||||||
|
sService = mManagerService.registerAdapter(sManagerCallback);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
mManagerService.unregisterAdapter(sManagerCallback);
|
||||||
|
sService = null;
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sServiceRegistered = wantRegistered;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -399,7 +399,7 @@ public final class BluetoothSocket implements Closeable {
|
|||||||
try {
|
try {
|
||||||
if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
|
if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
|
||||||
IBluetooth bluetoothProxy =
|
IBluetooth bluetoothProxy =
|
||||||
BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
|
BluetoothAdapter.getDefaultAdapter().getBluetoothService();
|
||||||
if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
|
if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
|
||||||
mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
|
mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
|
||||||
mUuid, mPort, getSecurityFlags());
|
mUuid, mPort, getSecurityFlags());
|
||||||
@@ -438,7 +438,7 @@ public final class BluetoothSocket implements Closeable {
|
|||||||
/*package*/ int bindListen() {
|
/*package*/ int bindListen() {
|
||||||
int ret;
|
int ret;
|
||||||
if (mSocketState == SocketState.CLOSED) return EBADFD;
|
if (mSocketState == SocketState.CLOSED) return EBADFD;
|
||||||
IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
|
IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
|
||||||
if (bluetoothProxy == null) {
|
if (bluetoothProxy == null) {
|
||||||
Log.e(TAG, "bindListen fail, reason: bluetooth is off");
|
Log.e(TAG, "bindListen fail, reason: bluetooth is off");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -706,7 +706,7 @@ public final class BluetoothSocket implements Closeable {
|
|||||||
throw new IOException("socket closed");
|
throw new IOException("socket closed");
|
||||||
}
|
}
|
||||||
IBluetooth bluetoothProxy =
|
IBluetooth bluetoothProxy =
|
||||||
BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
|
BluetoothAdapter.getDefaultAdapter().getBluetoothService();
|
||||||
if (bluetoothProxy == null) {
|
if (bluetoothProxy == null) {
|
||||||
throw new IOException("Bluetooth is off");
|
throw new IOException("Bluetooth is off");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user