| // |
| // Copyright (C) 2015 Google, Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at: |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #include "service/common/bluetooth/binder/parcel_helpers.h" |
| |
| #include "service/common/bluetooth/util/address_helper.h" |
| |
| using android::Parcel; |
| |
| using bluetooth::AdvertiseData; |
| using bluetooth::AdvertiseSettings; |
| using bluetooth::GattIdentifier; |
| using bluetooth::ScanFilter; |
| using bluetooth::ScanResult; |
| using bluetooth::ScanSettings; |
| using bluetooth::UUID; |
| |
| namespace ipc { |
| namespace binder { |
| |
| // TODO(armansito): The helpers below currently don't match the Java |
| // definitions. We need to change the AIDL and framework code to comply with the |
| // new definition and Parcel format provided here. |
| |
| void WriteAdvertiseDataToParcel(const AdvertiseData& data, Parcel* parcel) { |
| CHECK(parcel); |
| parcel->writeByteArray(data.data().size(), data.data().data()); // lol |
| parcel->writeInt32(data.include_device_name()); |
| parcel->writeInt32(data.include_tx_power_level()); |
| } |
| |
| std::unique_ptr<AdvertiseData> CreateAdvertiseDataFromParcel( |
| const Parcel& parcel) { |
| std::vector<uint8_t> data; |
| |
| // For len=0 Parcel::writeByteArray writes "-1" for the length value. So, any |
| // other value means that there is data to read. |
| // TODO(pavlin): We shouldn't need to worry about his here. Instead, Parcel |
| // should have an API for deserializing an array of bytes (e.g. |
| // Parcel::readByteArray()). |
| int data_len = parcel.readInt32(); |
| if (data_len != -1) { |
| uint8_t bytes[data_len]; |
| parcel.read(bytes, data_len); |
| |
| data = std::vector<uint8_t>(bytes, bytes + data_len); |
| } |
| |
| bool include_device_name = parcel.readInt32(); |
| bool include_tx_power = parcel.readInt32(); |
| |
| std::unique_ptr<AdvertiseData> adv(new AdvertiseData(data)); |
| adv->set_include_device_name(include_device_name); |
| adv->set_include_tx_power_level(include_tx_power); |
| |
| return adv; |
| } |
| |
| void WriteAdvertiseSettingsToParcel(const AdvertiseSettings& settings, |
| Parcel* parcel) { |
| CHECK(parcel); |
| parcel->writeInt32(settings.mode()); |
| parcel->writeInt32(settings.tx_power_level()); |
| parcel->writeInt32(settings.connectable()); |
| parcel->writeInt64(settings.timeout().InMilliseconds()); |
| } |
| |
| std::unique_ptr<AdvertiseSettings> CreateAdvertiseSettingsFromParcel( |
| const Parcel& parcel) { |
| AdvertiseSettings::Mode mode = |
| static_cast<AdvertiseSettings::Mode>(parcel.readInt32()); |
| AdvertiseSettings::TxPowerLevel tx_power = |
| static_cast<AdvertiseSettings::TxPowerLevel>(parcel.readInt32()); |
| bool connectable = parcel.readInt32(); |
| base::TimeDelta timeout = base::TimeDelta::FromMilliseconds( |
| parcel.readInt64()); |
| |
| return std::unique_ptr<AdvertiseSettings>( |
| new AdvertiseSettings(mode, timeout, tx_power, connectable)); |
| } |
| |
| void WriteUUIDToParcel(const UUID& uuid, android::Parcel* parcel) { |
| // The scheme used by android.os.ParcelUuid is to wrote the most significant |
| // bits first as one 64-bit integer, followed by the least significant bits in |
| // a second 64-bit integer. This is the same as writing the raw-bytes in |
| // sequence, but we don't want to assume any host-endianness here. So follow |
| // the same scheme and use the same Parcel APIs. |
| UUID::UUID128Bit bytes = uuid.GetFullBigEndian(); |
| |
| uint64_t most_sig_bits = |
| ((((uint64_t) bytes[0]) << 56) | |
| (((uint64_t) bytes[1]) << 48) | |
| (((uint64_t) bytes[2]) << 40) | |
| (((uint64_t) bytes[3]) << 32) | |
| (((uint64_t) bytes[4]) << 24) | |
| (((uint64_t) bytes[5]) << 16) | |
| (((uint64_t) bytes[6]) << 8) | |
| bytes[7]); |
| |
| uint64_t least_sig_bits = |
| ((((uint64_t) bytes[8]) << 56) | |
| (((uint64_t) bytes[9]) << 48) | |
| (((uint64_t) bytes[10]) << 40) | |
| (((uint64_t) bytes[11]) << 32) | |
| (((uint64_t) bytes[12]) << 24) | |
| (((uint64_t) bytes[13]) << 16) | |
| (((uint64_t) bytes[14]) << 8) | |
| bytes[15]); |
| |
| parcel->writeUint64(most_sig_bits); |
| parcel->writeUint64(least_sig_bits); |
| } |
| |
| std::unique_ptr<UUID> CreateUUIDFromParcel( |
| const android::Parcel& parcel) { |
| UUID::UUID128Bit bytes; |
| |
| uint64_t most_sig_bits = parcel.readUint64(); |
| uint64_t least_sig_bits = parcel.readUint64(); |
| |
| bytes[0] = (most_sig_bits >> 56) & 0xFF; |
| bytes[1] = (most_sig_bits >> 48) & 0xFF; |
| bytes[2] = (most_sig_bits >> 40) & 0xFF; |
| bytes[3] = (most_sig_bits >> 32) & 0xFF; |
| bytes[4] = (most_sig_bits >> 24) & 0xFF; |
| bytes[5] = (most_sig_bits >> 16) & 0xFF; |
| bytes[6] = (most_sig_bits >> 8) & 0xFF; |
| bytes[7] = most_sig_bits & 0xFF; |
| |
| bytes[8] = (least_sig_bits >> 56) & 0xFF; |
| bytes[9] = (least_sig_bits >> 48) & 0xFF; |
| bytes[10] = (least_sig_bits >> 40) & 0xFF; |
| bytes[11] = (least_sig_bits >> 32) & 0xFF; |
| bytes[12] = (least_sig_bits >> 24) & 0xFF; |
| bytes[13] = (least_sig_bits >> 16) & 0xFF; |
| bytes[14] = (least_sig_bits >> 8) & 0xFF; |
| bytes[15] = least_sig_bits & 0xFF; |
| |
| return std::unique_ptr<UUID>(new UUID(bytes)); |
| } |
| |
| void WriteGattIdentifierToParcel( |
| const GattIdentifier& gatt_id, |
| android::Parcel* parcel) { |
| parcel->writeCString(gatt_id.device_address().c_str()); |
| parcel->writeInt32(gatt_id.is_primary()); |
| |
| WriteUUIDToParcel(gatt_id.service_uuid(), parcel); |
| WriteUUIDToParcel(gatt_id.characteristic_uuid(), parcel); |
| WriteUUIDToParcel(gatt_id.descriptor_uuid(), parcel); |
| |
| parcel->writeInt32(gatt_id.service_instance_id()); |
| parcel->writeInt32(gatt_id.characteristic_instance_id()); |
| parcel->writeInt32(gatt_id.descriptor_instance_id()); |
| } |
| |
| std::unique_ptr<GattIdentifier> CreateGattIdentifierFromParcel( |
| const android::Parcel& parcel) { |
| std::string device_address = parcel.readCString(); |
| bool is_primary = parcel.readInt32(); |
| |
| auto service_uuid = CreateUUIDFromParcel(parcel); |
| auto char_uuid = CreateUUIDFromParcel(parcel); |
| auto desc_uuid = CreateUUIDFromParcel(parcel); |
| |
| int service_id = parcel.readInt32(); |
| int char_id = parcel.readInt32(); |
| int desc_id = parcel.readInt32(); |
| |
| return std::unique_ptr<GattIdentifier>( |
| new GattIdentifier( |
| device_address, is_primary, |
| *service_uuid, *char_uuid, *desc_uuid, |
| service_id, char_id, desc_id)); |
| } |
| |
| void WriteScanFilterToParcel( |
| const ScanFilter& filter, |
| android::Parcel* parcel) { |
| bool has_name = !filter.device_name().empty(); |
| parcel->writeInt32(has_name ? 1 : 0); |
| if (has_name) |
| parcel->writeCString(filter.device_name().c_str()); |
| |
| bool has_address = !filter.device_address().empty(); |
| parcel->writeInt32(has_address ? 1 : 0); |
| if (has_address) |
| parcel->writeCString(filter.device_address().c_str()); |
| |
| parcel->writeInt32(filter.service_uuid() ? 1 : 0); |
| if (filter.service_uuid()) { |
| WriteUUIDToParcel(*filter.service_uuid(), parcel); |
| parcel->writeInt32(filter.service_uuid_mask() ? 1 : 0); |
| if (filter.service_uuid_mask()) |
| WriteUUIDToParcel(*filter.service_uuid_mask(), parcel); |
| } |
| |
| // TODO(armansito): Support service and manufacturer data. |
| } |
| |
| std::unique_ptr<ScanFilter> CreateScanFilterFromParcel( |
| const android::Parcel& parcel) { |
| std::string device_name; |
| if (parcel.readInt32() == 1) |
| device_name = parcel.readCString(); |
| |
| std::string device_address; |
| if (parcel.readInt32() == 1) |
| device_address = parcel.readCString(); |
| |
| std::unique_ptr<UUID> service_uuid, service_uuid_mask; |
| if (parcel.readInt32() == 1) { |
| service_uuid = CreateUUIDFromParcel(parcel); |
| if (parcel.readInt32() == 1) |
| service_uuid_mask = CreateUUIDFromParcel(parcel); |
| } |
| |
| // TODO(armansito): Support service and manufacturer data. |
| |
| std::unique_ptr<ScanFilter> filter(new ScanFilter()); |
| |
| filter->set_device_name(device_name); |
| |
| if (!filter->SetDeviceAddress(device_address)) |
| return nullptr; |
| |
| if (!service_uuid) |
| return filter; |
| |
| if (service_uuid_mask) |
| filter->SetServiceUuidWithMask(*service_uuid, *service_uuid_mask); |
| else |
| filter->SetServiceUuid(*service_uuid); |
| |
| return filter; |
| } |
| |
| void WriteScanSettingsToParcel( |
| const ScanSettings& settings, |
| android::Parcel* parcel) { |
| parcel->writeInt32(settings.mode()); |
| parcel->writeInt32(settings.callback_type()); |
| parcel->writeInt32(settings.result_type()); |
| parcel->writeInt64(settings.report_delay().InMilliseconds()); |
| parcel->writeInt32(settings.match_mode()); |
| parcel->writeInt32(settings.match_count_per_filter()); |
| } |
| |
| std::unique_ptr<ScanSettings> CreateScanSettingsFromParcel( |
| const android::Parcel& parcel) { |
| ScanSettings::Mode mode = |
| static_cast<ScanSettings::Mode>(parcel.readInt32()); |
| ScanSettings::CallbackType callback_type = |
| static_cast<ScanSettings::CallbackType>(parcel.readInt32()); |
| ScanSettings::ResultType result_type = |
| static_cast<ScanSettings::ResultType>(parcel.readInt32()); |
| base::TimeDelta report_delay = base::TimeDelta::FromMilliseconds( |
| parcel.readInt64()); |
| ScanSettings::MatchMode match_mode = |
| static_cast<ScanSettings::MatchMode>(parcel.readInt32()); |
| ScanSettings::MatchCount match_count_per_filter = |
| static_cast<ScanSettings::MatchCount>(parcel.readInt32()); |
| |
| return std::unique_ptr<ScanSettings>(new ScanSettings( |
| mode, callback_type, result_type, report_delay, |
| match_mode, match_count_per_filter)); |
| } |
| |
| void WriteScanResultToParcel( |
| const bluetooth::ScanResult& scan_result, |
| android::Parcel* parcel) { |
| // The Java framework code conditionally inserts 1 or 0 to indicate if the |
| // device adress and the scan record fields are present, based on whether the |
| // Java object is null. We do something similar here for consistency, although |
| // the native definition of ScanResult requires a valid BD_ADDR. |
| if (util::IsAddressValid(scan_result.device_address())) { |
| parcel->writeInt32(1); |
| parcel->writeCString(scan_result.device_address().c_str()); |
| } else { |
| parcel->writeInt32(0); |
| } |
| |
| if (!scan_result.scan_record().empty()) { |
| parcel->writeInt32(1); |
| parcel->writeByteArray(scan_result.scan_record().size(), |
| scan_result.scan_record().data()); |
| } else { |
| parcel->writeInt32(0); |
| } |
| |
| parcel->writeInt32(scan_result.rssi()); |
| } |
| |
| std::unique_ptr<bluetooth::ScanResult> CreateScanResultFromParcel( |
| const android::Parcel& parcel) { |
| std::string device_address; |
| if (parcel.readInt32()) |
| device_address = parcel.readCString(); |
| |
| std::vector<uint8_t> scan_record; |
| if (parcel.readInt32()) { |
| int record_len = parcel.readInt32(); |
| if (record_len != -1) { |
| uint8_t bytes[record_len]; |
| parcel.read(bytes, record_len); |
| |
| scan_record = std::vector<uint8_t>(bytes, bytes + record_len); |
| } |
| } |
| |
| int rssi = parcel.readInt32(); |
| |
| return std::unique_ptr<ScanResult>(new ScanResult( |
| device_address, scan_record, rssi)); |
| } |
| |
| } // namespace binder |
| } // namespace ipc |