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

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

Snap for 12517605 from 4903dd33 to 25Q1-release

Change-Id: I0843ce9cd1e5b7a3b59b6c91d109009dad3197b8
parents 0bd3d919 4903dd33
Loading
Loading
Loading
Loading
+4 −90
Original line number Diff line number Diff line
@@ -78,8 +78,6 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -118,26 +116,8 @@ public final class Utils {
    /** Thread pool to handle background and outgoing blocking task */
    public static final ExecutorService BackgroundExecutor = Executors.newSingleThreadExecutor();

    /*
     * Special character
     *
     * (See "What is a phone number?" doc)
     * 'p' --- GSM pause character, same as comma
     * 'n' --- GSM wild character
     * 'w' --- GSM wait character
     */
    public static final char PAUSE = ',';
    public static final char WAIT = ';';
    public static final String PAIRING_UI_PROPERTY = "bluetooth.pairing_ui_package.name";

    private static boolean isPause(char c) {
        return c == 'p' || c == 'P';
    }

    private static boolean isToneWait(char c) {
        return c == 'w' || c == 'W';
    }

    /**
     * Check if dual mode audio is enabled. This is set via the system property
     * persist.bluetooth.enable_dual_mode_audio.
@@ -322,12 +302,6 @@ public final class Utils {
        return byteArrayToLong(valueBuf, 0);
    }

    public static short byteArrayToShort(byte[] valueBuf) {
        ByteBuffer converter = ByteBuffer.wrap(valueBuf);
        converter.order(ByteOrder.nativeOrder());
        return converter.getShort();
    }

    public static int byteArrayToInt(byte[] valueBuf, int offset) {
        ByteBuffer converter = ByteBuffer.wrap(valueBuf);
        converter.order(ByteOrder.nativeOrder());
@@ -422,66 +396,6 @@ public final class Utils {
        return puuids;
    }

    public static String debugGetAdapterStateString(int state) {
        switch (state) {
            case BluetoothAdapter.STATE_OFF:
                return "STATE_OFF";
            case BluetoothAdapter.STATE_ON:
                return "STATE_ON";
            case BluetoothAdapter.STATE_TURNING_ON:
                return "STATE_TURNING_ON";
            case BluetoothAdapter.STATE_TURNING_OFF:
                return "STATE_TURNING_OFF";
            default:
                return "UNKNOWN";
        }
    }

    public static String ellipsize(String s) {
        // Only ellipsize release builds
        if (!Build.TYPE.equals("user")) {
            return s;
        }
        if (s == null) {
            return null;
        }
        if (s.length() < 3) {
            return s;
        }
        return s.charAt(0) + "⋯" + s.charAt(s.length() - 1);
    }

    public static void copyStream(InputStream is, OutputStream os, int bufferSize)
            throws IOException {
        if (is != null && os != null) {
            byte[] buffer = new byte[bufferSize];
            int bytesRead = 0;
            while ((bytesRead = is.read(buffer)) >= 0) {
                os.write(buffer, 0, bytesRead);
            }
        }
    }

    public static void safeCloseStream(InputStream is) {
        if (is != null) {
            try {
                is.close();
            } catch (Throwable t) {
                Log.d(TAG, "Error closing stream", t);
            }
        }
    }

    public static void safeCloseStream(OutputStream os) {
        if (os != null) {
            try {
                os.close();
            } catch (Throwable t) {
                Log.d(TAG, "Error closing stream", t);
            }
        }
    }

    static int sSystemUiUid = USER_HANDLE_NULL.getIdentifier();

    public static void setSystemUiUid(int uid) {
@@ -1162,10 +1076,10 @@ public final class Utils {
        for (int i = 0; i < len; i++) {
            char c = phoneNumber.charAt(i);

            if (isPause(c)) {
                c = PAUSE;
            } else if (isToneWait(c)) {
                c = WAIT;
            if (c == 'p' || c == 'P') {
                c = ',';
            } else if (c == 'w' || c == 'W') {
                c = ';';
            }
            ret.append(c);
        }
+46 −25
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@ import java.util.concurrent.ConcurrentHashMap;
public class A2dpSinkService extends ProfileService {
    private static final String TAG = A2dpSinkService.class.getSimpleName();

    // This is also used as a lock for shared data in {@link A2dpSinkService}
    @GuardedBy("mDeviceStateMap")
    private final Map<BluetoothDevice, A2dpSinkStateMachine> mDeviceStateMap =
            new ConcurrentHashMap<>(1);

@@ -116,10 +118,12 @@ public class A2dpSinkService extends ProfileService {
    public void stop() {
        setA2dpSinkService(null);
        mNativeInterface.cleanup();
        synchronized (mDeviceStateMap) {
            for (A2dpSinkStateMachine stateMachine : mDeviceStateMap.values()) {
                stateMachine.quitNow();
            }
            mDeviceStateMap.clear();
        }
        synchronized (mStreamHandlerLock) {
            if (mA2dpSinkStreamHandler != null) {
                mA2dpSinkStreamHandler.cleanup();
@@ -362,7 +366,10 @@ public class A2dpSinkService extends ProfileService {
            throw new IllegalArgumentException("Null device");
        }

        A2dpSinkStateMachine stateMachine = mDeviceStateMap.get(device);
        A2dpSinkStateMachine stateMachine;
        synchronized (mDeviceStateMap) {
            stateMachine = mDeviceStateMap.get(device);
        }
        // a state machine instance doesn't exist. maybe it is already gone?
        if (stateMachine == null) {
            return false;
@@ -389,7 +396,9 @@ public class A2dpSinkService extends ProfileService {
        if (stateMachine == null) {
            return;
        }
        synchronized (mDeviceStateMap) {
            mDeviceStateMap.remove(stateMachine.getDevice());
        }
        stateMachine.quitNow();
    }

@@ -400,6 +409,7 @@ public class A2dpSinkService extends ProfileService {
    protected A2dpSinkStateMachine getOrCreateStateMachine(BluetoothDevice device) {
        A2dpSinkStateMachine newStateMachine =
                new A2dpSinkStateMachine(mLooper, device, this, mNativeInterface);
        synchronized (mDeviceStateMap) {
            A2dpSinkStateMachine existingStateMachine =
                    mDeviceStateMap.putIfAbsent(device, newStateMachine);
            // Given null is not a valid value in our map, ConcurrentHashMap will return null if the
@@ -411,11 +421,14 @@ public class A2dpSinkService extends ProfileService {
            }
            return existingStateMachine;
        }
    }

    @VisibleForTesting
    protected A2dpSinkStateMachine getStateMachineForDevice(BluetoothDevice device) {
        synchronized (mDeviceStateMap) {
            return mDeviceStateMap.get(device);
        }
    }

    List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
        Log.d(TAG, "getDevicesMatchingConnectionStates(states=" + Arrays.toString(states) + ")");
@@ -451,7 +464,10 @@ public class A2dpSinkService extends ProfileService {
     */
    public int getConnectionState(BluetoothDevice device) {
        if (device == null) return BluetoothProfile.STATE_DISCONNECTED;
        A2dpSinkStateMachine stateMachine = mDeviceStateMap.get(device);
        A2dpSinkStateMachine stateMachine;
        synchronized (mDeviceStateMap) {
            stateMachine = mDeviceStateMap.get(device);
        }
        return (stateMachine == null)
                    ? BluetoothProfile.STATE_DISCONNECTED
                    : stateMachine.getState();
@@ -501,6 +517,7 @@ public class A2dpSinkService extends ProfileService {
        super.dump(sb);
        ProfileService.println(sb, "Active Device = " + getActiveDevice());
        ProfileService.println(sb, "Max Connected Devices = " + mMaxConnectedAudioDevices);
        synchronized (mDeviceStateMap) {
            ProfileService.println(sb, "Devices Tracked = " + mDeviceStateMap.size());
            for (A2dpSinkStateMachine stateMachine : mDeviceStateMap.values()) {
                ProfileService.println(
@@ -508,10 +525,14 @@ public class A2dpSinkService extends ProfileService {
                stateMachine.dump(sb);
            }
        }
    }

    BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
        if (device == null) return null;
        A2dpSinkStateMachine stateMachine = mDeviceStateMap.get(device);
        A2dpSinkStateMachine stateMachine;
        synchronized (mDeviceStateMap) {
            stateMachine = mDeviceStateMap.get(device);
        }
        // a state machine instance doesn't exist. maybe it is already gone?
        if (stateMachine == null) {
            return null;
+45 −90
Original line number Diff line number Diff line
@@ -16,10 +16,11 @@

package com.android.bluetooth.bas;

import static java.util.Objects.requireNonNull;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -31,30 +32,45 @@ 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.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/** A profile service that connects to the Battery service (BAS) of BLE devices */
public class BatteryService extends ProfileService {
    private static final String TAG = "BatteryService";
    private static final String TAG = BatteryService.class.getSimpleName();

    // Timeout for state machine thread join, to prevent potential ANR.
    private static final int SM_THREAD_JOIN_TIMEOUT_MS = 1_000;

    private static BatteryService sBatteryService;
    private AdapterService mAdapterService;
    private DatabaseManager mDatabaseManager;
    private HandlerThread mStateMachinesThread;
    private Handler mHandler;

    private final AdapterService mAdapterService;
    private final DatabaseManager mDatabaseManager;
    private final HandlerThread mStateMachinesThread;
    private final Handler mHandler;

    @GuardedBy("mStateMachines")
    private final Map<BluetoothDevice, BatteryStateMachine> mStateMachines = new HashMap<>();

    public BatteryService(Context ctx) {
        super(ctx);
    public BatteryService(AdapterService adapterService) {
        this(adapterService, Looper.getMainLooper());
    }

    @VisibleForTesting
    BatteryService(AdapterService adapterService, Looper looper) {
        super(requireNonNull(adapterService));
        mAdapterService = adapterService;
        mDatabaseManager = requireNonNull(mAdapterService.getDatabase());
        mHandler = new Handler(requireNonNull(looper));

        mStateMachinesThread = new HandlerThread("BatteryService.StateMachines");
        mStateMachinesThread.start();
        setBatteryService(this);
    }

    public static boolean isEnabled() {
@@ -66,38 +82,9 @@ public class BatteryService extends ProfileService {
        return null;
    }

    @Override
    public void start() {
        Log.d(TAG, "start()");
        if (sBatteryService != null) {
            throw new IllegalStateException("start() called twice");
        }

        mAdapterService =
                Objects.requireNonNull(
                        AdapterService.getAdapterService(),
                        "AdapterService cannot be null when BatteryService starts");
        mDatabaseManager =
                Objects.requireNonNull(
                        mAdapterService.getDatabase(),
                        "DatabaseManager cannot be null when BatteryService starts");

        mHandler = new Handler(Looper.getMainLooper());
        mStateMachines.clear();
        mStateMachinesThread = new HandlerThread("BatteryService.StateMachines");
        mStateMachinesThread.start();

        setBatteryService(this);
    }

    @Override
    public void stop() {
        Log.d(TAG, "stop()");
        if (sBatteryService == null) {
            Log.w(TAG, "stop() called before start()");
            return;
        }

        setBatteryService(null);

        // Destroy state machines and stop handler thread
@@ -109,23 +96,14 @@ public class BatteryService extends ProfileService {
            mStateMachines.clear();
        }

        if (mStateMachinesThread != null) {
        try {
            mStateMachinesThread.quitSafely();
            mStateMachinesThread.join(SM_THREAD_JOIN_TIMEOUT_MS);
                mStateMachinesThread = null;
        } catch (InterruptedException e) {
            // Do not rethrow as we are shutting down anyway
        }
        }

        // Unregister Handler and stop all queued messages.
        if (mHandler != null) {
        mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }

        mAdapterService = null;
    }

    @Override
@@ -178,7 +156,7 @@ public class BatteryService extends ProfileService {
                Log.e(TAG, "Cannot connect to " + device + " : no state machine");
                return false;
            }
            sm.sendMessage(BatteryStateMachine.CONNECT);
            sm.sendMessage(BatteryStateMachine.MESSAGE_CONNECT);
        }

        return true;
@@ -208,7 +186,7 @@ public class BatteryService extends ProfileService {
        synchronized (mStateMachines) {
            BatteryStateMachine sm = getOrCreateStateMachine(device);
            if (sm != null) {
                sm.sendMessage(BatteryStateMachine.DISCONNECT);
                sm.sendMessage(BatteryStateMachine.MESSAGE_DISCONNECT);
            }
        }

@@ -231,12 +209,8 @@ public class BatteryService extends ProfileService {
    /**
     * Check whether it can connect to a peer device. The check considers a number of factors during
     * the evaluation.
     *
     * @param device the peer device to connect to
     * @return true if connection is allowed, otherwise false
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public boolean canConnect(BluetoothDevice device) {
    boolean canConnect(BluetoothDevice device) {
        // Check connectionPolicy and accept or reject the connection.
        int connectionPolicy = getConnectionPolicy(device);
        int bondState = mAdapterService.getBondState(device);
@@ -255,10 +229,8 @@ public class BatteryService extends ProfileService {
    }

    /** Called when the connection state of a state machine is changed */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public void handleConnectionStateChanged(BatteryStateMachine sm, int fromState, int toState) {
        BluetoothDevice device = sm.getDevice();
        if ((sm == null) || (fromState == toState)) {
    void handleConnectionStateChanged(BluetoothDevice device, int fromState, int toState) {
        if (fromState == toState) {
            Log.e(
                    TAG,
                    "connectionStateChanged: unexpected invocation. device="
@@ -366,16 +338,11 @@ public class BatteryService extends ProfileService {
    }

    /** Called when the battery level of the device is notified. */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public void handleBatteryChanged(BluetoothDevice device, int batteryLevel) {
    void handleBatteryChanged(BluetoothDevice device, int batteryLevel) {
        mAdapterService.setBatteryLevel(device, batteryLevel, /* isBas= */ true);
    }

    private BatteryStateMachine getOrCreateStateMachine(BluetoothDevice device) {
        if (device == null) {
            Log.e(TAG, "getOrCreateGatt failed: device cannot be null");
            return null;
        }
        synchronized (mStateMachines) {
            BatteryStateMachine sm = mStateMachines.get(device);
            if (sm != null) {
@@ -383,7 +350,7 @@ public class BatteryService extends ProfileService {
            }

            Log.d(TAG, "Creating a new state machine for " + device);
            sm = BatteryStateMachine.make(device, this, mStateMachinesThread.getLooper());
            sm = new BatteryStateMachine(this, device, mStateMachinesThread.getLooper());
            mStateMachines.put(device, sm);
            return sm;
        }
@@ -394,16 +361,8 @@ public class BatteryService extends ProfileService {
        mHandler.post(() -> bondStateChanged(device, toState));
    }

    /**
     * Remove state machine if the bonding for a device is removed
     *
     * @param device the device whose bonding state has changed
     * @param bondState the new bond state for the device. Possible values are: {@link
     *     BluetoothDevice#BOND_NONE}, {@link BluetoothDevice#BOND_BONDING}, {@link
     *     BluetoothDevice#BOND_BONDED}, {@link BluetoothDevice#ERROR}.
     */
    @VisibleForTesting
    void bondStateChanged(BluetoothDevice device, int bondState) {
    /** Remove state machine if the bonding for a device is removed */
    private void bondStateChanged(BluetoothDevice device, int bondState) {
        Log.d(TAG, "Bond state changed for device: " + device + " state: " + bondState);
        // Remove state machine if the bonding for a device is removed
        if (bondState != BluetoothDevice.BOND_NONE) {
@@ -423,16 +382,10 @@ public class BatteryService extends ProfileService {
    }

    private void removeStateMachine(BluetoothDevice device) {
        if (device == null) {
            Log.e(TAG, "removeStateMachine failed: device cannot be null");
            return;
        }
        synchronized (mStateMachines) {
            BatteryStateMachine sm = mStateMachines.remove(device);
            if (sm == null) {
                Log.w(
                        TAG,
                        "removeStateMachine: device " + device + " does not have a state machine");
                Log.w(TAG, "removeStateMachine: " + device + " does not have a state machine");
                return;
            }
            Log.i(TAG, "removeGatt: removing bluetooth gatt for device: " + device);
@@ -444,8 +397,10 @@ public class BatteryService extends ProfileService {
    @Override
    public void dump(StringBuilder sb) {
        super.dump(sb);
        synchronized (mStateMachines) {
            for (BatteryStateMachine sm : mStateMachines.values()) {
                sm.dump(sb);
            }
        }
    }
}
Loading