WifiP2pServiceImpl.java revision dde96dcb1758669a7840ca88cff767ffec218936
1/* 2 * Copyright (C) 2011 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 17package com.android.server.wifi.p2p; 18 19import android.app.AlertDialog; 20import android.app.Notification; 21import android.content.Context; 22import android.content.DialogInterface; 23import android.content.DialogInterface.OnClickListener; 24import android.content.Intent; 25import android.content.pm.PackageManager; 26import android.content.res.Configuration; 27import android.content.res.Resources; 28import android.net.BaseDhcpStateMachine; 29import android.net.ConnectivityManager; 30import android.net.DhcpResults; 31import android.net.DhcpStateMachine; 32import android.net.InterfaceConfiguration; 33import android.net.LinkAddress; 34import android.net.NetworkInfo; 35import android.net.NetworkUtils; 36import android.net.dhcp.DhcpClient; 37import android.net.wifi.WpsInfo; 38import android.net.wifi.p2p.IWifiP2pManager; 39import android.net.wifi.p2p.WifiP2pConfig; 40import android.net.wifi.p2p.WifiP2pDevice; 41import android.net.wifi.p2p.WifiP2pDeviceList; 42import android.net.wifi.p2p.WifiP2pGroup; 43import android.net.wifi.p2p.WifiP2pGroupList; 44import android.net.wifi.p2p.WifiP2pGroupList.GroupDeleteListener; 45import android.net.wifi.p2p.WifiP2pInfo; 46import android.net.wifi.p2p.WifiP2pManager; 47import android.net.wifi.p2p.WifiP2pProvDiscEvent; 48import android.net.wifi.p2p.WifiP2pWfdInfo; 49import android.net.wifi.p2p.nsd.WifiP2pServiceInfo; 50import android.net.wifi.p2p.nsd.WifiP2pServiceRequest; 51import android.net.wifi.p2p.nsd.WifiP2pServiceResponse; 52import android.os.Binder; 53import android.os.Bundle; 54import android.os.Handler; 55import android.os.HandlerThread; 56import android.os.IBinder; 57import android.os.INetworkManagementService; 58import android.os.Looper; 59import android.os.Message; 60import android.os.Messenger; 61import android.os.RemoteException; 62import android.os.ServiceManager; 63import android.os.UserHandle; 64import android.provider.Settings; 65import android.text.TextUtils; 66import android.util.Slog; 67import android.util.SparseArray; 68import android.view.KeyEvent; 69import android.view.LayoutInflater; 70import android.view.View; 71import android.view.ViewGroup; 72import android.view.WindowManager; 73import android.widget.EditText; 74import android.widget.TextView; 75 76import com.android.internal.R; 77import com.android.internal.util.AsyncChannel; 78import com.android.internal.util.Protocol; 79import com.android.internal.util.State; 80import com.android.internal.util.StateMachine; 81import com.android.server.wifi.WifiMonitor; 82import com.android.server.wifi.WifiNative; 83import com.android.server.wifi.WifiStateMachine; 84 85import java.io.FileDescriptor; 86import java.io.PrintWriter; 87import java.net.InetAddress; 88import java.util.ArrayList; 89import java.util.Collection; 90import java.util.HashMap; 91import java.util.List; 92import java.util.Locale; 93 94 95/** 96 * WifiP2pService includes a state machine to perform Wi-Fi p2p operations. Applications 97 * communicate with this service to issue device discovery and connectivity requests 98 * through the WifiP2pManager interface. The state machine communicates with the wifi 99 * driver through wpa_supplicant and handles the event responses through WifiMonitor. 100 * 101 * Note that the term Wifi when used without a p2p suffix refers to the client mode 102 * of Wifi operation 103 * @hide 104 */ 105public class WifiP2pServiceImpl extends IWifiP2pManager.Stub { 106 private static final String TAG = "WifiP2pService"; 107 private static final boolean DBG = false; 108 private static final String NETWORKTYPE = "WIFI_P2P"; 109 110 private Context mContext; 111 private Notification mNotification; 112 113 INetworkManagementService mNwService; 114 private BaseDhcpStateMachine mDhcpClient; 115 116 private P2pStateMachine mP2pStateMachine; 117 private AsyncChannel mReplyChannel = new AsyncChannel(); 118 private AsyncChannel mWifiChannel; 119 120 private static final Boolean JOIN_GROUP = true; 121 private static final Boolean FORM_GROUP = false; 122 123 private static final Boolean RELOAD = true; 124 private static final Boolean NO_RELOAD = false; 125 126 /* Two minutes comes from the wpa_supplicant setting */ 127 private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000; 128 private static int mGroupCreatingTimeoutIndex = 0; 129 130 private static final int DISABLE_P2P_WAIT_TIME_MS = 5 * 1000; 131 private static int mDisableP2pTimeoutIndex = 0; 132 133 /* Set a two minute discover timeout to avoid STA scans from being blocked */ 134 private static final int DISCOVER_TIMEOUT_S = 120; 135 136 /* Idle time after a peer is gone when the group is torn down */ 137 private static final int GROUP_IDLE_TIME_S = 10; 138 139 private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE; 140 141 /* Delayed message to timeout group creation */ 142 public static final int GROUP_CREATING_TIMED_OUT = BASE + 1; 143 144 /* User accepted a peer request */ 145 private static final int PEER_CONNECTION_USER_ACCEPT = BASE + 2; 146 /* User rejected a peer request */ 147 private static final int PEER_CONNECTION_USER_REJECT = BASE + 3; 148 /* User wants to disconnect wifi in favour of p2p */ 149 private static final int DROP_WIFI_USER_ACCEPT = BASE + 4; 150 /* User wants to keep his wifi connection and drop p2p */ 151 private static final int DROP_WIFI_USER_REJECT = BASE + 5; 152 /* Delayed message to timeout p2p disable */ 153 public static final int DISABLE_P2P_TIMED_OUT = BASE + 6; 154 155 156 /* Commands to the WifiStateMachine */ 157 public static final int P2P_CONNECTION_CHANGED = BASE + 11; 158 159 /* These commands are used to temporarily disconnect wifi when we detect 160 * a frequency conflict which would make it impossible to have with p2p 161 * and wifi active at the same time. 162 * 163 * If the user chooses to disable wifi temporarily, we keep wifi disconnected 164 * until the p2p connection is done and terminated at which point we will 165 * bring back wifi up 166 * 167 * DISCONNECT_WIFI_REQUEST 168 * msg.arg1 = 1 enables temporary disconnect and 0 disables it. 169 */ 170 public static final int DISCONNECT_WIFI_REQUEST = BASE + 12; 171 public static final int DISCONNECT_WIFI_RESPONSE = BASE + 13; 172 173 public static final int SET_MIRACAST_MODE = BASE + 14; 174 175 // During dhcp (and perhaps other times) we can't afford to drop packets 176 // but Discovery will switch our channel enough we will. 177 // msg.arg1 = ENABLED for blocking, DISABLED for resumed. 178 // msg.arg2 = msg to send when blocked 179 // msg.obj = StateMachine to send to when blocked 180 public static final int BLOCK_DISCOVERY = BASE + 15; 181 182 // set country code 183 public static final int SET_COUNTRY_CODE = BASE + 16; 184 185 public static final int ENABLED = 1; 186 public static final int DISABLED = 0; 187 188 private final boolean mP2pSupported; 189 190 private WifiP2pDevice mThisDevice = new WifiP2pDevice(); 191 192 /* When a group has been explicitly created by an app, we persist the group 193 * even after all clients have been disconnected until an explicit remove 194 * is invoked */ 195 private boolean mAutonomousGroup; 196 197 /* Invitation to join an existing p2p group */ 198 private boolean mJoinExistingGroup; 199 200 /* Track whether we are in p2p discovery. This is used to avoid sending duplicate 201 * broadcasts 202 */ 203 private boolean mDiscoveryStarted; 204 /* Track whether servcice/peer discovery is blocked in favor of other wifi actions 205 * (notably dhcp) 206 */ 207 private boolean mDiscoveryBlocked; 208 209 // Supplicant doesn't like setting the same country code multiple times (it may drop 210 // current connected network), so we save the country code here to avoid redundency 211 private String mLastSetCountryCode; 212 213 /* 214 * remember if we were in a scan when it had to be stopped 215 */ 216 private boolean mDiscoveryPostponed = false; 217 218 private NetworkInfo mNetworkInfo; 219 220 private boolean mTemporarilyDisconnectedWifi = false; 221 222 /* The transaction Id of service discovery request */ 223 private byte mServiceTransactionId = 0; 224 225 /* Service discovery request ID of wpa_supplicant. 226 * null means it's not set yet. */ 227 private String mServiceDiscReqId; 228 229 /* clients(application) information list. */ 230 private HashMap<Messenger, ClientInfo> mClientInfoList = new HashMap<Messenger, ClientInfo>(); 231 232 /* Is chosen as a unique address to avoid conflict with 233 the ranges defined in Tethering.java */ 234 private static final String SERVER_ADDRESS = "192.168.49.1"; 235 236 /** 237 * Error code definition. 238 * see the Table.8 in the WiFi Direct specification for the detail. 239 */ 240 public static enum P2pStatus { 241 /* Success. */ 242 SUCCESS, 243 244 /* The target device is currently unavailable. */ 245 INFORMATION_IS_CURRENTLY_UNAVAILABLE, 246 247 /* Protocol error. */ 248 INCOMPATIBLE_PARAMETERS, 249 250 /* The target device reached the limit of the number of the connectable device. 251 * For example, device limit or group limit is set. */ 252 LIMIT_REACHED, 253 254 /* Protocol error. */ 255 INVALID_PARAMETER, 256 257 /* Unable to accommodate request. */ 258 UNABLE_TO_ACCOMMODATE_REQUEST, 259 260 /* Previous protocol error, or disruptive behavior. */ 261 PREVIOUS_PROTOCOL_ERROR, 262 263 /* There is no common channels the both devices can use. */ 264 NO_COMMON_CHANNEL, 265 266 /* Unknown p2p group. For example, Device A tries to invoke the previous persistent group, 267 * but device B has removed the specified credential already. */ 268 UNKNOWN_P2P_GROUP, 269 270 /* Both p2p devices indicated an intent of 15 in group owner negotiation. */ 271 BOTH_GO_INTENT_15, 272 273 /* Incompatible provisioning method. */ 274 INCOMPATIBLE_PROVISIONING_METHOD, 275 276 /* Rejected by user */ 277 REJECTED_BY_USER, 278 279 /* Unknown error */ 280 UNKNOWN; 281 282 public static P2pStatus valueOf(int error) { 283 switch(error) { 284 case 0 : 285 return SUCCESS; 286 case 1: 287 return INFORMATION_IS_CURRENTLY_UNAVAILABLE; 288 case 2: 289 return INCOMPATIBLE_PARAMETERS; 290 case 3: 291 return LIMIT_REACHED; 292 case 4: 293 return INVALID_PARAMETER; 294 case 5: 295 return UNABLE_TO_ACCOMMODATE_REQUEST; 296 case 6: 297 return PREVIOUS_PROTOCOL_ERROR; 298 case 7: 299 return NO_COMMON_CHANNEL; 300 case 8: 301 return UNKNOWN_P2P_GROUP; 302 case 9: 303 return BOTH_GO_INTENT_15; 304 case 10: 305 return INCOMPATIBLE_PROVISIONING_METHOD; 306 case 11: 307 return REJECTED_BY_USER; 308 default: 309 return UNKNOWN; 310 } 311 } 312 } 313 314 /** 315 * Handles client connections 316 */ 317 private class ClientHandler extends Handler { 318 319 ClientHandler(android.os.Looper looper) { 320 super(looper); 321 } 322 323 @Override 324 public void handleMessage(Message msg) { 325 switch (msg.what) { 326 case WifiP2pManager.SET_DEVICE_NAME: 327 case WifiP2pManager.SET_WFD_INFO: 328 case WifiP2pManager.DISCOVER_PEERS: 329 case WifiP2pManager.STOP_DISCOVERY: 330 case WifiP2pManager.CONNECT: 331 case WifiP2pManager.CANCEL_CONNECT: 332 case WifiP2pManager.CREATE_GROUP: 333 case WifiP2pManager.REMOVE_GROUP: 334 case WifiP2pManager.START_LISTEN: 335 case WifiP2pManager.STOP_LISTEN: 336 case WifiP2pManager.SET_CHANNEL: 337 case WifiP2pManager.START_WPS: 338 case WifiP2pManager.ADD_LOCAL_SERVICE: 339 case WifiP2pManager.REMOVE_LOCAL_SERVICE: 340 case WifiP2pManager.CLEAR_LOCAL_SERVICES: 341 case WifiP2pManager.DISCOVER_SERVICES: 342 case WifiP2pManager.ADD_SERVICE_REQUEST: 343 case WifiP2pManager.REMOVE_SERVICE_REQUEST: 344 case WifiP2pManager.CLEAR_SERVICE_REQUESTS: 345 case WifiP2pManager.REQUEST_PEERS: 346 case WifiP2pManager.REQUEST_CONNECTION_INFO: 347 case WifiP2pManager.REQUEST_GROUP_INFO: 348 case WifiP2pManager.DELETE_PERSISTENT_GROUP: 349 case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO: 350 mP2pStateMachine.sendMessage(Message.obtain(msg)); 351 break; 352 default: 353 Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg); 354 break; 355 } 356 } 357 } 358 private ClientHandler mClientHandler; 359 360 public WifiP2pServiceImpl(Context context) { 361 mContext = context; 362 363 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, ""); 364 365 mP2pSupported = mContext.getPackageManager().hasSystemFeature( 366 PackageManager.FEATURE_WIFI_DIRECT); 367 368 mThisDevice.primaryDeviceType = mContext.getResources().getString( 369 com.android.internal.R.string.config_wifi_p2p_device_type); 370 371 HandlerThread wifiP2pThread = new HandlerThread("WifiP2pService"); 372 wifiP2pThread.start(); 373 mClientHandler = new ClientHandler(wifiP2pThread.getLooper()); 374 375 mP2pStateMachine = new P2pStateMachine(TAG, wifiP2pThread.getLooper(), mP2pSupported); 376 mP2pStateMachine.start(); 377 } 378 379 public void connectivityServiceReady() { 380 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 381 mNwService = INetworkManagementService.Stub.asInterface(b); 382 } 383 384 private void enforceAccessPermission() { 385 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, 386 "WifiP2pService"); 387 } 388 389 private void enforceChangePermission() { 390 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, 391 "WifiP2pService"); 392 } 393 394 private void enforceConnectivityInternalPermission() { 395 mContext.enforceCallingOrSelfPermission( 396 android.Manifest.permission.CONNECTIVITY_INTERNAL, 397 "WifiP2pService"); 398 } 399 400 private int checkConnectivityInternalPermission() { 401 return mContext.checkCallingOrSelfPermission( 402 android.Manifest.permission.CONNECTIVITY_INTERNAL); 403 } 404 405 private int checkLocationHardwarePermission() { 406 return mContext.checkCallingOrSelfPermission( 407 android.Manifest.permission.LOCATION_HARDWARE); 408 } 409 410 private void enforceConnectivityInternalOrLocationHardwarePermission() { 411 if (checkConnectivityInternalPermission() != PackageManager.PERMISSION_GRANTED 412 && checkLocationHardwarePermission() != PackageManager.PERMISSION_GRANTED) { 413 enforceConnectivityInternalPermission(); 414 } 415 } 416 417 /** 418 * Get a reference to handler. This is used by a client to establish 419 * an AsyncChannel communication with WifiP2pService 420 */ 421 public Messenger getMessenger() { 422 enforceAccessPermission(); 423 enforceChangePermission(); 424 return new Messenger(mClientHandler); 425 } 426 427 /** 428 * Get a reference to handler. This is used by a WifiStateMachine to establish 429 * an AsyncChannel communication with P2pStateMachine 430 * @hide 431 */ 432 public Messenger getP2pStateMachineMessenger() { 433 enforceConnectivityInternalOrLocationHardwarePermission(); 434 enforceAccessPermission(); 435 enforceChangePermission(); 436 return new Messenger(mP2pStateMachine.getHandler()); 437 } 438 439 /** This is used to provide information to drivers to optimize performance depending 440 * on the current mode of operation. 441 * 0 - disabled 442 * 1 - source operation 443 * 2 - sink operation 444 * 445 * As an example, the driver could reduce the channel dwell time during scanning 446 * when acting as a source or sink to minimize impact on miracast. 447 */ 448 public void setMiracastMode(int mode) { 449 enforceConnectivityInternalPermission(); 450 mP2pStateMachine.sendMessage(SET_MIRACAST_MODE, mode); 451 } 452 453 @Override 454 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 455 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 456 != PackageManager.PERMISSION_GRANTED) { 457 pw.println("Permission Denial: can't dump WifiP2pService from from pid=" 458 + Binder.getCallingPid() 459 + ", uid=" + Binder.getCallingUid()); 460 return; 461 } 462 mP2pStateMachine.dump(fd, pw, args); 463 pw.println("mAutonomousGroup " + mAutonomousGroup); 464 pw.println("mJoinExistingGroup " + mJoinExistingGroup); 465 pw.println("mDiscoveryStarted " + mDiscoveryStarted); 466 pw.println("mNetworkInfo " + mNetworkInfo); 467 pw.println("mTemporarilyDisconnectedWifi " + mTemporarilyDisconnectedWifi); 468 pw.println("mServiceDiscReqId " + mServiceDiscReqId); 469 pw.println(); 470 } 471 472 473 /** 474 * Handles interaction with WifiStateMachine 475 */ 476 private class P2pStateMachine extends StateMachine { 477 478 private DefaultState mDefaultState = new DefaultState(); 479 private P2pNotSupportedState mP2pNotSupportedState = new P2pNotSupportedState(); 480 private P2pDisablingState mP2pDisablingState = new P2pDisablingState(); 481 private P2pDisabledState mP2pDisabledState = new P2pDisabledState(); 482 private P2pEnablingState mP2pEnablingState = new P2pEnablingState(); 483 private P2pEnabledState mP2pEnabledState = new P2pEnabledState(); 484 // Inactive is when p2p is enabled with no connectivity 485 private InactiveState mInactiveState = new InactiveState(); 486 private GroupCreatingState mGroupCreatingState = new GroupCreatingState(); 487 private UserAuthorizingInviteRequestState mUserAuthorizingInviteRequestState 488 = new UserAuthorizingInviteRequestState(); 489 private UserAuthorizingNegotiationRequestState mUserAuthorizingNegotiationRequestState 490 = new UserAuthorizingNegotiationRequestState(); 491 private ProvisionDiscoveryState mProvisionDiscoveryState = new ProvisionDiscoveryState(); 492 private GroupNegotiationState mGroupNegotiationState = new GroupNegotiationState(); 493 private FrequencyConflictState mFrequencyConflictState =new FrequencyConflictState(); 494 495 private GroupCreatedState mGroupCreatedState = new GroupCreatedState(); 496 private UserAuthorizingJoinState mUserAuthorizingJoinState = new UserAuthorizingJoinState(); 497 private OngoingGroupRemovalState mOngoingGroupRemovalState = new OngoingGroupRemovalState(); 498 499 private WifiNative mWifiNative = WifiNative.getP2pNativeInterface(); 500 private WifiMonitor mWifiMonitor = WifiMonitor.getInstance(); 501 private final WifiP2pDeviceList mPeers = new WifiP2pDeviceList(); 502 /* During a connection, supplicant can tell us that a device was lost. From a supplicant's 503 * perspective, the discovery stops during connection and it purges device since it does 504 * not get latest updates about the device without being in discovery state. 505 * 506 * From the framework perspective, the device is still there since we are connecting or 507 * connected to it. so we keep these devices in a separate list, so that they are removed 508 * when connection is cancelled or lost 509 */ 510 private final WifiP2pDeviceList mPeersLostDuringConnection = new WifiP2pDeviceList(); 511 private final WifiP2pGroupList mGroups = new WifiP2pGroupList(null, 512 new GroupDeleteListener() { 513 @Override 514 public void onDeleteGroup(int netId) { 515 if (DBG) logd("called onDeleteGroup() netId=" + netId); 516 mWifiNative.removeNetwork(netId); 517 mWifiNative.saveConfig(); 518 sendP2pPersistentGroupsChangedBroadcast(); 519 } 520 }); 521 private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo(); 522 private WifiP2pGroup mGroup; 523 524 // Saved WifiP2pConfig for an ongoing peer connection. This will never be null. 525 // The deviceAddress will be an empty string when the device is inactive 526 // or if it is connected without any ongoing join request 527 private WifiP2pConfig mSavedPeerConfig = new WifiP2pConfig(); 528 529 // Saved WifiP2pGroup from invitation request 530 private WifiP2pGroup mSavedP2pGroup; 531 532 P2pStateMachine(String name, Looper looper, boolean p2pSupported) { 533 super(name, looper); 534 535 addState(mDefaultState); 536 addState(mP2pNotSupportedState, mDefaultState); 537 addState(mP2pDisablingState, mDefaultState); 538 addState(mP2pDisabledState, mDefaultState); 539 addState(mP2pEnablingState, mDefaultState); 540 addState(mP2pEnabledState, mDefaultState); 541 addState(mInactiveState, mP2pEnabledState); 542 addState(mGroupCreatingState, mP2pEnabledState); 543 addState(mUserAuthorizingInviteRequestState, mGroupCreatingState); 544 addState(mUserAuthorizingNegotiationRequestState, mGroupCreatingState); 545 addState(mProvisionDiscoveryState, mGroupCreatingState); 546 addState(mGroupNegotiationState, mGroupCreatingState); 547 addState(mFrequencyConflictState, mGroupCreatingState); 548 addState(mGroupCreatedState, mP2pEnabledState); 549 addState(mUserAuthorizingJoinState, mGroupCreatedState); 550 addState(mOngoingGroupRemovalState, mGroupCreatedState); 551 552 if (p2pSupported) { 553 setInitialState(mP2pDisabledState); 554 } else { 555 setInitialState(mP2pNotSupportedState); 556 } 557 setLogRecSize(50); 558 setLogOnlyTransitions(true); 559 560 String interfaceName = mWifiNative.getInterfaceName(); 561 mWifiMonitor.registerHandler(interfaceName, 562 WifiMonitor.AP_STA_CONNECTED_EVENT, getHandler()); 563 mWifiMonitor.registerHandler(interfaceName, 564 WifiMonitor.AP_STA_DISCONNECTED_EVENT, getHandler()); 565 mWifiMonitor.registerHandler(interfaceName, 566 WifiMonitor.AUTHENTICATION_FAILURE_EVENT, getHandler()); 567 mWifiMonitor.registerHandler(interfaceName, 568 WifiMonitor.NETWORK_CONNECTION_EVENT, getHandler()); 569 mWifiMonitor.registerHandler(interfaceName, 570 WifiMonitor.NETWORK_DISCONNECTION_EVENT, getHandler()); 571 mWifiMonitor.registerHandler(interfaceName, 572 WifiMonitor.P2P_DEVICE_FOUND_EVENT, getHandler()); 573 mWifiMonitor.registerHandler(interfaceName, 574 WifiMonitor.P2P_DEVICE_LOST_EVENT, getHandler()); 575 mWifiMonitor.registerHandler(interfaceName, 576 WifiMonitor.P2P_FIND_STOPPED_EVENT, getHandler()); 577 mWifiMonitor.registerHandler(interfaceName, 578 WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT, getHandler()); 579 mWifiMonitor.registerHandler(interfaceName, 580 WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT, getHandler()); 581 mWifiMonitor.registerHandler(interfaceName, 582 WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT, getHandler()); 583 mWifiMonitor.registerHandler(interfaceName, 584 WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT, getHandler()); 585 mWifiMonitor.registerHandler(interfaceName, 586 WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT, getHandler()); 587 mWifiMonitor.registerHandler(interfaceName, 588 WifiMonitor.P2P_GROUP_REMOVED_EVENT, getHandler()); 589 mWifiMonitor.registerHandler(interfaceName, 590 WifiMonitor.P2P_GROUP_STARTED_EVENT, getHandler()); 591 mWifiMonitor.registerHandler(interfaceName, 592 WifiMonitor.P2P_INVITATION_RECEIVED_EVENT, getHandler()); 593 mWifiMonitor.registerHandler(interfaceName, 594 WifiMonitor.P2P_INVITATION_RESULT_EVENT, getHandler()); 595 mWifiMonitor.registerHandler(interfaceName, 596 WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT, getHandler()); 597 mWifiMonitor.registerHandler(interfaceName, 598 WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT, getHandler()); 599 mWifiMonitor.registerHandler(interfaceName, 600 WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT, getHandler()); 601 mWifiMonitor.registerHandler(interfaceName, 602 WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT, getHandler()); 603 mWifiMonitor.registerHandler(interfaceName, 604 WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT, getHandler()); 605 mWifiMonitor.registerHandler(interfaceName, 606 WifiMonitor.P2P_SERV_DISC_RESP_EVENT, getHandler()); 607 mWifiMonitor.registerHandler(interfaceName, 608 WifiMonitor.SCAN_RESULTS_EVENT, getHandler()); 609 mWifiMonitor.registerHandler(interfaceName, 610 WifiMonitor.SUP_CONNECTION_EVENT, getHandler()); 611 mWifiMonitor.registerHandler(interfaceName, 612 WifiMonitor.SUP_DISCONNECTION_EVENT, getHandler()); 613 mWifiMonitor.registerHandler(interfaceName, 614 WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, getHandler()); 615 mWifiMonitor.registerHandler(interfaceName, 616 WifiMonitor.WPS_FAIL_EVENT, getHandler()); 617 mWifiMonitor.registerHandler(interfaceName, 618 WifiMonitor.WPS_OVERLAP_EVENT, getHandler()); 619 mWifiMonitor.registerHandler(interfaceName, 620 WifiMonitor.WPS_SUCCESS_EVENT, getHandler()); 621 mWifiMonitor.registerHandler(interfaceName, 622 WifiMonitor.WPS_TIMEOUT_EVENT, getHandler()); 623 } 624 625 class DefaultState extends State { 626 @Override 627 public boolean processMessage(Message message) { 628 if (DBG) logd(getName() + message.toString()); 629 switch (message.what) { 630 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 631 if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 632 if (DBG) logd("Full connection with WifiStateMachine established"); 633 mWifiChannel = (AsyncChannel) message.obj; 634 } else { 635 loge("Full connection failure, error = " + message.arg1); 636 mWifiChannel = null; 637 } 638 break; 639 640 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 641 if (message.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { 642 loge("Send failed, client connection lost"); 643 } else { 644 loge("Client connection lost with reason: " + message.arg1); 645 } 646 mWifiChannel = null; 647 break; 648 649 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: 650 AsyncChannel ac = new AsyncChannel(); 651 ac.connect(mContext, getHandler(), message.replyTo); 652 break; 653 case BLOCK_DISCOVERY: 654 mDiscoveryBlocked = (message.arg1 == ENABLED ? true : false); 655 // always reset this - we went to a state that doesn't support discovery so 656 // it would have stopped regardless 657 mDiscoveryPostponed = false; 658 if (mDiscoveryBlocked) { 659 try { 660 StateMachine m = (StateMachine)message.obj; 661 m.sendMessage(message.arg2); 662 } catch (Exception e) { 663 loge("unable to send BLOCK_DISCOVERY response: " + e); 664 } 665 } 666 break; 667 case WifiP2pManager.DISCOVER_PEERS: 668 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 669 WifiP2pManager.BUSY); 670 break; 671 case WifiP2pManager.STOP_DISCOVERY: 672 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, 673 WifiP2pManager.BUSY); 674 break; 675 case WifiP2pManager.DISCOVER_SERVICES: 676 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 677 WifiP2pManager.BUSY); 678 break; 679 case WifiP2pManager.CONNECT: 680 replyToMessage(message, WifiP2pManager.CONNECT_FAILED, 681 WifiP2pManager.BUSY); 682 break; 683 case WifiP2pManager.CANCEL_CONNECT: 684 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED, 685 WifiP2pManager.BUSY); 686 break; 687 case WifiP2pManager.CREATE_GROUP: 688 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, 689 WifiP2pManager.BUSY); 690 break; 691 case WifiP2pManager.REMOVE_GROUP: 692 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, 693 WifiP2pManager.BUSY); 694 break; 695 case WifiP2pManager.ADD_LOCAL_SERVICE: 696 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED, 697 WifiP2pManager.BUSY); 698 break; 699 case WifiP2pManager.REMOVE_LOCAL_SERVICE: 700 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED, 701 WifiP2pManager.BUSY); 702 break; 703 case WifiP2pManager.CLEAR_LOCAL_SERVICES: 704 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED, 705 WifiP2pManager.BUSY); 706 break; 707 case WifiP2pManager.ADD_SERVICE_REQUEST: 708 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED, 709 WifiP2pManager.BUSY); 710 break; 711 case WifiP2pManager.REMOVE_SERVICE_REQUEST: 712 replyToMessage(message, 713 WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED, 714 WifiP2pManager.BUSY); 715 break; 716 case WifiP2pManager.CLEAR_SERVICE_REQUESTS: 717 replyToMessage(message, 718 WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED, 719 WifiP2pManager.BUSY); 720 break; 721 case WifiP2pManager.SET_DEVICE_NAME: 722 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, 723 WifiP2pManager.BUSY); 724 break; 725 case WifiP2pManager.DELETE_PERSISTENT_GROUP: 726 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP, 727 WifiP2pManager.BUSY); 728 break; 729 case WifiP2pManager.SET_WFD_INFO: 730 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, 731 WifiP2pManager.BUSY); 732 break; 733 case WifiP2pManager.REQUEST_PEERS: 734 replyToMessage(message, WifiP2pManager.RESPONSE_PEERS, 735 new WifiP2pDeviceList(mPeers)); 736 break; 737 case WifiP2pManager.REQUEST_CONNECTION_INFO: 738 replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO, 739 new WifiP2pInfo(mWifiP2pInfo)); 740 break; 741 case WifiP2pManager.REQUEST_GROUP_INFO: 742 replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, 743 mGroup != null ? new WifiP2pGroup(mGroup) : null); 744 break; 745 case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO: 746 replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO, 747 new WifiP2pGroupList(mGroups, null)); 748 break; 749 case WifiP2pManager.START_WPS: 750 replyToMessage(message, WifiP2pManager.START_WPS_FAILED, 751 WifiP2pManager.BUSY); 752 break; 753 case WifiP2pManager.GET_HANDOVER_REQUEST: 754 case WifiP2pManager.GET_HANDOVER_SELECT: 755 replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE, null); 756 break; 757 case WifiP2pManager.INITIATOR_REPORT_NFC_HANDOVER: 758 case WifiP2pManager.RESPONDER_REPORT_NFC_HANDOVER: 759 replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED, 760 WifiP2pManager.BUSY); 761 break; 762 // Ignore 763 case WifiMonitor.P2P_INVITATION_RESULT_EVENT: 764 case WifiMonitor.SCAN_RESULTS_EVENT: 765 case WifiMonitor.SUP_CONNECTION_EVENT: 766 case WifiMonitor.SUP_DISCONNECTION_EVENT: 767 case WifiMonitor.NETWORK_CONNECTION_EVENT: 768 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 769 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 770 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 771 case WifiMonitor.WPS_SUCCESS_EVENT: 772 case WifiMonitor.WPS_FAIL_EVENT: 773 case WifiMonitor.WPS_OVERLAP_EVENT: 774 case WifiMonitor.WPS_TIMEOUT_EVENT: 775 case WifiMonitor.P2P_GROUP_REMOVED_EVENT: 776 case WifiMonitor.P2P_DEVICE_FOUND_EVENT: 777 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 778 case WifiMonitor.P2P_FIND_STOPPED_EVENT: 779 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT: 780 case PEER_CONNECTION_USER_ACCEPT: 781 case PEER_CONNECTION_USER_REJECT: 782 case DISCONNECT_WIFI_RESPONSE: 783 case DROP_WIFI_USER_ACCEPT: 784 case DROP_WIFI_USER_REJECT: 785 case GROUP_CREATING_TIMED_OUT: 786 case DISABLE_P2P_TIMED_OUT: 787 case DhcpStateMachine.CMD_PRE_DHCP_ACTION: 788 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 789 case DhcpStateMachine.CMD_ON_QUIT: 790 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT: 791 case SET_MIRACAST_MODE: 792 case WifiP2pManager.START_LISTEN: 793 case WifiP2pManager.STOP_LISTEN: 794 case WifiP2pManager.SET_CHANNEL: 795 case SET_COUNTRY_CODE: 796 break; 797 case WifiStateMachine.CMD_ENABLE_P2P: 798 // Enable is lazy and has no response 799 break; 800 case WifiStateMachine.CMD_DISABLE_P2P_REQ: 801 // If we end up handling in default, p2p is not enabled 802 mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP); 803 break; 804 /* unexpected group created, remove */ 805 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 806 mGroup = (WifiP2pGroup) message.obj; 807 loge("Unexpected group creation, remove " + mGroup); 808 mWifiNative.p2pGroupRemove(mGroup.getInterface()); 809 break; 810 // A group formation failure is always followed by 811 // a group removed event. Flushing things at group formation 812 // failure causes supplicant issues. Ignore right now. 813 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: 814 break; 815 default: 816 loge("Unhandled message " + message); 817 return NOT_HANDLED; 818 } 819 return HANDLED; 820 } 821 } 822 823 class P2pNotSupportedState extends State { 824 @Override 825 public boolean processMessage(Message message) { 826 switch (message.what) { 827 case WifiP2pManager.DISCOVER_PEERS: 828 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 829 WifiP2pManager.P2P_UNSUPPORTED); 830 break; 831 case WifiP2pManager.STOP_DISCOVERY: 832 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, 833 WifiP2pManager.P2P_UNSUPPORTED); 834 break; 835 case WifiP2pManager.DISCOVER_SERVICES: 836 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 837 WifiP2pManager.P2P_UNSUPPORTED); 838 break; 839 case WifiP2pManager.CONNECT: 840 replyToMessage(message, WifiP2pManager.CONNECT_FAILED, 841 WifiP2pManager.P2P_UNSUPPORTED); 842 break; 843 case WifiP2pManager.CANCEL_CONNECT: 844 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED, 845 WifiP2pManager.P2P_UNSUPPORTED); 846 break; 847 case WifiP2pManager.CREATE_GROUP: 848 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, 849 WifiP2pManager.P2P_UNSUPPORTED); 850 break; 851 case WifiP2pManager.REMOVE_GROUP: 852 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, 853 WifiP2pManager.P2P_UNSUPPORTED); 854 break; 855 case WifiP2pManager.ADD_LOCAL_SERVICE: 856 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED, 857 WifiP2pManager.P2P_UNSUPPORTED); 858 break; 859 case WifiP2pManager.REMOVE_LOCAL_SERVICE: 860 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED, 861 WifiP2pManager.P2P_UNSUPPORTED); 862 break; 863 case WifiP2pManager.CLEAR_LOCAL_SERVICES: 864 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED, 865 WifiP2pManager.P2P_UNSUPPORTED); 866 break; 867 case WifiP2pManager.ADD_SERVICE_REQUEST: 868 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED, 869 WifiP2pManager.P2P_UNSUPPORTED); 870 break; 871 case WifiP2pManager.REMOVE_SERVICE_REQUEST: 872 replyToMessage(message, 873 WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED, 874 WifiP2pManager.P2P_UNSUPPORTED); 875 break; 876 case WifiP2pManager.CLEAR_SERVICE_REQUESTS: 877 replyToMessage(message, 878 WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED, 879 WifiP2pManager.P2P_UNSUPPORTED); 880 break; 881 case WifiP2pManager.SET_DEVICE_NAME: 882 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, 883 WifiP2pManager.P2P_UNSUPPORTED); 884 break; 885 case WifiP2pManager.DELETE_PERSISTENT_GROUP: 886 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP, 887 WifiP2pManager.P2P_UNSUPPORTED); 888 break; 889 case WifiP2pManager.SET_WFD_INFO: 890 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, 891 WifiP2pManager.P2P_UNSUPPORTED); 892 break; 893 case WifiP2pManager.START_WPS: 894 replyToMessage(message, WifiP2pManager.START_WPS_FAILED, 895 WifiP2pManager.P2P_UNSUPPORTED); 896 break; 897 case WifiP2pManager.START_LISTEN: 898 replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED, 899 WifiP2pManager.P2P_UNSUPPORTED); 900 break; 901 case WifiP2pManager.STOP_LISTEN: 902 replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED, 903 WifiP2pManager.P2P_UNSUPPORTED); 904 break; 905 906 default: 907 return NOT_HANDLED; 908 } 909 return HANDLED; 910 } 911 } 912 913 class P2pDisablingState extends State { 914 @Override 915 public void enter() { 916 if (DBG) logd(getName()); 917 sendMessageDelayed(obtainMessage(DISABLE_P2P_TIMED_OUT, 918 ++mDisableP2pTimeoutIndex, 0), DISABLE_P2P_WAIT_TIME_MS); 919 } 920 921 @Override 922 public boolean processMessage(Message message) { 923 if (DBG) logd(getName() + message.toString()); 924 switch (message.what) { 925 case WifiMonitor.SUP_DISCONNECTION_EVENT: 926 if (DBG) logd("p2p socket connection lost"); 927 transitionTo(mP2pDisabledState); 928 break; 929 case WifiStateMachine.CMD_ENABLE_P2P: 930 case WifiStateMachine.CMD_DISABLE_P2P_REQ: 931 deferMessage(message); 932 break; 933 case DISABLE_P2P_TIMED_OUT: 934 if (mDisableP2pTimeoutIndex == message.arg1) { 935 loge("P2p disable timed out"); 936 transitionTo(mP2pDisabledState); 937 } 938 break; 939 default: 940 return NOT_HANDLED; 941 } 942 return HANDLED; 943 } 944 945 @Override 946 public void exit() { 947 mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP); 948 } 949 } 950 951 class P2pDisabledState extends State { 952 @Override 953 public void enter() { 954 if (DBG) logd(getName()); 955 } 956 957 @Override 958 public boolean processMessage(Message message) { 959 if (DBG) logd(getName() + message.toString()); 960 switch (message.what) { 961 case WifiStateMachine.CMD_ENABLE_P2P: 962 try { 963 mNwService.setInterfaceUp(mWifiNative.getInterfaceName()); 964 } catch (RemoteException re) { 965 loge("Unable to change interface settings: " + re); 966 } catch (IllegalStateException ie) { 967 loge("Unable to change interface settings: " + ie); 968 } 969 mWifiMonitor.startMonitoring(mWifiNative.getInterfaceName()); 970 transitionTo(mP2pEnablingState); 971 break; 972 default: 973 return NOT_HANDLED; 974 } 975 return HANDLED; 976 } 977 } 978 979 class P2pEnablingState extends State { 980 @Override 981 public void enter() { 982 if (DBG) logd(getName()); 983 } 984 985 @Override 986 public boolean processMessage(Message message) { 987 if (DBG) logd(getName() + message.toString()); 988 switch (message.what) { 989 case WifiMonitor.SUP_CONNECTION_EVENT: 990 if (DBG) logd("P2p socket connection successful"); 991 transitionTo(mInactiveState); 992 break; 993 case WifiMonitor.SUP_DISCONNECTION_EVENT: 994 loge("P2p socket connection failed"); 995 transitionTo(mP2pDisabledState); 996 break; 997 case WifiStateMachine.CMD_ENABLE_P2P: 998 case WifiStateMachine.CMD_DISABLE_P2P_REQ: 999 deferMessage(message); 1000 break; 1001 default: 1002 return NOT_HANDLED; 1003 } 1004 return HANDLED; 1005 } 1006 } 1007 1008 class P2pEnabledState extends State { 1009 @Override 1010 public void enter() { 1011 if (DBG) logd(getName()); 1012 sendP2pStateChangedBroadcast(true); 1013 mNetworkInfo.setIsAvailable(true); 1014 sendP2pConnectionChangedBroadcast(); 1015 initializeP2pSettings(); 1016 } 1017 1018 @Override 1019 public boolean processMessage(Message message) { 1020 if (DBG) logd(getName() + message.toString()); 1021 switch (message.what) { 1022 case WifiMonitor.SUP_DISCONNECTION_EVENT: 1023 loge("Unexpected loss of p2p socket connection"); 1024 transitionTo(mP2pDisabledState); 1025 break; 1026 case WifiStateMachine.CMD_ENABLE_P2P: 1027 //Nothing to do 1028 break; 1029 case WifiStateMachine.CMD_DISABLE_P2P_REQ: 1030 if (mPeers.clear()) { 1031 sendPeersChangedBroadcast(); 1032 } 1033 if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast(); 1034 1035 mWifiMonitor.stopMonitoring(mWifiNative.getInterfaceName()); 1036 transitionTo(mP2pDisablingState); 1037 break; 1038 case WifiP2pManager.SET_DEVICE_NAME: 1039 { 1040 WifiP2pDevice d = (WifiP2pDevice) message.obj; 1041 if (d != null && setAndPersistDeviceName(d.deviceName)) { 1042 if (DBG) logd("set device name " + d.deviceName); 1043 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED); 1044 } else { 1045 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, 1046 WifiP2pManager.ERROR); 1047 } 1048 break; 1049 } 1050 case WifiP2pManager.SET_WFD_INFO: 1051 { 1052 WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj; 1053 if (d != null && setWfdInfo(d)) { 1054 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED); 1055 } else { 1056 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, 1057 WifiP2pManager.ERROR); 1058 } 1059 break; 1060 } 1061 case BLOCK_DISCOVERY: 1062 boolean blocked = (message.arg1 == ENABLED ? true : false); 1063 if (mDiscoveryBlocked == blocked) break; 1064 mDiscoveryBlocked = blocked; 1065 if (blocked && mDiscoveryStarted) { 1066 mWifiNative.p2pStopFind(); 1067 mDiscoveryPostponed = true; 1068 } 1069 if (!blocked && mDiscoveryPostponed) { 1070 mDiscoveryPostponed = false; 1071 mWifiNative.p2pFind(DISCOVER_TIMEOUT_S); 1072 } 1073 if (blocked) { 1074 try { 1075 StateMachine m = (StateMachine)message.obj; 1076 m.sendMessage(message.arg2); 1077 } catch (Exception e) { 1078 loge("unable to send BLOCK_DISCOVERY response: " + e); 1079 } 1080 } 1081 break; 1082 case WifiP2pManager.DISCOVER_PEERS: 1083 if (mDiscoveryBlocked) { 1084 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 1085 WifiP2pManager.BUSY); 1086 break; 1087 } 1088 // do not send service discovery request while normal find operation. 1089 clearSupplicantServiceRequest(); 1090 if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) { 1091 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED); 1092 sendP2pDiscoveryChangedBroadcast(true); 1093 } else { 1094 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 1095 WifiP2pManager.ERROR); 1096 } 1097 break; 1098 case WifiMonitor.P2P_FIND_STOPPED_EVENT: 1099 sendP2pDiscoveryChangedBroadcast(false); 1100 break; 1101 case WifiP2pManager.STOP_DISCOVERY: 1102 if (mWifiNative.p2pStopFind()) { 1103 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED); 1104 } else { 1105 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, 1106 WifiP2pManager.ERROR); 1107 } 1108 break; 1109 case WifiP2pManager.DISCOVER_SERVICES: 1110 if (mDiscoveryBlocked) { 1111 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 1112 WifiP2pManager.BUSY); 1113 break; 1114 } 1115 if (DBG) logd(getName() + " discover services"); 1116 if (!updateSupplicantServiceRequest()) { 1117 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 1118 WifiP2pManager.NO_SERVICE_REQUESTS); 1119 break; 1120 } 1121 if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) { 1122 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_SUCCEEDED); 1123 } else { 1124 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 1125 WifiP2pManager.ERROR); 1126 } 1127 break; 1128 case WifiMonitor.P2P_DEVICE_FOUND_EVENT: 1129 WifiP2pDevice device = (WifiP2pDevice) message.obj; 1130 if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break; 1131 mPeers.updateSupplicantDetails(device); 1132 sendPeersChangedBroadcast(); 1133 break; 1134 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 1135 device = (WifiP2pDevice) message.obj; 1136 // Gets current details for the one removed 1137 device = mPeers.remove(device.deviceAddress); 1138 if (device != null) { 1139 sendPeersChangedBroadcast(); 1140 } 1141 break; 1142 case WifiP2pManager.ADD_LOCAL_SERVICE: 1143 if (DBG) logd(getName() + " add service"); 1144 WifiP2pServiceInfo servInfo = (WifiP2pServiceInfo)message.obj; 1145 if (addLocalService(message.replyTo, servInfo)) { 1146 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_SUCCEEDED); 1147 } else { 1148 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED); 1149 } 1150 break; 1151 case WifiP2pManager.REMOVE_LOCAL_SERVICE: 1152 if (DBG) logd(getName() + " remove service"); 1153 servInfo = (WifiP2pServiceInfo)message.obj; 1154 removeLocalService(message.replyTo, servInfo); 1155 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_SUCCEEDED); 1156 break; 1157 case WifiP2pManager.CLEAR_LOCAL_SERVICES: 1158 if (DBG) logd(getName() + " clear service"); 1159 clearLocalServices(message.replyTo); 1160 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_SUCCEEDED); 1161 break; 1162 case WifiP2pManager.ADD_SERVICE_REQUEST: 1163 if (DBG) logd(getName() + " add service request"); 1164 if (!addServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj)) { 1165 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED); 1166 break; 1167 } 1168 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_SUCCEEDED); 1169 break; 1170 case WifiP2pManager.REMOVE_SERVICE_REQUEST: 1171 if (DBG) logd(getName() + " remove service request"); 1172 removeServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj); 1173 replyToMessage(message, WifiP2pManager.REMOVE_SERVICE_REQUEST_SUCCEEDED); 1174 break; 1175 case WifiP2pManager.CLEAR_SERVICE_REQUESTS: 1176 if (DBG) logd(getName() + " clear service request"); 1177 clearServiceRequests(message.replyTo); 1178 replyToMessage(message, WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED); 1179 break; 1180 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT: 1181 if (DBG) logd(getName() + " receive service response"); 1182 List<WifiP2pServiceResponse> sdRespList = 1183 (List<WifiP2pServiceResponse>) message.obj; 1184 for (WifiP2pServiceResponse resp : sdRespList) { 1185 WifiP2pDevice dev = 1186 mPeers.get(resp.getSrcDevice().deviceAddress); 1187 resp.setSrcDevice(dev); 1188 sendServiceResponse(resp); 1189 } 1190 break; 1191 case WifiP2pManager.DELETE_PERSISTENT_GROUP: 1192 if (DBG) logd(getName() + " delete persistent group"); 1193 mGroups.remove(message.arg1); 1194 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED); 1195 break; 1196 case SET_MIRACAST_MODE: 1197 mWifiNative.setMiracastMode(message.arg1); 1198 break; 1199 case WifiP2pManager.START_LISTEN: 1200 if (DBG) logd(getName() + " start listen mode"); 1201 mWifiNative.p2pFlush(); 1202 if (mWifiNative.p2pExtListen(true, 500, 500)) { 1203 replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED); 1204 } else { 1205 replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED); 1206 } 1207 break; 1208 case WifiP2pManager.STOP_LISTEN: 1209 if (DBG) logd(getName() + " stop listen mode"); 1210 if (mWifiNative.p2pExtListen(false, 0, 0)) { 1211 replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED); 1212 } else { 1213 replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED); 1214 } 1215 mWifiNative.p2pFlush(); 1216 break; 1217 case WifiP2pManager.SET_CHANNEL: 1218 Bundle p2pChannels = (Bundle) message.obj; 1219 int lc = p2pChannels.getInt("lc", 0); 1220 int oc = p2pChannels.getInt("oc", 0); 1221 if (DBG) logd(getName() + " set listen and operating channel"); 1222 if (mWifiNative.p2pSetChannel(lc, oc)) { 1223 replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED); 1224 } else { 1225 replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED); 1226 } 1227 break; 1228 case SET_COUNTRY_CODE: 1229 String countryCode = (String) message.obj; 1230 countryCode = countryCode.toUpperCase(Locale.ROOT); 1231 if (mLastSetCountryCode == null || 1232 countryCode.equals(mLastSetCountryCode) == false) { 1233 if (mWifiNative.setCountryCode(countryCode)) { 1234 mLastSetCountryCode = countryCode; 1235 } 1236 } 1237 break; 1238 case WifiP2pManager.GET_HANDOVER_REQUEST: 1239 Bundle requestBundle = new Bundle(); 1240 requestBundle.putString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE, 1241 mWifiNative.getNfcHandoverRequest()); 1242 replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE, 1243 requestBundle); 1244 break; 1245 case WifiP2pManager.GET_HANDOVER_SELECT: 1246 Bundle selectBundle = new Bundle(); 1247 selectBundle.putString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE, 1248 mWifiNative.getNfcHandoverSelect()); 1249 replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE, 1250 selectBundle); 1251 break; 1252 default: 1253 return NOT_HANDLED; 1254 } 1255 return HANDLED; 1256 } 1257 1258 @Override 1259 public void exit() { 1260 sendP2pDiscoveryChangedBroadcast(false); 1261 sendP2pStateChangedBroadcast(false); 1262 mNetworkInfo.setIsAvailable(false); 1263 1264 mLastSetCountryCode = null; 1265 } 1266 } 1267 1268 class InactiveState extends State { 1269 @Override 1270 public void enter() { 1271 if (DBG) logd(getName()); 1272 mSavedPeerConfig.invalidate(); 1273 } 1274 1275 @Override 1276 public boolean processMessage(Message message) { 1277 if (DBG) logd(getName() + message.toString()); 1278 switch (message.what) { 1279 case WifiP2pManager.CONNECT: 1280 if (DBG) logd(getName() + " sending connect"); 1281 WifiP2pConfig config = (WifiP2pConfig) message.obj; 1282 if (isConfigInvalid(config)) { 1283 loge("Dropping connect requeset " + config); 1284 replyToMessage(message, WifiP2pManager.CONNECT_FAILED); 1285 break; 1286 } 1287 1288 mAutonomousGroup = false; 1289 mWifiNative.p2pStopFind(); 1290 if (reinvokePersistentGroup(config)) { 1291 transitionTo(mGroupNegotiationState); 1292 } else { 1293 transitionTo(mProvisionDiscoveryState); 1294 } 1295 mSavedPeerConfig = config; 1296 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); 1297 sendPeersChangedBroadcast(); 1298 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); 1299 break; 1300 case WifiP2pManager.STOP_DISCOVERY: 1301 if (mWifiNative.p2pStopFind()) { 1302 // When discovery stops in inactive state, flush to clear 1303 // state peer data 1304 mWifiNative.p2pFlush(); 1305 mServiceDiscReqId = null; 1306 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED); 1307 } else { 1308 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, 1309 WifiP2pManager.ERROR); 1310 } 1311 break; 1312 case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT: 1313 config = (WifiP2pConfig) message.obj; 1314 if (isConfigInvalid(config)) { 1315 loge("Dropping GO neg request " + config); 1316 break; 1317 } 1318 mSavedPeerConfig = config; 1319 mAutonomousGroup = false; 1320 mJoinExistingGroup = false; 1321 transitionTo(mUserAuthorizingNegotiationRequestState); 1322 break; 1323 case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT: 1324 WifiP2pGroup group = (WifiP2pGroup) message.obj; 1325 WifiP2pDevice owner = group.getOwner(); 1326 1327 if (owner == null) { 1328 loge("Ignored invitation from null owner"); 1329 break; 1330 } 1331 1332 config = new WifiP2pConfig(); 1333 config.deviceAddress = group.getOwner().deviceAddress; 1334 1335 if (isConfigInvalid(config)) { 1336 loge("Dropping invitation request " + config); 1337 break; 1338 } 1339 mSavedPeerConfig = config; 1340 1341 //Check if we have the owner in peer list and use appropriate 1342 //wps method. Default is to use PBC. 1343 if ((owner = mPeers.get(owner.deviceAddress)) != null) { 1344 if (owner.wpsPbcSupported()) { 1345 mSavedPeerConfig.wps.setup = WpsInfo.PBC; 1346 } else if (owner.wpsKeypadSupported()) { 1347 mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; 1348 } else if (owner.wpsDisplaySupported()) { 1349 mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY; 1350 } 1351 } 1352 1353 mAutonomousGroup = false; 1354 mJoinExistingGroup = true; 1355 transitionTo(mUserAuthorizingInviteRequestState); 1356 break; 1357 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: 1358 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 1359 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 1360 //We let the supplicant handle the provision discovery response 1361 //and wait instead for the GO_NEGOTIATION_REQUEST_EVENT. 1362 //Handling provision discovery and issuing a p2p_connect before 1363 //group negotiation comes through causes issues 1364 break; 1365 case WifiP2pManager.CREATE_GROUP: 1366 mAutonomousGroup = true; 1367 int netId = message.arg1; 1368 boolean ret = false; 1369 if (netId == WifiP2pGroup.PERSISTENT_NET_ID) { 1370 // check if the go persistent group is present. 1371 netId = mGroups.getNetworkId(mThisDevice.deviceAddress); 1372 if (netId != -1) { 1373 ret = mWifiNative.p2pGroupAdd(netId); 1374 } else { 1375 ret = mWifiNative.p2pGroupAdd(true); 1376 } 1377 } else { 1378 ret = mWifiNative.p2pGroupAdd(false); 1379 } 1380 1381 if (ret) { 1382 replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED); 1383 transitionTo(mGroupNegotiationState); 1384 } else { 1385 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, 1386 WifiP2pManager.ERROR); 1387 // remain at this state. 1388 } 1389 break; 1390 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 1391 mGroup = (WifiP2pGroup) message.obj; 1392 if (DBG) logd(getName() + " group started"); 1393 1394 // We hit this scenario when a persistent group is reinvoked 1395 if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) { 1396 mAutonomousGroup = false; 1397 deferMessage(message); 1398 transitionTo(mGroupNegotiationState); 1399 } else { 1400 loge("Unexpected group creation, remove " + mGroup); 1401 mWifiNative.p2pGroupRemove(mGroup.getInterface()); 1402 } 1403 break; 1404 case WifiP2pManager.START_LISTEN: 1405 if (DBG) logd(getName() + " start listen mode"); 1406 mWifiNative.p2pFlush(); 1407 if (mWifiNative.p2pExtListen(true, 500, 500)) { 1408 replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED); 1409 } else { 1410 replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED); 1411 } 1412 break; 1413 case WifiP2pManager.STOP_LISTEN: 1414 if (DBG) logd(getName() + " stop listen mode"); 1415 if (mWifiNative.p2pExtListen(false, 0, 0)) { 1416 replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED); 1417 } else { 1418 replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED); 1419 } 1420 mWifiNative.p2pFlush(); 1421 break; 1422 case WifiP2pManager.SET_CHANNEL: 1423 Bundle p2pChannels = (Bundle) message.obj; 1424 int lc = p2pChannels.getInt("lc", 0); 1425 int oc = p2pChannels.getInt("oc", 0); 1426 if (DBG) logd(getName() + " set listen and operating channel"); 1427 if (mWifiNative.p2pSetChannel(lc, oc)) { 1428 replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED); 1429 } else { 1430 replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED); 1431 } 1432 break; 1433 case WifiP2pManager.INITIATOR_REPORT_NFC_HANDOVER: 1434 String handoverSelect = null; 1435 1436 if (message.obj != null) { 1437 handoverSelect = ((Bundle) message.obj) 1438 .getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE); 1439 } 1440 1441 if (handoverSelect != null 1442 && mWifiNative.initiatorReportNfcHandover(handoverSelect)) { 1443 replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED); 1444 transitionTo(mGroupCreatingState); 1445 } else { 1446 replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED); 1447 } 1448 break; 1449 case WifiP2pManager.RESPONDER_REPORT_NFC_HANDOVER: 1450 String handoverRequest = null; 1451 1452 if (message.obj != null) { 1453 handoverRequest = ((Bundle) message.obj) 1454 .getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE); 1455 } 1456 1457 if (handoverRequest != null 1458 && mWifiNative.responderReportNfcHandover(handoverRequest)) { 1459 replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED); 1460 transitionTo(mGroupCreatingState); 1461 } else { 1462 replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED); 1463 } 1464 break; 1465 default: 1466 return NOT_HANDLED; 1467 } 1468 return HANDLED; 1469 } 1470 } 1471 1472 class GroupCreatingState extends State { 1473 @Override 1474 public void enter() { 1475 if (DBG) logd(getName()); 1476 sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT, 1477 ++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS); 1478 } 1479 1480 @Override 1481 public boolean processMessage(Message message) { 1482 if (DBG) logd(getName() + message.toString()); 1483 boolean ret = HANDLED; 1484 switch (message.what) { 1485 case GROUP_CREATING_TIMED_OUT: 1486 if (mGroupCreatingTimeoutIndex == message.arg1) { 1487 if (DBG) logd("Group negotiation timed out"); 1488 handleGroupCreationFailure(); 1489 transitionTo(mInactiveState); 1490 } 1491 break; 1492 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 1493 WifiP2pDevice device = (WifiP2pDevice) message.obj; 1494 if (!mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) { 1495 if (DBG) { 1496 logd("mSavedPeerConfig " + mSavedPeerConfig.deviceAddress + 1497 "device " + device.deviceAddress); 1498 } 1499 // Do the regular device lost handling 1500 ret = NOT_HANDLED; 1501 break; 1502 } 1503 // Do nothing 1504 if (DBG) logd("Add device to lost list " + device); 1505 mPeersLostDuringConnection.updateSupplicantDetails(device); 1506 break; 1507 case WifiP2pManager.DISCOVER_PEERS: 1508 /* Discovery will break negotiation */ 1509 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 1510 WifiP2pManager.BUSY); 1511 break; 1512 case WifiP2pManager.CANCEL_CONNECT: 1513 //Do a supplicant p2p_cancel which only cancels an ongoing 1514 //group negotiation. This will fail for a pending provision 1515 //discovery or for a pending user action, but at the framework 1516 //level, we always treat cancel as succeeded and enter 1517 //an inactive state 1518 mWifiNative.p2pCancelConnect(); 1519 handleGroupCreationFailure(); 1520 transitionTo(mInactiveState); 1521 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED); 1522 break; 1523 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT: 1524 // We hit this scenario when NFC handover is invoked. 1525 mAutonomousGroup = false; 1526 transitionTo(mGroupNegotiationState); 1527 break; 1528 default: 1529 ret = NOT_HANDLED; 1530 } 1531 return ret; 1532 } 1533 } 1534 1535 class UserAuthorizingNegotiationRequestState extends State { 1536 @Override 1537 public void enter() { 1538 if (DBG) logd(getName()); 1539 notifyInvitationReceived(); 1540 } 1541 1542 @Override 1543 public boolean processMessage(Message message) { 1544 if (DBG) logd(getName() + message.toString()); 1545 boolean ret = HANDLED; 1546 switch (message.what) { 1547 case PEER_CONNECTION_USER_ACCEPT: 1548 mWifiNative.p2pStopFind(); 1549 p2pConnectWithPinDisplay(mSavedPeerConfig); 1550 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); 1551 sendPeersChangedBroadcast(); 1552 transitionTo(mGroupNegotiationState); 1553 break; 1554 case PEER_CONNECTION_USER_REJECT: 1555 if (DBG) logd("User rejected negotiation " + mSavedPeerConfig); 1556 transitionTo(mInactiveState); 1557 break; 1558 default: 1559 return NOT_HANDLED; 1560 } 1561 return ret; 1562 } 1563 1564 @Override 1565 public void exit() { 1566 //TODO: dismiss dialog if not already done 1567 } 1568 } 1569 1570 class UserAuthorizingInviteRequestState extends State { 1571 @Override 1572 public void enter() { 1573 if (DBG) logd(getName()); 1574 notifyInvitationReceived(); 1575 } 1576 1577 @Override 1578 public boolean processMessage(Message message) { 1579 if (DBG) logd(getName() + message.toString()); 1580 boolean ret = HANDLED; 1581 switch (message.what) { 1582 case PEER_CONNECTION_USER_ACCEPT: 1583 mWifiNative.p2pStopFind(); 1584 if (!reinvokePersistentGroup(mSavedPeerConfig)) { 1585 // Do negotiation when persistence fails 1586 p2pConnectWithPinDisplay(mSavedPeerConfig); 1587 } 1588 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); 1589 sendPeersChangedBroadcast(); 1590 transitionTo(mGroupNegotiationState); 1591 break; 1592 case PEER_CONNECTION_USER_REJECT: 1593 if (DBG) logd("User rejected invitation " + mSavedPeerConfig); 1594 transitionTo(mInactiveState); 1595 break; 1596 default: 1597 return NOT_HANDLED; 1598 } 1599 return ret; 1600 } 1601 1602 @Override 1603 public void exit() { 1604 //TODO: dismiss dialog if not already done 1605 } 1606 } 1607 1608 1609 1610 class ProvisionDiscoveryState extends State { 1611 @Override 1612 public void enter() { 1613 if (DBG) logd(getName()); 1614 mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig); 1615 } 1616 1617 @Override 1618 public boolean processMessage(Message message) { 1619 if (DBG) logd(getName() + message.toString()); 1620 WifiP2pProvDiscEvent provDisc; 1621 WifiP2pDevice device; 1622 switch (message.what) { 1623 case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT: 1624 provDisc = (WifiP2pProvDiscEvent) message.obj; 1625 device = provDisc.device; 1626 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; 1627 1628 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { 1629 if (DBG) logd("Found a match " + mSavedPeerConfig); 1630 p2pConnectWithPinDisplay(mSavedPeerConfig); 1631 transitionTo(mGroupNegotiationState); 1632 } 1633 break; 1634 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 1635 provDisc = (WifiP2pProvDiscEvent) message.obj; 1636 device = provDisc.device; 1637 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; 1638 1639 if (mSavedPeerConfig.wps.setup == WpsInfo.KEYPAD) { 1640 if (DBG) logd("Found a match " + mSavedPeerConfig); 1641 /* we already have the pin */ 1642 if (!TextUtils.isEmpty(mSavedPeerConfig.wps.pin)) { 1643 p2pConnectWithPinDisplay(mSavedPeerConfig); 1644 transitionTo(mGroupNegotiationState); 1645 } else { 1646 mJoinExistingGroup = false; 1647 transitionTo(mUserAuthorizingNegotiationRequestState); 1648 } 1649 } 1650 break; 1651 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 1652 provDisc = (WifiP2pProvDiscEvent) message.obj; 1653 device = provDisc.device; 1654 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; 1655 1656 if (mSavedPeerConfig.wps.setup == WpsInfo.DISPLAY) { 1657 if (DBG) logd("Found a match " + mSavedPeerConfig); 1658 mSavedPeerConfig.wps.pin = provDisc.pin; 1659 p2pConnectWithPinDisplay(mSavedPeerConfig); 1660 notifyInvitationSent(provDisc.pin, device.deviceAddress); 1661 transitionTo(mGroupNegotiationState); 1662 } 1663 break; 1664 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT: 1665 loge("provision discovery failed"); 1666 handleGroupCreationFailure(); 1667 transitionTo(mInactiveState); 1668 break; 1669 default: 1670 return NOT_HANDLED; 1671 } 1672 return HANDLED; 1673 } 1674 } 1675 1676 class GroupNegotiationState extends State { 1677 @Override 1678 public void enter() { 1679 if (DBG) logd(getName()); 1680 } 1681 1682 @Override 1683 public boolean processMessage(Message message) { 1684 if (DBG) logd(getName() + message.toString()); 1685 switch (message.what) { 1686 // We ignore these right now, since we get a GROUP_STARTED notification 1687 // afterwards 1688 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT: 1689 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT: 1690 if (DBG) logd(getName() + " go success"); 1691 break; 1692 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 1693 mGroup = (WifiP2pGroup) message.obj; 1694 if (DBG) logd(getName() + " group started"); 1695 1696 if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) { 1697 /* 1698 * update cache information and set network id to mGroup. 1699 */ 1700 updatePersistentNetworks(NO_RELOAD); 1701 String devAddr = mGroup.getOwner().deviceAddress; 1702 mGroup.setNetworkId(mGroups.getNetworkId(devAddr, 1703 mGroup.getNetworkName())); 1704 } 1705 1706 if (mGroup.isGroupOwner()) { 1707 /* Setting an idle time out on GO causes issues with certain scenarios 1708 * on clients where it can be off-channel for longer and with the power 1709 * save modes used. 1710 * 1711 * TODO: Verify multi-channel scenarios and supplicant behavior are 1712 * better before adding a time out in future 1713 */ 1714 //Set group idle timeout of 10 sec, to avoid GO beaconing incase of any 1715 //failure during 4-way Handshake. 1716 if (!mAutonomousGroup) { 1717 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S); 1718 } 1719 startDhcpServer(mGroup.getInterface()); 1720 } else { 1721 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S); 1722 mDhcpClient = DhcpClient.makeDhcpStateMachine(mContext, 1723 P2pStateMachine.this, mGroup.getInterface()); 1724 // TODO: We should use DHCP state machine PRE message like WifiStateMachine 1725 mWifiNative.setP2pPowerSave(mGroup.getInterface(), false); 1726 mDhcpClient.sendMessage(DhcpStateMachine.CMD_START_DHCP); 1727 WifiP2pDevice groupOwner = mGroup.getOwner(); 1728 WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress); 1729 if (peer != null) { 1730 // update group owner details with peer details found at discovery 1731 groupOwner.updateSupplicantDetails(peer); 1732 mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED); 1733 sendPeersChangedBroadcast(); 1734 } else { 1735 // A supplicant bug can lead to reporting an invalid 1736 // group owner address (all zeroes) at times. Avoid a 1737 // crash, but continue group creation since it is not 1738 // essential. 1739 logw("Unknown group owner " + groupOwner); 1740 } 1741 } 1742 transitionTo(mGroupCreatedState); 1743 break; 1744 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT: 1745 P2pStatus status = (P2pStatus) message.obj; 1746 if (status == P2pStatus.NO_COMMON_CHANNEL) { 1747 transitionTo(mFrequencyConflictState); 1748 break; 1749 } 1750 /* continue with group removal handling */ 1751 case WifiMonitor.P2P_GROUP_REMOVED_EVENT: 1752 if (DBG) logd(getName() + " go failure"); 1753 handleGroupCreationFailure(); 1754 transitionTo(mInactiveState); 1755 break; 1756 // A group formation failure is always followed by 1757 // a group removed event. Flushing things at group formation 1758 // failure causes supplicant issues. Ignore right now. 1759 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: 1760 status = (P2pStatus) message.obj; 1761 if (status == P2pStatus.NO_COMMON_CHANNEL) { 1762 transitionTo(mFrequencyConflictState); 1763 break; 1764 } 1765 break; 1766 case WifiMonitor.P2P_INVITATION_RESULT_EVENT: 1767 status = (P2pStatus)message.obj; 1768 if (status == P2pStatus.SUCCESS) { 1769 // invocation was succeeded. 1770 // wait P2P_GROUP_STARTED_EVENT. 1771 break; 1772 } 1773 loge("Invitation result " + status); 1774 if (status == P2pStatus.UNKNOWN_P2P_GROUP) { 1775 // target device has already removed the credential. 1776 // So, remove this credential accordingly. 1777 int netId = mSavedPeerConfig.netId; 1778 if (netId >= 0) { 1779 if (DBG) logd("Remove unknown client from the list"); 1780 removeClientFromList(netId, mSavedPeerConfig.deviceAddress, true); 1781 } 1782 1783 // Reinvocation has failed, try group negotiation 1784 mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID; 1785 p2pConnectWithPinDisplay(mSavedPeerConfig); 1786 } else if (status == P2pStatus.INFORMATION_IS_CURRENTLY_UNAVAILABLE) { 1787 1788 // Devices setting persistent_reconnect to 0 in wpa_supplicant 1789 // always defer the invocation request and return 1790 // "information is currently unable" error. 1791 // So, try another way to connect for interoperability. 1792 mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID; 1793 p2pConnectWithPinDisplay(mSavedPeerConfig); 1794 } else if (status == P2pStatus.NO_COMMON_CHANNEL) { 1795 transitionTo(mFrequencyConflictState); 1796 } else { 1797 handleGroupCreationFailure(); 1798 transitionTo(mInactiveState); 1799 } 1800 break; 1801 default: 1802 return NOT_HANDLED; 1803 } 1804 return HANDLED; 1805 } 1806 } 1807 1808 class FrequencyConflictState extends State { 1809 private AlertDialog mFrequencyConflictDialog; 1810 @Override 1811 public void enter() { 1812 if (DBG) logd(getName()); 1813 notifyFrequencyConflict(); 1814 } 1815 1816 private void notifyFrequencyConflict() { 1817 logd("Notify frequency conflict"); 1818 Resources r = Resources.getSystem(); 1819 1820 AlertDialog dialog = new AlertDialog.Builder(mContext) 1821 .setMessage(r.getString(R.string.wifi_p2p_frequency_conflict_message, 1822 getDeviceName(mSavedPeerConfig.deviceAddress))) 1823 .setPositiveButton(r.getString(R.string.dlg_ok), new OnClickListener() { 1824 @Override 1825 public void onClick(DialogInterface dialog, int which) { 1826 sendMessage(DROP_WIFI_USER_ACCEPT); 1827 } 1828 }) 1829 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() { 1830 @Override 1831 public void onClick(DialogInterface dialog, int which) { 1832 sendMessage(DROP_WIFI_USER_REJECT); 1833 } 1834 }) 1835 .setOnCancelListener(new DialogInterface.OnCancelListener() { 1836 @Override 1837 public void onCancel(DialogInterface arg0) { 1838 sendMessage(DROP_WIFI_USER_REJECT); 1839 } 1840 }) 1841 .create(); 1842 1843 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1844 WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes(); 1845 attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 1846 dialog.getWindow().setAttributes(attrs); 1847 dialog.show(); 1848 mFrequencyConflictDialog = dialog; 1849 } 1850 1851 @Override 1852 public boolean processMessage(Message message) { 1853 if (DBG) logd(getName() + message.toString()); 1854 switch (message.what) { 1855 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT: 1856 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT: 1857 loge(getName() + "group sucess during freq conflict!"); 1858 break; 1859 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 1860 loge(getName() + "group started after freq conflict, handle anyway"); 1861 deferMessage(message); 1862 transitionTo(mGroupNegotiationState); 1863 break; 1864 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT: 1865 case WifiMonitor.P2P_GROUP_REMOVED_EVENT: 1866 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: 1867 // Ignore failures since we retry again 1868 break; 1869 case DROP_WIFI_USER_REJECT: 1870 // User rejected dropping wifi in favour of p2p 1871 handleGroupCreationFailure(); 1872 transitionTo(mInactiveState); 1873 break; 1874 case DROP_WIFI_USER_ACCEPT: 1875 // User accepted dropping wifi in favour of p2p 1876 mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 1); 1877 mTemporarilyDisconnectedWifi = true; 1878 break; 1879 case DISCONNECT_WIFI_RESPONSE: 1880 // Got a response from wifistatemachine, retry p2p 1881 if (DBG) logd(getName() + "Wifi disconnected, retry p2p"); 1882 transitionTo(mInactiveState); 1883 sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig); 1884 break; 1885 default: 1886 return NOT_HANDLED; 1887 } 1888 return HANDLED; 1889 } 1890 1891 public void exit() { 1892 if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss(); 1893 } 1894 } 1895 1896 class GroupCreatedState extends State { 1897 @Override 1898 public void enter() { 1899 if (DBG) logd(getName()); 1900 // Once connected, peer config details are invalid 1901 mSavedPeerConfig.invalidate(); 1902 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); 1903 1904 updateThisDevice(WifiP2pDevice.CONNECTED); 1905 1906 //DHCP server has already been started if I am a group owner 1907 if (mGroup.isGroupOwner()) { 1908 setWifiP2pInfoOnGroupFormation(NetworkUtils.numericToInetAddress(SERVER_ADDRESS)); 1909 } 1910 1911 // In case of a negotiation group, connection changed is sent 1912 // after a client joins. For autonomous, send now 1913 if (mAutonomousGroup) { 1914 sendP2pConnectionChangedBroadcast(); 1915 } 1916 } 1917 1918 @Override 1919 public boolean processMessage(Message message) { 1920 if (DBG) logd(getName() + message.toString()); 1921 switch (message.what) { 1922 case WifiMonitor.AP_STA_CONNECTED_EVENT: 1923 WifiP2pDevice device = (WifiP2pDevice) message.obj; 1924 String deviceAddress = device.deviceAddress; 1925 // Clear timeout that was set when group was started. 1926 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0); 1927 if (deviceAddress != null) { 1928 if (mPeers.get(deviceAddress) != null) { 1929 mGroup.addClient(mPeers.get(deviceAddress)); 1930 } else { 1931 mGroup.addClient(deviceAddress); 1932 } 1933 mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED); 1934 if (DBG) logd(getName() + " ap sta connected"); 1935 sendPeersChangedBroadcast(); 1936 } else { 1937 loge("Connect on null device address, ignore"); 1938 } 1939 sendP2pConnectionChangedBroadcast(); 1940 break; 1941 case WifiMonitor.AP_STA_DISCONNECTED_EVENT: 1942 device = (WifiP2pDevice) message.obj; 1943 deviceAddress = device.deviceAddress; 1944 if (deviceAddress != null) { 1945 mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE); 1946 if (mGroup.removeClient(deviceAddress)) { 1947 if (DBG) logd("Removed client " + deviceAddress); 1948 if (!mAutonomousGroup && mGroup.isClientListEmpty()) { 1949 logd("Client list empty, remove non-persistent p2p group"); 1950 mWifiNative.p2pGroupRemove(mGroup.getInterface()); 1951 // We end up sending connection changed broadcast 1952 // when this happens at exit() 1953 } else { 1954 // Notify when a client disconnects from group 1955 sendP2pConnectionChangedBroadcast(); 1956 } 1957 } else { 1958 if (DBG) logd("Failed to remove client " + deviceAddress); 1959 for (WifiP2pDevice c : mGroup.getClientList()) { 1960 if (DBG) logd("client " + c.deviceAddress); 1961 } 1962 } 1963 sendPeersChangedBroadcast(); 1964 if (DBG) logd(getName() + " ap sta disconnected"); 1965 } else { 1966 loge("Disconnect on unknown device: " + device); 1967 } 1968 break; 1969 case DhcpStateMachine.CMD_POST_DHCP_ACTION: 1970 DhcpResults dhcpResults = (DhcpResults) message.obj; 1971 if (message.arg1 == DhcpStateMachine.DHCP_SUCCESS && 1972 dhcpResults != null) { 1973 if (DBG) logd("DhcpResults: " + dhcpResults); 1974 setWifiP2pInfoOnGroupFormation(dhcpResults.serverAddress); 1975 sendP2pConnectionChangedBroadcast(); 1976 //Turn on power save on client 1977 mWifiNative.setP2pPowerSave(mGroup.getInterface(), true); 1978 try { 1979 String iface = mGroup.getInterface(); 1980 mNwService.addInterfaceToLocalNetwork(iface, 1981 dhcpResults.getRoutes(iface)); 1982 } catch (RemoteException e) { 1983 loge("Failed to add iface to local network " + e); 1984 } 1985 } else { 1986 loge("DHCP failed"); 1987 mWifiNative.p2pGroupRemove(mGroup.getInterface()); 1988 } 1989 break; 1990 case WifiP2pManager.REMOVE_GROUP: 1991 if (DBG) logd(getName() + " remove group"); 1992 if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) { 1993 transitionTo(mOngoingGroupRemovalState); 1994 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED); 1995 } else { 1996 handleGroupRemoved(); 1997 transitionTo(mInactiveState); 1998 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, 1999 WifiP2pManager.ERROR); 2000 } 2001 break; 2002 /* We do not listen to NETWORK_DISCONNECTION_EVENT for group removal 2003 * handling since supplicant actually tries to reconnect after a temporary 2004 * disconnect until group idle time out. Eventually, a group removal event 2005 * will come when group has been removed. 2006 * 2007 * When there are connectivity issues during temporary disconnect, the application 2008 * will also just remove the group. 2009 * 2010 * Treating network disconnection as group removal causes race conditions since 2011 * supplicant would still maintain the group at that stage. 2012 */ 2013 case WifiMonitor.P2P_GROUP_REMOVED_EVENT: 2014 if (DBG) logd(getName() + " group removed"); 2015 handleGroupRemoved(); 2016 transitionTo(mInactiveState); 2017 break; 2018 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 2019 device = (WifiP2pDevice) message.obj; 2020 //Device loss for a connected device indicates it is not in discovery any more 2021 if (mGroup.contains(device)) { 2022 if (DBG) logd("Add device to lost list " + device); 2023 mPeersLostDuringConnection.updateSupplicantDetails(device); 2024 return HANDLED; 2025 } 2026 // Do the regular device lost handling 2027 return NOT_HANDLED; 2028 case WifiStateMachine.CMD_DISABLE_P2P_REQ: 2029 sendMessage(WifiP2pManager.REMOVE_GROUP); 2030 deferMessage(message); 2031 break; 2032 // This allows any client to join the GO during the 2033 // WPS window 2034 case WifiP2pManager.START_WPS: 2035 WpsInfo wps = (WpsInfo) message.obj; 2036 if (wps == null) { 2037 replyToMessage(message, WifiP2pManager.START_WPS_FAILED); 2038 break; 2039 } 2040 boolean ret = true; 2041 if (wps.setup == WpsInfo.PBC) { 2042 ret = mWifiNative.startWpsPbc(mGroup.getInterface(), null); 2043 } else { 2044 if (wps.pin == null) { 2045 String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface()); 2046 try { 2047 Integer.parseInt(pin); 2048 notifyInvitationSent(pin, "any"); 2049 } catch (NumberFormatException ignore) { 2050 ret = false; 2051 } 2052 } else { 2053 ret = mWifiNative.startWpsPinKeypad(mGroup.getInterface(), 2054 wps.pin); 2055 } 2056 } 2057 replyToMessage(message, ret ? WifiP2pManager.START_WPS_SUCCEEDED : 2058 WifiP2pManager.START_WPS_FAILED); 2059 break; 2060 case WifiP2pManager.CONNECT: 2061 WifiP2pConfig config = (WifiP2pConfig) message.obj; 2062 if (isConfigInvalid(config)) { 2063 loge("Dropping connect requeset " + config); 2064 replyToMessage(message, WifiP2pManager.CONNECT_FAILED); 2065 break; 2066 } 2067 logd("Inviting device : " + config.deviceAddress); 2068 mSavedPeerConfig = config; 2069 if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) { 2070 mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED); 2071 sendPeersChangedBroadcast(); 2072 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); 2073 } else { 2074 replyToMessage(message, WifiP2pManager.CONNECT_FAILED, 2075 WifiP2pManager.ERROR); 2076 } 2077 // TODO: figure out updating the status to declined when invitation is rejected 2078 break; 2079 case WifiMonitor.P2P_INVITATION_RESULT_EVENT: 2080 P2pStatus status = (P2pStatus)message.obj; 2081 if (status == P2pStatus.SUCCESS) { 2082 // invocation was succeeded. 2083 break; 2084 } 2085 loge("Invitation result " + status); 2086 if (status == P2pStatus.UNKNOWN_P2P_GROUP) { 2087 // target device has already removed the credential. 2088 // So, remove this credential accordingly. 2089 int netId = mGroup.getNetworkId(); 2090 if (netId >= 0) { 2091 if (DBG) logd("Remove unknown client from the list"); 2092 if (!removeClientFromList(netId, 2093 mSavedPeerConfig.deviceAddress, false)) { 2094 // not found the client on the list 2095 loge("Already removed the client, ignore"); 2096 break; 2097 } 2098 // try invitation. 2099 sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig); 2100 } 2101 } 2102 break; 2103 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: 2104 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 2105 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 2106 WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj; 2107 mSavedPeerConfig = new WifiP2pConfig(); 2108 mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress; 2109 if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) { 2110 mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; 2111 } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) { 2112 mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY; 2113 mSavedPeerConfig.wps.pin = provDisc.pin; 2114 } else { 2115 mSavedPeerConfig.wps.setup = WpsInfo.PBC; 2116 } 2117 transitionTo(mUserAuthorizingJoinState); 2118 break; 2119 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 2120 loge("Duplicate group creation event notice, ignore"); 2121 break; 2122 default: 2123 return NOT_HANDLED; 2124 } 2125 return HANDLED; 2126 } 2127 2128 public void exit() { 2129 updateThisDevice(WifiP2pDevice.AVAILABLE); 2130 resetWifiP2pInfo(); 2131 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null); 2132 sendP2pConnectionChangedBroadcast(); 2133 } 2134 } 2135 2136 class UserAuthorizingJoinState extends State { 2137 @Override 2138 public void enter() { 2139 if (DBG) logd(getName()); 2140 notifyInvitationReceived(); 2141 } 2142 2143 @Override 2144 public boolean processMessage(Message message) { 2145 if (DBG) logd(getName() + message.toString()); 2146 switch (message.what) { 2147 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: 2148 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 2149 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 2150 //Ignore more client requests 2151 break; 2152 case PEER_CONNECTION_USER_ACCEPT: 2153 //Stop discovery to avoid failure due to channel switch 2154 mWifiNative.p2pStopFind(); 2155 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { 2156 mWifiNative.startWpsPbc(mGroup.getInterface(), null); 2157 } else { 2158 mWifiNative.startWpsPinKeypad(mGroup.getInterface(), 2159 mSavedPeerConfig.wps.pin); 2160 } 2161 transitionTo(mGroupCreatedState); 2162 break; 2163 case PEER_CONNECTION_USER_REJECT: 2164 if (DBG) logd("User rejected incoming request"); 2165 transitionTo(mGroupCreatedState); 2166 break; 2167 default: 2168 return NOT_HANDLED; 2169 } 2170 return HANDLED; 2171 } 2172 2173 @Override 2174 public void exit() { 2175 //TODO: dismiss dialog if not already done 2176 } 2177 } 2178 2179 class OngoingGroupRemovalState extends State { 2180 @Override 2181 public void enter() { 2182 if (DBG) logd(getName()); 2183 } 2184 2185 @Override 2186 public boolean processMessage(Message message) { 2187 if (DBG) logd(getName() + message.toString()); 2188 switch (message.what) { 2189 // Group removal ongoing. Multiple calls 2190 // end up removing persisted network. Do nothing. 2191 case WifiP2pManager.REMOVE_GROUP: 2192 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED); 2193 break; 2194 // Parent state will transition out of this state 2195 // when removal is complete 2196 default: 2197 return NOT_HANDLED; 2198 } 2199 return HANDLED; 2200 } 2201 } 2202 2203 @Override 2204 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2205 super.dump(fd, pw, args); 2206 pw.println("mWifiP2pInfo " + mWifiP2pInfo); 2207 pw.println("mGroup " + mGroup); 2208 pw.println("mSavedPeerConfig " + mSavedPeerConfig); 2209 pw.println("mSavedP2pGroup " + mSavedP2pGroup); 2210 pw.println(); 2211 } 2212 2213 private void sendP2pStateChangedBroadcast(boolean enabled) { 2214 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); 2215 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2216 if (enabled) { 2217 intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE, 2218 WifiP2pManager.WIFI_P2P_STATE_ENABLED); 2219 } else { 2220 intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE, 2221 WifiP2pManager.WIFI_P2P_STATE_DISABLED); 2222 } 2223 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2224 } 2225 2226 private void sendP2pDiscoveryChangedBroadcast(boolean started) { 2227 if (mDiscoveryStarted == started) return; 2228 mDiscoveryStarted = started; 2229 2230 if (DBG) logd("discovery change broadcast " + started); 2231 2232 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); 2233 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2234 intent.putExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, started ? 2235 WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED : 2236 WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED); 2237 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2238 } 2239 2240 private void sendThisDeviceChangedBroadcast() { 2241 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); 2242 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2243 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice)); 2244 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2245 } 2246 2247 private void sendPeersChangedBroadcast() { 2248 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); 2249 intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, new WifiP2pDeviceList(mPeers)); 2250 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2251 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2252 } 2253 2254 private void sendP2pConnectionChangedBroadcast() { 2255 if (DBG) logd("sending p2p connection changed broadcast"); 2256 Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); 2257 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 2258 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 2259 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo)); 2260 intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 2261 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, new WifiP2pGroup(mGroup)); 2262 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2263 mWifiChannel.sendMessage(WifiP2pServiceImpl.P2P_CONNECTION_CHANGED, 2264 new NetworkInfo(mNetworkInfo)); 2265 } 2266 2267 private void sendP2pPersistentGroupsChangedBroadcast() { 2268 if (DBG) logd("sending p2p persistent groups changed broadcast"); 2269 Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION); 2270 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2271 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2272 } 2273 2274 private void startDhcpServer(String intf) { 2275 InterfaceConfiguration ifcg = null; 2276 try { 2277 ifcg = mNwService.getInterfaceConfig(intf); 2278 ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress( 2279 SERVER_ADDRESS), 24)); 2280 ifcg.setInterfaceUp(); 2281 mNwService.setInterfaceConfig(intf, ifcg); 2282 /* This starts the dnsmasq server */ 2283 ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( 2284 Context.CONNECTIVITY_SERVICE); 2285 String[] tetheringDhcpRanges = cm.getTetheredDhcpRanges(); 2286 if (mNwService.isTetheringStarted()) { 2287 if (DBG) logd("Stop existing tethering and restart it"); 2288 mNwService.stopTethering(); 2289 } 2290 mNwService.tetherInterface(intf); 2291 mNwService.startTethering(tetheringDhcpRanges); 2292 } catch (Exception e) { 2293 loge("Error configuring interface " + intf + ", :" + e); 2294 return; 2295 } 2296 2297 logd("Started Dhcp server on " + intf); 2298 } 2299 2300 private void stopDhcpServer(String intf) { 2301 try { 2302 mNwService.untetherInterface(intf); 2303 for (String temp : mNwService.listTetheredInterfaces()) { 2304 logd("List all interfaces " + temp); 2305 if (temp.compareTo(intf) != 0) { 2306 logd("Found other tethering interfaces, so keep tethering alive"); 2307 return; 2308 } 2309 } 2310 mNwService.stopTethering(); 2311 } catch (Exception e) { 2312 loge("Error stopping Dhcp server" + e); 2313 return; 2314 } finally { 2315 logd("Stopped Dhcp server"); 2316 } 2317 } 2318 2319 private void notifyP2pEnableFailure() { 2320 Resources r = Resources.getSystem(); 2321 AlertDialog dialog = new AlertDialog.Builder(mContext) 2322 .setTitle(r.getString(R.string.wifi_p2p_dialog_title)) 2323 .setMessage(r.getString(R.string.wifi_p2p_failed_message)) 2324 .setPositiveButton(r.getString(R.string.ok), null) 2325 .create(); 2326 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 2327 WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes(); 2328 attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 2329 dialog.getWindow().setAttributes(attrs); 2330 dialog.show(); 2331 } 2332 2333 private void addRowToDialog(ViewGroup group, int stringId, String value) { 2334 Resources r = Resources.getSystem(); 2335 View row = LayoutInflater.from(mContext).inflate(R.layout.wifi_p2p_dialog_row, 2336 group, false); 2337 ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId)); 2338 ((TextView) row.findViewById(R.id.value)).setText(value); 2339 group.addView(row); 2340 } 2341 2342 private void notifyInvitationSent(String pin, String peerAddress) { 2343 Resources r = Resources.getSystem(); 2344 2345 final View textEntryView = LayoutInflater.from(mContext) 2346 .inflate(R.layout.wifi_p2p_dialog, null); 2347 2348 ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info); 2349 addRowToDialog(group, R.string.wifi_p2p_to_message, getDeviceName(peerAddress)); 2350 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, pin); 2351 2352 AlertDialog dialog = new AlertDialog.Builder(mContext) 2353 .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title)) 2354 .setView(textEntryView) 2355 .setPositiveButton(r.getString(R.string.ok), null) 2356 .create(); 2357 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 2358 WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes(); 2359 attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 2360 dialog.getWindow().setAttributes(attrs); 2361 dialog.show(); 2362 } 2363 2364 private void notifyInvitationReceived() { 2365 Resources r = Resources.getSystem(); 2366 final WpsInfo wps = mSavedPeerConfig.wps; 2367 final View textEntryView = LayoutInflater.from(mContext) 2368 .inflate(R.layout.wifi_p2p_dialog, null); 2369 2370 ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info); 2371 addRowToDialog(group, R.string.wifi_p2p_from_message, getDeviceName( 2372 mSavedPeerConfig.deviceAddress)); 2373 2374 final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin); 2375 2376 AlertDialog dialog = new AlertDialog.Builder(mContext) 2377 .setTitle(r.getString(R.string.wifi_p2p_invitation_to_connect_title)) 2378 .setView(textEntryView) 2379 .setPositiveButton(r.getString(R.string.accept), new OnClickListener() { 2380 public void onClick(DialogInterface dialog, int which) { 2381 if (wps.setup == WpsInfo.KEYPAD) { 2382 mSavedPeerConfig.wps.pin = pin.getText().toString(); 2383 } 2384 if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig); 2385 sendMessage(PEER_CONNECTION_USER_ACCEPT); 2386 } 2387 }) 2388 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() { 2389 @Override 2390 public void onClick(DialogInterface dialog, int which) { 2391 if (DBG) logd(getName() + " ignore connect"); 2392 sendMessage(PEER_CONNECTION_USER_REJECT); 2393 } 2394 }) 2395 .setOnCancelListener(new DialogInterface.OnCancelListener() { 2396 @Override 2397 public void onCancel(DialogInterface arg0) { 2398 if (DBG) logd(getName() + " ignore connect"); 2399 sendMessage(PEER_CONNECTION_USER_REJECT); 2400 } 2401 }) 2402 .create(); 2403 2404 //make the enter pin area or the display pin area visible 2405 switch (wps.setup) { 2406 case WpsInfo.KEYPAD: 2407 if (DBG) logd("Enter pin section visible"); 2408 textEntryView.findViewById(R.id.enter_pin_section).setVisibility(View.VISIBLE); 2409 break; 2410 case WpsInfo.DISPLAY: 2411 if (DBG) logd("Shown pin section visible"); 2412 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin); 2413 break; 2414 default: 2415 break; 2416 } 2417 2418 if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_APPLIANCE) == 2419 Configuration.UI_MODE_TYPE_APPLIANCE) { 2420 // For appliance devices, add a key listener which accepts. 2421 dialog.setOnKeyListener(new DialogInterface.OnKeyListener() { 2422 2423 @Override 2424 public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { 2425 // TODO: make the actual key come from a config value. 2426 if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) { 2427 sendMessage(PEER_CONNECTION_USER_ACCEPT); 2428 dialog.dismiss(); 2429 return true; 2430 } 2431 return false; 2432 } 2433 }); 2434 // TODO: add timeout for this dialog. 2435 // TODO: update UI in appliance mode to tell user what to do. 2436 } 2437 2438 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 2439 WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes(); 2440 attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 2441 dialog.getWindow().setAttributes(attrs); 2442 dialog.show(); 2443 } 2444 2445 /** 2446 * Synchronize the persistent group list between 2447 * wpa_supplicant and mGroups. 2448 */ 2449 private void updatePersistentNetworks(boolean reload) { 2450 String listStr = mWifiNative.listNetworks(); 2451 if (listStr == null) return; 2452 2453 boolean isSaveRequired = false; 2454 String[] lines = listStr.split("\n"); 2455 if (lines == null) return; 2456 2457 if (reload) mGroups.clear(); 2458 2459 // Skip the first line, which is a header 2460 for (int i = 1; i < lines.length; i++) { 2461 String[] result = lines[i].split("\t"); 2462 if (result == null || result.length < 4) { 2463 continue; 2464 } 2465 // network-id | ssid | bssid | flags 2466 int netId = -1; 2467 String ssid = result[1]; 2468 String bssid = result[2]; 2469 String flags = result[3]; 2470 try { 2471 netId = Integer.parseInt(result[0]); 2472 } catch(NumberFormatException e) { 2473 e.printStackTrace(); 2474 continue; 2475 } 2476 2477 if (flags.indexOf("[CURRENT]") != -1) { 2478 continue; 2479 } 2480 if (flags.indexOf("[P2P-PERSISTENT]") == -1) { 2481 /* 2482 * The unused profile is sometimes remained when the p2p group formation is failed. 2483 * So, we clean up the p2p group here. 2484 */ 2485 if (DBG) logd("clean up the unused persistent group. netId=" + netId); 2486 mWifiNative.removeNetwork(netId); 2487 isSaveRequired = true; 2488 continue; 2489 } 2490 2491 if (mGroups.contains(netId)) { 2492 continue; 2493 } 2494 2495 WifiP2pGroup group = new WifiP2pGroup(); 2496 group.setNetworkId(netId); 2497 group.setNetworkName(ssid); 2498 String mode = mWifiNative.getNetworkVariable(netId, "mode"); 2499 if (mode != null && mode.equals("3")) { 2500 group.setIsGroupOwner(true); 2501 } 2502 if (bssid.equalsIgnoreCase(mThisDevice.deviceAddress)) { 2503 group.setOwner(mThisDevice); 2504 } else { 2505 WifiP2pDevice device = new WifiP2pDevice(); 2506 device.deviceAddress = bssid; 2507 group.setOwner(device); 2508 } 2509 mGroups.add(group); 2510 isSaveRequired = true; 2511 } 2512 2513 if (reload || isSaveRequired) { 2514 mWifiNative.saveConfig(); 2515 sendP2pPersistentGroupsChangedBroadcast(); 2516 } 2517 } 2518 2519 /** 2520 * A config is valid if it has a peer address that has already been 2521 * discovered 2522 * @return true if it is invalid, false otherwise 2523 */ 2524 private boolean isConfigInvalid(WifiP2pConfig config) { 2525 if (config == null) return true; 2526 if (TextUtils.isEmpty(config.deviceAddress)) return true; 2527 if (mPeers.get(config.deviceAddress) == null) return true; 2528 return false; 2529 } 2530 2531 /* TODO: The supplicant does not provide group capability changes as an event. 2532 * Having it pushed as an event would avoid polling for this information right 2533 * before a connection 2534 */ 2535 private WifiP2pDevice fetchCurrentDeviceDetails(WifiP2pConfig config) { 2536 /* Fetch & update group capability from supplicant on the device */ 2537 int gc = mWifiNative.getGroupCapability(config.deviceAddress); 2538 mPeers.updateGroupCapability(config.deviceAddress, gc); 2539 return mPeers.get(config.deviceAddress); 2540 } 2541 2542 /** 2543 * Start a p2p group negotiation and display pin if necessary 2544 * @param config for the peer 2545 */ 2546 private void p2pConnectWithPinDisplay(WifiP2pConfig config) { 2547 WifiP2pDevice dev = fetchCurrentDeviceDetails(config); 2548 2549 String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner()); 2550 try { 2551 Integer.parseInt(pin); 2552 notifyInvitationSent(pin, config.deviceAddress); 2553 } catch (NumberFormatException ignore) { 2554 // do nothing if p2pConnect did not return a pin 2555 } 2556 } 2557 2558 /** 2559 * Reinvoke a persistent group. 2560 * 2561 * @param config for the peer 2562 * @return true on success, false on failure 2563 */ 2564 private boolean reinvokePersistentGroup(WifiP2pConfig config) { 2565 WifiP2pDevice dev = fetchCurrentDeviceDetails(config); 2566 2567 boolean join = dev.isGroupOwner(); 2568 String ssid = mWifiNative.p2pGetSsid(dev.deviceAddress); 2569 if (DBG) logd("target ssid is " + ssid + " join:" + join); 2570 2571 if (join && dev.isGroupLimit()) { 2572 if (DBG) logd("target device reaches group limit."); 2573 2574 // if the target group has reached the limit, 2575 // try group formation. 2576 join = false; 2577 } else if (join) { 2578 int netId = mGroups.getNetworkId(dev.deviceAddress, ssid); 2579 if (netId >= 0) { 2580 // Skip WPS and start 4way handshake immediately. 2581 if (!mWifiNative.p2pGroupAdd(netId)) { 2582 return false; 2583 } 2584 return true; 2585 } 2586 } 2587 2588 if (!join && dev.isDeviceLimit()) { 2589 loge("target device reaches the device limit."); 2590 return false; 2591 } 2592 2593 if (!join && dev.isInvitationCapable()) { 2594 int netId = WifiP2pGroup.PERSISTENT_NET_ID; 2595 if (config.netId >= 0) { 2596 if (config.deviceAddress.equals(mGroups.getOwnerAddr(config.netId))) { 2597 netId = config.netId; 2598 } 2599 } else { 2600 netId = mGroups.getNetworkId(dev.deviceAddress); 2601 } 2602 if (netId < 0) { 2603 netId = getNetworkIdFromClientList(dev.deviceAddress); 2604 } 2605 if (DBG) logd("netId related with " + dev.deviceAddress + " = " + netId); 2606 if (netId >= 0) { 2607 // Invoke the persistent group. 2608 if (mWifiNative.p2pReinvoke(netId, dev.deviceAddress)) { 2609 // Save network id. It'll be used when an invitation result event is received. 2610 config.netId = netId; 2611 return true; 2612 } else { 2613 loge("p2pReinvoke() failed, update networks"); 2614 updatePersistentNetworks(RELOAD); 2615 return false; 2616 } 2617 } 2618 } 2619 2620 return false; 2621 } 2622 2623 /** 2624 * Return the network id of the group owner profile which has the p2p client with 2625 * the specified device address in it's client list. 2626 * If more than one persistent group of the same address is present in its client 2627 * lists, return the first one. 2628 * 2629 * @param deviceAddress p2p device address. 2630 * @return the network id. if not found, return -1. 2631 */ 2632 private int getNetworkIdFromClientList(String deviceAddress) { 2633 if (deviceAddress == null) return -1; 2634 2635 Collection<WifiP2pGroup> groups = mGroups.getGroupList(); 2636 for (WifiP2pGroup group : groups) { 2637 int netId = group.getNetworkId(); 2638 String[] p2pClientList = getClientList(netId); 2639 if (p2pClientList == null) continue; 2640 for (String client : p2pClientList) { 2641 if (deviceAddress.equalsIgnoreCase(client)) { 2642 return netId; 2643 } 2644 } 2645 } 2646 return -1; 2647 } 2648 2649 /** 2650 * Return p2p client list associated with the specified network id. 2651 * @param netId network id. 2652 * @return p2p client list. if not found, return null. 2653 */ 2654 private String[] getClientList(int netId) { 2655 String p2pClients = mWifiNative.getNetworkVariable(netId, "p2p_client_list"); 2656 if (p2pClients == null) { 2657 return null; 2658 } 2659 return p2pClients.split(" "); 2660 } 2661 2662 /** 2663 * Remove the specified p2p client from the specified profile. 2664 * @param netId network id of the profile. 2665 * @param addr p2p client address to be removed. 2666 * @param isRemovable if true, remove the specified profile if its client list becomes empty. 2667 * @return whether removing the specified p2p client is successful or not. 2668 */ 2669 private boolean removeClientFromList(int netId, String addr, boolean isRemovable) { 2670 StringBuilder modifiedClientList = new StringBuilder(); 2671 String[] currentClientList = getClientList(netId); 2672 boolean isClientRemoved = false; 2673 if (currentClientList != null) { 2674 for (String client : currentClientList) { 2675 if (!client.equalsIgnoreCase(addr)) { 2676 modifiedClientList.append(" "); 2677 modifiedClientList.append(client); 2678 } else { 2679 isClientRemoved = true; 2680 } 2681 } 2682 } 2683 if (modifiedClientList.length() == 0 && isRemovable) { 2684 // the client list is empty. so remove it. 2685 if (DBG) logd("Remove unknown network"); 2686 mGroups.remove(netId); 2687 return true; 2688 } 2689 2690 if (!isClientRemoved) { 2691 // specified p2p client is not found. already removed. 2692 return false; 2693 } 2694 2695 if (DBG) logd("Modified client list: " + modifiedClientList); 2696 if (modifiedClientList.length() == 0) { 2697 modifiedClientList.append("\"\""); 2698 } 2699 mWifiNative.setNetworkVariable(netId, 2700 "p2p_client_list", modifiedClientList.toString()); 2701 mWifiNative.saveConfig(); 2702 return true; 2703 } 2704 2705 private void setWifiP2pInfoOnGroupFormation(InetAddress serverInetAddress) { 2706 mWifiP2pInfo.groupFormed = true; 2707 mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner(); 2708 mWifiP2pInfo.groupOwnerAddress = serverInetAddress; 2709 } 2710 2711 private void resetWifiP2pInfo() { 2712 mWifiP2pInfo.groupFormed = false; 2713 mWifiP2pInfo.isGroupOwner = false; 2714 mWifiP2pInfo.groupOwnerAddress = null; 2715 } 2716 2717 private String getDeviceName(String deviceAddress) { 2718 WifiP2pDevice d = mPeers.get(deviceAddress); 2719 if (d != null) { 2720 return d.deviceName; 2721 } 2722 //Treat the address as name if there is no match 2723 return deviceAddress; 2724 } 2725 2726 private String getPersistedDeviceName() { 2727 String deviceName = Settings.Global.getString(mContext.getContentResolver(), 2728 Settings.Global.WIFI_P2P_DEVICE_NAME); 2729 if (deviceName == null) { 2730 /* We use the 4 digits of the ANDROID_ID to have a friendly 2731 * default that has low likelihood of collision with a peer */ 2732 String id = Settings.Secure.getString(mContext.getContentResolver(), 2733 Settings.Secure.ANDROID_ID); 2734 return "Android_" + id.substring(0,4); 2735 } 2736 return deviceName; 2737 } 2738 2739 private boolean setAndPersistDeviceName(String devName) { 2740 if (devName == null) return false; 2741 2742 if (!mWifiNative.setDeviceName(devName)) { 2743 loge("Failed to set device name " + devName); 2744 return false; 2745 } 2746 2747 mThisDevice.deviceName = devName; 2748 mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName); 2749 2750 Settings.Global.putString(mContext.getContentResolver(), 2751 Settings.Global.WIFI_P2P_DEVICE_NAME, devName); 2752 sendThisDeviceChangedBroadcast(); 2753 return true; 2754 } 2755 2756 private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) { 2757 boolean success; 2758 2759 if (!wfdInfo.isWfdEnabled()) { 2760 success = mWifiNative.setWfdEnable(false); 2761 } else { 2762 success = 2763 mWifiNative.setWfdEnable(true) 2764 && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex()); 2765 } 2766 2767 if (!success) { 2768 loge("Failed to set wfd properties"); 2769 return false; 2770 } 2771 2772 mThisDevice.wfdInfo = wfdInfo; 2773 sendThisDeviceChangedBroadcast(); 2774 return true; 2775 } 2776 2777 private void initializeP2pSettings() { 2778 mWifiNative.setPersistentReconnect(true); 2779 mThisDevice.deviceName = getPersistedDeviceName(); 2780 mWifiNative.setDeviceName(mThisDevice.deviceName); 2781 // DIRECT-XY-DEVICENAME (XY is randomly generated) 2782 mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName); 2783 mWifiNative.setDeviceType(mThisDevice.primaryDeviceType); 2784 // Supplicant defaults to using virtual display with display 2785 // which refers to a remote display. Use physical_display 2786 mWifiNative.setConfigMethods("virtual_push_button physical_display keypad"); 2787 // STA has higher priority over P2P 2788 mWifiNative.setConcurrencyPriority("sta"); 2789 2790 mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress(); 2791 updateThisDevice(WifiP2pDevice.AVAILABLE); 2792 if (DBG) logd("DeviceAddress: " + mThisDevice.deviceAddress); 2793 2794 mClientInfoList.clear(); 2795 mWifiNative.p2pFlush(); 2796 mWifiNative.p2pServiceFlush(); 2797 mServiceTransactionId = 0; 2798 mServiceDiscReqId = null; 2799 2800 String countryCode = Settings.Global.getString(mContext.getContentResolver(), 2801 Settings.Global.WIFI_COUNTRY_CODE); 2802 if (countryCode != null && !countryCode.isEmpty()) { 2803 mP2pStateMachine.sendMessage(SET_COUNTRY_CODE, countryCode); 2804 } 2805 2806 updatePersistentNetworks(RELOAD); 2807 } 2808 2809 private void updateThisDevice(int status) { 2810 mThisDevice.status = status; 2811 sendThisDeviceChangedBroadcast(); 2812 } 2813 2814 private void handleGroupCreationFailure() { 2815 resetWifiP2pInfo(); 2816 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.FAILED, null, null); 2817 sendP2pConnectionChangedBroadcast(); 2818 2819 // Remove only the peer we failed to connect to so that other devices discovered 2820 // that have not timed out still remain in list for connection 2821 boolean peersChanged = mPeers.remove(mPeersLostDuringConnection); 2822 if (TextUtils.isEmpty(mSavedPeerConfig.deviceAddress) == false && 2823 mPeers.remove(mSavedPeerConfig.deviceAddress) != null) { 2824 peersChanged = true; 2825 } 2826 if (peersChanged) { 2827 sendPeersChangedBroadcast(); 2828 } 2829 2830 mPeersLostDuringConnection.clear(); 2831 mServiceDiscReqId = null; 2832 sendMessage(WifiP2pManager.DISCOVER_PEERS); 2833 } 2834 2835 private void handleGroupRemoved() { 2836 if (mGroup.isGroupOwner()) { 2837 stopDhcpServer(mGroup.getInterface()); 2838 } else { 2839 if (DBG) logd("stop DHCP client"); 2840 mDhcpClient.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); 2841 mDhcpClient.doQuit(); 2842 mDhcpClient = null; 2843 try { 2844 mNwService.removeInterfaceFromLocalNetwork(mGroup.getInterface()); 2845 } catch (RemoteException e) { 2846 loge("Failed to remove iface from local network " + e); 2847 } 2848 } 2849 2850 try { 2851 mNwService.clearInterfaceAddresses(mGroup.getInterface()); 2852 } catch (Exception e) { 2853 loge("Failed to clear addresses " + e); 2854 } 2855 NetworkUtils.resetConnections(mGroup.getInterface(), NetworkUtils.RESET_ALL_ADDRESSES); 2856 2857 // Clear any timeout that was set. This is essential for devices 2858 // that reuse the main p2p interface for a created group. 2859 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0); 2860 2861 boolean peersChanged = false; 2862 // Remove only peers part of the group, so that other devices discovered 2863 // that have not timed out still remain in list for connection 2864 for (WifiP2pDevice d : mGroup.getClientList()) { 2865 if (mPeers.remove(d)) peersChanged = true; 2866 } 2867 if (mPeers.remove(mGroup.getOwner())) peersChanged = true; 2868 if (mPeers.remove(mPeersLostDuringConnection)) peersChanged = true; 2869 if (peersChanged) { 2870 sendPeersChangedBroadcast(); 2871 } 2872 2873 mGroup = null; 2874 mPeersLostDuringConnection.clear(); 2875 mServiceDiscReqId = null; 2876 2877 if (mTemporarilyDisconnectedWifi) { 2878 mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 0); 2879 mTemporarilyDisconnectedWifi = false; 2880 } 2881 } 2882 2883 //State machine initiated requests can have replyTo set to null indicating 2884 //there are no recipients, we ignore those reply actions 2885 private void replyToMessage(Message msg, int what) { 2886 if (msg.replyTo == null) return; 2887 Message dstMsg = obtainMessage(msg); 2888 dstMsg.what = what; 2889 mReplyChannel.replyToMessage(msg, dstMsg); 2890 } 2891 2892 private void replyToMessage(Message msg, int what, int arg1) { 2893 if (msg.replyTo == null) return; 2894 Message dstMsg = obtainMessage(msg); 2895 dstMsg.what = what; 2896 dstMsg.arg1 = arg1; 2897 mReplyChannel.replyToMessage(msg, dstMsg); 2898 } 2899 2900 private void replyToMessage(Message msg, int what, Object obj) { 2901 if (msg.replyTo == null) return; 2902 Message dstMsg = obtainMessage(msg); 2903 dstMsg.what = what; 2904 dstMsg.obj = obj; 2905 mReplyChannel.replyToMessage(msg, dstMsg); 2906 } 2907 2908 /* arg2 on the source message has a hash code that needs to be retained in replies 2909 * see WifiP2pManager for details */ 2910 private Message obtainMessage(Message srcMsg) { 2911 Message msg = Message.obtain(); 2912 msg.arg2 = srcMsg.arg2; 2913 return msg; 2914 } 2915 2916 @Override 2917 protected void logd(String s) { 2918 Slog.d(TAG, s); 2919 } 2920 2921 @Override 2922 protected void loge(String s) { 2923 Slog.e(TAG, s); 2924 } 2925 2926 /** 2927 * Update service discovery request to wpa_supplicant. 2928 */ 2929 private boolean updateSupplicantServiceRequest() { 2930 clearSupplicantServiceRequest(); 2931 2932 StringBuffer sb = new StringBuffer(); 2933 for (ClientInfo c: mClientInfoList.values()) { 2934 int key; 2935 WifiP2pServiceRequest req; 2936 for (int i=0; i < c.mReqList.size(); i++) { 2937 req = c.mReqList.valueAt(i); 2938 if (req != null) { 2939 sb.append(req.getSupplicantQuery()); 2940 } 2941 } 2942 } 2943 2944 if (sb.length() == 0) { 2945 return false; 2946 } 2947 2948 mServiceDiscReqId = mWifiNative.p2pServDiscReq("00:00:00:00:00:00", sb.toString()); 2949 if (mServiceDiscReqId == null) { 2950 return false; 2951 } 2952 return true; 2953 } 2954 2955 /** 2956 * Clear service discovery request in wpa_supplicant 2957 */ 2958 private void clearSupplicantServiceRequest() { 2959 if (mServiceDiscReqId == null) return; 2960 2961 mWifiNative.p2pServDiscCancelReq(mServiceDiscReqId); 2962 mServiceDiscReqId = null; 2963 } 2964 2965 /* TODO: We could track individual service adds separately and avoid 2966 * having to do update all service requests on every new request 2967 */ 2968 private boolean addServiceRequest(Messenger m, WifiP2pServiceRequest req) { 2969 clearClientDeadChannels(); 2970 ClientInfo clientInfo = getClientInfo(m, true); 2971 if (clientInfo == null) { 2972 return false; 2973 } 2974 2975 ++mServiceTransactionId; 2976 //The Wi-Fi p2p spec says transaction id should be non-zero 2977 if (mServiceTransactionId == 0) ++mServiceTransactionId; 2978 req.setTransactionId(mServiceTransactionId); 2979 clientInfo.mReqList.put(mServiceTransactionId, req); 2980 2981 if (mServiceDiscReqId == null) { 2982 return true; 2983 } 2984 2985 return updateSupplicantServiceRequest(); 2986 } 2987 2988 private void removeServiceRequest(Messenger m, WifiP2pServiceRequest req) { 2989 ClientInfo clientInfo = getClientInfo(m, false); 2990 if (clientInfo == null) { 2991 return; 2992 } 2993 2994 //Application does not have transaction id information 2995 //go through stored requests to remove 2996 boolean removed = false; 2997 for (int i=0; i<clientInfo.mReqList.size(); i++) { 2998 if (req.equals(clientInfo.mReqList.valueAt(i))) { 2999 removed = true; 3000 clientInfo.mReqList.removeAt(i); 3001 break; 3002 } 3003 } 3004 3005 if (!removed) return; 3006 3007 if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) { 3008 if (DBG) logd("remove client information from framework"); 3009 mClientInfoList.remove(clientInfo.mMessenger); 3010 } 3011 3012 if (mServiceDiscReqId == null) { 3013 return; 3014 } 3015 3016 updateSupplicantServiceRequest(); 3017 } 3018 3019 private void clearServiceRequests(Messenger m) { 3020 3021 ClientInfo clientInfo = getClientInfo(m, false); 3022 if (clientInfo == null) { 3023 return; 3024 } 3025 3026 if (clientInfo.mReqList.size() == 0) { 3027 return; 3028 } 3029 3030 clientInfo.mReqList.clear(); 3031 3032 if (clientInfo.mServList.size() == 0) { 3033 if (DBG) logd("remove channel information from framework"); 3034 mClientInfoList.remove(clientInfo.mMessenger); 3035 } 3036 3037 if (mServiceDiscReqId == null) { 3038 return; 3039 } 3040 3041 updateSupplicantServiceRequest(); 3042 } 3043 3044 private boolean addLocalService(Messenger m, WifiP2pServiceInfo servInfo) { 3045 clearClientDeadChannels(); 3046 ClientInfo clientInfo = getClientInfo(m, true); 3047 if (clientInfo == null) { 3048 return false; 3049 } 3050 3051 if (!clientInfo.mServList.add(servInfo)) { 3052 return false; 3053 } 3054 3055 if (!mWifiNative.p2pServiceAdd(servInfo)) { 3056 clientInfo.mServList.remove(servInfo); 3057 return false; 3058 } 3059 3060 return true; 3061 } 3062 3063 private void removeLocalService(Messenger m, WifiP2pServiceInfo servInfo) { 3064 ClientInfo clientInfo = getClientInfo(m, false); 3065 if (clientInfo == null) { 3066 return; 3067 } 3068 3069 mWifiNative.p2pServiceDel(servInfo); 3070 3071 clientInfo.mServList.remove(servInfo); 3072 if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) { 3073 if (DBG) logd("remove client information from framework"); 3074 mClientInfoList.remove(clientInfo.mMessenger); 3075 } 3076 } 3077 3078 private void clearLocalServices(Messenger m) { 3079 ClientInfo clientInfo = getClientInfo(m, false); 3080 if (clientInfo == null) { 3081 return; 3082 } 3083 3084 for (WifiP2pServiceInfo servInfo: clientInfo.mServList) { 3085 mWifiNative.p2pServiceDel(servInfo); 3086 } 3087 3088 clientInfo.mServList.clear(); 3089 if (clientInfo.mReqList.size() == 0) { 3090 if (DBG) logd("remove client information from framework"); 3091 mClientInfoList.remove(clientInfo.mMessenger); 3092 } 3093 } 3094 3095 private void clearClientInfo(Messenger m) { 3096 clearLocalServices(m); 3097 clearServiceRequests(m); 3098 } 3099 3100 /** 3101 * Send the service response to the WifiP2pManager.Channel. 3102 * 3103 * @param resp 3104 */ 3105 private void sendServiceResponse(WifiP2pServiceResponse resp) { 3106 for (ClientInfo c : mClientInfoList.values()) { 3107 WifiP2pServiceRequest req = c.mReqList.get(resp.getTransactionId()); 3108 if (req != null) { 3109 Message msg = Message.obtain(); 3110 msg.what = WifiP2pManager.RESPONSE_SERVICE; 3111 msg.arg1 = 0; 3112 msg.arg2 = 0; 3113 msg.obj = resp; 3114 try { 3115 c.mMessenger.send(msg); 3116 } catch (RemoteException e) { 3117 if (DBG) logd("detect dead channel"); 3118 clearClientInfo(c.mMessenger); 3119 return; 3120 } 3121 } 3122 } 3123 } 3124 3125 /** 3126 * We dont get notifications of clients that have gone away. 3127 * We detect this actively when services are added and throw 3128 * them away. 3129 * 3130 * TODO: This can be done better with full async channels. 3131 */ 3132 private void clearClientDeadChannels() { 3133 ArrayList<Messenger> deadClients = new ArrayList<Messenger>(); 3134 3135 for (ClientInfo c : mClientInfoList.values()) { 3136 Message msg = Message.obtain(); 3137 msg.what = WifiP2pManager.PING; 3138 msg.arg1 = 0; 3139 msg.arg2 = 0; 3140 msg.obj = null; 3141 try { 3142 c.mMessenger.send(msg); 3143 } catch (RemoteException e) { 3144 if (DBG) logd("detect dead channel"); 3145 deadClients.add(c.mMessenger); 3146 } 3147 } 3148 3149 for (Messenger m : deadClients) { 3150 clearClientInfo(m); 3151 } 3152 } 3153 3154 /** 3155 * Return the specified ClientInfo. 3156 * @param m Messenger 3157 * @param createIfNotExist if true and the specified channel info does not exist, 3158 * create new client info. 3159 * @return the specified ClientInfo. 3160 */ 3161 private ClientInfo getClientInfo(Messenger m, boolean createIfNotExist) { 3162 ClientInfo clientInfo = mClientInfoList.get(m); 3163 3164 if (clientInfo == null && createIfNotExist) { 3165 if (DBG) logd("add a new client"); 3166 clientInfo = new ClientInfo(m); 3167 mClientInfoList.put(m, clientInfo); 3168 } 3169 3170 return clientInfo; 3171 } 3172 3173 } 3174 3175 /** 3176 * Information about a particular client and we track the service discovery requests 3177 * and the local services registered by the client. 3178 */ 3179 private class ClientInfo { 3180 3181 /* 3182 * A reference to WifiP2pManager.Channel handler. 3183 * The response of this request is notified to WifiP2pManager.Channel handler 3184 */ 3185 private Messenger mMessenger; 3186 3187 /* 3188 * A service discovery request list. 3189 */ 3190 private SparseArray<WifiP2pServiceRequest> mReqList; 3191 3192 /* 3193 * A local service information list. 3194 */ 3195 private List<WifiP2pServiceInfo> mServList; 3196 3197 private ClientInfo(Messenger m) { 3198 mMessenger = m; 3199 mReqList = new SparseArray(); 3200 mServList = new ArrayList<WifiP2pServiceInfo>(); 3201 } 3202 } 3203} 3204