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

Commit 53d598ec authored by weichinweng's avatar weichinweng
Browse files

Use mDatabaseManager when calling database functions

In some corner cases, when the Bluetooth is turning off,
setConnectionPolicy() in each profile could be invoked right after
mAdapterService is set to null.
This patch replaces mAdapterService.getDatabase() to mDatabaseManager
in order to avoid null pointer dereference. It also makes
setConnectionPolicy() to return the correct result.

Bug: 157973675
Test: atest BluetoothInstrumentationTests
Tag: #stability

Change-Id: I422571e63a9f01bc531e2ba21c0b303e92383efb
parent 2532505d
Loading
Loading
Loading
Loading
+18 −13
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -64,6 +65,7 @@ public class A2dpService extends ProfileService {
    private static A2dpService sA2dpService;

    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    private HandlerThread mStateMachinesThread;

    @VisibleForTesting
@@ -108,12 +110,14 @@ public class A2dpService extends ProfileService {
            throw new IllegalStateException("start() called twice");
        }

        // Step 1: Get AdapterService, A2dpNativeInterface, AudioManager.
        // Step 1: Get AdapterService, A2dpNativeInterface, DatabaseManager, AudioManager.
        // None of them can be null.
        mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(),
                "AdapterService cannot be null when A2dpService starts");
        mA2dpNativeInterface = Objects.requireNonNull(A2dpNativeInterface.getInstance(),
                "A2dpNativeInterface cannot be null when A2dpService starts");
        mDatabaseManager = Objects.requireNonNull(mAdapterService.getDatabase(),
                "DatabaseManager cannot be null when A2dpService starts");
        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        Objects.requireNonNull(mAudioManager,
                               "AudioManager cannot be null when A2dpService starts");
@@ -641,16 +645,17 @@ public class A2dpService extends ProfileService {
        if (DBG) {
            Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy);
        }
        boolean setSuccessfully;
        setSuccessfully = mAdapterService.getDatabase()
                .setProfileConnectionPolicy(device, BluetoothProfile.A2DP, connectionPolicy);
        if (setSuccessfully && connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED) {

        if (!mDatabaseManager.setProfileConnectionPolicy(device, BluetoothProfile.A2DP,
                  connectionPolicy)) {
            return false;
        }
        if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
            connect(device);
        } else if (setSuccessfully
                && connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
        } else if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
            disconnect(device);
        }
        return setSuccessfully;
        return true;
    }

    /**
@@ -666,7 +671,7 @@ public class A2dpService extends ProfileService {
     * @hide
     */
    public int getConnectionPolicy(BluetoothDevice device) {
        return mAdapterService.getDatabase()
        return mDatabaseManager
                .getProfileConnectionPolicy(device, BluetoothProfile.A2DP);
    }

@@ -834,14 +839,14 @@ public class A2dpService extends ProfileService {
     */
    public @OptionalCodecsSupportStatus int getSupportsOptionalCodecs(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
        return mAdapterService.getDatabase().getA2dpSupportsOptionalCodecs(device);
        return mDatabaseManager.getA2dpSupportsOptionalCodecs(device);
    }

    public void setSupportsOptionalCodecs(BluetoothDevice device, boolean doesSupport) {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
        int value = doesSupport ? BluetoothA2dp.OPTIONAL_CODECS_SUPPORTED
                : BluetoothA2dp.OPTIONAL_CODECS_NOT_SUPPORTED;
        mAdapterService.getDatabase().setA2dpSupportsOptionalCodecs(device, value);
        mDatabaseManager.setA2dpSupportsOptionalCodecs(device, value);
    }

    /**
@@ -855,7 +860,7 @@ public class A2dpService extends ProfileService {
     */
    public @OptionalCodecsPreferenceStatus int getOptionalCodecsEnabled(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH_ADMIN permission");
        return mAdapterService.getDatabase().getA2dpOptionalCodecsEnabled(device);
        return mDatabaseManager.getA2dpOptionalCodecsEnabled(device);
    }

    /**
@@ -876,7 +881,7 @@ public class A2dpService extends ProfileService {
            Log.w(TAG, "Unexpected value passed to setOptionalCodecsEnabled:" + value);
            return;
        }
        mAdapterService.getDatabase().setA2dpOptionalCodecsEnabled(device, value);
        mDatabaseManager.setA2dpOptionalCodecsEnabled(device, value);
    }

    // Handle messages from native (JNI) to Java
+12 −3
Original line number Diff line number Diff line
@@ -26,12 +26,14 @@ import android.util.Log;
import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@@ -45,6 +47,7 @@ public class A2dpSinkService extends ProfileService {
    static final int MAXIMUM_CONNECTED_DEVICES = 1;

    private final BluetoothAdapter mAdapter;
    private DatabaseManager mDatabaseManager;
    protected Map<BluetoothDevice, A2dpSinkStateMachine> mDeviceStateMap =
            new ConcurrentHashMap<>(1);

@@ -59,6 +62,9 @@ public class A2dpSinkService extends ProfileService {

    @Override
    protected boolean start() {
        mDatabaseManager = Objects.requireNonNull(AdapterService.getAdapterService().getDatabase(),
                "DatabaseManager cannot be null when A2dpSinkService starts");

        synchronized (mStreamHandlerLock) {
            mA2dpSinkStreamHandler = new A2dpSinkStreamHandler(this, this);
        }
@@ -389,8 +395,11 @@ public class A2dpSinkService extends ProfileService {
        if (DBG) {
            Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy);
        }
        AdapterService.getAdapterService().getDatabase()
                .setProfileConnectionPolicy(device, BluetoothProfile.A2DP_SINK, connectionPolicy);

        if (!mDatabaseManager.setProfileConnectionPolicy(device, BluetoothProfile.A2DP_SINK,
                  connectionPolicy)) {
            return false;
        }
        if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
            connect(device);
        } else if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
@@ -408,7 +417,7 @@ public class A2dpSinkService extends ProfileService {
    public int getConnectionPolicy(BluetoothDevice device) {
        enforceCallingOrSelfPermission(
                BLUETOOTH_PRIVILEGED, "Need BLUETOOTH_PRIVILEGED permission");
        return AdapterService.getAdapterService().getDatabase()
        return mDatabaseManager
                .getProfileConnectionPolicy(device, BluetoothProfile.A2DP_SINK);
    }

+3 −3
Original line number Diff line number Diff line
@@ -459,6 +459,9 @@ public class AdapterService extends Service {
        mSdpManager = SdpManager.init(this);
        registerReceiver(mAlarmBroadcastReceiver, new IntentFilter(ACTION_ALARM_WAKEUP));

        mDatabaseManager = new DatabaseManager(this);
        mDatabaseManager.start(MetadataDatabase.createDatabase(this));

        // Phone policy is specific to phone implementations and hence if a device wants to exclude
        // it out then it can be disabled by using the flag below.
        if (getResources().getBoolean(com.android.bluetooth.R.bool.enable_phone_policy)) {
@@ -472,9 +475,6 @@ public class AdapterService extends Service {
        mActiveDeviceManager = new ActiveDeviceManager(this, new ServiceFactory());
        mActiveDeviceManager.start();

        mDatabaseManager = new DatabaseManager(this);
        mDatabaseManager.start(MetadataDatabase.createDatabase(this));

        mSilenceDeviceManager = new SilenceDeviceManager(this, new ServiceFactory(),
                Looper.getMainLooper());
        mSilenceDeviceManager.start();
+9 −4
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.os.Parcelable;
import android.util.Log;

import com.android.bluetooth.a2dp.A2dpService;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.hearingaid.HearingAidService;
import com.android.bluetooth.hfp.HeadsetService;
import com.android.bluetooth.hid.HidHostService;
@@ -45,6 +46,7 @@ import com.android.internal.util.ArrayUtils;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;

// Describes the phone policy
//
@@ -86,6 +88,7 @@ class PhonePolicy {
    // Timeouts
    @VisibleForTesting static int sConnectOtherProfilesTimeoutMillis = 6000; // 6s

    private DatabaseManager mDatabaseManager;
    private final AdapterService mAdapterService;
    private final ServiceFactory mFactory;
    private final Handler mHandler;
@@ -242,6 +245,8 @@ class PhonePolicy {

    PhonePolicy(AdapterService service, ServiceFactory factory) {
        mAdapterService = service;
        mDatabaseManager = Objects.requireNonNull(mAdapterService.getDatabase(),
                "DatabaseManager cannot be null when PhonePolicy starts");
        mFactory = factory;
        mHandler = new PhonePolicyHandler(service.getMainLooper());
    }
@@ -318,7 +323,7 @@ class PhonePolicy {
            }
            if (nextState == BluetoothProfile.STATE_DISCONNECTED) {
                if (profileId == BluetoothProfile.A2DP) {
                    mAdapterService.getDatabase().setDisconnection(device);
                    mDatabaseManager.setDisconnection(device);
                }
                handleAllProfilesDisconnected(device);
            }
@@ -335,13 +340,13 @@ class PhonePolicy {
        debugLog("processActiveDeviceChanged, device=" + device + ", profile=" + profileId);

        if (device != null) {
            mAdapterService.getDatabase().setConnection(device, profileId == BluetoothProfile.A2DP);
            mDatabaseManager.setConnection(device, profileId == BluetoothProfile.A2DP);
        }
    }

    private void processDeviceConnected(BluetoothDevice device) {
        debugLog("processDeviceConnected, device=" + device);
        mAdapterService.getDatabase().setConnection(device, false);
        mDatabaseManager.setConnection(device, false);
    }

    private boolean handleAllProfilesDisconnected(BluetoothDevice device) {
@@ -397,7 +402,7 @@ class PhonePolicy {
        if (!mAdapterService.isQuietModeEnabled()) {
            debugLog("autoConnect: Initiate auto connection on BT on...");
            final BluetoothDevice mostRecentlyActiveA2dpDevice =
                    mAdapterService.getDatabase().getMostRecentlyConnectedA2dpDevice();
                    mDatabaseManager.getMostRecentlyConnectedA2dpDevice();
            if (mostRecentlyActiveA2dpDevice == null) {
                errorLog("autoConnect: most recently active a2dp device is null");
                return;
+10 −5
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import com.android.bluetooth.btservice.AdapterService;
import com.android.bluetooth.btservice.MetricsLogger;
import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;

@@ -60,6 +61,7 @@ public class HearingAidService extends ProfileService {
    private static HearingAidService sHearingAidService;

    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    private HandlerThread mStateMachinesThread;
    private BluetoothDevice mPreviousAudioDevice;

@@ -101,12 +103,12 @@ public class HearingAidService extends ProfileService {
            throw new IllegalStateException("start() called twice");
        }

        // Get AdapterService, HearingAidNativeInterface, AudioManager.
        // None of them can be null.
        mAdapterService = Objects.requireNonNull(AdapterService.getAdapterService(),
                "AdapterService cannot be null when HearingAidService starts");
        mHearingAidNativeInterface = Objects.requireNonNull(HearingAidNativeInterface.getInstance(),
                "HearingAidNativeInterface cannot be null when HearingAidService starts");
        mDatabaseManager = Objects.requireNonNull(mAdapterService.getDatabase(),
                "DatabaseManager cannot be null when HearingAidService starts");
        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        Objects.requireNonNull(mAudioManager,
                "AudioManager cannot be null when HearingAidService starts");
@@ -485,8 +487,11 @@ public class HearingAidService extends ProfileService {
        if (DBG) {
            Log.d(TAG, "Saved connectionPolicy " + device + " = " + connectionPolicy);
        }
        mAdapterService.getDatabase()
                .setProfileConnectionPolicy(device, BluetoothProfile.HEARING_AID, connectionPolicy);

        if (!mDatabaseManager.setProfileConnectionPolicy(device, BluetoothProfile.HEARING_AID,
                  connectionPolicy)) {
            return false;
        }
        if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
            connect(device);
        } else if (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN) {
@@ -510,7 +515,7 @@ public class HearingAidService extends ProfileService {
    public int getConnectionPolicy(BluetoothDevice device) {
        enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
                "Need BLUETOOTH_PRIVILEGED permission");
        return mAdapterService.getDatabase()
        return mDatabaseManager
                .getProfileConnectionPolicy(device, BluetoothProfile.HEARING_AID);
    }

Loading