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