1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi.p2p; 18 19 import android.net.wifi.p2p.WifiP2pConfig; 20 import android.net.wifi.p2p.WifiP2pDevice; 21 import android.net.wifi.p2p.WifiP2pGroup; 22 import android.net.wifi.p2p.WifiP2pProvDiscEvent; 23 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; 24 import android.os.Handler; 25 import android.os.Message; 26 import android.util.ArraySet; 27 import android.util.Log; 28 import android.util.SparseArray; 29 30 import com.android.internal.annotations.VisibleForTesting; 31 import com.android.internal.util.Protocol; 32 import com.android.server.wifi.WifiInjector; 33 import com.android.server.wifi.p2p.WifiP2pServiceImpl.P2pStatus; 34 35 import java.util.HashMap; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.Set; 39 40 /** 41 * Listens for events from the wpa_supplicant, and passes them on 42 * to the {@link WifiP2pServiceImpl} for handling. 43 * 44 * @hide 45 */ 46 public class WifiP2pMonitor { 47 private static final String TAG = "WifiP2pMonitor"; 48 49 /* Supplicant events reported to a state machine */ 50 private static final int BASE = Protocol.BASE_WIFI_MONITOR; 51 52 /* Connection to supplicant established */ 53 public static final int SUP_CONNECTION_EVENT = BASE + 1; 54 /* Connection to supplicant lost */ 55 public static final int SUP_DISCONNECTION_EVENT = BASE + 2; 56 57 /* P2P events */ 58 public static final int P2P_DEVICE_FOUND_EVENT = BASE + 21; 59 public static final int P2P_DEVICE_LOST_EVENT = BASE + 22; 60 public static final int P2P_GO_NEGOTIATION_REQUEST_EVENT = BASE + 23; 61 public static final int P2P_GO_NEGOTIATION_SUCCESS_EVENT = BASE + 25; 62 public static final int P2P_GO_NEGOTIATION_FAILURE_EVENT = BASE + 26; 63 public static final int P2P_GROUP_FORMATION_SUCCESS_EVENT = BASE + 27; 64 public static final int P2P_GROUP_FORMATION_FAILURE_EVENT = BASE + 28; 65 public static final int P2P_GROUP_STARTED_EVENT = BASE + 29; 66 public static final int P2P_GROUP_REMOVED_EVENT = BASE + 30; 67 public static final int P2P_INVITATION_RECEIVED_EVENT = BASE + 31; 68 public static final int P2P_INVITATION_RESULT_EVENT = BASE + 32; 69 public static final int P2P_PROV_DISC_PBC_REQ_EVENT = BASE + 33; 70 public static final int P2P_PROV_DISC_PBC_RSP_EVENT = BASE + 34; 71 public static final int P2P_PROV_DISC_ENTER_PIN_EVENT = BASE + 35; 72 public static final int P2P_PROV_DISC_SHOW_PIN_EVENT = BASE + 36; 73 public static final int P2P_FIND_STOPPED_EVENT = BASE + 37; 74 public static final int P2P_SERV_DISC_RESP_EVENT = BASE + 38; 75 public static final int P2P_PROV_DISC_FAILURE_EVENT = BASE + 39; 76 77 /* hostap events */ 78 public static final int AP_STA_DISCONNECTED_EVENT = BASE + 41; 79 public static final int AP_STA_CONNECTED_EVENT = BASE + 42; 80 81 82 private final WifiInjector mWifiInjector; 83 private boolean mVerboseLoggingEnabled = false; 84 private boolean mConnected = false; 85 86 public WifiP2pMonitor(WifiInjector wifiInjector) { 87 mWifiInjector = wifiInjector; 88 } 89 90 void enableVerboseLogging(int verbose) { 91 if (verbose > 0) { 92 mVerboseLoggingEnabled = true; 93 } else { 94 mVerboseLoggingEnabled = false; 95 } 96 } 97 98 // TODO(b/27569474) remove support for multiple handlers for the same event 99 private final Map<String, SparseArray<Set<Handler>>> mHandlerMap = new HashMap<>(); 100 101 /** 102 * Registers a callback handler for the provided event. 103 */ 104 public synchronized void registerHandler(String iface, int what, Handler handler) { 105 SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface); 106 if (ifaceHandlers == null) { 107 ifaceHandlers = new SparseArray<>(); 108 mHandlerMap.put(iface, ifaceHandlers); 109 } 110 Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(what); 111 if (ifaceWhatHandlers == null) { 112 ifaceWhatHandlers = new ArraySet<>(); 113 ifaceHandlers.put(what, ifaceWhatHandlers); 114 } 115 ifaceWhatHandlers.add(handler); 116 } 117 118 private final Map<String, Boolean> mMonitoringMap = new HashMap<>(); 119 private boolean isMonitoring(String iface) { 120 Boolean val = mMonitoringMap.get(iface); 121 if (val == null) { 122 return false; 123 } else { 124 return val.booleanValue(); 125 } 126 } 127 128 /** 129 * Enable/Disable monitoring for the provided iface. 130 * 131 * @param iface Name of the iface. 132 * @param enabled true to enable, false to disable. 133 */ 134 @VisibleForTesting 135 public void setMonitoring(String iface, boolean enabled) { 136 mMonitoringMap.put(iface, enabled); 137 } 138 139 private void setMonitoringNone() { 140 for (String iface : mMonitoringMap.keySet()) { 141 setMonitoring(iface, false); 142 } 143 } 144 145 /** 146 * Wait for wpa_supplicant's control interface to be ready. 147 * 148 * TODO: Add unit tests for these once we remove the legacy code. 149 */ 150 private boolean ensureConnectedLocked() { 151 if (mConnected) { 152 return true; 153 } 154 if (mVerboseLoggingEnabled) Log.d(TAG, "connecting to supplicant"); 155 int connectTries = 0; 156 while (true) { 157 mConnected = mWifiInjector.getWifiP2pNative().connectToSupplicant(); 158 if (mConnected) { 159 return true; 160 } 161 if (connectTries++ < 50) { 162 try { 163 Thread.sleep(100); 164 } catch (InterruptedException ignore) { 165 } 166 } else { 167 return false; 168 } 169 } 170 } 171 172 /** 173 * Start Monitoring for wpa_supplicant events. 174 * 175 * @param iface Name of iface. 176 * TODO: Add unit tests for these once we remove the legacy code. 177 */ 178 public synchronized void startMonitoring(String iface) { 179 if (ensureConnectedLocked()) { 180 setMonitoring(iface, true); 181 broadcastSupplicantConnectionEvent(iface); 182 } else { 183 boolean originalMonitoring = isMonitoring(iface); 184 setMonitoring(iface, true); 185 broadcastSupplicantDisconnectionEvent(iface); 186 setMonitoring(iface, originalMonitoring); 187 Log.e(TAG, "startMonitoring(" + iface + ") failed!"); 188 } 189 } 190 191 /** 192 * Stop Monitoring for wpa_supplicant events. 193 * 194 * @param iface Name of iface. 195 * TODO: Add unit tests for these once we remove the legacy code. 196 */ 197 public synchronized void stopMonitoring(String iface) { 198 if (mVerboseLoggingEnabled) Log.d(TAG, "stopMonitoring(" + iface + ")"); 199 setMonitoring(iface, true); 200 broadcastSupplicantDisconnectionEvent(iface); 201 setMonitoring(iface, false); 202 } 203 204 /** 205 * Stop Monitoring for wpa_supplicant events. 206 * 207 * TODO: Add unit tests for these once we remove the legacy code. 208 */ 209 public synchronized void stopAllMonitoring() { 210 mConnected = false; 211 setMonitoringNone(); 212 } 213 214 /** 215 * Similar functions to Handler#sendMessage that send the message to the registered handler 216 * for the given interface and message what. 217 * All of these should be called with the WifiMonitor class lock 218 */ 219 private void sendMessage(String iface, int what) { 220 sendMessage(iface, Message.obtain(null, what)); 221 } 222 223 private void sendMessage(String iface, int what, Object obj) { 224 sendMessage(iface, Message.obtain(null, what, obj)); 225 } 226 227 private void sendMessage(String iface, int what, int arg1) { 228 sendMessage(iface, Message.obtain(null, what, arg1, 0)); 229 } 230 231 private void sendMessage(String iface, int what, int arg1, int arg2) { 232 sendMessage(iface, Message.obtain(null, what, arg1, arg2)); 233 } 234 235 private void sendMessage(String iface, int what, int arg1, int arg2, Object obj) { 236 sendMessage(iface, Message.obtain(null, what, arg1, arg2, obj)); 237 } 238 239 private void sendMessage(String iface, Message message) { 240 SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface); 241 if (iface != null && ifaceHandlers != null) { 242 if (isMonitoring(iface)) { 243 Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(message.what); 244 if (ifaceWhatHandlers != null) { 245 for (Handler handler : ifaceWhatHandlers) { 246 if (handler != null) { 247 sendMessage(handler, Message.obtain(message)); 248 } 249 } 250 } 251 } else { 252 if (mVerboseLoggingEnabled) { 253 Log.d(TAG, "Dropping event because (" + iface + ") is stopped"); 254 } 255 } 256 } else { 257 if (mVerboseLoggingEnabled) { 258 Log.d(TAG, "Sending to all monitors because there's no matching iface"); 259 } 260 for (Map.Entry<String, SparseArray<Set<Handler>>> entry : mHandlerMap.entrySet()) { 261 if (isMonitoring(entry.getKey())) { 262 Set<Handler> ifaceWhatHandlers = entry.getValue().get(message.what); 263 for (Handler handler : ifaceWhatHandlers) { 264 if (handler != null) { 265 sendMessage(handler, Message.obtain(message)); 266 } 267 } 268 } 269 } 270 } 271 272 message.recycle(); 273 } 274 275 private void sendMessage(Handler handler, Message message) { 276 message.setTarget(handler); 277 message.sendToTarget(); 278 } 279 280 /** 281 * Broadcast the connection to wpa_supplicant event to all the handlers registered for 282 * this event. 283 * 284 * @param iface Name of iface on which this occurred. 285 */ 286 public void broadcastSupplicantConnectionEvent(String iface) { 287 sendMessage(iface, SUP_CONNECTION_EVENT); 288 } 289 290 /** 291 * Broadcast the loss of connection to wpa_supplicant event to all the handlers registered for 292 * this event. 293 * 294 * @param iface Name of iface on which this occurred. 295 */ 296 public void broadcastSupplicantDisconnectionEvent(String iface) { 297 sendMessage(iface, SUP_DISCONNECTION_EVENT); 298 } 299 300 /** 301 * Broadcast new p2p device discovered event to all handlers registered for this event. 302 * 303 * @param iface Name of iface on which this occurred. 304 * @param device Device that has been discovered during recent scan. 305 */ 306 public void broadcastP2pDeviceFound(String iface, WifiP2pDevice device) { 307 if (device != null) { 308 sendMessage(iface, P2P_DEVICE_FOUND_EVENT, device); 309 } 310 } 311 312 /** 313 * Broadcast p2p device lost event to all handlers registered for this event. 314 * 315 * @param iface Name of iface on which this occurred. 316 * @param device Device that has been lost in recent scan. 317 */ 318 public void broadcastP2pDeviceLost(String iface, WifiP2pDevice device) { 319 if (device != null) { 320 sendMessage(iface, P2P_DEVICE_LOST_EVENT, device); 321 } 322 } 323 324 /** 325 * Broadcast scan termination event to all handlers registered for this event. 326 * 327 * @param iface Name of iface on which this occurred. 328 */ 329 public void broadcastP2pFindStopped(String iface) { 330 sendMessage(iface, P2P_FIND_STOPPED_EVENT); 331 } 332 333 /** 334 * Broadcast group owner negotiation request event to all handlers registered for this event. 335 * 336 * @param iface Name of iface on which this occurred. 337 * @param config P2p configuration. 338 */ 339 public void broadcastP2pGoNegotiationRequest(String iface, WifiP2pConfig config) { 340 if (config != null) { 341 sendMessage(iface, P2P_GO_NEGOTIATION_REQUEST_EVENT, config); 342 } 343 } 344 345 /** 346 * Broadcast group owner negotiation success event to all handlers registered for this event. 347 * 348 * @param iface Name of iface on which this occurred. 349 */ 350 public void broadcastP2pGoNegotiationSuccess(String iface) { 351 sendMessage(iface, P2P_GO_NEGOTIATION_SUCCESS_EVENT); 352 } 353 354 /** 355 * Broadcast group owner negotiation failure event to all handlers registered for this event. 356 * 357 * @param iface Name of iface on which this occurred. 358 * @param reason Failure reason. 359 */ 360 public void broadcastP2pGoNegotiationFailure(String iface, P2pStatus reason) { 361 sendMessage(iface, P2P_GO_NEGOTIATION_FAILURE_EVENT, reason); 362 } 363 364 /** 365 * Broadcast group formation success event to all handlers registered for this event. 366 * 367 * @param iface Name of iface on which this occurred. 368 */ 369 public void broadcastP2pGroupFormationSuccess(String iface) { 370 sendMessage(iface, P2P_GROUP_FORMATION_SUCCESS_EVENT); 371 } 372 373 /** 374 * Broadcast group formation failure event to all handlers registered for this event. 375 * 376 * @param iface Name of iface on which this occurred. 377 * @param reason Failure reason. 378 */ 379 public void broadcastP2pGroupFormationFailure(String iface, String reason) { 380 P2pStatus err = P2pStatus.UNKNOWN; 381 if (reason.equals("FREQ_CONFLICT")) { 382 err = P2pStatus.NO_COMMON_CHANNEL; 383 } 384 sendMessage(iface, P2P_GROUP_FORMATION_FAILURE_EVENT, err); 385 } 386 387 /** 388 * Broadcast group started event to all handlers registered for this event. 389 * 390 * @param iface Name of iface on which this occurred. 391 * @param group Started group. 392 */ 393 public void broadcastP2pGroupStarted(String iface, WifiP2pGroup group) { 394 if (group != null) { 395 sendMessage(iface, P2P_GROUP_STARTED_EVENT, group); 396 } 397 } 398 399 /** 400 * Broadcast group removed event to all handlers registered for this event. 401 * 402 * @param iface Name of iface on which this occurred. 403 * @param group Removed group. 404 */ 405 public void broadcastP2pGroupRemoved(String iface, WifiP2pGroup group) { 406 if (group != null) { 407 sendMessage(iface, P2P_GROUP_REMOVED_EVENT, group); 408 } 409 } 410 411 /** 412 * Broadcast invitation received event to all handlers registered for this event. 413 * 414 * @param iface Name of iface on which this occurred. 415 * @param group Group to which invitation has been received. 416 */ 417 public void broadcastP2pInvitationReceived(String iface, WifiP2pGroup group) { 418 if (group != null) { 419 sendMessage(iface, P2P_INVITATION_RECEIVED_EVENT, group); 420 } 421 } 422 423 /** 424 * Broadcast invitation result event to all handlers registered for this event. 425 * 426 * @param iface Name of iface on which this occurred. 427 * @param result Result of invitation. 428 */ 429 public void broadcastP2pInvitationResult(String iface, P2pStatus result) { 430 sendMessage(iface, P2P_INVITATION_RESULT_EVENT, result); 431 } 432 433 /** 434 * Broadcast PB discovery request event to all handlers registered for this event. 435 * 436 * @param iface Name of iface on which this occurred. 437 * @param event Provision discovery request event. 438 */ 439 public void broadcastP2pProvisionDiscoveryPbcRequest(String iface, WifiP2pProvDiscEvent event) { 440 if (event != null) { 441 sendMessage(iface, P2P_PROV_DISC_PBC_REQ_EVENT, event); 442 } 443 } 444 445 /** 446 * Broadcast PB discovery response event to all handlers registered for this event. 447 * 448 * @param iface Name of iface on which this occurred. 449 * @param event Provision discovery response event. 450 */ 451 public void broadcastP2pProvisionDiscoveryPbcResponse( 452 String iface, WifiP2pProvDiscEvent event) { 453 if (event != null) { 454 sendMessage(iface, P2P_PROV_DISC_PBC_RSP_EVENT, event); 455 } 456 } 457 458 /** 459 * Broadcast PIN discovery request event to all handlers registered for this event. 460 * 461 * @param iface Name of iface on which this occurred. 462 * @param event Provision discovery request event. 463 */ 464 public void broadcastP2pProvisionDiscoveryEnterPin(String iface, WifiP2pProvDiscEvent event) { 465 if (event != null) { 466 sendMessage(iface, P2P_PROV_DISC_ENTER_PIN_EVENT, event); 467 } 468 } 469 470 /** 471 * Broadcast PIN discovery response event to all handlers registered for this event. 472 * 473 * @param iface Name of iface on which this occurred. 474 * @param event Provision discovery response event. 475 */ 476 public void broadcastP2pProvisionDiscoveryShowPin(String iface, WifiP2pProvDiscEvent event) { 477 if (event != null) { 478 sendMessage(iface, P2P_PROV_DISC_SHOW_PIN_EVENT, event); 479 } 480 } 481 482 /** 483 * Broadcast P2P discovery failure event to all handlers registered for this event. 484 * 485 * @param iface Name of iface on which this occurred. 486 */ 487 public void broadcastP2pProvisionDiscoveryFailure(String iface) { 488 sendMessage(iface, P2P_PROV_DISC_FAILURE_EVENT); 489 } 490 491 /** 492 * Broadcast service discovery response event to all handlers registered for this event. 493 * 494 * @param iface Name of iface on which this occurred. 495 * @param services List of discovered services. 496 */ 497 public void broadcastP2pServiceDiscoveryResponse( 498 String iface, List<WifiP2pServiceResponse> services) { 499 sendMessage(iface, P2P_SERV_DISC_RESP_EVENT, services); 500 } 501 502 /** 503 * Broadcast AP STA connection event. 504 * 505 * @param iface Name of iface on which this occurred. 506 */ 507 public void broadcastP2pApStaConnected(String iface, WifiP2pDevice device) { 508 sendMessage(iface, AP_STA_CONNECTED_EVENT, device); 509 } 510 511 /** 512 * Broadcast AP STA disconnection event. 513 * 514 * @param iface Name of iface on which this occurred. 515 */ 516 public void broadcastP2pApStaDisconnected(String iface, WifiP2pDevice device) { 517 sendMessage(iface, AP_STA_DISCONNECTED_EVENT, device); 518 } 519 } 520