Chapter 1 Bluetooth basics

Source of Bluetooth name

The word Bluetooth comes from Harald Bluetooth, the name given to the 10th-century King of Denmark. He is famous for uniting Scandinavia. The official adoption of Bluetooth as the name of the wireless technology standard was proposed by Jim Kardach, an engineer from Intel, at a standardization meeting of the industry leaders of Intel, Ericsson and Nokia in 1996. He hopes that Bluetooth will become a unified, universal transmission standard just as King Harald unified the peninsula — connecting all scattered devices to content.

The Bluetooth LOGO comes from a combination of post-Versak runes, combining king Harald’s initials H and B to create the blue LOGO we know today.

2. Bluetooth technology concept

Bluetooth is a wireless technology standard that enables short-range data exchange (using uHF radio waves in the ISM band of 2.4 — 2.485GHz) between fixed devices, mobile devices, and personal building networks. Bluetooth technology was first developed by telecom giant Ericsson in 1994 as an alternative to RS232 data lines. It is currently managed by the Bluetooth Technology Alliance, which has more than 25,000 member companies worldwide in telecommunications, computing, networking, and consumer electronics.

3. Bluetooth technology changes

  • 1.0 + BR era

Earlier versions 1.0 and 1.1 had many problems and were incompatible with products from several vendors. At the same time, the device address of Bluetooth cannot be hidden during the connection process, which is prone to the risk of data leakage and leads to low market usage

Version 1.2 improved the anonymous approach, added the ability to mask device hardware addresses to protect users from identity sniffing attacks and tracking, and added AFH (Adaptive frequency modulation) and eSCO (Extended Synchronous Link Directed Channel technology) to greatly improve bluetooth anti-jamming and voice transmission quality.

  • Version 2.0 + EDR

Bluetooth 2.0 is an improved version of version 1.2, with the addition of EDR technology that enables bluetooth devices to deliver up to 3Mbps by increasing multitasking and the ability to run multiple Bluetooth devices at the same time. Version 2.0 also supports duplex mode, which allows voice communication while transmitting documents/high pixel images. And EDR reduces power consumption by reducing workload cycles, while Bluetooth 2.0 increases the number of connected devices as bandwidth increases.

Bluetooth 2.1 has added a power saving feature to Sniff Subrating, extending the signal transmission interval between devices to about 0.5 seconds from 0.1 seconds in the old version, thus greatly reducing the workload of Bluetooth chips.

In addition, the SSP simple security pairing function is added to improve the pairing experience of Bluetooth devices, while enhancing the use and security intensity.

The OOB pairing mode of NFC is supported. As long as two Bluetooth devices with BUILT-IN NFC chip are close to each other, the pairing password will be transmitted through NFC without manual input.

  • Version 3.0 + HS

Bluetooth 3.0 has added the optional technology High Speed, which enables Bluetooth to call 802.11 for high-speed data transmission. The transmission rate is up to 24Mbps, which is 8 times higher than Bluetooth 2.0.

At the core of Bluetooth 3.0 is the Generic Alternate MAC/PHY (AMP), a new Alternate RF technology that allows the Bluetooth protocol stack to dynamically select the correct RF for any task. In terms of power consumption, Bluetooth 3.0 introduces EPC enhanced power control technology, supplemented by 802.11, which significantly reduces the actual idle power consumption.

  • Version 4.0 + BLE

Bluetooth 4.0 is the first bluetooth comprehensive protocol specification to date, integrating three specifications into one. Low power Bluetooth, traditional Bluetooth and high speed Bluetooth modes are also proposed.

High-speed Bluetooth focuses on data exchange and transmission; Traditional Bluetooth focuses on information communication and device connection. Low Power Bluetooth is designed to connect to devices that do not require much bandwidth, reducing power consumption by 90% compared to older versions

BLE, the predecessor of Wibree technology developed by NOKIA, was originally developed as an extremely Low power mobile wireless communication technology for mobile devices. After being adopted and normalized by the SIG, BLE was renamed Bluetooth Low Energy.

Bluetooth 4.0 has Single mode and Dual mode chip modes. Single Mode can only communicate with Bluetooth 4.0 and is not compatible with version 3.0/2.1/2.0. Dual Mode is backward compatible with version 3.0/2.1/2.0. The former is used in sensor devices that use button batteries, such as power-hungry heart rate detectors and thermometers. The latter is applied to traditional Bluetooth devices with low power consumption. In addition, Bluetooth 4.0 also increases the transmission distance of Bluetooth to more than 100 meters, and has a faster response time. The connection can be set up and data can be transmitted in as little as 3 milliseconds. At the same time, the AES-128 CCM encryption algorithm is used for data encryption and authentication, making data transmission more secure and reliable.

Bluetooth 4.1 has few changes in speed and range, but significant improvements in software are intended to make Bluetooth Smart technology the core driving force behind IOT development.

Support for cloud synchronization: Bluetooth 4.1 has a dedicated IPv6 channel. Bluetooth 4.1 devices only need to connect to an internet-connected device to synchronize data with the cloud over IPv6 to meet the application requirements of the Internet of Things.

Switch roles between central devices and peripheral devices: Supports bluetooth 4.1 standard earphones, watches, keys and mice, and can send and receive data independently without using data hubs such as PCS, tablets, and mobile phones. Smartwatches and pedometers, for example, can bypass smartphones and enable direct conversations.

Bluetooth 4.2 is even faster, 2.5 times faster than its predecessor, because Bluetooth Smart packets can hold about 10 times as much data as before.

Improved transmission rates and privacy. Bluetooth signals must be approved by the user if they want to connect to or track the user’s device. Users can use wearable devices without fear of being tracked.

  • 5.0 + IOT era

Bluetooth 5.0 has faster and longer transmission capabilities in low-power mode, with a transmission rate twice that of Bluetooth 4.2 (with a speed cap of 2Mbps), an effective distance four times that of Bluetooth 4.2 (theoretically up to 300 meters), and eight times the packet capacity.

Bluetooth Mesh networking: Mesh networking is an independently developed networking technology that can use Bluetooth devices as signal relay stations to cover data over a very large physical area. Traditional Bluetooth connections are achieved by pairing one device to another, establishing one-to-one or one-to-many micro-network relationships. Mesh networks enable devices to implement many-to-many relationships. Each device node in a Mesh network can send and receive information. As long as one device is connected to the gateway, the information can be relayed between the nodes. In this way, messages can be transmitted farther than the normal transmission distance of radio waves.

Bluetooth 5.1 improves indoor location services by using direction-finding to detect the direction of Bluetooth signals. With Bluetooth direction-finding, developers can bring to market products that can detect device orientation and achieve centimeter-level positioning accuracy.

AOA (Angle of Arrival) : Used for real-time indoor positioning, item tracking, and landmark information.

AOD (Angle of Departure) : it can be used in indoor positioning system. Mobile phones use this method to receive signals through low-power receivers and coordinate with surrounding positioning beacons.

Bluetooth 5.2 introduces a new generation of Bluetooth audio technology, breaking the market monopoly of classical Bluetooth audio and creating a new market of Bluetooth wireless audio. LE Audio not only improves Audio quality, but also adds low power consumption features, making Bluetooth Audio available in more scenarios.

LC3 edit decoder to build better, higher sound quality and lower power consumption: LE Audio will use a new Low Complexity Communication Codec (LC3) to achieve higher sound quality and lower power consumption, although LC3 is not comparable to APTX,APTX-HD Audio encoding, However, compared with the classical Bluetooth Audio encoding SBC, LC3 has greatly improved the encoding efficiency and quality, which makes LE Audio has a greater technical advantage than the classical Bluetooth Audio technology, and the monopoly of classical Bluetooth Audio will be broken by LE Audio.

Multi-stream Audio: LE Audio’s multi-stream Audio can help build better in-ear headphones. The multi-streaming audio function will realize the synchronization of multiple and independent audio streaming transmission between a single source device or a single or multiple sink devices such as smart phones.

4. Bluetooth protocol architecture

Bluetooth protocol architecture, from top to bottom, includes application configuration layer, application protocol layer, logical link adaptation layer, host control interface layer, link management protocol layer, baseband protocol layer, link control protocol layer, radio frequency protocol layer

Application configuration layer: A2DP, AVRCP, HFP, and GATT each represent a Bluetooth profile that defines potential application scenarios and specifies the general behavior that Bluetooth enabled devices use to communicate with other Bluetooth devices. Each Profile defines a scenario for bluetooth use, such as an A2dp Profile for playing music over Bluetooth, or an Hfp Profile for making phone calls over Bluetooth. Here is a list of profiles that are used daily:

Application protocol layer: the basic protocol of the upper configuration file, which specifically refines the data and control processing of each use scenario function. For example, AVDTP specifies how two Bluetooth devices establish audio and video connections, including how to discover the audio and video capabilities supported by the peer, negotiate coDEC, etc.

Logical Link Adaptation layer: The core protocol of Bluetooth, which supports high level protocol multiplexing, data segmentation and recombination, and transmission of quality of service information, referencing the endpoints of each L2CAP channel by channel identifier (CID).

Host control interface layer: Provides access to the unity of the bluetooth host/control interface, popular, is defined by the bluetooth protocol stack to control a bluetooth chip to make the corresponding action (such as inquiry, connect and disconnect) of a particular format, The Bluetooth chip responds to bluetooth protocol stack status and event messages.

Link management: The Link Manager protocol (LMP) controls and coordinates all aspects of Bluetooth connection operation between two devices. Includes setting up and controlling logical transport, logical link and physical link control for communication between link managers (LMS) of two devices connected by ACL logical transport.

Baseband protocol layer: When Bluetooth sends data, the baseband carries out channel coding for the data from the upper layer and sends it down to the RF. When receiving data, the demodulation restores the airborne data and sends it up to the baseband, which carries out channel coding and sends it to the upper layer.

Link control protocol layer: The link control protocol layer is responsible for the encryption and decryption of Bluetooth packet, such as physical channel, logical transmission and data of logical link.

Rf protocol layer: RF refers to the electromagnetic frequency between the sound frequency and infrared frequency. Bluetooth RF protocol specifies the bluetooth RF frequency band, modulation mode, frequency modulation, transmission power, receiving sensitivity and other parameters.

Chapter 2 Android Bluetooth knowledge

Android Bluetooth architecture

On Android, the architecture of Bluetooth is shown in the figure above

  1. Android Applications: Bluetooth APIs are developed for various Bluetooth Applications
  • Setting App: an application for controlling bluetooth switch state and system operation
  • Media App: Play music through Bluetooth device, and can control the remote play, pause, previous song, next song and other logic
  • Bluetooth Share App: Transfer files to the peer phone through the Bluetooth sharing function
  • Phone App: Enables you to use the Phone function through Bluetooth and synchronize contacts with the peer device
  • Ble App: Bluetooth App with low power consumption, which can synchronize data with Ble devices, such as bracelets and watches
  1. Bluetooth Services: The upper core of the Bluetooth process processes Services, which encapsulate the logical calls to the APP, pass them down to Bluetooth HAL, and receive HAL messages, callback data, and return them to the upper app
  1. Bluetooth HAL: the core code of Bluedroid, which implements the underlying protocol of Bluetooth, and segments and reorganizes the data, and transmits it to the Bluetooth driver through the host control interface
  1. UART Driver: A common bluetooth physical transmission channel on mobile phones. It is a universal serial data bus used for asynchronous communication. The bus is bidirectional and can realize full-duplex transmission and reception
  1. Bluetooth Chipset: The Bluetooth chip, internal link manager, baseband manager, and rf system is responsible for final channel encoding, packet encryption and decryption, and radio transmission and reception.

Key classes and interfaces

BluetoothAdapter: a local BluetoothAdapter that is the entry point for all bluetooth interactions. With this class, you can discover other Bluetooth devices, query the list of bound (paired) devices, instantiate bluetoothDevices with known MAC addresses, and listen for communications from other devices by creating bluetoothServerSockets.

BluetoothDevice: remote BluetoothDevice. With this class, BluetoothSocket could request to establish a connection with a remote device, or query information about the device, such as the name, address, class and binding status of the device.

BluetoothSocket: BluetoothSocket interface (similar to TCP Socket), allowing applications to exchange data with other bluetooth devices using InputStream and OutputStream.

BluetoothClass: Describes the general features and functions of Bluetooth devices. This is a set of read-only properties that define the device’s classes and services and provide most of the useful information about bluetooth types.

BluetoothHeadset: Bluetooth interface supported by the headset, providing headset and hands-free control functions, called by binder

Talk to the HeadsetService.

BluetoothA2dp: defines how to use bluetooth Advanced Audio Transfer Profile (A2DP) to stream high quality audio from one device to another via bluetooth connection, communicating with A2dpService through binder calls.

BluetoothPbap: directory support bluetooth interface class, provides support for bluetooth address book function, through the binder calls and PbapService communication.

BluetoothHidHost: bluetooth input device control support interface class, provides for the remote input device support, through the binder calls and HidHostService communication.

BluetoothHearingAid: BluetoothHearingAid interface class for BluetoothHearingAid device control support, providing volume adjustment support for remote hearing AIDS, communication with the HearingAidService called by binder.

BluetoothGatt: BluetoothGatt: Bluetooth BLE device Center side control interface class, providing peripheral device connection, control support, communication through binder calls and GattService.

BluetoothGattServer: The interface class supported by peripheral end of Bluetooth BLE device provides function simulation of peripheral devices, such as creation of Services and Characteristic, and communicates with GattService through calling with binder.

Android Bluetooth workflow

  1. Bluetooth scan process

The timing diagram of Bluetooth scanning process is shown above

  1. From the Bluetooth options set by the system, call startDiscovery to initiate a scan
frameworks/base/core/java/android/bluetooth/BluetoothAdapter.java public boolean startDiscovery() { // ... try { mServiceLock.readLock().lock(); if (mService ! = null) { return mService.startDiscovery(getOpPackageName());Copy the code
  1. Through AIDL call to bluetooth process core processing class AdapterService, and then through JNI call native method startDiscoveryNative
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java
synchronized (mDiscoveringPackages) {
    mDiscoveringPackages.add(new DiscoveringPackage(callingPackage, permission));
}
return startDiscoveryNative();
Copy the code
  1. In the JNI class, we called the following method, sBluetoothInterface->start_discovery
packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
  // ...
  int ret = sBluetoothInterface->start_discovery();
  return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
Copy the code
packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp if (hal_util_load_bt_library((bt_interface_t const**)&sBluetoothInterface)) { ALOGE("No Bluetooth Library found"); } } int hal_util_load_bt_library(const bt_interface_t** interface) { // bluetoothInterface const char* sym = BLUETOOTH_INTERFACE_STRING; bt_interface_t* itf = nullptr; // The library name is not set by default, so the preset library name is used. char path[PROPERTY_VALUE_MAX] = ""; // #define PROPERTY_BT_LIBRARY_NAME "ro.bluetooth.library_name" //#define DEFAULT_BT_LIBRARY_NAME "libbluetooth.so" property_get(PROPERTY_BT_LIBRARY_NAME, path, DEFAULT_BT_LIBRARY_NAME); // Open library void* handle = dlopen(path, RTLD_NOW); if (! handle) { const char* err_str = dlerror(); LOG(ERROR) << __func__ << ": failed to load Bluetooth library, error=" << (err_str ? err_str : "error unknown"); goto error; } // Get the address of the bt_interface_t. itf = (bt_interface_t*)dlsym(handle, sym); if (! itf) { LOG(ERROR) << __func__ << ": failed to load symbol from Bluetooth library " << sym; goto error; } // Success. LOG(INFO) << __func__ << " loaded HAL: btinterface=" << itf << ", handle=" << handle; *interface = itf; return 0; error: *interface = NULL; if (handle) dlclose(handle); return -EINVAL; }Copy the code

When jni lib is loaded, hal_util_load_bt_library is called in classInitNative and the argument is sBluetoothInterface above

In hal_util_load_bt_library, the first thing to look for is whether the prop of “ro.bluetooth.library_name” has a library, and if so, open the corresponding library through dlopen, otherwise use the default library, In this example, Darwin uses Qualcomm’s Bluetooth protocol stack library

darwin:/ # getprop | grep "ro.bluetooth.library_name"
[ro.bluetooth.library_name]: [libbluetooth_qti.so]
Copy the code

A bluetoothInterface address is then returned via dlSYM and assigned to the interface

So the above sBluetoothInterface->start_discovery was eventually called into the logic of the Bluetooth protocol stack

  1. Entering the protocol stack code, you can see that the structure of bT_interface_t is initialized below. Further down, call btif_dm_start_discovery
vendor/qcom/opensource/commonsys/system/bt/btif/src/bluetooth.cc
EXPORT_SYMBOL bt_interface_t bluetoothInterface = {
    sizeof(bluetoothInterface),
    // ...
    start_discovery,
    cancel_discovery,
    create_bond,
    create_bond_out_of_band,
    remove_bond,
    // ...
};
static int start_discovery(void) {
  /* sanity check */
  if (interface_ready() == false) return BT_STATUS_NOT_READY;
  return btif_dm_start_discovery();
}
Copy the code
  1. In bitF_DM_STARt_discovery, some of the scan parameters are preset, such as duration, which defaults to 10, so bluetooth’s default scan period is 1.28 x 10, or 12.8s, and then goes down to call BTA_DMSearch
vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_dm.cc
// #define BTIF_DM_DEFAULT_INQ_MAX_DURATION 10
inq_params.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION;
// #define BTIF_DM_DEFAULT_INQ_MAX_RESULTS 0
inq_params.max_resps = BTIF_DM_DEFAULT_INQ_MAX_RESULTS;
inq_params.report_dup = true;
// ...
/* find nearby devices */
BTA_DmSearch(&inq_params, services, bte_search_devices_evt);
Copy the code
  1. Create a new search MSG, assign the corresponding event, scan parameter, and callback, and send it via bTA_sys_send_msg (GKI MSG)
vendor/qcom/opensource/commonsys/system/bt/bta/dm/bta_dm_api.cc
void BTA_DmSearch(tBTA_DM_INQ* p_dm_inq, tBTA_SERVICE_MASK services,
                  tBTA_DM_SEARCH_CBACK* p_cback) {
  p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
  memcpy(&p_msg->inq_params, p_dm_inq, sizeof(tBTA_DM_INQ));
  p_msg->services = services;
  p_msg->p_cback = p_cback;
  p_msg->rs_res = BTA_DM_RS_NONE;
  bta_sys_sendmsg(p_msg);
}
Copy the code
  1. The bTA_DM_inq_results_cb and bTA_DM_inq_cmPL_cb callback functions are used as parameters. Continue calling BTM_StartInquiry
vendor/qcom/opensource/commonsys/system/bt/bta/dm/bta_dm_act.cc void bta_dm_search_start(tBTA_DM_MSG* p_data) { // ... BTM_ClearInqDb(NULL); /* save search params */ bta_dm_search_cb.p_search_cback = p_data->search.p_cback; bta_dm_search_cb.services = p_data->search.services; osi_free_and_reset((void**)&bta_dm_search_cb.p_srvc_uuid); if ((bta_dm_search_cb.num_uuid = p_data->search.num_uuid) ! = 0 && p_data->search.p_uuid ! = NULL) { bta_dm_search_cb.p_srvc_uuid = (Uuid*)osi_malloc(len); *bta_dm_search_cb.p_srvc_uuid = *p_data->search.p_uuid; } result.status = BTM_StartInquiry((tBTM_INQ_PARMS*)&p_data->search.inq_params, bta_dm_inq_results_cb, (tBTM_CMPL_CB*)bta_dm_inq_cmpl_cb); }}Copy the code
  1. In BTM_StartInquiry, the callback passed is saved. Since it is a dual-mode Bluetooth chip that supports BLE, the BLE scan method btm_ble_STARt_inquiry is called first
vendor/qcom/opensource/commonsys/system/bt/stack/btm/btm_inq.cc tBTM_STATUS BTM_StartInquiry(tBTM_INQ_PARMS* p_inqparms,  tBTM_INQ_RESULTS_CB* p_results_cb, tBTM_CMPL_CB* p_cmpl_cb) { if (! controller_get_interface()->supports_ble()) { p_inq->inqparms.mode &= ~BTM_BLE_INQUIRY_MASK; status = BTM_ILLEGAL_VALUE; } /* BLE for now does not support filter condition for inquiry */ else { status = btm_ble_start_inquiry( (uint8_t)(p_inqparms->mode & BTM_BLE_INQUIRY_MASK), p_inqparms->duration); }}Copy the code
  1. Here, the BLE scan parameters are sent to the controller via hCI, and then btM_BLE_STARt_SCAN is called
vendor/qcom/opensource/commonsys/system/bt/stack/btm/btm_ble_gap.cc if (! BTM_BLE_IS_SCAN_ACTIVE(p_ble_cb->scan_activity)) { btm_send_hci_set_scan_params( scan_phy, BTM_BLE_SCAN_MODE_ACTI, scan_interval, scan_window, btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, SP_ADV_ALL); / /... status = btm_ble_start_scan();Copy the code
vendor/qcom/opensource/commonsys/system/bt/stack/btm/btm_ble_gap.cc
tBTM_STATUS btm_ble_start_scan(void) {
  tBTM_BLE_INQ_CB* p_inq = &btm_cb.ble_ctr_cb.inq_var;
  /* start scan, disable duplicate filtering */
  btm_send_hci_scan_enable(BTM_BLE_SCAN_ENABLE, p_inq->scan_duplicate_filter);
}
Copy the code
vendor/qcom/opensource/commonsys/system/bt/stack/btm/btm_ble_gap.cc void btm_send_hci_scan_enable(uint8_t enable, uint8_t filter_duplicates) { if (controller_get_interface()->supports_ble_extended_advertising()) { btsnd_hcic_ble_set_extended_scan_enable(enable, filter_duplicates, 0x0000, 0x0000); } else { btsnd_hcic_ble_set_scan_enable(enable, filter_duplicates); }}Copy the code

Through the above two internal calls, the ble scan parameter is set to enable, and hCI Layer is called to send command to bluetooth Controller to start execution, and BLE scan starts

  1. But when we click scan from the Settings page, we can see not only ble devices, but also classical Bluetooth devices, which indicates that the BR/EDR scan is also being performed. Let’s see where this is being performed. Back in btM_inq. cc’s BTM_StartInquiry function, This calls btM_set_INq_EVENT_filter, sets the current inquiry Event filter, and then sends it to bluetooth Controller for execution via HCI Command
vendor/qcom/opensource/commonsys/system/bt/stack/btm/btm_inq.cc
/* Before beginning the inquiry the current filter must be cleared, so
 * initiate the command */
status = btm_set_inq_event_filter(p_inqparms->filter_cond_type,
                                  &p_inqparms->filter_cond);
Copy the code
  1. After the event Filter is executed by the controller, it is reported to the protocol stack through the HCI event. The bTM_EVENT_filter_complete callback is executed after the HCI_SET_EVENT_FILTER event is received
vendor/qcom/opensource/commonsys/system/bt/stack/btu/btu_hcif.cc
static void btu_hcif_hdl_command_complete(uint16_t opcode, uint8_t* p,
                                          uint16_t evt_len,
                                          void* p_cplt_cback) {
  switch (opcode) {
    case HCI_SET_EVENT_FILTER:
      btm_event_filter_complete(p);
Copy the code
  1. Back in btM_inq.cc, when the Event Complete callback is received, the BtM_Initiate_inquiry operation is officially executed
vendor/qcom/opensource/commonsys/system/bt/stack/btm/btm_inq.cc
else /* Initiate the Inquiry or Periodic Inquiry */
{
  p_inq->state = BTM_INQ_ACTIVE_STATE;
  p_inq->inqfilt_active = false;
  btm_initiate_inquiry(p_inq);
}
Copy the code
  1. Send hCI Command to bluetooth Controller to perform BR/EDR scan
vendor/qcom/opensource/commonsys/system/bt/stack/btm/btm_inq.cc
btsnd_hcic_inquiry(*lap, p_inqparms->duration, 0);
Copy the code
  1. Bluetooth scanning is an asynchronous process. When bluetooth Controller starts scanning, the protocol stack will receive the BTA_DM_BUSY_LEVEL_EVT event, which determines the current Level_flag. The current Bluetooth scan status is reported to the upper layer through DISCOVERy_state_changed_CB
vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_dm.cc
case BTA_DM_BUSY_LEVEL_EVT: {
    } else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_CANCELLED) {
      HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb,
                BT_DISCOVERY_STOPPED);
Copy the code
  1. After receiving the corresponding callback, the upper layer sends the current scan status to each recipient through broadcast
packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
static void discovery_state_changed_callback(bt_discovery_state_t state) {
    // ...
    sCallbackEnv->CallVoidMethod(
      sJniCallbacksObj, method_discoveryStateChangeCallback, (jint)state);
}
Copy the code
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/AdapterProperties.java void discoveryStateChangeCallback(int  state) { infoLog("Callback:discoveryStateChangeCallback with state:" + state); synchronized (mObject) { Intent intent; if ((state == AbstractionLayer.BT_DISCOVERY_STOPPED) && mDiscovering) { // ... } else if (state == AbstractionLayer.BT_DISCOVERY_STARTED) { // ... intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED); mService.sendBroadcast(intent, AdapterService.BLUETOOTH_PERM); }}}Copy the code
  1. Bluetooth scan status is the same process. When bluetooth Controller scans a device, it reports the corresponding device information
vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_dm.cc
/* Callback to notify upper layer of device */
HAL_CBACK(bt_hal_cbacks, device_found_cb, num_properties, properties);
Copy the code
  1. After receiving the scanned Bluetooth device information callback, the upper layer sends it to each receiver in the form of broadcast
packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp
static void device_found_callback(int num_properties,
                                  bt_property_t* properties) {
 // ...
  sCallbackEnv->CallVoidMethod(sJniCallbacksObj, method_deviceFoundCallback,
                               addr.get());
}
Copy the code
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/RemoteDevices.java void deviceFoundCallback(byte[] address) {/ /... Intent intent = new Intent(BluetoothDevice.ACTION_FOUND); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.putExtra(BluetoothDevice.EXTRA_CLASS, new BluetoothClass(deviceProp.mBluetoothClass)); intent.putExtra(BluetoothDevice.EXTRA_RSSI, deviceProp.mRssi); intent.putExtra(BluetoothDevice.EXTRA_NAME, deviceProp.mName); }Copy the code
  1. Process for connecting the BLE device for the first time

As can be seen from the sequence diagram above, the first connection of BLE device is actually divided into two steps:

  • Ble app register
  • Ble device connection

The following describes the call flow of Android code

  1. From the BLE scan of bluetoothdevices, select the device you want to connect and call connectGatt, where a BluetoothGatt object is new and then call gatt.connect
frameworks/base/core/java/android/bluetooth/BluetoothDevice.java
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
        BluetoothGattCallback callback, int transport,
        boolean opportunistic, int phy, Handler handler) {
    // ...
    try {
        IBluetoothGatt iGatt = managerService.getBluetoothGatt();
        // ...
        BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport, opportunistic, phy);
        gatt.connect(autoConnect, callback, handler);
        return gatt;
}
Copy the code
  1. In the Connect method of BluetoothGatt, a random UUID is generated for each registered app and then entered into the GattService of the Bluetooth process by calling the registerClient via aiDL
frameworks/base/core/java/android/bluetooth/BluetoothGatt.java
private boolean registerApp(BluetoothGattCallback callback, Handler handler) {
    // ...
    UUID uuid = UUID.randomUUID();
    try {
        mService.registerClient(new ParcelUuid(uuid), mBluetoothGattCallback);
    }
Copy the code
  1. GattService, would use the map to uuid and passed the callback to save, the follow-up protocol stack up the callback will be given out according to the map to do, and then continue to call down gattClientRegsiterAppNative native method
packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java
void registerClient(UUID uuid, IBluetoothGattCallback callback) {
    // ...
    mClientMap.add(uuid, null, callback, null, this);
    gattClientRegisterAppNative(uuid.getLeastSignificantBits(), uuid.getMostSignificantBits());
}
Copy the code
  1. In jNI method, the high uUID and low UUID are merged again and called to bluetooth protocol stack
packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static void gattClientRegisterAppNative(JNIEnv* env, jobject object,
                                        jlong app_uuid_lsb,
                                        jlong app_uuid_msb) {
  // ...
  Uuid uuid = from_java_uuid(app_uuid_msb, app_uuid_lsb);
  sGattIf->client->register_client(uuid);
}
Copy the code
  1. In btif_gattC_regsiter_app, create a task in the JNI Thread to handle the app register
vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_gatt_client.cc bt_status_t btif_gattc_register_app(const Uuid& uuid) { return do_in_jni_thread(Bind( [](const Uuid& uuid) { BTA_GATTC_AppRegister( bta_gattc_cback, base::Bind( [](const Uuid& uuid, uint8_t client_id, uint8_t status) { do_in_jni_thread(Bind( [](const Uuid& uuid, uint8_t client_id, uint8_t status) { HAL_CBACK(bt_gatt_callbacks, client->register_client_cb, status, client_id, uuid); }},Copy the code
  1. Create a task in the BTA thread and call bTA_gattc_regsiter
vendor/qcom/opensource/commonsys/system/bt/bta/gatt/bta_gattc_api.cc
void BTA_GATTC_AppRegister(tBTA_GATTC_CBACK* p_client_cb,
                           BtaAppRegisterCallback cb) {
  // ...
  do_in_bta_thread(FROM_HERE, base::Bind(&bta_gattc_register, Uuid::GetRandom(),
                                         p_client_cb, std::move(cb)));
}
Copy the code
  1. In the bta_gattc_register method, the for loop iterates through a maximum of 32 supported client applications. If the bta_gattc_register method is not currently in use, the GATT_Register method is called
vendor/qcom/opensource/commonsys/system/bt/bta/gatt/bta_gattc_act.cc /** Register a GATT client application with BTA */ void bta_gattc_register(const Uuid& app_uuid, tBTA_GATTC_CBACK* p_cback, BtaAppRegisterCallback cb) { // ... for (uint8_t i = 0; i < BTA_GATTC_CL_MAX; i++) { if (! bta_gattc_cb.cl_rcb[i].in_use) { if ((bta_gattc_cb.cl_rcb[i].client_if = GATT_Register(app_uuid, &bta_gattc_cl_cback)) == 0) { // .... }Copy the code
  1. Here we can see that up to 32 app client registers are traversed to find the one that is not yet used, the current client is registered, and the corresponding gatt_if is returned
vendor/qcom/opensource/commonsys/system/bt/stack/gatt/gatt_api.cc
tGATT_IF GATT_Register(const Uuid& app_uuid128, tGATT_CBACK* p_cb_info) {
  // ...
  for (i_gatt_if = 0, p_reg = gatt_cb.cl_rcb; i_gatt_if < GATT_MAX_APPS;
       i_gatt_if++, p_reg++) {
    if (!p_reg->in_use) {
      memset(p_reg, 0, sizeof(tGATT_REG));
      i_gatt_if++; /* one based number */
      p_reg->app_uuid128 = app_uuid128;
      gatt_if = p_reg->gatt_if = (tGATT_IF)i_gatt_if;
      return gatt_if;
    }
  }
Copy the code
  1. Bta_gattc_register = bTA_gattc_start_IF = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf = GATT_StartIf After that, if CB! = null, the register callback will be called
vendor/qcom/opensource/commonsys/system/bt/bta/gatt/bta_gattc_act.cc /** Register a GATT client application with BTA */ void bta_gattc_register(const Uuid& app_uuid, tBTA_GATTC_CBACK* p_cback, BtaAppRegisterCallback cb) { // ... if (! bta_gattc_cb.cl_rcb[i].in_use) { // ... } else { bta_gattc_cb.cl_rcb[i].in_use = true; bta_gattc_cb.cl_rcb[i].p_cback = p_cback; bta_gattc_cb.cl_rcb[i].app_uuid = app_uuid; /* BTA use the same client interface as BTE GATT statck */ client_if = bta_gattc_cb.cl_rcb[i].client_if; do_in_bta_thread(FROM_HERE, base::Bind(&bta_gattc_start_if, client_if)); status = GATT_SUCCESS; } } } } if (! cb.is_null()) cb.Run(client_if, status);Copy the code
  1. In the previous step, cb.run calls back the task in bt_status_btif_gattC_regsiter_app and then passes the result of register app and the assigned client ID to the JNI layer via register_client_CB
vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_gatt_client.cc
bt_status_t btif_gattc_register_app(const Uuid& uuid) {
    HAL_CBACK(bt_gatt_callbacks, client->register_client_cb,
            status, client_id, uuid);
}
Copy the code
  1. The Jni layer continues reporting through onClientRegistered
packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
void btgattc_register_app_cb(int status, int clientIf, const Uuid& app_uuid) {
  // ...
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientRegistered, status,
                               clientIf, UUID_PARAMS(app_uuid));
}
Copy the code
  1. When GattService receives a callback from JNI, it looks for the corresponding app in ClientMap using the uploaded UUID. If it finds one, it reports it to the framework
packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java
void onClientRegistered(int status, int clientIf, long uuidLsb, long uuidMsb)
        throws RemoteException {
    UUID uuid = new UUID(uuidMsb, uuidLsb);
    ClientMap.App app = mClientMap.getByUuid(uuid);
    if (app != null) {
        // ...     
        app.callback.onClientRegistered(status, clientIf);
    }
}
Copy the code
  1. BluetoothGatt, upon receipt of a return, calls clientConnect to formally initiate a BLE connection
frameworks/base/core/java/android/bluetooth/BluetoothGatt.java
public void onClientRegistered(int status, int clientIf) {
    // ...
    mClientIf = clientIf;
    try {
        mService.clientConnect(mClientIf, mDevice.getAddress(),
                !mAutoConnect, mTransport, mOpportunistic,
                mPhy); // autoConnect is inverse of "isDirect"
    } catch (RemoteException e) {
        Log.e(TAG, "", e);
    }
}
Copy the code
  1. In GattService, the JNI method gattClientConnectNative is called
packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java
void clientConnect(int clientIf, String address, boolean isDirect, int transport,
        boolean opportunistic, int phy) {
    // ...
    gattClientConnectNative(clientIf, address, isDirect, transport, opportunistic, phy);
}
Copy the code
  1. Client ->connect continues to call the protocol stack
packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
static void gattClientConnectNative(JNIEnv* env, jobject object, jint clientif,
                                    jstring address, jboolean isDirect,
                                    jint transport, jboolean opportunistic,
                                    jint initiating_phys) {
  // ...
  sGattIf->client->connect(clientif, str2addr(env, address), isDirect,
                           transport, opportunistic, initiating_phys);
}
Copy the code
  1. In bitF_gattC_open_IMPl, the bTA method BTA_GATTC_Open is called
vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_gatt_client.cc
void btif_gattc_open_impl(int client_if, RawAddress address, bool is_direct,
                          int transport_p, bool opportunistic,
                          int initiating_phys) {
  // ...
  BTA_GATTC_Open(client_if, address, is_direct, transport, opportunistic,
                 initiating_phys);
}
Copy the code
  1. Here, the BTA_GATTC_API_OPEN_EVT message is encapsulated and sent to bTA_gattc_act.cc via bTA_SYS_SENDMSG
vendor/qcom/opensource/commonsys/system/bt/bta/gatt/bta_gattc_api.cc
void BTA_GATTC_Open(tGATT_IF client_if, const RawAddress& remote_bda,
                    bool is_direct, tGATT_TRANSPORT transport,
                    bool opportunistic, uint8_t initiating_phys) {
  p_buf->hdr.event = BTA_GATTC_API_OPEN_EVT;
  p_buf->client_if = client_if;
  p_buf->is_direct = is_direct;
  // ...
  bta_sys_sendmsg(p_buf);
}
Copy the code
  1. Open a BLE connection through GATT_Connect
vendor/qcom/opensource/commonsys/system/bt/bta/gatt/bta_gattc_act.cc void bta_gattc_open(tBTA_GATTC_CLCB* p_clcb, tBTA_GATTC_DATA* p_data) { /* open/hold a connection */ if (! GATT_Connect(p_clcb->p_rcb->client_if, p_data->api_conn.remote_bda, true, p_data->api_conn.transport, p_data->api_conn.opportunistic, p_data->api_conn.initiating_phys)) { }Copy the code
  1. If true, gatt_act_connect initiates a direct connection. If false, gatt_act_connect determines whether the current connected peripheral is a known one. If not, gatt_act_connect returns the value of is_direct. Otherwise do passive connections in the background, our scenario is active connections, so is_direct is true and go to the gatt_act_connect call
vendor/qcom/opensource/commonsys/system/bt/stack/gatt/gatt_api.cc bool GATT_Connect(tGATT_IF gatt_if, const RawAddress& bd_addr, bool is_direct, tBT_TRANSPORT transport, bool opportunistic, uint8_t initiating_phys) { if (is_direct) { ret = gatt_act_connect(p_reg, bd_addr, transport, initiating_phys); } else { if (! BTM_BackgroundConnectAddressKnown(bd_addr)) { // RPA can rotate, causing address to "expire" in the background // connection list. RPA is allowed for direct connect, as such request // times out after 30 seconds LOG(INFO) << "Can't add RPA to background connection."; ret = true; } else { ret = connection_manager::background_connect_add(gatt_if, bd_addr); }}}Copy the code
  1. Add the peer device address to the direct connection list using the direct_CONNECt_add method of connection_manager
vendor/qcom/opensource/commonsys/system/bt/stack/gatt/gatt_main.cc
bool gatt_connect(const RawAddress& rem_bda, tGATT_TCB* p_tcb,
                  tBT_TRANSPORT transport, uint8_t initiating_phys,
                  tGATT_IF gatt_if) {
  p_tcb->att_lcid = L2CAP_ATT_CID;
  return connection_manager::direct_connect_add(gatt_if, rem_bda);
}
Copy the code
  1. The system checks whether the peer MAC address is in the whitelist. If not, the peer MAC address is added to the whitelist
vendor/qcom/opensource/commonsys/system/bt/stack/gatt/connection_manager.cc bool direct_connect_add(uint8_t app_id, const RawAddress& address) { // ... if (! in_white_list) { if (! BTM_WhiteListAdd(address)) { // ... }Copy the code
  1. If the current whitelist is not full, add the address to the controller whitelist. The automatic connection is then started by calling BtM_SEND_hci_create_connection to send hCI Command to the controller for execution
vendor/qcom/opensource/commonsys/system/bt/stack/btm/btm_ble_bgconn.cc
bool BTM_WhiteListAdd(const RawAddress& address) {
  if (background_connections_count() ==
      controller_get_interface()->get_ble_white_list_size()) {
    BTM_TRACE_ERROR("%s Whitelist full, unable to add device", __func__);
    return false;
  }
  btm_add_dev_to_controller(true, address);
  btm_ble_resume_bg_conn();
  return true;
}
Copy the code
vendor/qcom/opensource/commonsys/system/bt/stack/btm/btm_ble_bgconn.cc
bool btm_ble_start_auto_conn() {
  // ...
  btm_send_hci_create_connection(
      scan_int,                       /* uint16_t scan_int      */
      scan_win,                       /* uint16_t scan_win      */
      0x01,                           /* uint8_t white_list     */
      peer_addr_type,                 /* uint8_t addr_type_peer */
      RawAddress::kEmpty,             /* BD_ADDR bda_peer     */
      own_addr_type,                  /* uint8_t addr_type_own */
      BTM_BLE_CONN_INT_MIN_DEF,       /* uint16_t conn_int_min  */
      BTM_BLE_CONN_INT_MAX_DEF,       /* uint16_t conn_int_max  */
      BTM_BLE_CONN_SLAVE_LATENCY_DEF, /* uint16_t conn_latency  */
      BTM_BLE_CONN_TIMEOUT_DEF,       /* uint16_t conn_timeout  */
      0,                              /* uint16_t min_len       */
      0,                              /* uint16_t max_len       */
      phy);
}
Copy the code
  1. After an ACL link is established and the BLE connection is successful, the controller reports the BTA_GATTC_OPEN_EVT to the protocol stack, and then reports the BTA_GATTC_OPEN_EVT to the JNI through open_CB
vendor/qcom/opensource/commonsys/system/bt/btif/src/btif_gatt_client.cc
case BTA_GATTC_OPEN_EVT: {
  HAL_CBACK(bt_gatt_callbacks, client->open_cb, p_data->open.conn_id,
            p_data->open.status, p_data->open.client_if,
            p_data->open.remote_bda);
}
Copy the code
  1. Jni receives a callback and finds the corresponding Java layer method onConnected to continue reporting
packages/apps/Bluetooth/jni/com_android_bluetooth_gatt.cpp
void btgattc_open_cb(int conn_id, int status, int clientIf,
                     const RawAddress& bda) {
  // ...
  sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnected, clientIf,
                               conn_id, status, address.get());
}
Copy the code
  1. If the BLE connection is successful, the peer address and the corresponding client ID are added to the clientMap, and then the corresponding APP is extracted from the previously registered clientMap. The BLE connection status is notified to the APP through onClientConnectionState
packages/apps/Bluetooth/src/com/android/bluetooth/gatt/GattService.java
void onConnected(int clientIf, int connId, int status, String address) throws RemoteException {
    // ... 
    if (status == 0) {
        mClientMap.addConnection(clientIf, connId, address);
    }
    ClientMap.App app = mClientMap.getById(clientIf);
    if (app != null) {
        app.callback.onClientConnectionState(status, clientIf,
                (status == BluetoothGatt.GATT_SUCCESS), address);
    }
}
Copy the code

Chapter 3 New Android R Bluetooth features

With the release of Google’s new Android R operating system, here’s a look at what’s added to the Bluetooth module

PBAP likes group synchronization

This Favorite grouping was defined in BAP1.2.1, but was not implemented in previous Versions of Android. If Pbap synchronization is performed between mobile phone and vehicle device before, only missed call records, call records, call records, merge call records (including call, call, missed call records) and contact book can be pulled from mobile phone.

// missed call history
private static final String MCH = "mch";
// incoming call history
private static final String ICH = "ich";
// outgoing call history
private static final String OCH = "och";
// combined call history
private static final String CCH = "cch";
// phone book
private static final String PB = "pb";
Copy the code

On Android R, it’s finally here. With this synchronous contact group, users only need to add common contacts to Favorite group, and then synchronize only the contacts saved in Favorite during the next on-board synchronization.

// favorites
private static final String FAV = "fav";
private static final String FAV_PATH = "/telecom/fav";
Copy the code

2. Bluetooth keyStore mechanism

The Android keyStore System allows developers to store encryption keys in containers, making it more difficult to extract keys from devices. Once the keys are in the keystore, they can be used for encryption operations, while the key material remains unexportable. In addition, it provides restrictions on when and how the key can be used, such as requiring user authentication to use the key, or limiting it to use only in certain encryption modes.

Conf file is stored in the /data/misc/bluedroid/ directory in plain text. If bt_config.conf is stolen due to external attacks, the bt_config.conf file is stored in the /data/misc/bluedroid/ directory. Sniffer software can be used to monitor all communication with the peer bluetooth, including phone music and some private data, which is very dangerous.

On Android R, Google introduced KeyStore system to encrypt and decrypt keys in bt_config.conf, which is not presented in plaintext, greatly improving security.

packages/apps/Bluetooth/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreService.java private @Nullable String encrypt(String data) { BluetoothKeystoreProto.EncryptedData protobuf; byte[] outputBytes; String outputBase64 = null; try { if (data == null) { errorLog("encrypt: data is null"); return outputBase64; } Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); SecretKey secretKeyReference = getOrCreateSecretKey(); if (secretKeyReference ! = null) { cipher.init(Cipher.ENCRYPT_MODE, secretKeyReference); protobuf = BluetoothKeystoreProto.EncryptedData.newBuilder() .setEncryptedData(ByteString.copyFrom(cipher.doFinal(data.getBytes()))) .setInitVector(ByteString.copyFrom(cipher.getIV())).build(); outputBytes = protobuf.toByteArray(); if (outputBytes == null) { errorLog("encrypt: Failed to serialize EncryptedData protobuf."); return outputBase64; } outputBase64 = mEncoder.encodeToString(outputBytes); }Copy the code
packages/apps/Bluetooth/src/com/android/bluetooth/btservice/bluetoothKeystore/BluetoothKeystoreService.java private @Nullable String decrypt(String encryptedDataBase64) { BluetoothKeystoreProto.EncryptedData protobuf; byte[] encryptedDataBytes; byte[] decryptedDataBytes; String output = null; try { if (encryptedDataBase64 == null) { errorLog("decrypt: encryptedDataBase64 is null"); return output; } encryptedDataBytes = mDecoder.decode(encryptedDataBase64); protobuf = BluetoothKeystoreProto.EncryptedData.parser().parseFrom(encryptedDataBytes); Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, protobuf.getInitVector().toByteArray()); SecretKey secretKeyReference = getOrCreateSecretKey(); if (secretKeyReference ! = null) { cipher.init(Cipher.DECRYPT_MODE, secretKeyReference, spec); decryptedDataBytes = cipher.doFinal(protobuf.getEncryptedData().toByteArray()); output = new String(decryptedDataBytes); }Copy the code

Bluetooth added to apex upgrade

In order to solve the problem of serious fragmentation of The Android system, Google introduced a container format Android Pony EXpress (APEX) in Android 10 to be used in the installation process of lower level system modules. This format helps update system components that do not fit into the standard Android application model.

On Android R, the Bluetooth module is included in the Apex upgrade package, which helps the demand update of Bluetooth module to be adapted and modified by relevant app developers in a faster time.

packages/apps/Bluetooth/Android.bp
 
required: ["libbluetooth"],
    apex_available: [
        "//apex_available:platform",
        "com.android.bluetooth.updatable",
    ],
Copy the code

Avrcp Controller Cover Art & Play Mode (Automotive)

Cover Art is the album Cover of a song. In early versions of Android Automotive, AVRCP did not implement the synchronization of Cover Art, so when the phone and car are connected to listen to music, the car cannot get the album Cover of the song played on the other end.

With the latest Android R, Google has implemented Cover Art delivery, which allows more song information to be synchronized in real time via Bluetooth.

Main implementation classes:

packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtManager.java

packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtProvider.java

packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpCoverArtStorage.java

packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpBipClient.java

The play mode is the way that the music player plays songs, generally divided into single cycle, random play and sequence play three modes. Previous versions of Android Automotive did not support single loop and random mode Settings. On Android R, Google implements the avRCP control of these two modes, allowing users to switch the playing mode of mobile music directly from the car terminal.

packages/apps/Bluetooth/src/com/android/bluetooth/avrcpcontroller/AvrcpControllerStateMachine.java
static final int MSG_AVRCP_SET_SHUFFLE = 303;
static final int MSG_AVRCP_SET_REPEAT = 304;
private void setRepeat(int repeatMode) {
    mService.setPlayerApplicationSettingValuesNative(mDeviceAddress, (byte) 1,
        new byte[]{PlayerApplicationSettings.REPEAT_STATUS}, new byte[]{
            PlayerApplicationSettings.mapAvrcpPlayerSettingstoBTattribVal(
                PlayerApplicationSettings.REPEAT_STATUS, repeatMode)});
}
private void setShuffle(int shuffleMode) {
    mService.setPlayerApplicationSettingValuesNative(mDeviceAddress, (byte) 1,
        new byte[]{PlayerApplicationSettings.SHUFFLE_STATUS}, new byte[]{
            PlayerApplicationSettings.mapAvrcpPlayerSettingstoBTattribVal(
                PlayerApplicationSettings.SHUFFLE_STATUS, shuffleMode)});
}
Copy the code

Chapter 4 Analysis of Bluetooth compatibility problems

I. When the car of BRAND A is connected to the mobile phone, it switches from the music app to Douyin, and The Contents of Douyin play normally, while the headset has no sound

Problem analysis

  • Description: AvDTP signaling starts the audio stream and sends the audio stream ok

  • Check whether the avRCP status is OK. Look down the avRCP status on the vehicle from the avDTP stream start time node. After AVDTP stream start, the play status of the mobile phone changes to playing, which is OK, but after 9s, The play Status is set to Paused, which is incorrect if there is no paused action on the phone

  • It was further confirmed with adb log that when music was active, mediaController reported the wrong playState 2, resulting in the vehicle receiving the AVRCP paused instruction and ignoring the subsequent avDTP stream received, resulting in no sound on the vehicle
// final static byte PLAYSTATUS_STOPPED = 0; // final static byte PLAYSTATUS_PLAYING = 1; // final static byte PLAYSTATUS_PAUSED = 2; 31656 31770 V Avrcp_ext: newPlayStatus:2mReportedPlayStatus:-1 31770 V Avrcp_ext: updatePlaybackState, state: PlaybackState {state=2, position=8406, Buffered Position =0, Speed =1.0, updated=10990642, Actions =695, custom actions=[], active item id=-1, error=null} device: nullCopy the code

Problem solving

Add the three-digit MAC address representing this model to the blacklist updated by PlayStatus through MAC address filtering. For this model, when requesting PlayStatus, it is necessary to judge the status of A2dp playState and musicActive at the same time. Make sure playStatus updates are correct.

private static final String playerStateUpdateBlackListedAddr[] = {
     "BC:30:7E", //bc-30-7e-5e-f6-27, Name: Porsche BT 0310; bc-30-7e-8c-22-cb, Name: Audi MMI 1193
     "2C:DC:AD", //2C-DC-AD-BB-2F-25, Name: PORSCHE
     "00:1E:43", //00-1e-43-14-f0-68, Name: Audi MMI 4365
     "9C:DF:03", //9C:DF:03:D3:C0:17, Name: Benz S600L
     "00:0A:08",  //00:0A:08:51:1E:E7, Name: BMW530
// ...
Copy the code

Ii. B brand earphone and mobile phone connected, playing music silent

Problem analysis

  • Check the status of avDTP stream and find that there is only open and no start, which proves that audio does not actually start to send audio. Therefore, we guess that there may be something wrong with audio select device or start output stream

  • Query related logs. The following abnormal logs are found:
858 31680 E audio_hw_primary: out_set_parameters: A2DP profile is not ready,ignoring routing request 
858 22492 D audio_hw_primary: start_output_stream: enter: stream(0xe9286800)usecase(0: deep-buffer-playback) devices(0x80) is_haptic_usecase(0), regdump_on(0)
858 22492 E audio_hw_primary: start_output_stream: A2DP profile is not ready, return error
Copy the code

When audio displays start_output_stream, the A2dp Profile is not ready. As a result, the routing fails

8709  8893 I AudioManager: In startbluetoothSco(), calling application: com.tencent.mm
1453  3033 I AS.BtHelper: In connectBluetoothScoAudioHelper(), calling startScoUsingVirtualVoiceCallEx()                                                                              
1453  3033 D BluetoothHeadset: startScoUsingVirtualVoiceCall()
13084 13201 D HeadsetService: startScoUsingVirtualVoiceCall, Calling : 8709
13084 13201 I HeadsetService: startScoUsingVirtualVoiceCall: uid/pid=1000/1453
Copy the code
  • Cut down the audio routing failure continue to forward queries related to the log, found on a2dp connection, WeChat startScoUsingVirtualVoiceCall initiative to call, this is called an exception. Normal logic, this function will only be triggered when WeChat dial telephone voice to create sco links, and voice over, stopScoUsingVirtualVoiceCall WeChat will call release sco links.

Problem solving

Through the above analysis, the conclusion is that after monitoring Hfp Connected, a certain version of wechat mistakenly requested SCO link, resulting in the subsequent music playing is silent because the audio channel is occupied and cannot be switched. The feedback is sent to wechat to update relevant codes to solve the problem.