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

Commit dfbb839c authored by Jakub Pawlowski's avatar Jakub Pawlowski Committed by android-build-merger
Browse files

Merge "Change how Advertise Data is passed to BTIF (3/3)"

am: fd121217

Change-Id: I427d27acf325b4319bd10e0942a3233440b5c0eb
parents 8a400b2f fd121217
Loading
Loading
Loading
Loading
+15 −41
Original line number Diff line number Diff line
@@ -1097,30 +1097,16 @@ static void gattAdvertiseNative(JNIEnv *env, jobject object,
    sGattIf->client->listen(client_if, start);
}

static void gattSetAdvDataNative(JNIEnv *env, jobject object, jint client_if,
        jboolean setScanRsp, jboolean inclName, jboolean inclTxPower, jint minInterval,
        jint maxInterval, jint appearance, jbyteArray manufacturerData, jbyteArray serviceData,
        jbyteArray serviceUuid)
static void gattSetAdvDataNative(JNIEnv *env, jobject object,
                                 jboolean setScanRsp, jbyteArray data)
{
    if (!sGattIf) return;
    jbyte* arr_data = env->GetByteArrayElements(manufacturerData, NULL);
    uint16_t arr_len = (uint16_t) env->GetArrayLength(manufacturerData);
    vector<uint8_t> data(arr_data, arr_data + arr_len);
    env->ReleaseByteArrayElements(manufacturerData, arr_data, JNI_ABORT);
    jbyte* data_data = env->GetByteArrayElements(data, NULL);
    uint16_t data_len = (uint16_t) env->GetArrayLength(data);
    vector<uint8_t> data_vec(data_data, data_data + data_len);
    env->ReleaseByteArrayElements(data, data_data, JNI_ABORT);

    jbyte* arr_service_data = env->GetByteArrayElements(serviceData, NULL);
    uint16_t arr_service_data_len = (uint16_t) env->GetArrayLength(serviceData);
    vector<uint8_t> service_data(arr_service_data, arr_service_data + arr_service_data_len);
    env->ReleaseByteArrayElements(serviceData, arr_service_data, JNI_ABORT);

    jbyte* arr_service_uuid = env->GetByteArrayElements(serviceUuid, NULL);
    uint16_t arr_service_uuid_len = (uint16_t) env->GetArrayLength(serviceUuid);
    vector<uint8_t> service_uuid(arr_service_uuid, arr_service_uuid + arr_service_uuid_len);
    env->ReleaseByteArrayElements(serviceUuid, arr_service_uuid, JNI_ABORT);

    sGattIf->advertiser->SetData(client_if, setScanRsp, inclName, inclTxPower,
        minInterval, maxInterval, appearance, std::move(data),
        std::move(service_data), std::move(service_uuid));
    sGattIf->advertiser->SetData(setScanRsp, std::move(data_vec));
}

static void gattSetScanParametersNative(JNIEnv* env, jobject object,
@@ -1387,28 +1373,16 @@ static void gattClientSetAdvParamsNative(JNIEnv* env, jobject object, jint adver
}

static void gattClientSetAdvDataNative(JNIEnv* env, jobject object, jint advertiser_id,
        jboolean set_scan_rsp, jboolean incl_name, jboolean incl_txpower, jint appearance,
        jbyteArray manufacturer_data,jbyteArray service_data, jbyteArray service_uuid)
        jboolean set_scan_rsp, jbyteArray data)
{
    if (!sGattIf) return;
    jbyte* manu_data = env->GetByteArrayElements(manufacturer_data, NULL);
    uint16_t manu_len = (uint16_t) env->GetArrayLength(manufacturer_data);
    vector<uint8_t> manu_vec(manu_data, manu_data + manu_len);
    env->ReleaseByteArrayElements(manufacturer_data, manu_data, JNI_ABORT);

    jbyte* serv_data = env->GetByteArrayElements(service_data, NULL);
    uint16_t serv_data_len = (uint16_t) env->GetArrayLength(service_data);
    vector<uint8_t> serv_data_vec(serv_data, serv_data + serv_data_len);
    env->ReleaseByteArrayElements(service_data, serv_data, JNI_ABORT);

    jbyte* serv_uuid = env->GetByteArrayElements(service_uuid, NULL);
    uint16_t serv_uuid_len = (uint16_t) env->GetArrayLength(service_uuid);
    vector<uint8_t> serv_uuid_vec(serv_uuid, serv_uuid + serv_uuid_len);
    env->ReleaseByteArrayElements(service_uuid, serv_uuid, JNI_ABORT);
    jbyte* data_data = env->GetByteArrayElements(data, NULL);
    uint16_t data_len = (uint16_t) env->GetArrayLength(data);
    vector<uint8_t> data_vec(data_data, data_data + data_len);
    env->ReleaseByteArrayElements(data, data_data, JNI_ABORT);

    sGattIf->advertiser->MultiAdvSetInstData(
        advertiser_id, set_scan_rsp, incl_name, incl_txpower, appearance,
        std::move(manu_vec), std::move(serv_data_vec), std::move(serv_uuid_vec),
        advertiser_id, set_scan_rsp, std::move(data_vec),
        base::Bind(&ble_advertiser_setadv_data_cb, advertiser_id));
}

@@ -1648,9 +1622,9 @@ static JNINativeMethod sAdvertiseMethods[] = {
    {"registerAdvertiserNative", "(JJ)V", (void *) registerAdvertiserNative},
    {"unregisterAdvertiserNative", "(I)V", (void *) unregisterAdvertiserNative},
    {"gattClientSetParamsNative", "(IIIIII)V", (void *) gattClientSetAdvParamsNative},
    {"gattClientSetAdvDataNative", "(IZZZI[B[B[B)V", (void *) gattClientSetAdvDataNative},
    {"gattClientSetAdvDataNative", "(IZ[B)V", (void *) gattClientSetAdvDataNative},
    {"gattClientEnableAdvNative", "(IZI)V", (void *) gattClientEnableAdvNative},
    {"gattSetAdvDataNative", "(IZZZIII[B[B[B)V", (void *) gattSetAdvDataNative},
    {"gattSetAdvDataNative", "(Z[B)V", (void *) gattSetAdvDataNative},
    {"gattAdvertiseNative", "(IZ)V", (void *) gattAdvertiseNative},
};

+1 −1
Original line number Diff line number Diff line
@@ -1507,7 +1507,7 @@ public class AdapterService extends Service {
        return mAdapterProperties.getUuids();
    }

     String getName() {
    public String getName() {
        enforceCallingOrSelfPermission(BLUETOOTH_PERM,
                                       "Need BLUETOOTH permission");

+148 −73
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import com.android.bluetooth.btservice.AdapterService;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.io.ByteArrayOutputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@@ -390,82 +391,158 @@ class AdvertiseManager {
            }
        }

        private void setAdvertisingData(AdvertiseClient client, AdvertiseData data,
                boolean isScanResponse) {
            if (data == null) {
                return;
            }
            boolean includeName = data.getIncludeDeviceName();
            boolean includeTxPower = data.getIncludeTxPowerLevel();
            int appearance = 0;
            byte[] manufacturerData = getManufacturerData(data);
        private static final int DEVICE_NAME_MAX = 18;

        private static final int COMPLETE_LIST_16_BIT_SERVICE_UUIDS = 0X03;
        private static final int COMPLETE_LIST_32_BIT_SERVICE_UUIDS = 0X05;
        private static final int COMPLETE_LIST_128_BIT_SERVICE_UUIDS = 0X07;
        private static final int SHORTENED_LOCAL_NAME = 0X08;
        private static final int COMPLETE_LOCAL_NAME = 0X09;
        private static final int TX_POWER_LEVEL = 0x0A;
        private static final int SERVICE_DATA_16_BIT_UUID = 0X16;
        private static final int SERVICE_DATA_32_BIT_UUID = 0X20;
        private static final int SERVICE_DATA_128_BIT_UUID = 0X21;
        private static final int MANUFACTURER_SPECIFIC_DATA = 0XFF;

        private byte[] advertiseDataToBytes(AdvertiseData data) {
            // Flags are added by lower layers of the stack, only if needed;
            // no need to add them here.

            byte[] serviceData = getServiceData(data);
            byte[] serviceUuids;
            if (data.getServiceUuids() == null) {
                serviceUuids = new byte[0];
            ByteArrayOutputStream ret = new ByteArrayOutputStream();

            if (data.getIncludeDeviceName()) {
                String name = mAdapterService.getName();
                try {
                    byte[] nameBytes = name.getBytes("UTF-8");

                    int nameLength = nameBytes.length;
                    byte type;

                    // TODO(jpawlowski) put a better limit on device name!
                    if (nameLength > DEVICE_NAME_MAX) {
                      nameLength = DEVICE_NAME_MAX;
                      type = SHORTENED_LOCAL_NAME;
                    } else {
                ByteBuffer advertisingUuidBytes = ByteBuffer.allocate(
                        data.getServiceUuids().size() * 16)
                        .order(ByteOrder.LITTLE_ENDIAN);
                for (ParcelUuid parcelUuid : data.getServiceUuids()) {
                    UUID uuid = parcelUuid.getUuid();
                    // Least significant bits first as the advertising UUID should be in
                    // little-endian.
                    advertisingUuidBytes.putLong(uuid.getLeastSignificantBits())
                            .putLong(uuid.getMostSignificantBits());
                }
                serviceUuids = advertisingUuidBytes.array();
                      type = COMPLETE_LOCAL_NAME;
                    }
            if (mAdapterService.isMultiAdvertisementSupported()) {
                gattClientSetAdvDataNative(client.advertiserId, isScanResponse, includeName,
                        includeTxPower, appearance,
                        manufacturerData, serviceData, serviceUuids);
            } else {
                gattSetAdvDataNative(client.advertiserId, isScanResponse, includeName,
                        includeTxPower, 0, 0, appearance,
                        manufacturerData, serviceData, serviceUuids);

                    ret.write(nameLength + 1);
                    ret.write(type);
                    ret.write(nameBytes, 0, nameLength);
                } catch (java.io.UnsupportedEncodingException e) {
                    loge("Can't include name - encoding error!", e);
                }
            }

        // Combine manufacturer id and manufacturer data.
        private byte[] getManufacturerData(AdvertiseData advertiseData) {
            if (advertiseData.getManufacturerSpecificData().size() == 0) {
                return new byte[0];
            }
            int manufacturerId = advertiseData.getManufacturerSpecificData().keyAt(0);
            byte[] manufacturerData = advertiseData.getManufacturerSpecificData().get(
            for (int i = 0; i< data.getManufacturerSpecificData().size(); i++) {
                int manufacturerId = data.getManufacturerSpecificData().keyAt(i);

                byte[] manufacturerData = data.getManufacturerSpecificData().get(
                        manufacturerId);
                int dataLen = 2 + (manufacturerData == null ? 0 : manufacturerData.length);
                byte[] concated = new byte[dataLen];
            // / First two bytes are manufacturer id in little-endian.
                // First two bytes are manufacturer id in little-endian.
                concated[0] = (byte) (manufacturerId & 0xFF);
                concated[1] = (byte) ((manufacturerId >> 8) & 0xFF);
                if (manufacturerData != null) {
                    System.arraycopy(manufacturerData, 0, concated, 2, manufacturerData.length);
                }
            return concated;

                ret.write(concated.length + 1);
                ret.write(MANUFACTURER_SPECIFIC_DATA);
                ret.write(concated, 0, concated.length);
            }

            if (data.getIncludeTxPowerLevel()) {
                ret.write(2 /* Length */);
                ret.write(TX_POWER_LEVEL);
                ret.write(0);  // lower layers will fill this value.
            }

            if (data.getServiceUuids() != null) {
                ByteArrayOutputStream serviceUuids16 = new ByteArrayOutputStream();
                ByteArrayOutputStream serviceUuids32 = new ByteArrayOutputStream();
                ByteArrayOutputStream serviceUuids128 = new ByteArrayOutputStream();

                for (ParcelUuid parcelUuid : data.getServiceUuids()) {
                    byte[] uuid = BluetoothUuid.uuidToBytes(parcelUuid);

                    if (uuid.length == BluetoothUuid.UUID_BYTES_16_BIT) {
                        serviceUuids16.write(uuid, 0, uuid.length);
                    } else if (uuid.length == BluetoothUuid.UUID_BYTES_32_BIT) {
                        serviceUuids32.write(uuid, 0, uuid.length);
                    } else /*if (uuid.length == BluetoothUuid.UUID_BYTES_128_BIT)*/ {
                        serviceUuids128.write(uuid, 0, uuid.length);
                    }
                }

        // Combine service UUID and service data.
        private byte[] getServiceData(AdvertiseData advertiseData) {
            if (advertiseData.getServiceData().isEmpty()) {
                return new byte[0];
                if (serviceUuids16.size() != 0) {
                    ret.write(serviceUuids16.size() + 1);
                    ret.write(COMPLETE_LIST_16_BIT_SERVICE_UUIDS);
                    ret.write(serviceUuids16.toByteArray(), 0, serviceUuids16.size());
                }
            ParcelUuid uuid = advertiseData.getServiceData().keySet().iterator().next();
            byte[] serviceData = advertiseData.getServiceData().get(uuid);
            int dataLen = 2 + (serviceData == null ? 0 : serviceData.length);

                if (serviceUuids32.size() != 0) {
                    ret.write(serviceUuids32.size() + 1);
                    ret.write(COMPLETE_LIST_32_BIT_SERVICE_UUIDS);
                    ret.write(serviceUuids32.toByteArray(), 0, serviceUuids32.size());
                }

                if (serviceUuids128.size() != 0) {
                    ret.write(serviceUuids128.size() + 1);
                    ret.write(COMPLETE_LIST_128_BIT_SERVICE_UUIDS);
                    ret.write(serviceUuids128.toByteArray(), 0, serviceUuids128.size());
                }
            }

            if (!data.getServiceData().isEmpty()) {
                for (ParcelUuid parcelUuid: data.getServiceData().keySet()) {
                    byte[] serviceData = data.getServiceData().get(parcelUuid);

                    byte[] uuid = BluetoothUuid.uuidToBytes(parcelUuid);
                    int uuidLen = uuid.length;

                    int dataLen = uuidLen + (serviceData == null ? 0 : serviceData.length);
                    byte[] concated = new byte[dataLen];
            // Extract 16 bit UUID value.
            int uuidValue = BluetoothUuid.getServiceIdentifierFromParcelUuid(
                    uuid);
            // First two bytes are service data UUID in little-endian.
            concated[0] = (byte) (uuidValue & 0xFF);
            concated[1] = (byte) ((uuidValue >> 8) & 0xFF);

                    System.arraycopy(uuid, 0, concated, 0, uuidLen);

                    if (serviceData != null) {
                System.arraycopy(serviceData, 0, concated, 2, serviceData.length);
                        System.arraycopy(serviceData, 0, concated, uuidLen, serviceData.length);
                    }

                    if (uuid.length == BluetoothUuid.UUID_BYTES_16_BIT) {
                        ret.write(concated.length + 1);
                        ret.write(SERVICE_DATA_16_BIT_UUID);
                        ret.write(concated, 0, concated.length);
                    } else if (uuid.length == BluetoothUuid.UUID_BYTES_32_BIT) {
                        ret.write(concated.length + 1);
                        ret.write(SERVICE_DATA_32_BIT_UUID);
                        ret.write(concated, 0, concated.length);
                    } else /*if (uuid.length == BluetoothUuid.UUID_BYTES_128_BIT)*/ {
                        ret.write(concated.length + 1);
                        ret.write(SERVICE_DATA_128_BIT_UUID);
                        ret.write(concated, 0, concated.length);
                    }
                }
            }

            return ret.toByteArray();
        }

        private void setAdvertisingData(AdvertiseClient client, AdvertiseData data,
                boolean isScanResponse) {
            if (data == null) {
                return;
            }

            byte [] data_out = advertiseDataToBytes(data);

            if (mAdapterService.isMultiAdvertisementSupported()) {
                gattClientSetAdvDataNative(client.advertiserId, isScanResponse, data_out);
            } else {
                gattSetAdvDataNative(isScanResponse, data_out);
            }
            return concated;
        }

        // Convert settings tx power level to stack tx power level.
@@ -521,14 +598,12 @@ class AdvertiseManager {
                int min_interval, int max_interval, int adv_type, int chnl_map, int tx_power);

        private native void gattClientSetAdvDataNative(int advertiserId,
                boolean set_scan_rsp, boolean incl_name, boolean incl_txpower, int appearance,
                byte[] manufacturer_data, byte[] service_data, byte[] service_uuid);
                boolean set_scan_rsp, byte[] data);

        private native void gattClientEnableAdvNative(int advertiserId, boolean enable, int timeout_s);
        private native void gattClientEnableAdvNative(int advertiserId,
                boolean enable, int timeout_s);

        private native void gattSetAdvDataNative(int advertiserId, boolean setScanRsp, boolean inclName,
                boolean inclTxPower, int minSlaveConnectionInterval, int maxSlaveConnectionInterval,
                int appearance, byte[] manufacturerData, byte[] serviceData, byte[] serviceUuid);
        private native void gattSetAdvDataNative(boolean setScanRsp, byte[] data);

        private native void gattAdvertiseNative(int advertiserId, boolean start);
    }