Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e51953b5 authored by xiaowang's avatar xiaowang
Browse files

Add support for encrypted non-collocated source

Bug: 243013264
Test: bluetooth_test_gd_unit, manual
Change-Id: Ia71383b8fc58dec61e69f6e4e517d28447f652fd
parent 75e7181e
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -190,7 +190,7 @@ static jmethodID method_onSyncLost;
static jmethodID method_onSyncReport;
static jmethodID method_onSyncStarted;
static jmethodID method_onSyncTransferredCallback;

static jmethodID method_onBigInfoReport;
/**
 * Distance Measurement callback methods
 */
@@ -1157,6 +1157,19 @@ class JniScanningCallbacks : ScanningCallbacks {
                                 method_onSyncTransferredCallback, pa_source,
                                 status, addr.get());
  }

  void OnBigInfoReport(uint16_t sync_handle, bool encrypted) {
        std::shared_lock<std::shared_mutex> lock(callbacks_mutex);
    CallbackEnv sCallbackEnv(__func__);
    if (!sCallbackEnv.valid()) return;

    if (!mPeriodicScanCallbacksObj) {
      ALOGE("mPeriodicScanCallbacksObj is NULL. Return.");
      return;
    }
    sCallbackEnv->CallVoidMethod(mPeriodicScanCallbacksObj,
                                 method_onBigInfoReport, sync_handle, encrypted);
  }
};

class JniDistanceMeasurementCallbacks : DistanceMeasurementCallbacks {
@@ -2511,6 +2524,7 @@ static void periodicScanClassInitNative(JNIEnv* env, jclass clazz) {
  method_onSyncLost = env->GetMethodID(clazz, "onSyncLost", "(I)V");
  method_onSyncTransferredCallback = env->GetMethodID(
      clazz, "onSyncTransferredCallback", "(IILjava/lang/String;)V");
  method_onBigInfoReport = env->GetMethodID(clazz, "onBigInfoReport", "(IZ)V");
}

static void periodicScanInitializeNative(JNIEnv* env, jobject object) {
+41 −8
Original line number Diff line number Diff line
@@ -175,12 +175,13 @@ public class BassClientService extends ProfileService {
        return mPeriodicAdvertisementResultMap.get(device);
    }

    PeriodicAdvertisementResult clearPeriodicAdvertisementResult(BluetoothDevice device) {
        if (mPeriodicAdvertisementResultMap == null) {
            Log.e(TAG, "getPeriodicAdvertisementResult: mPeriodicAdvertisementResultMap is null");
            return null;
    void clearNotifiedFlags() {
        log("clearNotifiedFlags");
        for (PeriodicAdvertisementResult result:
                mPeriodicAdvertisementResultMap.values()) {
            result.setNotified(false);
            result.print();
        }
        return mPeriodicAdvertisementResultMap.remove(device);
    }

    void updateBase(int syncHandlemap, BaseData base) {
@@ -318,6 +319,10 @@ public class BassClientService extends ProfileService {
            mDeviceToSyncHandleMap.clear();
            mDeviceToSyncHandleMap = null;
        }
        if (mPeriodicAdvertisementResultMap != null) {
            mPeriodicAdvertisementResultMap.clear();
            mPeriodicAdvertisementResultMap = null;
        }
        if (mActiveSourceMap != null) {
            mActiveSourceMap.clear();
            mActiveSourceMap = null;
@@ -526,9 +531,17 @@ public class BassClientService extends ProfileService {
    }

    private boolean hasRoomForBroadcastSourceAddition(BluetoothDevice device) {
        BassClientStateMachine stateMachine = null;
        synchronized (mStateMachines) {
            stateMachine = getOrCreateStateMachine(device);
        }
        if (stateMachine == null) {
            log("stateMachine is null");
            return false;
        }
        boolean isRoomAvailable = false;
        String emptyBluetoothDevice = "00:00:00:00:00:00";
        for (BluetoothLeBroadcastReceiveState recvState: getAllSources(device)) {
        for (BluetoothLeBroadcastReceiveState recvState: stateMachine.getAllSources()) {
            if (recvState.getSourceDevice().getAddress().equals(emptyBluetoothDevice)) {
                isRoomAvailable = true;
                break;
@@ -779,7 +792,7 @@ public class BassClientService extends ProfileService {
     * Get a list of all LE Audio Broadcast Sinks connected with the LE Audio Broadcast Assistant.
     * @return list of connected devices
     */
    List<BluetoothDevice> getConnectedDevices() {
    public List<BluetoothDevice> getConnectedDevices() {
        synchronized (mStateMachines) {
            List<BluetoothDevice> devices = new ArrayList<>();
            for (BassClientStateMachine sm : mStateMachines.values()) {
@@ -1079,6 +1092,12 @@ public class BassClientService extends ProfileService {
            Message message = stateMachine.obtainMessage(BassClientStateMachine.ADD_BCAST_SOURCE);
            message.obj = sourceMetadata;
            stateMachine.sendMessage(message);
            if (code != null && code.length != 0) {
                message = stateMachine.obtainMessage(BassClientStateMachine.SET_BCAST_CODE);
                message.obj = sourceMetadata;
                message.arg1 = BassClientStateMachine.ARGTYPE_METADATA;
                stateMachine.sendMessage(message);
            }
        }
    }

@@ -1147,6 +1166,12 @@ public class BassClientService extends ProfileService {
            message.arg2 = BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_INVALID;
            message.obj = updatedMetadata;
            stateMachine.sendMessage(message);
            if (code != null && code.length != 0) {
                message = stateMachine.obtainMessage(BassClientStateMachine.SET_BCAST_CODE);
                message.obj = updatedMetadata;
                message.arg1 = BassClientStateMachine.ARGTYPE_METADATA;
                stateMachine.sendMessage(message);
            }
        }
    }

@@ -1230,7 +1255,15 @@ public class BassClientService extends ProfileService {
                log("stateMachine is null");
                return Collections.emptyList();
            }
            return stateMachine.getAllSources();
            List<BluetoothLeBroadcastReceiveState> recvStates =
                    new ArrayList<BluetoothLeBroadcastReceiveState>();
            for (BluetoothLeBroadcastReceiveState rs: stateMachine.getAllSources()) {
                String emptyBluetoothDevice = "00:00:00:00:00:00";
                if (!rs.getSourceDevice().getAddress().equals(emptyBluetoothDevice)) {
                    recvStates.add(rs);
                }
            }
            return recvStates;
        }
    }

+85 −45
Original line number Diff line number Diff line
@@ -105,6 +105,10 @@ public class BassClientStateMachine extends StateMachine {
    @VisibleForTesting
    private int mConnectTimeoutMs;

    // Type of argument for set broadcast code operation
    static final int ARGTYPE_METADATA = 1;
    static final int ARGTYPE_RCVSTATE = 2;

    /*key is combination of sourceId, Address and advSid for this hashmap*/
    private final Map<Integer, BluetoothLeBroadcastReceiveState>
            mBluetoothLeBroadcastReceiveStates =
@@ -130,7 +134,7 @@ public class BassClientStateMachine extends StateMachine {
    BassClientService mService;
    @VisibleForTesting
    BluetoothGattCharacteristic mBroadcastScanControlPoint;
    private boolean mFirstTimeBisDiscovery = false;
    private final Map<Integer, Boolean> mFirstTimeBisDiscoveryMap;
    private int mPASyncRetryCounter = 0;
    private ScanResult mScanRes = null;
    @VisibleForTesting
@@ -144,7 +148,7 @@ public class BassClientStateMachine extends StateMachine {
    byte mPendingSourceId = -1;
    @VisibleForTesting
    BluetoothLeBroadcastMetadata mPendingMetadata = null;
    private BluetoothLeBroadcastReceiveState mSetBroadcastPINRcvState = null;
    private BluetoothLeBroadcastMetadata mSetBroadcastPINMetadata = null;
    @VisibleForTesting
    boolean mSetBroadcastCodePending = false;
    private final Map<Integer, Boolean> mPendingRemove = new HashMap();
@@ -180,6 +184,7 @@ public class BassClientStateMachine extends StateMachine {
        if (mBluetoothAdapter != null) {
            mPeriodicAdvManager = mBluetoothAdapter.getPeriodicAdvertisingManager();
        }
        mFirstTimeBisDiscoveryMap = new HashMap<Integer, Boolean>();
        long token = Binder.clearCallingIdentity();
        mIsAllowedList = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_BLUETOOTH,
                "persist.vendor.service.bt.wl", true);
@@ -346,7 +351,6 @@ public class BassClientStateMachine extends StateMachine {
            ScanResult scanRes, boolean autoTriggered) {
        log("selectSource: ScanResult " + scanRes);
        mAutoTriggered = autoTriggered;
        mFirstTimeBisDiscovery = true;
        mPASyncRetryCounter = 1;
        // Cache Scan res for Retrys
        mScanRes = scanRes;
@@ -389,7 +393,7 @@ public class BassClientStateMachine extends StateMachine {
    }

    private void cancelActiveSync(BluetoothDevice sourceDev) {
        log("cancelActiveSync");
        log("cancelActiveSync: sourceDev = " + sourceDev);
        BluetoothDevice activeSyncedSrc = mService.getActiveSyncedSource(mDevice);

        /* Stop sync if there is some running */
@@ -401,7 +405,7 @@ public class BassClientStateMachine extends StateMachine {
            } catch (IllegalArgumentException ex) {
                Log.w(TAG, "unregisterSync:IllegalArgumentException");
            }
            mService.clearPeriodicAdvertisementResult(activeSyncedSrc);
            mService.clearNotifiedFlags();
            mService.setActiveSyncedSource(mDevice, null);
            if (!mNoStopScanOffload) {
                // trigger scan stop here
@@ -414,6 +418,11 @@ public class BassClientStateMachine extends StateMachine {

    private BluetoothLeBroadcastMetadata getBroadcastMetadataFromBaseData(BaseData baseData,
            BluetoothDevice device) {
        return getBroadcastMetadataFromBaseData(baseData, device, false);
    }

    private BluetoothLeBroadcastMetadata getBroadcastMetadataFromBaseData(BaseData baseData,
            BluetoothDevice device, boolean encrypted) {
        BluetoothLeBroadcastMetadata.Builder metaData =
                new BluetoothLeBroadcastMetadata.Builder();
        int index = 0;
@@ -458,6 +467,7 @@ public class BassClientStateMachine extends StateMachine {
            metaData.setBroadcastId(broadcastId);
            metaData.setSourceAdvertisingSid(result.getAdvSid());
        }
        metaData.setEncrypted(encrypted);
        return metaData.build();
    }

@@ -490,6 +500,7 @@ public class BassClientStateMachine extends StateMachine {
                        sendMessageDelayed(PSYNC_ACTIVE_TIMEOUT,
                                BassConstants.PSYNC_ACTIVE_TIMEOUT_MS);
                        mService.setActiveSyncedSource(mDevice, device);
                        mFirstTimeBisDiscoveryMap.put(syncHandle, true);
                    } else {
                        log("failed to sync to PA: " + mPASyncRetryCounter);
                        mScanRes = null;
@@ -504,17 +515,11 @@ public class BassClientStateMachine extends StateMachine {
                @Override
                public void onPeriodicAdvertisingReport(PeriodicAdvertisingReport report) {
                    log("onPeriodicAdvertisingReport");
                    Boolean first = mFirstTimeBisDiscoveryMap.get(report.getSyncHandle());
                    // Parse the BIS indices from report's service data
                    if (mFirstTimeBisDiscovery) {
                    if (first != null && first.booleanValue() == true) {
                        parseScanRecord(report.getSyncHandle(), report.getData());
                        BaseData baseData = mService.getBase(report.getSyncHandle());
                        if (baseData != null) {
                            BluetoothLeBroadcastMetadata metaData =
                                    getBroadcastMetadataFromBaseData(baseData,
                                            mService.getDeviceForSyncHandle(report.getSyncHandle()));
                            mService.getCallbacks().notifySourceFound(metaData);
                        }
                        mFirstTimeBisDiscovery = false;
                        mFirstTimeBisDiscoveryMap.put(report.getSyncHandle(), false);
                    }
                }

@@ -524,6 +529,36 @@ public class BassClientStateMachine extends StateMachine {
                    BluetoothDevice srcDevice = mService.getDeviceForSyncHandle(syncHandle);
                    cancelActiveSync(srcDevice);
                }

                @Override
                public void onBigInfoAdvertisingReport(int syncHandle, boolean encrypted) {
                    log("onBIGInfoAdvertisingReport: syncHandle=" + syncHandle +
                            " ,encrypted =" + encrypted);
                    BluetoothDevice srcDevice = mService.getDeviceForSyncHandle(syncHandle);
                    if (srcDevice == null) {
                        log("No device found.");
                        return;
                    }
                    PeriodicAdvertisementResult result =
                            mService.getPeriodicAdvertisementResult(srcDevice);
                    if (result == null) {
                        log("No PA record found");
                        return;
                    }
                    if (!result.isNotified()) {
                        result.setNotified(true);
                        BaseData baseData = mService.getBase(syncHandle);
                        if (baseData == null) {
                            log("No BaseData found");
                            return;
                        }
                        BluetoothLeBroadcastMetadata metaData =
                                getBroadcastMetadataFromBaseData(baseData,
                                        mService.getDeviceForSyncHandle(syncHandle), encrypted);
                        log("Notify broadcast source found");
                        mService.getCallbacks().notifySourceFound(metaData);
                    }
                }
            };

    private void broadcastReceiverState(
@@ -600,18 +635,16 @@ public class BassClientStateMachine extends StateMachine {
                == BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_CODE_REQUIRED
                && mSetBroadcastCodePending) {
            log("Update the Broadcast now");
            if (mSetBroadcastPINMetadata != null) {
                setCurrentBroadcastMetadata(recvState.getSourceId(),
                        mSetBroadcastPINMetadata);
            }
            Message m = obtainMessage(BassClientStateMachine.SET_BCAST_CODE);

            /* Use cached receiver state if previousely didn't finished setting broadcast code or
             * use current receiver state if this is a first check and update
             */
            if (mSetBroadcastPINRcvState != null) {
                m.obj = mSetBroadcastPINRcvState;
            } else {
            m.obj = recvState;
            }

            m.arg1 = ARGTYPE_RCVSTATE;
            sendMessage(m);
            mSetBroadcastCodePending = false;
            mSetBroadcastPINMetadata = null;
        }
    }

@@ -1568,14 +1601,24 @@ public class BassClientStateMachine extends StateMachine {
                    }
                    break;
                case SET_BCAST_CODE:
                    BluetoothLeBroadcastReceiveState recvState =
                            (BluetoothLeBroadcastReceiveState) message.obj;
                    log("SET_BCAST_CODE metaData: " + recvState);
                    if (!isItRightTimeToUpdateBroadcastPin((byte) recvState.getSourceId())) {
                    int argType = message.arg1;
                    mSetBroadcastCodePending = false;
                    BluetoothLeBroadcastReceiveState recvState = null;
                    if (argType == ARGTYPE_METADATA) {
                        mSetBroadcastPINMetadata =
                                (BluetoothLeBroadcastMetadata) message.obj;
                        mSetBroadcastCodePending = true;
                        mSetBroadcastPINRcvState = recvState;
                        log("Ignore SET_BCAST now, but store it for later");
                    } else {
                        recvState = (BluetoothLeBroadcastReceiveState) message.obj;
                        if (!isItRightTimeToUpdateBroadcastPin(
                                (byte) recvState.getSourceId())) {
                            mSetBroadcastCodePending = true;
                        }
                    }
                    if (mSetBroadcastCodePending == true) {
                        log("Ignore SET_BCAST now, but restore it for later");
                        break;
                    }
                    byte[] setBroadcastPINcmd =
                            convertRecvStateToSetBroadcastCodeByteArray(recvState);
                    if (setBroadcastPINcmd == null) {
@@ -1589,9 +1632,6 @@ public class BassClientStateMachine extends StateMachine {
                        mPendingSourceId = (byte) recvState.getSourceId();
                        transitionTo(mConnectedProcessing);
                        sendMessageDelayed(GATT_TXN_TIMEOUT, BassConstants.GATT_TXN_TIMEOUT_MS);
                            mSetBroadcastCodePending = false;
                            mSetBroadcastPINRcvState = null;
                        }
                    }
                    break;
                case REMOVE_BCAST_SOURCE:
+18 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ public class PeriodicAdvertisementResult {
    private int mSyncHandle;
    private int mPAInterval;
    private int mBroadcastId;
    private boolean mIsNotified;

    PeriodicAdvertisementResult(BluetoothDevice device,
                                int addressType,
@@ -44,6 +45,7 @@ public class PeriodicAdvertisementResult {
        mSyncHandle = syncHandle;
        mPAInterval = paInterval;
        mBroadcastId = broadcastId;
        mIsNotified = false;
    }

    /**
@@ -60,6 +62,21 @@ public class PeriodicAdvertisementResult {
        return mSyncHandle;
    }

    /**
     * Get mIsNotified flag
     */
    public boolean isNotified() {
        synchronized (this) {
            return mIsNotified;
        }
    }

    public void setNotified(boolean isNotified) {
        synchronized (this) {
            mIsNotified = isNotified;
        }
    }

    /**
     * Update Adv ID
     */
@@ -127,6 +144,7 @@ public class PeriodicAdvertisementResult {
        log("mSyncHandle:" + mSyncHandle);
        log("mPAInterval:" + mPAInterval);
        log("mBroadcastId:" + mBroadcastId);
        log("mIsNotified: " + mIsNotified);
        log("-- END: PeriodicAdvertisementResult --");
    }

+17 −0
Original line number Diff line number Diff line
@@ -258,6 +258,23 @@ public class PeriodicScanManager {
        }
    }

    void onBigInfoReport(int syncHandle, boolean encrypted)
        throws Exception {
        if (DBG) {
            Log.d(TAG, "onBigInfoReport() - syncHandle=" + syncHandle +
                    " , encrypted=" + encrypted);
        }
        Map<IBinder, SyncInfo> syncMap = findAllSync(syncHandle);
        if (syncMap.isEmpty()) {
            Log.i(TAG, "onBigInfoReport() - no callback found for syncHandle " + syncHandle);
            return;
        }
        for (Map.Entry<IBinder, SyncInfo> e : syncMap.entrySet()) {
            IPeriodicAdvertisingCallback callback = e.getValue().callback;
            callback.onBigInfoAdvertisingReport(syncHandle, encrypted);
        }
    }

    void startSync(ScanResult scanResult, int skip, int timeout,
            IPeriodicAdvertisingCallback callback) {
        SyncDeathRecipient deathRecipient = new SyncDeathRecipient(callback);
Loading