• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }