Merge "Register IBluetoothManagerCallback per-process." into sc-dev
This commit is contained in:
@@ -64,6 +64,8 @@ import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -78,6 +80,7 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
@@ -715,10 +718,21 @@ public final class BluetoothAdapter {
|
||||
private final IBluetoothManager mManagerService;
|
||||
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
|
||||
@GuardedBy("mServiceLock")
|
||||
private IBluetooth mService;
|
||||
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 Map<LeScanCallback, ScanCallback> mLeScanClients;
|
||||
private final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
|
||||
@@ -792,19 +806,11 @@ public final class BluetoothAdapter {
|
||||
* Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
|
||||
*/
|
||||
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);
|
||||
mAttributionSource = Objects.requireNonNull(attributionSource);
|
||||
synchronized (mServiceLock.writeLock()) {
|
||||
mService = getBluetoothService(mManagerCallback);
|
||||
}
|
||||
mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
|
||||
mToken = new Binder(DESCRIPTOR);
|
||||
}
|
||||
@@ -3154,21 +3160,16 @@ public final class BluetoothAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("AndroidFrameworkBluetoothPermission")
|
||||
private final IBluetoothManagerCallback mManagerCallback =
|
||||
private static final IBluetoothManagerCallback sManagerCallback =
|
||||
new IBluetoothManagerCallback.Stub() {
|
||||
@SuppressLint("AndroidFrameworkRequiresPermission")
|
||||
public void onBluetoothServiceUp(IBluetooth bluetoothService) {
|
||||
if (DBG) {
|
||||
Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
|
||||
}
|
||||
|
||||
mServiceLock.writeLock().lock();
|
||||
mService = bluetoothService;
|
||||
mServiceLock.writeLock().unlock();
|
||||
|
||||
synchronized (mProxyServiceStateCallbacks) {
|
||||
for (IBluetoothManagerCallback cb : mProxyServiceStateCallbacks) {
|
||||
synchronized (sServiceLock) {
|
||||
sService = bluetoothService;
|
||||
for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
|
||||
try {
|
||||
if (cb != null) {
|
||||
cb.onBluetoothServiceUp(bluetoothService);
|
||||
@@ -3180,6 +3181,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) {
|
||||
mMetadataListeners.forEach((device, pair) -> {
|
||||
try {
|
||||
@@ -3204,12 +3255,7 @@ public final class BluetoothAdapter {
|
||||
}
|
||||
|
||||
public void onBluetoothServiceDown() {
|
||||
if (DBG) {
|
||||
Log.d(TAG, "onBluetoothServiceDown: " + mService);
|
||||
}
|
||||
|
||||
try {
|
||||
mServiceLock.writeLock().lock();
|
||||
synchronized (mServiceLock.writeLock()) {
|
||||
mService = null;
|
||||
if (mLeScanClients != null) {
|
||||
mLeScanClients.clear();
|
||||
@@ -3220,29 +3266,10 @@ public final class BluetoothAdapter {
|
||||
if (mBluetoothLeScanner != null) {
|
||||
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() {
|
||||
if (VDBG) {
|
||||
Log.i(TAG, "onBrEdrDown: " + mService);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3477,15 +3504,12 @@ public final class BluetoothAdapter {
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
try {
|
||||
mManagerService.unregisterAdapter(mManagerCallback);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "", e);
|
||||
removeServiceStateCallback(mManagerCallback);
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
|
||||
* <p>Alphabetic characters must be uppercase to be valid.
|
||||
@@ -3549,24 +3573,64 @@ public final class BluetoothAdapter {
|
||||
return mAttributionSource;
|
||||
}
|
||||
|
||||
private final ArrayList<IBluetoothManagerCallback> mProxyServiceStateCallbacks =
|
||||
new ArrayList<IBluetoothManagerCallback>();
|
||||
@GuardedBy("sServiceLock")
|
||||
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
|
||||
/*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
|
||||
synchronized (mProxyServiceStateCallbacks) {
|
||||
if (cb == null) {
|
||||
Log.w(TAG, "getBluetoothService() called with no BluetoothManagerCallback");
|
||||
} else if (!mProxyServiceStateCallbacks.contains(cb)) {
|
||||
mProxyServiceStateCallbacks.add(cb);
|
||||
}
|
||||
Objects.requireNonNull(cb);
|
||||
synchronized (sServiceLock) {
|
||||
sProxyServiceStateCallbacks.put(cb, null);
|
||||
registerOrUnregisterAdapterLocked();
|
||||
return sService;
|
||||
}
|
||||
return mService;
|
||||
}
|
||||
|
||||
/*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
|
||||
synchronized (mProxyServiceStateCallbacks) {
|
||||
mProxyServiceStateCallbacks.remove(cb);
|
||||
Objects.requireNonNull(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 {
|
||||
if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
|
||||
IBluetooth bluetoothProxy =
|
||||
BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
|
||||
BluetoothAdapter.getDefaultAdapter().getBluetoothService();
|
||||
if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
|
||||
mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
|
||||
mUuid, mPort, getSecurityFlags());
|
||||
@@ -438,7 +438,7 @@ public final class BluetoothSocket implements Closeable {
|
||||
/*package*/ int bindListen() {
|
||||
int ret;
|
||||
if (mSocketState == SocketState.CLOSED) return EBADFD;
|
||||
IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
|
||||
IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
|
||||
if (bluetoothProxy == null) {
|
||||
Log.e(TAG, "bindListen fail, reason: bluetooth is off");
|
||||
return -1;
|
||||
@@ -706,7 +706,7 @@ public final class BluetoothSocket implements Closeable {
|
||||
throw new IOException("socket closed");
|
||||
}
|
||||
IBluetooth bluetoothProxy =
|
||||
BluetoothAdapter.getDefaultAdapter().getBluetoothService(null);
|
||||
BluetoothAdapter.getDefaultAdapter().getBluetoothService();
|
||||
if (bluetoothProxy == null) {
|
||||
throw new IOException("Bluetooth is off");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user