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 149 private class ClientInfo { 150 private final AsyncChannel mChannel; 151 private final Messenger mMessenger; 152 HashMap<Integer, RttRequest> mRequests = new HashMap<Integer, 153 RttRequest>(); 154 155 ClientInfo(AsyncChannel c, Messenger m) { 156 mChannel = c; 157 mMessenger = m; 158 } 159 160 boolean addRttRequest(int key, RttManager.ParcelableRttParams parcelableParams) { 161 if (parcelableParams == null) { 162 return false; 163 } 164 165 RttManager.RttParams params[] = parcelableParams.mParams; 166 167 RttRequest request = new RttRequest(); 168 request.key = key; 169 request.ci = this; 170 request.params = params; 171 mRequests.put(key, request); 172 mRequestQueue.add(request); 173 return true; 174 } 175 176 void removeRttRequest(int key) { 177 mRequests.remove(key); 178 } 179 180 void reportResult(RttRequest request, RttManager.RttResult[] results) { 181 RttManager.ParcelableRttResults parcelableResults = 182 new RttManager.ParcelableRttResults(results); 183 184 mChannel.sendMessage(RttManager.CMD_OP_SUCCEEDED, 185 0, request.key, parcelableResults); 186 mRequests.remove(request.key); 187 } 188 189 void reportFailed(RttRequest request, int reason, String description) { 190 reportFailed(request.key, reason, description); 191 } 192 193 void reportFailed(int key, int reason, String description) { 194 Bundle bundle = new Bundle(); 195 bundle.putString(RttManager.DESCRIPTION_KEY, description); 196 mChannel.sendMessage(RttManager.CMD_OP_FAILED, key, reason, bundle); 197 mRequests.remove(key); 198 } 199 200 void reportAborted(int key) { 201 mChannel.sendMessage(RttManager.CMD_OP_ABORTED, key); 202 mRequests.remove(key); 203 } 204 205 void cleanup() { 206 mRequests.clear(); 207 } 208 } 209 210 private Queue<RttRequest> mRequestQueue = new LinkedList<RttRequest>(); 211 private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>(4); 212 213 private static final int BASE = Protocol.BASE_WIFI_RTT_SERVICE; 214 215 private static final int CMD_DRIVER_LOADED = BASE + 0; 216 private static final int CMD_DRIVER_UNLOADED = BASE + 1; 217 private static final int CMD_ISSUE_NEXT_REQUEST = BASE + 2; 218 private static final int CMD_RTT_RESPONSE = BASE + 3; 219 220 class RttStateMachine extends StateMachine { 221 222 DefaultState mDefaultState = new DefaultState(); 223 EnabledState mEnabledState = new EnabledState(); 224 RequestPendingState mRequestPendingState = new RequestPendingState(); 225 226 RttStateMachine(Looper looper) { 227 super("RttStateMachine", looper); 228 229 addState(mDefaultState); 230 addState(mEnabledState); 231 addState(mRequestPendingState, mEnabledState); 232 233 setInitialState(mDefaultState); 234 } 235 236 class DefaultState extends State { 237 @Override 238 public boolean processMessage(Message msg) { 239 if (DBG) Log.d(TAG, "DefaultState got" + msg); 240 switch (msg.what) { 241 case CMD_DRIVER_LOADED: 242 transitionTo(mEnabledState); 243 break; 244 case CMD_ISSUE_NEXT_REQUEST: 245 deferMessage(msg); 246 break; 247 case RttManager.CMD_OP_START_RANGING: 248 replyFailed(msg, RttManager.REASON_NOT_AVAILABLE, "Try later"); 249 break; 250 case RttManager.CMD_OP_STOP_RANGING: 251 return HANDLED; 252 default: 253 return NOT_HANDLED; 254 } 255 return HANDLED; 256 } 257 } 258 259 class EnabledState extends State { 260 @Override 261 public boolean processMessage(Message msg) { 262 if (DBG) Log.d(TAG, "EnabledState got" + msg); 263 ClientInfo ci = mClients.get(msg.replyTo); 264 265 switch (msg.what) { 266 case CMD_DRIVER_UNLOADED: 267 transitionTo(mDefaultState); 268 break; 269 case CMD_ISSUE_NEXT_REQUEST: 270 deferMessage(msg); 271 transitionTo(mRequestPendingState); 272 break; 273 case RttManager.CMD_OP_START_RANGING: { 274 RttManager.ParcelableRttParams params = 275 (RttManager.ParcelableRttParams)msg.obj; 276 if (params == null) { 277 replyFailed(msg, 278 RttManager.REASON_INVALID_REQUEST, "No params"); 279 } else if (ci.addRttRequest(msg.arg2, params) == false) { 280 replyFailed(msg, 281 RttManager.REASON_INVALID_REQUEST, "Unspecified"); 282 } else { 283 sendMessage(CMD_ISSUE_NEXT_REQUEST); 284 } 285 } 286 break; 287 case RttManager.CMD_OP_STOP_RANGING: 288 for (Iterator<RttRequest> it = mRequestQueue.iterator(); 289 it.hasNext(); ) { 290 RttRequest request = it.next(); 291 if (request.key == msg.arg2) { 292 if (DBG) Log.d(TAG, "Cancelling not-yet-scheduled RTT"); 293 mRequestQueue.remove(request); 294 request.ci.reportAborted(request.key); 295 break; 296 } 297 } 298 break; 299 default: 300 return NOT_HANDLED; 301 } 302 return HANDLED; 303 } 304 } 305 306 class RequestPendingState extends State { 307 RttRequest mOutstandingRequest; 308 @Override 309 public boolean processMessage(Message msg) { 310 if (DBG) Log.d(TAG, "RequestPendingState got" + msg); 311 switch (msg.what) { 312 case CMD_DRIVER_UNLOADED: 313 if (mOutstandingRequest != null) { 314 WifiNative.cancelRtt(mOutstandingRequest.params); 315 mOutstandingRequest.ci.reportAborted(mOutstandingRequest.key); 316 mOutstandingRequest = null; 317 } 318 transitionTo(mDefaultState); 319 break; 320 case CMD_ISSUE_NEXT_REQUEST: 321 if (mOutstandingRequest == null) { 322 mOutstandingRequest = issueNextRequest(); 323 if (mOutstandingRequest == null) { 324 transitionTo(mEnabledState); 325 } 326 } else { 327 /* just wait; we'll issue next request after 328 * current one is finished */ 329 if (DBG) Log.d(TAG, "Ignoring CMD_ISSUE_NEXT_REQUEST"); 330 } 331 break; 332 case CMD_RTT_RESPONSE: 333 if (DBG) Log.d(TAG, "Received an RTT response"); 334 mOutstandingRequest.ci.reportResult( 335 mOutstandingRequest, (RttManager.RttResult[])msg.obj); 336 mOutstandingRequest = null; 337 sendMessage(CMD_ISSUE_NEXT_REQUEST); 338 break; 339 case RttManager.CMD_OP_STOP_RANGING: 340 if (mOutstandingRequest != null 341 && msg.arg2 == mOutstandingRequest.key) { 342 if (DBG) Log.d(TAG, "Cancelling ongoing RTT"); 343 WifiNative.cancelRtt(mOutstandingRequest.params); 344 mOutstandingRequest.ci.reportAborted(mOutstandingRequest.key); 345 mOutstandingRequest = null; 346 sendMessage(CMD_ISSUE_NEXT_REQUEST); 347 } else { 348 /* Let EnabledState handle this */ 349 return NOT_HANDLED; 350 } 351 break; 352 default: 353 return NOT_HANDLED; 354 } 355 return HANDLED; 356 } 357 } 358 } 359 360 void replySucceeded(Message msg, Object obj) { 361 if (msg.replyTo != null) { 362 Message reply = Message.obtain(); 363 reply.what = RttManager.CMD_OP_SUCCEEDED; 364 reply.arg2 = msg.arg2; 365 reply.obj = obj; 366 try { 367 msg.replyTo.send(reply); 368 } catch (RemoteException e) { 369 // There's not much we can do if reply can't be sent! 370 } 371 } else { 372 // locally generated message; doesn't need a reply! 373 } 374 } 375 376 void replyFailed(Message msg, int reason, String description) { 377 Message reply = Message.obtain(); 378 reply.what = RttManager.CMD_OP_FAILED; 379 reply.arg1 = reason; 380 reply.arg2 = msg.arg2; 381 382 Bundle bundle = new Bundle(); 383 bundle.putString(RttManager.DESCRIPTION_KEY, description); 384 reply.obj = bundle; 385 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 } 392 393 private WifiNative.RttEventHandler mEventHandler = new WifiNative.RttEventHandler() { 394 @Override 395 public void onRttResults(RttManager.RttResult[] result) { 396 mStateMachine.sendMessage(CMD_RTT_RESPONSE, result); 397 } 398 }; 399 400 RttRequest issueNextRequest() { 401 RttRequest request = null; 402 while (mRequestQueue.isEmpty() == false) { 403 request = mRequestQueue.remove(); 404 if (WifiNative.requestRtt(request.params, mEventHandler)) { 405 if (DBG) Log.d(TAG, "Issued next RTT request"); 406 return request; 407 } else { 408 request.ci.reportFailed(request, 409 RttManager.REASON_UNSPECIFIED, "Failed to start"); 410 } 411 } 412 413 /* all requests exhausted */ 414 if (DBG) Log.d(TAG, "No more requests left"); 415 return null; 416 } 417 } 418 419 private static final String TAG = "RttService"; 420 RttServiceImpl mImpl; 421 422 public RttService(Context context) { 423 super(context); 424 Log.i(TAG, "Creating " + Context.WIFI_RTT_SERVICE); 425 } 426 427 @Override 428 public void onStart() { 429 mImpl = new RttServiceImpl(getContext()); 430 431 Log.i(TAG, "Starting " + Context.WIFI_RTT_SERVICE); 432 publishBinderService(Context.WIFI_RTT_SERVICE, mImpl); 433 } 434 435 @Override 436 public void onBootPhase(int phase) { 437 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 438 Log.i(TAG, "Registering " + Context.WIFI_RTT_SERVICE); 439 if (mImpl == null) { 440 mImpl = new RttServiceImpl(getContext()); 441 } 442 mImpl.startService(getContext()); 443 } 444 } 445} 446