RttService.java revision f95649f33db0a328cb4c0bb5e10c7075e6c828f8
1package com.android.server.wifi; 2 3import android.content.BroadcastReceiver; 4import android.content.Context; 5import android.content.Intent; 6import android.content.IntentFilter; 7import android.net.wifi.RttManager; 8import android.net.wifi.WifiManager; 9import android.os.Bundle; 10import android.os.Handler; 11import android.os.HandlerThread; 12import android.os.Looper; 13import android.os.Message; 14import android.os.Messenger; 15import android.os.Parcel; 16import android.os.RemoteException; 17import android.util.Log; 18import android.net.wifi.IRttManager; 19import android.util.Slog; 20 21import com.android.internal.util.AsyncChannel; 22import com.android.internal.util.Protocol; 23import com.android.internal.util.StateMachine; 24import com.android.internal.util.State; 25import com.android.server.SystemService; 26 27import java.util.HashMap; 28import java.util.Iterator; 29import java.util.LinkedList; 30import java.util.Queue; 31 32class RttService extends SystemService { 33 34 public static final boolean DBG = true; 35 36 class RttServiceImpl extends IRttManager.Stub { 37 38 @Override 39 public Messenger getMessenger() { 40 return new Messenger(mClientHandler); 41 } 42 43 private class ClientHandler extends Handler { 44 45 ClientHandler(android.os.Looper looper) { 46 super(looper); 47 } 48 49 @Override 50 public void handleMessage(Message msg) { 51 52 if (DBG) Log.d(TAG, "ClientHandler got" + msg); 53 54 switch (msg.what) { 55 56 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 57 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 58 AsyncChannel c = (AsyncChannel) msg.obj; 59 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages: " + 60 msg.replyTo); 61 ClientInfo cInfo = new ClientInfo(c, msg.replyTo); 62 mClients.put(msg.replyTo, cInfo); 63 } else { 64 Slog.e(TAG, "Client connection failure, error=" + msg.arg1); 65 } 66 return; 67 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 68 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { 69 Slog.e(TAG, "Send failed, client connection lost"); 70 } else { 71 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); 72 } 73 if (DBG) Slog.d(TAG, "closing client " + msg.replyTo); 74 ClientInfo ci = mClients.remove(msg.replyTo); 75 if (ci != null) ci.cleanup(); 76 return; 77 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: 78 AsyncChannel ac = new AsyncChannel(); 79 ac.connect(mContext, this, msg.replyTo); 80 return; 81 } 82 83 ClientInfo ci = mClients.get(msg.replyTo); 84 if (ci == null) { 85 Slog.e(TAG, "Could not find client info for message " + msg.replyTo); 86 replyFailed(msg, RttManager.REASON_INVALID_LISTENER, "Could not find listener"); 87 return; 88 } 89 90 int validCommands[] = { 91 RttManager.CMD_OP_START_RANGING, 92 RttManager.CMD_OP_STOP_RANGING 93 }; 94 95 for(int cmd : validCommands) { 96 if (cmd == msg.what) { 97 mStateMachine.sendMessage(Message.obtain(msg)); 98 return; 99 } 100 } 101 102 replyFailed(msg, RttManager.REASON_INVALID_REQUEST, "Invalid request"); 103 } 104 } 105 106 private Context mContext; 107 private RttStateMachine mStateMachine; 108 private ClientHandler mClientHandler; 109 110 RttServiceImpl() { } 111 112 RttServiceImpl(Context context) { 113 mContext = context; 114 } 115 116 public void startService(Context context) { 117 mContext = context; 118 119 HandlerThread thread = new HandlerThread("WifiRttService"); 120 thread.start(); 121 122 mClientHandler = new ClientHandler(thread.getLooper()); 123 mStateMachine = new RttStateMachine(thread.getLooper()); 124 125 mContext.registerReceiver( 126 new BroadcastReceiver() { 127 @Override 128 public void onReceive(Context context, Intent intent) { 129 int state = intent.getIntExtra( 130 WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED); 131 if (DBG) Log.d(TAG, "SCAN_AVAILABLE : " + state); 132 if (state == WifiManager.WIFI_STATE_ENABLED) { 133 mStateMachine.sendMessage(CMD_DRIVER_LOADED); 134 } else if (state == WifiManager.WIFI_STATE_DISABLED) { 135 mStateMachine.sendMessage(CMD_DRIVER_UNLOADED); 136 } 137 } 138 }, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE)); 139 140 mStateMachine.start(); 141 } 142 143 private class RttRequest { 144 Integer key; 145 ClientInfo ci; 146 RttManager.RttParams[] params; 147 148 @Override 149 public String toString() { 150 String str = getClass().getName() + "@" + Integer.toHexString(hashCode()); 151 if(this.key != null) { 152 return str + " key: " + this.key; 153 } else { 154 return str + " key: " + " , null"; 155 } 156 } 157 } 158 159 private class ClientInfo { 160 private final AsyncChannel mChannel; 161 private final Messenger mMessenger; 162 HashMap<Integer, RttRequest> mRequests = new HashMap<Integer, 163 RttRequest>(); 164 165 ClientInfo(AsyncChannel c, Messenger m) { 166 mChannel = c; 167 mMessenger = m; 168 } 169 170 boolean addRttRequest(int key, RttManager.ParcelableRttParams parcelableParams) { 171 if (parcelableParams == null) { 172 return false; 173 } 174 175 RttManager.RttParams params[] = parcelableParams.mParams; 176 177 RttRequest request = new RttRequest(); 178 request.key = key; 179 request.ci = this; 180 request.params = params; 181 mRequests.put(key, request); 182 mRequestQueue.add(request); 183 return true; 184 } 185 186 void removeRttRequest(int key) { 187 mRequests.remove(key); 188 } 189 190 void reportResult(RttRequest request, RttManager.RttResult[] results) { 191 RttManager.ParcelableRttResults parcelableResults = 192 new RttManager.ParcelableRttResults(results); 193 194 mChannel.sendMessage(RttManager.CMD_OP_SUCCEEDED, 195 0, request.key, parcelableResults); 196 mRequests.remove(request.key); 197 } 198 199 void reportFailed(RttRequest request, int reason, String description) { 200 reportFailed(request.key, reason, description); 201 } 202 203 void reportFailed(int key, int reason, String description) { 204 Bundle bundle = new Bundle(); 205 bundle.putString(RttManager.DESCRIPTION_KEY, description); 206 mChannel.sendMessage(RttManager.CMD_OP_FAILED, key, reason, bundle); 207 mRequests.remove(key); 208 } 209 210 void reportAborted(int key) { 211 mChannel.sendMessage(RttManager.CMD_OP_ABORTED, 0, key); 212 //All Queued RTT request will be cleaned 213 cleanup(); 214 } 215 216 void cleanup() { 217 mRequests.clear(); 218 mRequestQueue.clear(); 219 } 220 } 221 222 private Queue<RttRequest> mRequestQueue = new LinkedList<RttRequest>(); 223 private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>(4); 224 225 private static final int BASE = Protocol.BASE_WIFI_RTT_SERVICE; 226 227 private static final int CMD_DRIVER_LOADED = BASE + 0; 228 private static final int CMD_DRIVER_UNLOADED = BASE + 1; 229 private static final int CMD_ISSUE_NEXT_REQUEST = BASE + 2; 230 private static final int CMD_RTT_RESPONSE = BASE + 3; 231 232 class RttStateMachine extends StateMachine { 233 234 DefaultState mDefaultState = new DefaultState(); 235 EnabledState mEnabledState = new EnabledState(); 236 RequestPendingState mRequestPendingState = new RequestPendingState(); 237 238 RttStateMachine(Looper looper) { 239 super("RttStateMachine", looper); 240 241 addState(mDefaultState); 242 addState(mEnabledState); 243 addState(mRequestPendingState, mEnabledState); 244 245 setInitialState(mDefaultState); 246 } 247 248 class DefaultState extends State { 249 @Override 250 public boolean processMessage(Message msg) { 251 if (DBG) Log.d(TAG, "DefaultState got" + msg); 252 switch (msg.what) { 253 case CMD_DRIVER_LOADED: 254 transitionTo(mEnabledState); 255 break; 256 case CMD_ISSUE_NEXT_REQUEST: 257 deferMessage(msg); 258 break; 259 case RttManager.CMD_OP_START_RANGING: 260 replyFailed(msg, RttManager.REASON_NOT_AVAILABLE, "Try later"); 261 break; 262 case RttManager.CMD_OP_STOP_RANGING: 263 return HANDLED; 264 default: 265 return NOT_HANDLED; 266 } 267 return HANDLED; 268 } 269 } 270 271 class EnabledState extends State { 272 @Override 273 public boolean processMessage(Message msg) { 274 if (DBG) Log.d(TAG, "EnabledState got" + msg); 275 ClientInfo ci = mClients.get(msg.replyTo); 276 277 switch (msg.what) { 278 case CMD_DRIVER_UNLOADED: 279 transitionTo(mDefaultState); 280 break; 281 case CMD_ISSUE_NEXT_REQUEST: 282 deferMessage(msg); 283 transitionTo(mRequestPendingState); 284 break; 285 case RttManager.CMD_OP_START_RANGING: { 286 RttManager.ParcelableRttParams params = 287 (RttManager.ParcelableRttParams)msg.obj; 288 if (params == null) { 289 replyFailed(msg, 290 RttManager.REASON_INVALID_REQUEST, "No params"); 291 } else if (ci.addRttRequest(msg.arg2, params) == false) { 292 replyFailed(msg, 293 RttManager.REASON_INVALID_REQUEST, "Unspecified"); 294 } else { 295 sendMessage(CMD_ISSUE_NEXT_REQUEST); 296 } 297 } 298 break; 299 case RttManager.CMD_OP_STOP_RANGING: 300 for (Iterator<RttRequest> it = mRequestQueue.iterator(); 301 it.hasNext(); ) { 302 RttRequest request = it.next(); 303 if (request.key == msg.arg2) { 304 if (DBG) Log.d(TAG, "Cancelling not-yet-scheduled RTT"); 305 mRequestQueue.remove(request); 306 request.ci.reportAborted(request.key); 307 break; 308 } 309 } 310 break; 311 default: 312 return NOT_HANDLED; 313 } 314 return HANDLED; 315 } 316 } 317 318 class RequestPendingState extends State { 319 RttRequest mOutstandingRequest; 320 @Override 321 public boolean processMessage(Message msg) { 322 if (DBG) Log.d(TAG, "RequestPendingState got" + msg); 323 switch (msg.what) { 324 case CMD_DRIVER_UNLOADED: 325 if (mOutstandingRequest != null) { 326 WifiNative.cancelRtt(mOutstandingRequest.params); 327 if (DBG) Log.d(TAG, "abort key: " + mOutstandingRequest.key); 328 mOutstandingRequest.ci.reportAborted(mOutstandingRequest.key); 329 mOutstandingRequest = null; 330 } 331 transitionTo(mDefaultState); 332 break; 333 case CMD_ISSUE_NEXT_REQUEST: 334 if (mOutstandingRequest == null) { 335 mOutstandingRequest = issueNextRequest(); 336 if (mOutstandingRequest == null) { 337 transitionTo(mEnabledState); 338 } 339 if(mOutstandingRequest != null) { 340 if (DBG) Log.d(TAG, "new mOutstandingRequest.key is: " + mOutstandingRequest.key); 341 } else { 342 if (DBG) Log.d(TAG, "CMD_ISSUE_NEXT_REQUEST: mOutstandingRequest =null "); 343 } 344 } else { 345 /* just wait; we'll issue next request after 346 * current one is finished */ 347 if (DBG) Log.d(TAG, "Current mOutstandingRequest.key is: " + 348 mOutstandingRequest.key); 349 if (DBG) Log.d(TAG, "Ignoring CMD_ISSUE_NEXT_REQUEST"); 350 } 351 break; 352 case CMD_RTT_RESPONSE: 353 if (DBG) Log.d(TAG, "Received an RTT response from: " + msg.arg2); 354 mOutstandingRequest.ci.reportResult( 355 mOutstandingRequest, (RttManager.RttResult[])msg.obj); 356 mOutstandingRequest = null; 357 sendMessage(CMD_ISSUE_NEXT_REQUEST); 358 break; 359 case RttManager.CMD_OP_STOP_RANGING: 360 if (mOutstandingRequest != null 361 && msg.arg2 == mOutstandingRequest.key) { 362 if (DBG) Log.d(TAG, "Cancelling ongoing RTT of: " + msg.arg2); 363 WifiNative.cancelRtt(mOutstandingRequest.params); 364 mOutstandingRequest.ci.reportAborted(mOutstandingRequest.key); 365 mOutstandingRequest = null; 366 sendMessage(CMD_ISSUE_NEXT_REQUEST); 367 } else { 368 /* Let EnabledState handle this */ 369 return NOT_HANDLED; 370 } 371 break; 372 default: 373 return NOT_HANDLED; 374 } 375 return HANDLED; 376 } 377 } 378 } 379 380 void replySucceeded(Message msg, Object obj) { 381 if (msg.replyTo != null) { 382 Message reply = Message.obtain(); 383 reply.what = RttManager.CMD_OP_SUCCEEDED; 384 reply.arg2 = msg.arg2; 385 reply.obj = obj; 386 try { 387 msg.replyTo.send(reply); 388 } catch (RemoteException e) { 389 // There's not much we can do if reply can't be sent! 390 } 391 } else { 392 // locally generated message; doesn't need a reply! 393 } 394 } 395 396 void replyFailed(Message msg, int reason, String description) { 397 Message reply = Message.obtain(); 398 reply.what = RttManager.CMD_OP_FAILED; 399 reply.arg1 = reason; 400 reply.arg2 = msg.arg2; 401 402 Bundle bundle = new Bundle(); 403 bundle.putString(RttManager.DESCRIPTION_KEY, description); 404 reply.obj = bundle; 405 406 try { 407 msg.replyTo.send(reply); 408 } catch (RemoteException e) { 409 // There's not much we can do if reply can't be sent! 410 } 411 } 412 413 private WifiNative.RttEventHandler mEventHandler = new WifiNative.RttEventHandler() { 414 @Override 415 public void onRttResults(RttManager.RttResult[] result) { 416 mStateMachine.sendMessage(CMD_RTT_RESPONSE, result); 417 } 418 }; 419 420 RttRequest issueNextRequest() { 421 RttRequest request = null; 422 while (mRequestQueue.isEmpty() == false) { 423 request = mRequestQueue.remove(); 424 if(request != null) { 425 if (WifiNative.requestRtt(request.params, mEventHandler)) { 426 if (DBG) Log.d(TAG, "Issued next RTT request with key: " + request.key); 427 return request; 428 } else { 429 Log.e(TAG, "Fail to issue key at native layer"); 430 request.ci.reportFailed(request, 431 RttManager.REASON_UNSPECIFIED, "Failed to start"); 432 } 433 } 434 } 435 436 /* all requests exhausted */ 437 if (DBG) Log.d(TAG, "No more requests left"); 438 return null; 439 } 440 @Override 441 public RttManager.RttCapabilities getRttCapabilities() { 442 return WifiNative.getRttCapabilities(); 443 } 444 } 445 446 private static final String TAG = "RttService"; 447 RttServiceImpl mImpl; 448 449 public RttService(Context context) { 450 super(context); 451 Log.i(TAG, "Creating " + Context.WIFI_RTT_SERVICE); 452 } 453 454 @Override 455 public void onStart() { 456 mImpl = new RttServiceImpl(getContext()); 457 458 Log.i(TAG, "Starting " + Context.WIFI_RTT_SERVICE); 459 publishBinderService(Context.WIFI_RTT_SERVICE, mImpl); 460 } 461 462 @Override 463 public void onBootPhase(int phase) { 464 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 465 Log.i(TAG, "Registering " + Context.WIFI_RTT_SERVICE); 466 if (mImpl == null) { 467 mImpl = new RttServiceImpl(getContext()); 468 } 469 mImpl.startService(getContext()); 470 } 471 } 472 473 474} 475