• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package android.net.wifi;
2 
3 import android.annotation.SystemApi;
4 import android.content.Context;
5 import android.os.Bundle;
6 import android.os.Handler;
7 import android.os.HandlerThread;
8 import android.os.Looper;
9 import android.os.Message;
10 import android.os.Messenger;
11 import android.os.Parcel;
12 import android.os.Parcelable;
13 import android.os.RemoteException;
14 import android.util.Log;
15 import android.util.SparseArray;
16 
17 import com.android.internal.util.AsyncChannel;
18 import com.android.internal.util.Protocol;
19 
20 import java.util.concurrent.CountDownLatch;
21 
22 /** @hide */
23 @SystemApi
24 public class RttManager {
25 
26     private static final boolean DBG = true;
27     private static final String TAG = "RttManager";
28 
29     public static final int RTT_TYPE_UNSPECIFIED    = 0;
30     public static final int RTT_TYPE_ONE_SIDED      = 1;
31     public static final int RTT_TYPE_11_V           = 2;
32     public static final int RTT_TYPE_11_MC          = 4;
33 
34     public static final int RTT_PEER_TYPE_UNSPECIFIED    = 0;
35     public static final int RTT_PEER_TYPE_AP             = 1;
36     public static final int RTT_PEER_TYPE_STA            = 2;       /* requires NAN */
37 
38     public static final int RTT_CHANNEL_WIDTH_20      = 0;
39     public static final int RTT_CHANNEL_WIDTH_40      = 1;
40     public static final int RTT_CHANNEL_WIDTH_80      = 2;
41     public static final int RTT_CHANNEL_WIDTH_160     = 3;
42     public static final int RTT_CHANNEL_WIDTH_80P80   = 4;
43     public static final int RTT_CHANNEL_WIDTH_5       = 5;
44     public static final int RTT_CHANNEL_WIDTH_10      = 6;
45     public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1;
46 
47     public static final int RTT_STATUS_SUCCESS                  = 0;
48     public static final int RTT_STATUS_FAILURE                  = 1;
49     public static final int RTT_STATUS_FAIL_NO_RSP              = 2;
50     public static final int RTT_STATUS_FAIL_REJECTED            = 3;
51     public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET   = 4;
52     public static final int RTT_STATUS_FAIL_TM_TIMEOUT          = 5;
53     public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL  = 6;
54     public static final int RTT_STATUS_FAIL_NO_CAPABILITY       = 7;
55     public static final int RTT_STATUS_ABORTED                  = 8;
56 
57     public static final int REASON_UNSPECIFIED              = -1;
58     public static final int REASON_NOT_AVAILABLE            = -2;
59     public static final int REASON_INVALID_LISTENER         = -3;
60     public static final int REASON_INVALID_REQUEST          = -4;
61 
62     public static final String DESCRIPTION_KEY  = "android.net.wifi.RttManager.Description";
63 
64     public class Capabilities {
65         public int supportedType;
66         public int supportedPeerType;
67     }
68 
getCapabilities()69     public Capabilities getCapabilities() {
70         return new Capabilities();
71     }
72 
73     /** specifies parameters for RTT request */
74     public static class RttParams {
75 
76         /** type of device being ranged; one of RTT_PEER_TYPE_AP or RTT_PEER_TYPE_STA */
77         public int deviceType;
78 
79         /** type of RTT being sought; one of RTT_TYPE_ONE_SIDED
80          *  RTT_TYPE_11_V or RTT_TYPE_11_MC or RTT_TYPE_UNSPECIFIED */
81         public int requestType;
82 
83         /** mac address of the device being ranged */
84         public String bssid;
85 
86         /** channel frequency that the device is on; optional */
87         public int frequency;
88 
89         /** optional channel width. wider channels result in better accuracy,
90          *  but they take longer time, and even get aborted may times; use
91          *  RTT_CHANNEL_WIDTH_UNSPECIFIED if not specifying */
92         public int channelWidth;
93 
94         /** number of samples to be taken */
95         public int num_samples;
96 
97         /** number of retries if a sample fails */
98         public int num_retries;
99     }
100 
101     /** pseudo-private class used to parcel arguments */
102     public static class ParcelableRttParams implements Parcelable {
103 
104         public RttParams mParams[];
105 
ParcelableRttParams(RttParams[] params)106         ParcelableRttParams(RttParams[] params) {
107             mParams = params;
108         }
109 
110         /** Implement the Parcelable interface {@hide} */
describeContents()111         public int describeContents() {
112             return 0;
113         }
114 
115         /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)116         public void writeToParcel(Parcel dest, int flags) {
117             if (mParams != null) {
118                 dest.writeInt(mParams.length);
119 
120                 for (RttParams params : mParams) {
121                     dest.writeInt(params.deviceType);
122                     dest.writeInt(params.requestType);
123                     dest.writeString(params.bssid);
124                     dest.writeInt(params.frequency);
125                     dest.writeInt(params.channelWidth);
126                     dest.writeInt(params.num_samples);
127                     dest.writeInt(params.num_retries);
128                 }
129             } else {
130                 dest.writeInt(0);
131             }
132         }
133 
134         /** Implement the Parcelable interface {@hide} */
135         public static final Creator<ParcelableRttParams> CREATOR =
136                 new Creator<ParcelableRttParams>() {
137                     public ParcelableRttParams createFromParcel(Parcel in) {
138 
139                         int num = in.readInt();
140 
141                         if (num == 0) {
142                             return new ParcelableRttParams(null);
143                         }
144 
145                         RttParams params[] = new RttParams[num];
146                         for (int i = 0; i < num; i++) {
147                             params[i] = new RttParams();
148                             params[i].deviceType = in.readInt();
149                             params[i].requestType = in.readInt();
150                             params[i].bssid = in.readString();
151                             params[i].frequency = in.readInt();
152                             params[i].channelWidth = in.readInt();
153                             params[i].num_samples = in.readInt();
154                             params[i].num_retries = in.readInt();
155 
156                         }
157 
158                         ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
159                         return parcelableParams;
160                     }
161 
162                     public ParcelableRttParams[] newArray(int size) {
163                         return new ParcelableRttParams[size];
164                     }
165                 };
166     }
167 
168     /** specifies RTT results */
169     public static class RttResult {
170         /** mac address of the device being ranged */
171         public String bssid;
172 
173         /** status of the request */
174         public int status;
175 
176         /** type of the request used */
177         public int requestType;
178 
179         /** timestamp of completion, in microsecond since boot */
180         public long ts;
181 
182         /** average RSSI observed */
183         public int rssi;
184 
185         /** RSSI spread (i.e. max - min) */
186         public int rssi_spread;
187 
188         /** average transmit rate */
189         public int tx_rate;
190 
191         /** average round trip time in nano second */
192         public long rtt_ns;
193 
194         /** standard deviation observed in round trip time */
195         public long rtt_sd_ns;
196 
197         /** spread (i.e. max - min) round trip time */
198         public long rtt_spread_ns;
199 
200         /** average distance in centimeter, computed based on rtt_ns */
201         public int distance_cm;
202 
203         /** standard deviation observed in distance */
204         public int distance_sd_cm;
205 
206         /** spread (i.e. max - min) distance */
207         public int distance_spread_cm;
208     }
209 
210 
211     /** pseudo-private class used to parcel results */
212     public static class ParcelableRttResults implements Parcelable {
213 
214         public RttResult mResults[];
215 
ParcelableRttResults(RttResult[] results)216         public ParcelableRttResults(RttResult[] results) {
217             mResults = results;
218         }
219 
220         /** Implement the Parcelable interface {@hide} */
describeContents()221         public int describeContents() {
222             return 0;
223         }
224 
225         /** Implement the Parcelable interface {@hide} */
writeToParcel(Parcel dest, int flags)226         public void writeToParcel(Parcel dest, int flags) {
227             if (mResults != null) {
228                 dest.writeInt(mResults.length);
229                 for (RttResult result : mResults) {
230                     dest.writeString(result.bssid);
231                     dest.writeInt(result.status);
232                     dest.writeInt(result.requestType);
233                     dest.writeLong(result.ts);
234                     dest.writeInt(result.rssi);
235                     dest.writeInt(result.rssi_spread);
236                     dest.writeInt(result.tx_rate);
237                     dest.writeLong(result.rtt_ns);
238                     dest.writeLong(result.rtt_sd_ns);
239                     dest.writeLong(result.rtt_spread_ns);
240                     dest.writeInt(result.distance_cm);
241                     dest.writeInt(result.distance_sd_cm);
242                     dest.writeInt(result.distance_spread_cm);
243                 }
244             } else {
245                 dest.writeInt(0);
246             }
247         }
248 
249         /** Implement the Parcelable interface {@hide} */
250         public static final Creator<ParcelableRttResults> CREATOR =
251                 new Creator<ParcelableRttResults>() {
252                     public ParcelableRttResults createFromParcel(Parcel in) {
253 
254                         int num = in.readInt();
255 
256                         if (num == 0) {
257                             return new ParcelableRttResults(null);
258                         }
259 
260                         RttResult results[] = new RttResult[num];
261                         for (int i = 0; i < num; i++) {
262                             results[i] = new RttResult();
263                             results[i].bssid = in.readString();
264                             results[i].status = in.readInt();
265                             results[i].requestType = in.readInt();
266                             results[i].ts = in.readLong();
267                             results[i].rssi = in.readInt();
268                             results[i].rssi_spread = in.readInt();
269                             results[i].tx_rate = in.readInt();
270                             results[i].rtt_ns = in.readLong();
271                             results[i].rtt_sd_ns = in.readLong();
272                             results[i].rtt_spread_ns = in.readLong();
273                             results[i].distance_cm = in.readInt();
274                             results[i].distance_sd_cm = in.readInt();
275                             results[i].distance_spread_cm = in.readInt();
276                         }
277 
278                         ParcelableRttResults parcelableResults = new ParcelableRttResults(results);
279                         return parcelableResults;
280                     }
281 
282                     public ParcelableRttResults[] newArray(int size) {
283                         return new ParcelableRttResults[size];
284                     }
285                 };
286     }
287 
288 
289     public static interface RttListener {
onSuccess(RttResult[] results)290         public void onSuccess(RttResult[] results);
onFailure(int reason, String description)291         public void onFailure(int reason, String description);
onAborted()292         public void onAborted();
293     }
294 
startRanging(RttParams[] params, RttListener listener)295     public void startRanging(RttParams[] params, RttListener listener) {
296         validateChannel();
297         ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
298         sAsyncChannel.sendMessage(CMD_OP_START_RANGING,
299                 0, putListener(listener), parcelableParams);
300     }
301 
stopRanging(RttListener listener)302     public void stopRanging(RttListener listener) {
303         validateChannel();
304         sAsyncChannel.sendMessage(CMD_OP_STOP_RANGING, 0, removeListener(listener));
305     }
306 
307     /* private methods */
308     public static final int BASE = Protocol.BASE_WIFI_RTT_MANAGER;
309 
310     public static final int CMD_OP_START_RANGING        = BASE + 0;
311     public static final int CMD_OP_STOP_RANGING         = BASE + 1;
312     public static final int CMD_OP_FAILED               = BASE + 2;
313     public static final int CMD_OP_SUCCEEDED            = BASE + 3;
314     public static final int CMD_OP_ABORTED              = BASE + 4;
315 
316     private Context mContext;
317     private IRttManager mService;
318 
319     private static final int INVALID_KEY = 0;
320     private static int sListenerKey = 1;
321 
322     private static final SparseArray sListenerMap = new SparseArray();
323     private static final Object sListenerMapLock = new Object();
324 
325     private static AsyncChannel sAsyncChannel;
326     private static CountDownLatch sConnected;
327 
328     private static final Object sThreadRefLock = new Object();
329     private static int sThreadRefCount;
330     private static HandlerThread sHandlerThread;
331 
332     /**
333      * Create a new WifiScanner instance.
334      * Applications will almost always want to use
335      * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
336      * the standard {@link android.content.Context#WIFI_RTT_SERVICE Context.WIFI_RTT_SERVICE}.
337      * @param context the application context
338      * @param service the Binder interface
339      * @hide
340      */
341 
RttManager(Context context, IRttManager service)342     public RttManager(Context context, IRttManager service) {
343         mContext = context;
344         mService = service;
345         init();
346     }
347 
init()348     private void init() {
349         synchronized (sThreadRefLock) {
350             if (++sThreadRefCount == 1) {
351                 Messenger messenger = null;
352                 try {
353                     Log.d(TAG, "Get the messenger from " + mService);
354                     messenger = mService.getMessenger();
355                 } catch (RemoteException e) {
356                     /* do nothing */
357                 } catch (SecurityException e) {
358                     /* do nothing */
359                 }
360 
361                 if (messenger == null) {
362                     sAsyncChannel = null;
363                     return;
364                 }
365 
366                 sHandlerThread = new HandlerThread("WifiScanner");
367                 sAsyncChannel = new AsyncChannel();
368                 sConnected = new CountDownLatch(1);
369 
370                 sHandlerThread.start();
371                 Handler handler = new ServiceHandler(sHandlerThread.getLooper());
372                 sAsyncChannel.connect(mContext, handler, messenger);
373                 try {
374                     sConnected.await();
375                 } catch (InterruptedException e) {
376                     Log.e(TAG, "interrupted wait at init");
377                 }
378             }
379         }
380     }
381 
validateChannel()382     private void validateChannel() {
383         if (sAsyncChannel == null) throw new IllegalStateException(
384                 "No permission to access and change wifi or a bad initialization");
385     }
386 
putListener(Object listener)387     private static int putListener(Object listener) {
388         if (listener == null) return INVALID_KEY;
389         int key;
390         synchronized (sListenerMapLock) {
391             do {
392                 key = sListenerKey++;
393             } while (key == INVALID_KEY);
394             sListenerMap.put(key, listener);
395         }
396         return key;
397     }
398 
getListener(int key)399     private static Object getListener(int key) {
400         if (key == INVALID_KEY) return null;
401         synchronized (sListenerMapLock) {
402             Object listener = sListenerMap.get(key);
403             return listener;
404         }
405     }
406 
getListenerKey(Object listener)407     private static int getListenerKey(Object listener) {
408         if (listener == null) return INVALID_KEY;
409         synchronized (sListenerMapLock) {
410             int index = sListenerMap.indexOfValue(listener);
411             if (index == -1) {
412                 return INVALID_KEY;
413             } else {
414                 return sListenerMap.keyAt(index);
415             }
416         }
417     }
418 
removeListener(int key)419     private static Object removeListener(int key) {
420         if (key == INVALID_KEY) return null;
421         synchronized (sListenerMapLock) {
422             Object listener = sListenerMap.get(key);
423             sListenerMap.remove(key);
424             return listener;
425         }
426     }
427 
removeListener(Object listener)428     private static int removeListener(Object listener) {
429         int key = getListenerKey(listener);
430         if (key == INVALID_KEY) return key;
431         synchronized (sListenerMapLock) {
432             sListenerMap.remove(key);
433             return key;
434         }
435     }
436 
437     private static class ServiceHandler extends Handler {
ServiceHandler(Looper looper)438         ServiceHandler(Looper looper) {
439             super(looper);
440         }
441         @Override
handleMessage(Message msg)442         public void handleMessage(Message msg) {
443             switch (msg.what) {
444                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
445                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
446                         sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
447                     } else {
448                         Log.e(TAG, "Failed to set up channel connection");
449                         // This will cause all further async API calls on the WifiManager
450                         // to fail and throw an exception
451                         sAsyncChannel = null;
452                     }
453                     sConnected.countDown();
454                     return;
455                 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
456                     return;
457                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
458                     Log.e(TAG, "Channel connection lost");
459                     // This will cause all further async API calls on the WifiManager
460                     // to fail and throw an exception
461                     sAsyncChannel = null;
462                     getLooper().quit();
463                     return;
464             }
465 
466             Object listener = getListener(msg.arg2);
467             if (listener == null) {
468                 if (DBG) Log.d(TAG, "invalid listener key = " + msg.arg2);
469                 return;
470             } else {
471                 if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
472             }
473 
474             switch (msg.what) {
475                 /* ActionListeners grouped together */
476                 case CMD_OP_SUCCEEDED :
477                     reportSuccess(listener, msg);
478                     removeListener(msg.arg2);
479                     break;
480                 case CMD_OP_FAILED :
481                     reportFailure(listener, msg);
482                     removeListener(msg.arg2);
483                     break;
484                 case CMD_OP_ABORTED :
485                     ((RttListener) listener).onAborted();
486                     removeListener(msg.arg2);
487                     break;
488                 default:
489                     if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
490                     return;
491             }
492         }
493 
reportSuccess(Object listener, Message msg)494         void reportSuccess(Object listener, Message msg) {
495             RttListener rttListener = (RttListener) listener;
496             ParcelableRttResults parcelableResults = (ParcelableRttResults) msg.obj;
497             ((RttListener) listener).onSuccess(parcelableResults.mResults);
498         }
499 
reportFailure(Object listener, Message msg)500         void reportFailure(Object listener, Message msg) {
501             RttListener rttListener = (RttListener) listener;
502             Bundle bundle = (Bundle) msg.obj;
503             ((RttListener) listener).onFailure(msg.arg1, bundle.getString(DESCRIPTION_KEY));
504         }
505     }
506 
507 }
508 
509