1 package com.github.google.bumble.remotehci; 2 3 import android.hardware.bluetooth.V1_0.Status; 4 import android.os.IBinder; 5 import android.os.RemoteException; 6 import android.os.ServiceManager; 7 import android.os.Trace; 8 import android.util.Log; 9 10 import java.util.ArrayList; 11 import java.util.NoSuchElementException; 12 13 public interface HciHal { 14 public enum Status { 15 SUCCESS("SUCCESS"), 16 ALREADY_INITIALIZED("ALREADY_INITIALIZED"), 17 UNABLE_TO_OPEN_INTERFACE("UNABLE_TO_OPEN_INTERFACE"), 18 INITIALIZATION_ERROR("INITIALIZATION_ERROR"), 19 TRANSPORT_ERROR("TRANSPORT_ERROR"), 20 UNKNOWN("UNKNOWN"); 21 22 public final String label; 23 Status(String label)24 private Status(String label) { 25 this.label = label; 26 } 27 } 28 static final String TAG = "HciHal"; create(HciHalCallback hciCallbacks)29 public static HciHal create(HciHalCallback hciCallbacks) { 30 // First try HIDL 31 HciHal hciHal = HciHidlHal.create(hciCallbacks); 32 if (hciHal != null) { 33 Log.d(TAG, "Found HIDL HAL"); 34 return hciHal; 35 } 36 37 // Then try AIDL 38 hciHal = HciAidlHal.create(hciCallbacks); 39 if (hciHal != null) { 40 Log.d(TAG, "Found AIDL HAL"); 41 return hciHal; 42 } 43 44 Log.d(TAG, "No HAL found"); 45 return null; 46 } 47 initialize()48 public Status initialize() throws RemoteException, InterruptedException; sendPacket(HciPacket.Type type, byte[] packet)49 public void sendPacket(HciPacket.Type type, byte[] packet); 50 } 51 52 class HciHidlHal extends android.hardware.bluetooth.V1_0.IBluetoothHciCallbacks.Stub implements HciHal { 53 private static final String TAG = "HciHidlHal"; 54 private final android.hardware.bluetooth.V1_0.IBluetoothHci mHciService; 55 private final HciHalCallback mHciCallbacks; 56 private int mInitializationStatus = -1; 57 private final boolean mTracingEnabled = Trace.isEnabled(); 58 59 create(HciHalCallback hciCallbacks)60 public static HciHidlHal create(HciHalCallback hciCallbacks) { 61 // Get the HAL service. 62 android.hardware.bluetooth.V1_0.IBluetoothHci hciService; 63 try { 64 hciService = android.hardware.bluetooth.V1_0.IBluetoothHci.getService(true); 65 } catch (NoSuchElementException e) { 66 Log.d(TAG, "HIDL HAL V1.0 not found"); 67 return null; 68 } catch (android.os.RemoteException e) { 69 Log.w(TAG, "Exception from getService: " + e); 70 return null; 71 } 72 Log.d(TAG, "Found HIDL HAL V1.0"); 73 return new HciHidlHal(hciService, hciCallbacks); 74 } 75 HciHidlHal(android.hardware.bluetooth.V1_0.IBluetoothHci hciService, HciHalCallback hciCallbacks)76 private HciHidlHal(android.hardware.bluetooth.V1_0.IBluetoothHci hciService, HciHalCallback hciCallbacks) { 77 mHciService = hciService; 78 mHciCallbacks = hciCallbacks; 79 } 80 initialize()81 public Status initialize() throws RemoteException, InterruptedException { 82 // Trigger the initialization. 83 mHciService.initialize(this); 84 85 // Wait for the initialization to complete. 86 Log.d(TAG, "Waiting for initialization status..."); 87 synchronized (this) { 88 while (mInitializationStatus == -1) { 89 wait(); 90 } 91 } 92 93 // Map the status code. 94 Log.d(TAG, "Initialization status = " + mInitializationStatus); 95 switch (mInitializationStatus) { 96 case android.hardware.bluetooth.V1_0.Status.SUCCESS: 97 return Status.SUCCESS; 98 99 case android.hardware.bluetooth.V1_0.Status.TRANSPORT_ERROR: 100 return Status.TRANSPORT_ERROR; 101 102 case android.hardware.bluetooth.V1_0.Status.INITIALIZATION_ERROR: 103 return Status.INITIALIZATION_ERROR; 104 105 default: 106 return Status.UNKNOWN; 107 } 108 } 109 110 @Override sendPacket(HciPacket.Type type, byte[] packet)111 public void sendPacket(HciPacket.Type type, byte[] packet) { 112 ArrayList<Byte> data = HciPacket.byteArrayToList(packet); 113 114 if (mTracingEnabled) { 115 Trace.beginAsyncSection("SEND_PACKET_TO_HAL", 1); 116 } 117 118 try { 119 switch (type) { 120 case COMMAND: 121 mHciService.sendHciCommand(data); 122 break; 123 124 case ACL_DATA: 125 mHciService.sendAclData(data); 126 break; 127 128 case SCO_DATA: 129 mHciService.sendScoData(data); 130 break; 131 } 132 } catch (RemoteException error) { 133 Log.w(TAG, "failed to forward packet: " + error); 134 } 135 136 if (mTracingEnabled) { 137 Trace.endAsyncSection("SEND_PACKET_TO_HAL", 1); 138 } 139 } 140 141 @Override initializationComplete(int status)142 public synchronized void initializationComplete(int status) throws RemoteException { 143 mInitializationStatus = status; 144 notifyAll(); 145 } 146 147 @Override hciEventReceived(ArrayList<Byte> event)148 public void hciEventReceived(ArrayList<Byte> event) throws RemoteException { 149 byte[] packet = HciPacket.listToByteArray(event); 150 mHciCallbacks.onPacket(HciPacket.Type.EVENT, packet); 151 } 152 153 @Override aclDataReceived(ArrayList<Byte> data)154 public void aclDataReceived(ArrayList<Byte> data) throws RemoteException { 155 byte[] packet = HciPacket.listToByteArray(data); 156 mHciCallbacks.onPacket(HciPacket.Type.ACL_DATA, packet); 157 } 158 159 @Override scoDataReceived(ArrayList<Byte> data)160 public void scoDataReceived(ArrayList<Byte> data) throws RemoteException { 161 byte[] packet = HciPacket.listToByteArray(data); 162 mHciCallbacks.onPacket(HciPacket.Type.SCO_DATA, packet); 163 } 164 } 165 166 class HciAidlHal extends android.hardware.bluetooth.IBluetoothHciCallbacks.Stub implements HciHal { 167 private static final String TAG = "HciAidlHal"; 168 private final android.hardware.bluetooth.IBluetoothHci mHciService; 169 private final HciHalCallback mHciCallbacks; 170 private int mInitializationStatus = android.hardware.bluetooth.Status.SUCCESS; 171 private final boolean mTracingEnabled = Trace.isEnabled(); 172 create(HciHalCallback hciCallbacks)173 public static HciAidlHal create(HciHalCallback hciCallbacks) { 174 IBinder binder = ServiceManager.getService("android.hardware.bluetooth.IBluetoothHci/default"); 175 if (binder == null) { 176 Log.d(TAG, "AIDL HAL not found"); 177 return null; 178 } 179 android.hardware.bluetooth.IBluetoothHci hciService = android.hardware.bluetooth.IBluetoothHci.Stub.asInterface(binder); 180 return new HciAidlHal(hciService, hciCallbacks); 181 } 182 HciAidlHal(android.hardware.bluetooth.IBluetoothHci hciService, HciHalCallback hciCallbacks)183 private HciAidlHal(android.hardware.bluetooth.IBluetoothHci hciService, HciHalCallback hciCallbacks) { 184 super(); 185 mHciService = hciService; 186 mHciCallbacks = hciCallbacks; 187 } 188 initialize()189 public Status initialize() throws RemoteException, InterruptedException { 190 // Trigger the initialization. 191 mHciService.initialize(this); 192 193 // Wait for the initialization to complete. 194 Log.d(TAG, "Waiting for initialization status..."); 195 synchronized (this) { 196 while (mInitializationStatus == -1) { 197 wait(); 198 } 199 } 200 201 // Map the status code. 202 Log.d(TAG, "Initialization status = " + mInitializationStatus); 203 switch (mInitializationStatus) { 204 case android.hardware.bluetooth.Status.SUCCESS: 205 return Status.SUCCESS; 206 207 case android.hardware.bluetooth.Status.ALREADY_INITIALIZED: 208 return Status.ALREADY_INITIALIZED; 209 210 case android.hardware.bluetooth.Status.UNABLE_TO_OPEN_INTERFACE: 211 return Status.UNABLE_TO_OPEN_INTERFACE; 212 213 case android.hardware.bluetooth.Status.HARDWARE_INITIALIZATION_ERROR: 214 return Status.INITIALIZATION_ERROR; 215 216 default: 217 return Status.UNKNOWN; 218 } 219 } 220 221 // HciHal methods. 222 @Override sendPacket(HciPacket.Type type, byte[] packet)223 public void sendPacket(HciPacket.Type type, byte[] packet) { 224 if (mTracingEnabled) { 225 Trace.beginAsyncSection("SEND_PACKET_TO_HAL", 1); 226 } 227 228 try { 229 switch (type) { 230 case COMMAND: 231 mHciService.sendHciCommand(packet); 232 break; 233 234 case ACL_DATA: 235 mHciService.sendAclData(packet); 236 break; 237 238 case SCO_DATA: 239 mHciService.sendScoData(packet); 240 break; 241 242 case ISO_DATA: 243 mHciService.sendIsoData(packet); 244 break; 245 } 246 } catch (RemoteException error) { 247 Log.w(TAG, "failed to forward packet: " + error); 248 } 249 250 if (mTracingEnabled) { 251 Trace.endAsyncSection("SEND_PACKET_TO_HAL", 1); 252 } 253 } 254 255 // IBluetoothHciCallbacks methods. 256 @Override initializationComplete(int status)257 public synchronized void initializationComplete(int status) throws RemoteException { 258 mInitializationStatus = status; 259 notifyAll(); 260 } 261 262 @Override hciEventReceived(byte[] event)263 public void hciEventReceived(byte[] event) throws RemoteException { 264 mHciCallbacks.onPacket(HciPacket.Type.EVENT, event); 265 } 266 267 @Override aclDataReceived(byte[] data)268 public void aclDataReceived(byte[] data) throws RemoteException { 269 mHciCallbacks.onPacket(HciPacket.Type.ACL_DATA, data); 270 } 271 272 @Override scoDataReceived(byte[] data)273 public void scoDataReceived(byte[] data) throws RemoteException { 274 mHciCallbacks.onPacket(HciPacket.Type.SCO_DATA, data); 275 } 276 277 @Override isoDataReceived(byte[] data)278 public void isoDataReceived(byte[] data) throws RemoteException { 279 mHciCallbacks.onPacket(HciPacket.Type.ISO_DATA, data); 280 } 281 }