1 // Copyright 2020 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.webauth.authenticator; 6 7 import android.bluetooth.BluetoothAdapter; 8 import android.bluetooth.le.AdvertiseCallback; 9 import android.bluetooth.le.AdvertiseData; 10 import android.bluetooth.le.AdvertiseSettings; 11 import android.bluetooth.le.BluetoothLeAdvertiser; 12 import android.os.ParcelUuid; 13 14 import org.chromium.base.Log; 15 import org.chromium.base.annotations.CalledByNative; 16 17 import java.io.Closeable; 18 import java.nio.ByteBuffer; 19 import java.util.UUID; 20 21 class BLEAdvert implements Closeable { 22 private static final String TAG = "CableBLEAdvert"; 23 // This UUID is allocated to Google. 24 private static final String CABLE_UUID = "0000fde2-0000-1000-8000-00805f9b34fb"; 25 26 private AdvertiseCallback mCallback; 27 BLEAdvert(byte[] payload)28 BLEAdvert(byte[] payload) { 29 assert payload.length == 20; 30 31 BluetoothLeAdvertiser advertiser = 32 BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser(); 33 mCallback = new AdvertiseCallback() { 34 @Override 35 public void onStartFailure(int errorCode) { 36 Log.i(TAG, "advertising failure " + errorCode); 37 } 38 39 @Override 40 public void onStartSuccess(AdvertiseSettings settingsInEffect) { 41 Log.i(TAG, "advertising success"); 42 } 43 }; 44 45 AdvertiseSettings settings = 46 (new AdvertiseSettings.Builder()) 47 .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) 48 .setConnectable(false) 49 .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) 50 .build(); 51 ParcelUuid fidoUuid = new ParcelUuid(UUID.fromString(CABLE_UUID)); 52 53 // The first 16 bytes of the payload are encoded into a 16-byte UUID. 54 ByteBuffer bb = ByteBuffer.wrap(payload); 55 long high = bb.getLong(); 56 long low = bb.getLong(); 57 final UUID uuid16 = new UUID(high, low); 58 59 // The final four bytes of the payload are turned into a 4-byte UUID. 60 // Depending on the value of those four bytes, this might happen to be a 61 // 2-byte UUID, but the desktop handles that. 62 high = (long) bb.getInt(); 63 high <<= 32; 64 // This is the fixed suffix for short UUIDs in Bluetooth. 65 high |= 0x1000; 66 low = 0x800000805f9b34fbL; 67 final UUID uuid4 = new UUID(high, low); 68 69 AdvertiseData data = (new AdvertiseData.Builder()) 70 .addServiceUuid(fidoUuid) 71 .addServiceUuid(new ParcelUuid(uuid16)) 72 .addServiceUuid(new ParcelUuid(uuid4)) 73 .setIncludeDeviceName(false) 74 .setIncludeTxPowerLevel(false) 75 .build(); 76 77 advertiser.startAdvertising(settings, data, mCallback); 78 } 79 80 @Override 81 @CalledByNative close()82 public void close() { 83 if (mCallback == null) { 84 return; 85 } 86 87 BluetoothLeAdvertiser advertiser = 88 BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser(); 89 Log.i(TAG, "stopping advertising"); 90 advertiser.stopAdvertising(mCallback); 91 mCallback = null; 92 } 93 } 94