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

Commit 6919c2d7 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 8656240 from 634fb41d to tm-release

Change-Id: Ief45e6dd7f8bbefceb810ed4d97603d6693539cb
parents 987cb2d1 634fb41d
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -519,12 +519,9 @@
                <action android:name="android.bluetooth.IBluetoothPbapClient"/>
            </intent-filter>
        </service>
        <!--  Note: This service doesn't get started, it just indicates to the Authentication
              framework that we can create accounts of a specific type. As such, its safe to
              have as enabled on all targets and not just the ones that use PBAP Client  -->
        <service android:process="@string/process"
             android:name="com.android.bluetooth.pbapclient.AuthenticationService"
             android:enabled="true"
             android:enabled="false"
             android:exported="true">
            <intent-filter>
                <action android:name="android.accounts.AccountAuthenticator"/>
+45 −6
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.internal.annotations.VisibleForTesting;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -68,6 +69,7 @@ public class BassClientService extends ProfileService {

    private final Map<BluetoothDevice, BassClientStateMachine> mStateMachines = new HashMap<>();
    private final Object mSearchScanCallbackLock = new Object();
    private final Map<Integer, ScanResult> mScanBroadcasts = new HashMap<>();

    private HandlerThread mStateMachinesThread;
    private HandlerThread mCallbackHandlerThread;
@@ -325,8 +327,16 @@ public class BassClientService extends ProfileService {
    }

    private boolean hasRoomForBroadcastSourceAddition(BluetoothDevice device) {
        List<BluetoothLeBroadcastReceiveState> currentAllSources = getAllSources(device);
        return currentAllSources.size() < getMaximumSourceCapacity(device);
        boolean isRoomAvailable = false;
        String emptyBluetoothDevice = "00:00:00:00:00:00";
        for (BluetoothLeBroadcastReceiveState recvState: getAllSources(device)) {
            if (recvState.getSourceDevice().getAddress().equals(emptyBluetoothDevice)) {
                isRoomAvailable = true;
                break;
            }
        }
        log("isRoomAvailable: " + isRoomAvailable);
        return isRoomAvailable;
    }

    private BassClientStateMachine getOrCreateStateMachine(BluetoothDevice device) {
@@ -632,16 +642,29 @@ public class BassClientService extends ProfileService {
                            BassConstants.BAAS_UUID)) {
                        return;
                    }
                    Message msg = mBassUtils.getAutoAssistScanHandler()
                            .obtainMessage(BassConstants.AA_SCAN_SUCCESS);
                    msg.obj = result;
                    mBassUtils.getAutoAssistScanHandler().sendMessage(msg);
                    log( "Broadcast Source Found:" + result.getDevice());
                    byte[] broadcastIdArray = listOfUuids.get(BassConstants.BAAS_UUID);
                    int broadcastId = (int)(((broadcastIdArray[2] & 0xff) << 16)
                            | ((broadcastIdArray[1] & 0xff) << 8)
                            | (broadcastIdArray[0] & 0xff));
                    if (mScanBroadcasts.get(broadcastId) == null) {
                        log("selectBroadcastSource: broadcastId " + broadcastId);
                        mScanBroadcasts.put(broadcastId, result);
                        synchronized (mStateMachines) {
                            for (BassClientStateMachine sm : mStateMachines.values()) {
                                if (sm.isConnected()) {
                                    selectSource(sm.getDevice(), result, false);
                                }
                            }
                        }
                    }
                }

                public void onScanFailed(int errorCode) {
                    Log.e(TAG, "Scan Failure:" + errorCode);
                }
            };
            mScanBroadcasts.clear();
            ScanSettings settings = new ScanSettings.Builder().setCallbackType(
                    ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
                    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
@@ -687,6 +710,7 @@ public class BassClientService extends ProfileService {
            scanner.stopScan(mSearchScanCallback);
            mSearchScanCallback = null;
            mCallbacks.notifySearchStopped(BluetoothStatusCodes.REASON_LOCAL_APP_REQUEST);
            mScanBroadcasts.clear();
        }
    }

@@ -792,6 +816,7 @@ public class BassClientService extends ProfileService {
        }
        Message message = stateMachine.obtainMessage(BassClientStateMachine.UPDATE_BCAST_SOURCE);
        message.arg1 = sourceId;
        message.arg2 = BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_INVALID;
        message.obj = updatedMetadata;
        stateMachine.sendMessage(message);
    }
@@ -820,6 +845,20 @@ public class BassClientService extends ProfileService {
                    BluetoothStatusCodes.ERROR_REMOTE_LINK_ERROR);
            return;
        }
        BluetoothLeBroadcastReceiveState recvState =
                stateMachine.getBroadcastReceiveStateForSourceId(sourceId);
        BluetoothLeBroadcastMetadata metaData =
                stateMachine.getCurrentBroadcastMetadata(sourceId);
        if (metaData != null && recvState != null && recvState.getPaSyncState() ==
                BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED) {
            log("Force source to lost PA sync");
            Message message = stateMachine.obtainMessage(
                    BassClientStateMachine.UPDATE_BCAST_SOURCE);
            message.arg1 = sourceId;
            message.arg2 = BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_IDLE;
            message.obj = metaData;
            stateMachine.sendMessage(message);
        }
        Message message = stateMachine.obtainMessage(BassClientStateMachine.REMOVE_BCAST_SOURCE);
        message.arg1 = sourceId;
        stateMachine.sendMessage(message);
+36 −12
Original line number Diff line number Diff line
@@ -436,11 +436,13 @@ public class BassClientStateMachine extends StateMachine {
                channel.setSelected(false);
                subGroup.addChannel(channel.build());
            }
            subGroup.setCodecId((long)(baseLevel2.codecId[4] << 32
                    | baseLevel2.codecId[3] << 24
                    | baseLevel2.codecId[2] << 16
                    | baseLevel2.codecId[1] << 8
                    | baseLevel2.codecId[0]));
            byte[] arrayCodecId = baseLevel2.codecId;
            long codeId = (long) ((arrayCodecId[4] & 0xff) << 32
                    | (arrayCodecId[3] & 0xff) << 24
                    | (arrayCodecId[2] & 0xff) << 16
                    | (arrayCodecId[1] & 0xff) << 8
                    | (arrayCodecId[0] & 0xff));
            subGroup.setCodecId(codeId);
            subGroup.setCodecSpecificConfig(BluetoothLeAudioCodecConfigMetadata.
                    fromRawBytes(baseLevel2.codecConfigInfo));
            subGroup.setContentMetadata(BluetoothLeAudioContentMetadata.
@@ -448,6 +450,18 @@ public class BassClientStateMachine extends StateMachine {
            metaData.addSubgroup(subGroup.build());
        }
        metaData.setSourceDevice(device, device.getAddressType());
        byte[] arrayPresentationDelay = baseData.getLevelOne().presentationDelay;
        int presentationDelay = (int) ((arrayPresentationDelay[2] & 0xff) << 16
                | (arrayPresentationDelay[1] & 0xff)
                | (arrayPresentationDelay[0] & 0xff));
        metaData.setPresentationDelayMicros(presentationDelay);
        PeriodicAdvertisementResult result =
                mService.getPeriodicAdvertisementResult(device);
        if (result != null) {
            int broadcastId = result.getBroadcastId();
            log("broadcast ID: " + broadcastId);
            metaData.setBroadcastId(broadcastId);
        }
        return metaData.build();
    }

@@ -638,6 +652,7 @@ public class BassClientStateMachine extends StateMachine {
            byte metaDataSyncState = receiverState[BassConstants.BCAST_RCVR_STATE_PA_SYNC_IDX];
            byte encryptionStatus = receiverState[BassConstants.BCAST_RCVR_STATE_ENC_STATUS_IDX];
            byte[] badBroadcastCode = null;
            int badBroadcastCodeLen = 0;
            if (encryptionStatus
                    == BluetoothLeBroadcastReceiveState.BIG_ENCRYPTION_STATE_BAD_CODE) {
                badBroadcastCode = new byte[BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE];
@@ -648,11 +663,12 @@ public class BassClientStateMachine extends StateMachine {
                        0,
                        BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE);
                badBroadcastCode = reverseBytes(badBroadcastCode);
                badBroadcastCodeLen = BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE;
            }
            byte numSubGroups = receiverState[BassConstants.BCAST_RCVR_STATE_BADCODE_START_IDX
                    + BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE];
                    + badBroadcastCodeLen];
            int offset = BassConstants.BCAST_RCVR_STATE_BADCODE_START_IDX
                    + BassConstants.BCAST_RCVR_STATE_BADCODE_SIZE + 1;
                    + badBroadcastCodeLen + 1;
            ArrayList<BluetoothLeAudioContentMetadata> metadataList =
                    new ArrayList<BluetoothLeAudioContentMetadata>();
            ArrayList<Long> audioSyncState = new ArrayList<Long>();
@@ -664,7 +680,7 @@ public class BassClientStateMachine extends StateMachine {
                log("BIS index byte array: ");
                BassUtils.printByteArray(audioSyncIndex);
                ByteBuffer wrapped = ByteBuffer.wrap(reverseBytes(audioSyncIndex));
                audioSyncState.add(wrapped.getLong());
                audioSyncState.add((long) wrapped.getInt());

                byte metaDataLength = receiverState[offset++];
                if (metaDataLength > 0) {
@@ -1255,7 +1271,7 @@ public class BassClientStateMachine extends StateMachine {
    }

    private byte[] convertBroadcastMetadataToUpdateSourceByteArray(int sourceId,
            BluetoothLeBroadcastMetadata metaData) {
            BluetoothLeBroadcastMetadata metaData, int paSync) {
        BluetoothLeBroadcastReceiveState existingState =
                getBroadcastReceiveStateForSourceId(sourceId);
        if (existingState == null) {
@@ -1287,7 +1303,9 @@ public class BassClientStateMachine extends StateMachine {
        // Source_ID
        res[offset++] = (byte) sourceId;
        // PA_Sync
        if (existingState.getPaSyncState()
        if (paSync != BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_INVALID) {
            res[offset++] = (byte) paSync;
        } else if (existingState.getPaSyncState()
                == BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_SYNCHRONIZED) {
            res[offset++] = (byte) (0x01);
        } else {
@@ -1299,7 +1317,12 @@ public class BassClientStateMachine extends StateMachine {
        // Num_Subgroups
        res[offset++] = numSubGroups;
        for (int i = 0; i < numSubGroups; i++) {
            int bisIndexValue = existingState.getBisSyncState().get(i).intValue();
            int bisIndexValue;
            if (paSync != BluetoothLeBroadcastReceiveState.PA_SYNC_STATE_INVALID) {
                bisIndexValue = 0;
            } else {
                bisIndexValue = existingState.getBisSyncState().get(i).intValue();
            }
            log("UPDATE_BCAST_SOURCE: bisIndexValue : " + bisIndexValue);
            // BIS_Sync
            res[offset++] = (byte) (bisIndexValue & 0x00000000000000FF);
@@ -1497,9 +1520,10 @@ public class BassClientStateMachine extends StateMachine {
                case UPDATE_BCAST_SOURCE:
                    metaData = (BluetoothLeBroadcastMetadata) message.obj;
                    int sourceId = message.arg1;
                    int paSync = message.arg2;
                    log("Updating Broadcast source" + metaData);
                    byte[] updateSourceInfo = convertBroadcastMetadataToUpdateSourceByteArray(
                            sourceId, metaData);
                            sourceId, metaData, paSync);
                    if (updateSourceInfo == null) {
                        Log.e(TAG, "update source: source Info is NULL");
                        break;
+86 −3
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.provider.CallLog;
import android.sysprop.BluetoothProperties;
import android.util.Log;
@@ -60,6 +61,12 @@ public class PbapClientService extends ProfileService {
    private static final String TAG = "PbapClientService";
    private static final String SERVICE_NAME = "Phonebook Access PCE";

    /**
     * The component names for the owned authenticator service
     */
    private static final String AUTHENTICATOR_SERVICE =
            AuthenticationService.class.getCanonicalName();

    // MAXIMUM_DEVICES set to 10 to prevent an excessive number of simultaneous devices.
    private static final int MAXIMUM_DEVICES = 10;
    private Map<BluetoothDevice, PbapClientStateMachine> mPbapClientStateMachineMap =
@@ -70,6 +77,40 @@ public class PbapClientService extends ProfileService {

    private DatabaseManager mDatabaseManager;

    /**
     * There's an ~1-2 second latency between when our Authentication service is set as available to
     * the system and when the Authentication/Account framework code will recognize it and allow us
     * to alter accounts. In lieu of the Accounts team dealing with this race condition, we're going
     * to periodically poll over 3 seconds until our accounts are visible, remove old accounts, and
     * then notify device state machines that they can create accounts and download contacts.
     */
    // TODO(233361365): Remove this pattern when the framework solves their race condition
    private static final int ACCOUNT_VISIBILITY_CHECK_MS = 500;
    private static final int ACCOUNT_VISIBILITY_CHECK_TRIES_MAX = 6;
    private int mAccountVisibilityCheckTries = 0;
    private final Handler mAuthServiceHandler = new Handler();
    private final Runnable mCheckAuthService = new Runnable() {
        @Override
        public void run() {
            // If our accounts are finally visible to use, clean up old ones and tell devices they
            // can issue downloads if they're ready. Otherwise, wait and try again.
            if (isAuthenticationServiceReady()) {
                Log.i(TAG, "Service ready! Clean up old accounts and try contacts downloads");
                removeUncleanAccounts();
                for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) {
                    stateMachine.tryDownloadIfConnected();
                }
            } else if (mAccountVisibilityCheckTries < ACCOUNT_VISIBILITY_CHECK_TRIES_MAX) {
                mAccountVisibilityCheckTries += 1;
                Log.w(TAG, "AccountManager hasn't registered our service yet. Retry "
                        + mAccountVisibilityCheckTries + "/" + ACCOUNT_VISIBILITY_CHECK_TRIES_MAX);
                mAuthServiceHandler.postDelayed(this, ACCOUNT_VISIBILITY_CHECK_MS);
            } else {
                Log.e(TAG, "Failed to register Authenication Service and get account visibility");
            }
        }
    };

    public static boolean isEnabled() {
        return BluetoothProperties.isProfilePbapClientEnabled().orElse(false);
    }
@@ -88,6 +129,8 @@ public class PbapClientService extends ProfileService {
        mDatabaseManager = Objects.requireNonNull(AdapterService.getAdapterService().getDatabase(),
                "DatabaseManager cannot be null when PbapClientService starts");

        setComponentAvailable(AUTHENTICATOR_SERVICE, true);

        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        // delay initial download until after the user is unlocked to add an account.
@@ -101,7 +144,7 @@ public class PbapClientService extends ProfileService {
            Log.w(TAG, "Unable to register pbapclient receiver", e);
        }

        removeUncleanAccounts();
        initializeAuthenticationService();
        registerSdpRecord();
        setPbapClientService(this);
        return true;
@@ -119,7 +162,8 @@ public class PbapClientService extends ProfileService {
        for (PbapClientStateMachine pbapClientStateMachine : mPbapClientStateMachineMap.values()) {
            pbapClientStateMachine.doQuit();
        }
        removeUncleanAccounts();
        cleanupAuthenicationService();
        setComponentAvailable(AUTHENTICATOR_SERVICE, false);
        return true;
    }

@@ -133,7 +177,45 @@ public class PbapClientService extends ProfileService {
        }
    }

    /**
     * Periodically check if the account framework has recognized our service and will allow us to
     * interact with our accounts. Notify state machines once our service is ready so we can trigger
     * account downloads.
     */
    private void initializeAuthenticationService() {
        mAuthServiceHandler.postDelayed(mCheckAuthService, ACCOUNT_VISIBILITY_CHECK_MS);
    }

    private void cleanupAuthenicationService() {
        mAuthServiceHandler.removeCallbacks(mCheckAuthService);
        removeUncleanAccounts();
    }

    /**
     * Determine if our account type is visible to us yet. If it is, then our service is ready and
     * our account type is ready to use.
     *
     * Make a placeholder device account and determine our visibility relative to it. Note that this
     * function uses the same restrictions are the other add and remove functions, but is *also*
     * available to all system apps instead of throwing a runtime SecurityException.
     */
    protected boolean isAuthenticationServiceReady() {
        Account account = new Account("00:00:00:00:00:00", getString(R.string.pbap_account_type));
        AccountManager accountManager = AccountManager.get(this);
        int visibility = accountManager.getAccountVisibility(account, getPackageName());
        if (DBG) {
            Log.d(TAG, "Checking visibility, visibility=" + visibility);
        }
        return visibility == AccountManager.VISIBILITY_VISIBLE
                || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE;
    }

    private void removeUncleanAccounts() {
        if (!isAuthenticationServiceReady()) {
            Log.w(TAG, "Can't remove accounts. AccountManager hasn't registered our service yet.");
            return;
        }

        // Find all accounts that match the type "pbap" and delete them.
        AccountManager accountManager = AccountManager.get(this);
        Account[] accounts =
@@ -208,7 +290,7 @@ public class PbapClientService extends ProfileService {
                }
            } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
                for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) {
                    stateMachine.resumeDownload();
                    stateMachine.tryDownloadIfConnected();
                }
            } else if (action.equals(BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED)) {
                // PbapClientConnectionHandler has code to remove calllogs when PBAP disconnects.
@@ -542,6 +624,7 @@ public class PbapClientService extends ProfileService {
    @Override
    public void dump(StringBuilder sb) {
        super.dump(sb);
        ProfileService.println(sb, "isAuthServiceReady: " + isAuthenticationServiceReady());
        for (PbapClientStateMachine stateMachine : mPbapClientStateMachineMap.values()) {
            stateMachine.dump(sb);
        }
+18 −7
Original line number Diff line number Diff line
@@ -301,10 +301,7 @@ final class PbapClientStateMachine extends StateMachine {
            onConnectionStateChanged(mCurrentDevice, mMostRecentState,
                    BluetoothProfile.STATE_CONNECTED);
            mMostRecentState = BluetoothProfile.STATE_CONNECTED;
            if (mUserManager.isUserUnlocked()) {
                mConnectionHandler.obtainMessage(PbapClientConnectionHandler.MSG_DOWNLOAD)
                        .sendToTarget();
            }
            downloadIfReady();
        }

        @Override
@@ -321,8 +318,7 @@ final class PbapClientStateMachine extends StateMachine {
                    break;

                case MSG_RESUME_DOWNLOAD:
                    mConnectionHandler.obtainMessage(PbapClientConnectionHandler.MSG_DOWNLOAD)
                            .sendToTarget();
                    downloadIfReady();
                    break;

                default:
@@ -333,6 +329,21 @@ final class PbapClientStateMachine extends StateMachine {
        }
    }

    /**
     * Trigger a contacts download if the user is unlocked and our accounts are available to us
     */
    private void downloadIfReady() {
        boolean userReady = mUserManager.isUserUnlocked();
        boolean accountServiceReady = mService.isAuthenticationServiceReady();
        if (!userReady || !accountServiceReady) {
            Log.w(TAG, "Cannot download contacts yet, userReady=" + userReady
                    + ", accountServiceReady=" + accountServiceReady);
            return;
        }
        mConnectionHandler.obtainMessage(PbapClientConnectionHandler.MSG_DOWNLOAD)
                .sendToTarget();
    }

    private void onConnectionStateChanged(BluetoothDevice device, int prevState, int state) {
        if (device == null) {
            Log.w(TAG, "onConnectionStateChanged with invalid device");
@@ -357,7 +368,7 @@ final class PbapClientStateMachine extends StateMachine {
        sendMessage(MSG_DISCONNECT, device);
    }

    public void resumeDownload() {
    public void tryDownloadIfConnected() {
        sendMessage(MSG_RESUME_DOWNLOAD);
    }

Loading