Summary of Low Energy Bluetooth in Android

(Star this for Selected Android Development)

Source: Android Developer Community

First, we need to clarify one point: the Bluetooth broadcast packet we obtain through the Android SDK is a 62-byte array that has been processed by the underlying SDK. How is this 62-byte array generated?

To understand this, we first need to know what the original broadcast packet sent by <span>iBeacon</span> looks like.

Bluetooth data transmission is divided into two parts: normal broadcast packets and response packets. This is stipulated by the Bluetooth protocol for all Bluetooth devices (iBeacon is just one type of Bluetooth device).

  • The format of a normal broadcast packet is predefined, with a length of <span>30 byte</span>

  • The contents of the response packet can be filled by various manufacturers as they wish, with a maximum length of <span>32 byte</span>

It is important to note that data is sent from the low byte to the high byte, so the received data needs to be concatenated byte by byte. For example, if the received MAC is 8b 03 00 b0 01 c2, the actual MAC is c2:01:b0:00:03:8b.

Bluetooth Broadcast Packet

First, let’s take a look at the first Bluetooth broadcast packet (from an iBeacon device), which consists of 59 bytes:

04 3e 38 0d 01 13 00 01 8b 03 00 b0 01 c2 01 00 ff 7f af 00 00 00 00 00 00 00 00 00 1e       29 bytes
02 01 06 1a ff 4c 00 02 15 fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25 27 11 4c b9 c5  30 bytes

The content of the first line can be considered as the auxiliary information in the Bluetooth broadcast packet, which cannot be seen through the Android SDK. The second line corresponds to the first part of the broadcast packet we receive in the Android SDK.

The first byte is HCI Packet Type, 04 indicates this is an HCI Event; the remaining 58 bytes are the specific content of the HCI Event.
The second byte is Event Code, 3e is the code for this event; the third byte is Parameter Length, 0x38 (decimal 56) indicates the length of the following data is 56 bytes.
The fourth byte is Sub Event, 0d indicates this is an LE Extended Advertising Report; the fifth byte is Num Reports, which is 01.
1b 00 these two bytes represent Event Type; since data is sent byte by byte and from low to high, the actual value is 001b.
01 indicates this is a random device address.
8b 03 00 b0 01 c2 is the MAC of this device; according to the low to high sending rule, the real MAC is c2:01:b0:00:03:8b.
01 represents the bandwidth of the primary broadcast channel.
00 represents the bandwidth of the secondary broadcast channel, indicating that the secondary channel is not in use.
ff represents the broadcast SID.
7f represents the size of Tx Power, which is 127dbm.
af represents the size of RSSI, which is -81dbm.
00 00 represents the periodic broadcast interval.
00 represents the direct address type, which is a public device address.
00 00 00 00 00 00 represents the direct BD_ADDR.
1e represents the length of the following data; the following data is the most important broadcast data.

The above content corresponds to the explanation of the first line. In fact, the Android SDK has already parsed some of the content from this data, and we can directly obtain it through the corresponding SDK methods.

Next, let’s look at the real broadcast packet.

The format is as follows:

Summary of Low Energy Bluetooth in Android

A broadcast packet consists of several broadcast units called AD Structures. Each AD Structure consists of: the first byte indicates the length value, length, indicating that the next length bytes are the data part; the first byte of the data part indicates the data type AD Type, which determines what the following data represents. For more information on each value’s data type, see the official documentation. The remaining length – 1 bytes represent the actual data.

02 01 06  

02 indicates the next data has two bytes. 01 indicates the data type, which is Flags. 06 is the specific value, 0x06 = 0000 0110, each bit has different meanings, see the official documentation.
Summary of Low Energy Bluetooth in Android
1a ff 4c 00 02 15 fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25 27 11 4c b9 c5

1a indicates that the next data has 26 bytes.
FF indicates the data type, which is a vendor-specific data type (here the vendor refers to Apple, as iBeacon was proposed by Apple).
4C 00 indicates the company ID, where 004C represents Apple.
02 15 is the Beacon identifier, which must be in this format.
fd a5 06 93 a4 e2 4f b1 af cf c6 eb 07 64 78 25 indicates the Beacon UUID.
27 11 is the major value.
4C b9 is the minor value.
C5 indicates Measured Power, which is the RSSI value of this device at 1 meter, used for distance estimation.

This section mainly defines the data based on the Bluetooth protocol by Apple.

If it matches 1AFF4C000215, it indicates that this device is an <span>iBeacon</span> device.

Bluetooth Response Packet

04 3e 38 0d 01 1b 00 01 8b 03 00 b0 01 c2 01 00 ff 7f af 00 00 00 00 00 00 00 00 00 1e      29 bytes
02 0a 00 08 16 f0 ff 64 27 11 4c b9 11 09 4d 69 6e 69 42 65 61 63 6f 6e 5f 30 30 39 30 37   30 bytes
The first line is the same as above, so we will not introduce it again.

02 0a 00 
02 indicates the next data length is 2 bytes.
0a indicates the data type, which indicates Tx Power Level, with a range of -127 to 127 dBm.
00 indicates 0 dBm.

08 16 f0 ff 64 27 11 4c b9
08 indicates the data length.
16 indicates Service Data, consisting of Service UUID and service data; the first two bytes are UUID, and the rest are data.
f0ff is the Service UUID.
64 27 11 4c b9 is the data.

11 09 4d 69 6e 69 42 65 61 63 6f 6e
11 indicates the data length.
09 indicates the complete name of the device.
4d 69 6e 69 42 65 61 63 6f 6e is the ASCII code of the device name, corresponding to MiniBeacon.
M   i n  i  B  e  a  c  o  n 

5f 30 30 39 30 37
These data are arbitrary data added by the Beacon developer, not conforming to the protocol content.

Receiving Broadcast Packets in Android

We have analyzed the broadcast and response packets in the original Bluetooth data packet. For <span>iBeacon</span>, most contents in the broadcast packet are fixed, only <span>UUID Major Minor</span> will vary. Moreover, the function of each position has already been defined by <span>Apple</span>. If we want the data packets sent by <span>iBeacon</span> to contain more content, we can add data in the response packet, which has 32 bytes. We just need to add data to the response packet according to the protocol.

For the Android client, the broadcast packet obtained through <span>Scanresult.getScanRecord().getBytes()</span> is <span>62</span> bytes long. It extracts the content from the original data packet and retains only the second line content: the Bluetooth broadcast packet second line (30 bytes) + Bluetooth response packet second line (up to 32 bytes, uncertain number), and if there are not enough bits, it is padded with 0.

Therefore, we can now easily parse the broadcast packet based on the obtained byte[] array.

// Now we get the broadcast packet
byte[] result = ScanResult.getScanRecord().getBytes();
// UUID  includes result[9] and result[24]
result[9]---result[24];
// Major
result[25]  result[26];
// Minor
result[27]   result[28];    
// Measured Power
result[29];

// Generally, we will first convert the broadcast packet to hex format and then extract
String uuid = broadcast.substring(18, 50);   

// As for the content of the response packet, it needs to be parsed according to the specific broadcast packet format. For example, if your company's hardware developers put the battery level in it, then you just need to agree on where to put it, and you can directly take it later.
About the Methods in ScanResult
Summary of Low Energy Bluetooth in Android

The contents obtained from these methods are not directly parsed from the broadcast received in Android (ScanResult.getScanRecord().getBytes()), but are parsed from the original data packet.

<span>getTxPower</span> retrieves the transmission power. If this iBeacon does not support it, the result is 127.

The following methods are not very significant; it mainly depends on whether the device supports them.

Key Methods

Summary of Low Energy Bluetooth in Android

<span>ScanRecord</span> contains several important methods related to the broadcast packet we received.

For example, if the response packet sets the <span>Tx Power Level</span>, we can directly retrieve it using <span>getTxPowerLevel()</span>. In the example above, by calling the method <span>getTxPowerLevel()</span>, we can get 0.

Other methods are similar; as long as the data format in your response packet is correct, it can be parsed.

For example:

For instance, the broadcast packet received by the Android side is:

0201061AFF4C0002150123456789ABCDEF0123456789ABCDEF00000007C5   Broadcast Packet

020A00    0303F1FF  0E16F1FF6400000007AC233F66C401   070965526F7574650000  Response Packet

<span>getTxPowerLevel()</span> returns 0 because the response packet contains correctly formatted data <span>020A00</span>

<span>getServiceData()</span> will also return a value because the response packet contains corresponding data <span>0E16F1FF6400000007AC233F66C401</span>

0E indicates data length.
16 indicates type, which indicates Service Data - 16-bit UUID (not only UUID but also data); the first two bytes indicate UUID, and the rest is data.
F1FF indicates UUID.

6400000007AC233F66C401  indicates data.

Map<ParcelUuid, byte[]>  getServiceData() returns values in the form of key-value pairs using UUID and data.
Here, the contents of the returned Map collection are: Note: the changing UUID will not change the other digits; if the broadcast packet UUID is not F1FF, just replace it accordingly.
ParcelUuid = ParcelUuid.fromString("0000fff1-0000-1000-8000-00805f9b34fb");
byte[] is the corresponding byte value of the data part.

<span>List<ParcelUuid> getServiceUuids()</span> method corresponds to the data in the response packet <span>0303F1FF</span> Since it appears only once, the size of the list is only one, which is <span>F1FF</span> The corresponding ParcelUuid is <span>ParcelUuid.fromString("0000fff1-0000-1000-8000-00805f9b34fb");</span>

The following methods are also derived from the parsing of the 62-byte broadcast packet received on the Android side.

<span>String getDeviceName()</span> retrieves the name, requiring corresponding data in the broadcast packet <span>070965526F7574650000</span>

<span>SpareArray<byte[]> getManufacturerSpecificaData()</span> retrieves manufacturer data, corresponding to <span>4C000215</span>

<span>byte[] getManufacturerSpecificData(int manufacture)</span> retrieves byte data based on the manufacturer code (4c corresponds to decimal).

Data Type Correspondence Table

Some fields are still not translated finely enough; for details, see the official documentation: https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile/

Summary of Low Energy Bluetooth in Android

– EOF –

Summary of Low Energy Bluetooth in Android

Recommended Reading Click the title to jump

1. Android 11 will remove third-party camera functionality

2. Android 10 compatibility guide, have you adapted?

3. Android 11 Developer Preview released: brings many new features

If you gained something from this article, please share it with more people.

Follow ‘Selected Android Development’ to improve your Android development skills

Summary of Low Energy Bluetooth in Android

Good article, I am reading it❤️

Leave a Comment