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