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

Commit 85bc9c76 authored by Sal Savage's avatar Sal Savage Committed by Automerger Merge Worker
Browse files

Merge "Block contact download until we can use accounts" into tm-dev am: 94f088cd am: d7ef43af

parents eac5b99e d7ef43af
Loading
Loading
Loading
Loading
+1 −4
Original line number Original line Diff line number Diff line
@@ -519,12 +519,9 @@
                <action android:name="android.bluetooth.IBluetoothPbapClient"/>
                <action android:name="android.bluetooth.IBluetoothPbapClient"/>
            </intent-filter>
            </intent-filter>
        </service>
        </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"
        <service android:process="@string/process"
             android:name="com.android.bluetooth.pbapclient.AuthenticationService"
             android:name="com.android.bluetooth.pbapclient.AuthenticationService"
             android:enabled="true"
             android:enabled="false"
             android:exported="true">
             android:exported="true">
            <intent-filter>
            <intent-filter>
                <action android:name="android.accounts.AccountAuthenticator"/>
                <action android:name="android.accounts.AccountAuthenticator"/>
+86 −3
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter;
import android.os.Handler;
import android.provider.CallLog;
import android.provider.CallLog;
import android.sysprop.BluetoothProperties;
import android.sysprop.BluetoothProperties;
import android.util.Log;
import android.util.Log;
@@ -60,6 +61,12 @@ public class PbapClientService extends ProfileService {
    private static final String TAG = "PbapClientService";
    private static final String TAG = "PbapClientService";
    private static final String SERVICE_NAME = "Phonebook Access PCE";
    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.
    // MAXIMUM_DEVICES set to 10 to prevent an excessive number of simultaneous devices.
    private static final int MAXIMUM_DEVICES = 10;
    private static final int MAXIMUM_DEVICES = 10;
    private Map<BluetoothDevice, PbapClientStateMachine> mPbapClientStateMachineMap =
    private Map<BluetoothDevice, PbapClientStateMachine> mPbapClientStateMachineMap =
@@ -70,6 +77,40 @@ public class PbapClientService extends ProfileService {


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


        setComponentAvailable(AUTHENTICATOR_SERVICE, true);

        IntentFilter filter = new IntentFilter();
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        // delay initial download until after the user is unlocked to add an account.
        // 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);
            Log.w(TAG, "Unable to register pbapclient receiver", e);
        }
        }


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


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


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


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


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