WifiP2pServiceImpl.java revision 782eac0bacec797262eb4d721ad58cfcf2fbf885
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 transitionTo(mP2pDisabledState); 716 } 717 break; 718 719 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 720 if (message.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { 721 loge("Send failed, client connection lost"); 722 } else { 723 loge("Client connection lost with reason: " + message.arg1); 724 } 725 mWifiChannel = null; 726 transitionTo(mP2pDisabledState); 727 break; 728 729 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: 730 AsyncChannel ac = new WifiAsyncChannel(TAG); 731 ac.connect(mContext, getHandler(), message.replyTo); 732 break; 733 case BLOCK_DISCOVERY: 734 mDiscoveryBlocked = (message.arg1 == ENABLED ? true : false); 735 // always reset this - we went to a state that doesn't support discovery so 736 // it would have stopped regardless 737 mDiscoveryPostponed = false; 738 if (mDiscoveryBlocked) { 739 try { 740 StateMachine m = (StateMachine) message.obj; 741 m.sendMessage(message.arg2); 742 } catch (Exception e) { 743 loge("unable to send BLOCK_DISCOVERY response: " + e); 744 } 745 } 746 break; 747 case WifiP2pManager.DISCOVER_PEERS: 748 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 749 WifiP2pManager.BUSY); 750 break; 751 case WifiP2pManager.STOP_DISCOVERY: 752 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, 753 WifiP2pManager.BUSY); 754 break; 755 case WifiP2pManager.DISCOVER_SERVICES: 756 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 757 WifiP2pManager.BUSY); 758 break; 759 case WifiP2pManager.CONNECT: 760 replyToMessage(message, WifiP2pManager.CONNECT_FAILED, 761 WifiP2pManager.BUSY); 762 break; 763 case WifiP2pManager.CANCEL_CONNECT: 764 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED, 765 WifiP2pManager.BUSY); 766 break; 767 case WifiP2pManager.CREATE_GROUP: 768 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, 769 WifiP2pManager.BUSY); 770 break; 771 case WifiP2pManager.REMOVE_GROUP: 772 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, 773 WifiP2pManager.BUSY); 774 break; 775 case WifiP2pManager.ADD_LOCAL_SERVICE: 776 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED, 777 WifiP2pManager.BUSY); 778 break; 779 case WifiP2pManager.REMOVE_LOCAL_SERVICE: 780 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED, 781 WifiP2pManager.BUSY); 782 break; 783 case WifiP2pManager.CLEAR_LOCAL_SERVICES: 784 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED, 785 WifiP2pManager.BUSY); 786 break; 787 case WifiP2pManager.ADD_SERVICE_REQUEST: 788 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED, 789 WifiP2pManager.BUSY); 790 break; 791 case WifiP2pManager.REMOVE_SERVICE_REQUEST: 792 replyToMessage(message, 793 WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED, 794 WifiP2pManager.BUSY); 795 break; 796 case WifiP2pManager.CLEAR_SERVICE_REQUESTS: 797 replyToMessage(message, 798 WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED, 799 WifiP2pManager.BUSY); 800 break; 801 case WifiP2pManager.SET_DEVICE_NAME: 802 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, 803 WifiP2pManager.BUSY); 804 break; 805 case WifiP2pManager.DELETE_PERSISTENT_GROUP: 806 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP, 807 WifiP2pManager.BUSY); 808 break; 809 case WifiP2pManager.SET_WFD_INFO: 810 if (!getWfdPermission(message.sendingUid)) { 811 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, 812 WifiP2pManager.ERROR); 813 } else { 814 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, 815 WifiP2pManager.BUSY); 816 } 817 break; 818 case WifiP2pManager.REQUEST_PEERS: 819 replyToMessage(message, WifiP2pManager.RESPONSE_PEERS, 820 getPeers((Bundle) message.obj, message.sendingUid)); 821 break; 822 case WifiP2pManager.REQUEST_CONNECTION_INFO: 823 replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO, 824 new WifiP2pInfo(mWifiP2pInfo)); 825 break; 826 case WifiP2pManager.REQUEST_GROUP_INFO: 827 replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, 828 mGroup != null ? new WifiP2pGroup(mGroup) : null); 829 break; 830 case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO: 831 replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO, 832 new WifiP2pGroupList(mGroups, null)); 833 break; 834 case WifiP2pManager.START_WPS: 835 replyToMessage(message, WifiP2pManager.START_WPS_FAILED, 836 WifiP2pManager.BUSY); 837 break; 838 case WifiP2pManager.GET_HANDOVER_REQUEST: 839 case WifiP2pManager.GET_HANDOVER_SELECT: 840 replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE, null); 841 break; 842 case WifiP2pManager.INITIATOR_REPORT_NFC_HANDOVER: 843 case WifiP2pManager.RESPONDER_REPORT_NFC_HANDOVER: 844 replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED, 845 WifiP2pManager.BUSY); 846 break; 847 case WifiMonitor.P2P_INVITATION_RESULT_EVENT: 848 case WifiMonitor.SCAN_RESULTS_EVENT: 849 case WifiMonitor.SUP_CONNECTION_EVENT: 850 case WifiMonitor.SUP_DISCONNECTION_EVENT: 851 case WifiMonitor.NETWORK_CONNECTION_EVENT: 852 case WifiMonitor.NETWORK_DISCONNECTION_EVENT: 853 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: 854 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: 855 case WifiMonitor.WPS_SUCCESS_EVENT: 856 case WifiMonitor.WPS_FAIL_EVENT: 857 case WifiMonitor.WPS_OVERLAP_EVENT: 858 case WifiMonitor.WPS_TIMEOUT_EVENT: 859 case WifiMonitor.P2P_GROUP_REMOVED_EVENT: 860 case WifiMonitor.P2P_DEVICE_FOUND_EVENT: 861 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 862 case WifiMonitor.P2P_FIND_STOPPED_EVENT: 863 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT: 864 case PEER_CONNECTION_USER_ACCEPT: 865 case PEER_CONNECTION_USER_REJECT: 866 case DISCONNECT_WIFI_RESPONSE: 867 case DROP_WIFI_USER_ACCEPT: 868 case DROP_WIFI_USER_REJECT: 869 case GROUP_CREATING_TIMED_OUT: 870 case DISABLE_P2P_TIMED_OUT: 871 case IPM_PRE_DHCP_ACTION: 872 case IPM_POST_DHCP_ACTION: 873 case IPM_DHCP_RESULTS: 874 case IPM_PROVISIONING_SUCCESS: 875 case IPM_PROVISIONING_FAILURE: 876 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT: 877 case SET_MIRACAST_MODE: 878 case WifiP2pManager.START_LISTEN: 879 case WifiP2pManager.STOP_LISTEN: 880 case WifiP2pManager.SET_CHANNEL: 881 case WifiStateMachine.CMD_ENABLE_P2P: 882 // Enable is lazy and has no response 883 break; 884 case WifiStateMachine.CMD_DISABLE_P2P_REQ: 885 // If we end up handling in default, p2p is not enabled 886 if (mWifiChannel != null) { 887 mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP); 888 } else { 889 loge("Unexpected disable request when WifiChannel is null"); 890 } 891 break; 892 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 893 // unexpected group created, remove 894 mGroup = (WifiP2pGroup) message.obj; 895 loge("Unexpected group creation, remove " + mGroup); 896 mWifiNative.p2pGroupRemove(mGroup.getInterface()); 897 break; 898 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: 899 // A group formation failure is always followed by 900 // a group removed event. Flushing things at group formation 901 // failure causes supplicant issues. Ignore right now. 902 break; 903 default: 904 loge("Unhandled message " + message); 905 return NOT_HANDLED; 906 } 907 return HANDLED; 908 } 909 } 910 911 class P2pNotSupportedState extends State { 912 @Override 913 public boolean processMessage(Message message) { 914 switch (message.what) { 915 case WifiP2pManager.DISCOVER_PEERS: 916 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 917 WifiP2pManager.P2P_UNSUPPORTED); 918 break; 919 case WifiP2pManager.STOP_DISCOVERY: 920 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, 921 WifiP2pManager.P2P_UNSUPPORTED); 922 break; 923 case WifiP2pManager.DISCOVER_SERVICES: 924 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 925 WifiP2pManager.P2P_UNSUPPORTED); 926 break; 927 case WifiP2pManager.CONNECT: 928 replyToMessage(message, WifiP2pManager.CONNECT_FAILED, 929 WifiP2pManager.P2P_UNSUPPORTED); 930 break; 931 case WifiP2pManager.CANCEL_CONNECT: 932 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED, 933 WifiP2pManager.P2P_UNSUPPORTED); 934 break; 935 case WifiP2pManager.CREATE_GROUP: 936 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, 937 WifiP2pManager.P2P_UNSUPPORTED); 938 break; 939 case WifiP2pManager.REMOVE_GROUP: 940 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, 941 WifiP2pManager.P2P_UNSUPPORTED); 942 break; 943 case WifiP2pManager.ADD_LOCAL_SERVICE: 944 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED, 945 WifiP2pManager.P2P_UNSUPPORTED); 946 break; 947 case WifiP2pManager.REMOVE_LOCAL_SERVICE: 948 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED, 949 WifiP2pManager.P2P_UNSUPPORTED); 950 break; 951 case WifiP2pManager.CLEAR_LOCAL_SERVICES: 952 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED, 953 WifiP2pManager.P2P_UNSUPPORTED); 954 break; 955 case WifiP2pManager.ADD_SERVICE_REQUEST: 956 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED, 957 WifiP2pManager.P2P_UNSUPPORTED); 958 break; 959 case WifiP2pManager.REMOVE_SERVICE_REQUEST: 960 replyToMessage(message, 961 WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED, 962 WifiP2pManager.P2P_UNSUPPORTED); 963 break; 964 case WifiP2pManager.CLEAR_SERVICE_REQUESTS: 965 replyToMessage(message, 966 WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED, 967 WifiP2pManager.P2P_UNSUPPORTED); 968 break; 969 case WifiP2pManager.SET_DEVICE_NAME: 970 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, 971 WifiP2pManager.P2P_UNSUPPORTED); 972 break; 973 case WifiP2pManager.DELETE_PERSISTENT_GROUP: 974 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP, 975 WifiP2pManager.P2P_UNSUPPORTED); 976 break; 977 case WifiP2pManager.SET_WFD_INFO: 978 if (!getWfdPermission(message.sendingUid)) { 979 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, 980 WifiP2pManager.ERROR); 981 } else { 982 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, 983 WifiP2pManager.P2P_UNSUPPORTED); 984 } 985 break; 986 case WifiP2pManager.START_WPS: 987 replyToMessage(message, WifiP2pManager.START_WPS_FAILED, 988 WifiP2pManager.P2P_UNSUPPORTED); 989 break; 990 case WifiP2pManager.START_LISTEN: 991 replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED, 992 WifiP2pManager.P2P_UNSUPPORTED); 993 break; 994 case WifiP2pManager.STOP_LISTEN: 995 replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED, 996 WifiP2pManager.P2P_UNSUPPORTED); 997 break; 998 999 default: 1000 return NOT_HANDLED; 1001 } 1002 return HANDLED; 1003 } 1004 } 1005 1006 class P2pDisablingState extends State { 1007 @Override 1008 public void enter() { 1009 if (DBG) logd(getName()); 1010 sendMessageDelayed(obtainMessage(DISABLE_P2P_TIMED_OUT, 1011 ++sDisableP2pTimeoutIndex, 0), DISABLE_P2P_WAIT_TIME_MS); 1012 } 1013 1014 @Override 1015 public boolean processMessage(Message message) { 1016 if (DBG) logd(getName() + message.toString()); 1017 switch (message.what) { 1018 case WifiMonitor.SUP_DISCONNECTION_EVENT: 1019 if (DBG) logd("p2p socket connection lost"); 1020 transitionTo(mP2pDisabledState); 1021 break; 1022 case WifiStateMachine.CMD_ENABLE_P2P: 1023 case WifiStateMachine.CMD_DISABLE_P2P_REQ: 1024 deferMessage(message); 1025 break; 1026 case DISABLE_P2P_TIMED_OUT: 1027 if (sDisableP2pTimeoutIndex == message.arg1) { 1028 loge("P2p disable timed out"); 1029 transitionTo(mP2pDisabledState); 1030 } 1031 break; 1032 default: 1033 return NOT_HANDLED; 1034 } 1035 return HANDLED; 1036 } 1037 1038 @Override 1039 public void exit() { 1040 if (mWifiChannel != null) { 1041 mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP); 1042 } else { 1043 loge("P2pDisablingState exit(): WifiChannel is null"); 1044 } 1045 } 1046 } 1047 1048 class P2pDisabledState extends State { 1049 @Override 1050 public void enter() { 1051 if (DBG) logd(getName()); 1052 } 1053 1054 @Override 1055 public boolean processMessage(Message message) { 1056 if (DBG) logd(getName() + message.toString()); 1057 switch (message.what) { 1058 case WifiStateMachine.CMD_ENABLE_P2P: 1059 try { 1060 mNwService.setInterfaceUp(mWifiNative.getInterfaceName()); 1061 } catch (RemoteException re) { 1062 loge("Unable to change interface settings: " + re); 1063 } catch (IllegalStateException ie) { 1064 loge("Unable to change interface settings: " + ie); 1065 } 1066 mWifiMonitor.startMonitoring(mWifiNative.getInterfaceName()); 1067 transitionTo(mP2pEnablingState); 1068 break; 1069 default: 1070 return NOT_HANDLED; 1071 } 1072 return HANDLED; 1073 } 1074 } 1075 1076 class P2pEnablingState extends State { 1077 @Override 1078 public void enter() { 1079 if (DBG) logd(getName()); 1080 } 1081 1082 @Override 1083 public boolean processMessage(Message message) { 1084 if (DBG) logd(getName() + message.toString()); 1085 switch (message.what) { 1086 case WifiMonitor.SUP_CONNECTION_EVENT: 1087 if (DBG) logd("P2p socket connection successful"); 1088 transitionTo(mInactiveState); 1089 break; 1090 case WifiMonitor.SUP_DISCONNECTION_EVENT: 1091 loge("P2p socket connection failed"); 1092 transitionTo(mP2pDisabledState); 1093 break; 1094 case WifiStateMachine.CMD_ENABLE_P2P: 1095 case WifiStateMachine.CMD_DISABLE_P2P_REQ: 1096 deferMessage(message); 1097 break; 1098 default: 1099 return NOT_HANDLED; 1100 } 1101 return HANDLED; 1102 } 1103 } 1104 1105 class P2pEnabledState extends State { 1106 @Override 1107 public void enter() { 1108 if (DBG) logd(getName()); 1109 sendP2pStateChangedBroadcast(true); 1110 mNetworkInfo.setIsAvailable(true); 1111 sendP2pConnectionChangedBroadcast(); 1112 initializeP2pSettings(); 1113 } 1114 1115 @Override 1116 public boolean processMessage(Message message) { 1117 if (DBG) logd(getName() + message.toString()); 1118 switch (message.what) { 1119 case WifiMonitor.SUP_DISCONNECTION_EVENT: 1120 loge("Unexpected loss of p2p socket connection"); 1121 transitionTo(mP2pDisabledState); 1122 break; 1123 case WifiStateMachine.CMD_ENABLE_P2P: 1124 // Nothing to do 1125 break; 1126 case WifiStateMachine.CMD_DISABLE_P2P_REQ: 1127 if (mPeers.clear()) { 1128 sendPeersChangedBroadcast(); 1129 } 1130 if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast(); 1131 1132 mWifiMonitor.stopMonitoring(mWifiNative.getInterfaceName()); 1133 transitionTo(mP2pDisablingState); 1134 break; 1135 case WifiP2pManager.SET_DEVICE_NAME: 1136 { 1137 WifiP2pDevice d = (WifiP2pDevice) message.obj; 1138 if (d != null && setAndPersistDeviceName(d.deviceName)) { 1139 if (DBG) logd("set device name " + d.deviceName); 1140 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED); 1141 } else { 1142 replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED, 1143 WifiP2pManager.ERROR); 1144 } 1145 break; 1146 } 1147 case WifiP2pManager.SET_WFD_INFO: 1148 { 1149 WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj; 1150 if (!getWfdPermission(message.sendingUid)) { 1151 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, 1152 WifiP2pManager.ERROR); 1153 } else if (d != null && setWfdInfo(d)) { 1154 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED); 1155 } else { 1156 replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED, 1157 WifiP2pManager.ERROR); 1158 } 1159 break; 1160 } 1161 case BLOCK_DISCOVERY: 1162 boolean blocked = (message.arg1 == ENABLED ? true : false); 1163 if (mDiscoveryBlocked == blocked) break; 1164 mDiscoveryBlocked = blocked; 1165 if (blocked && mDiscoveryStarted) { 1166 mWifiNative.p2pStopFind(); 1167 mDiscoveryPostponed = true; 1168 } 1169 if (!blocked && mDiscoveryPostponed) { 1170 mDiscoveryPostponed = false; 1171 mWifiNative.p2pFind(DISCOVER_TIMEOUT_S); 1172 } 1173 if (blocked) { 1174 try { 1175 StateMachine m = (StateMachine) message.obj; 1176 m.sendMessage(message.arg2); 1177 } catch (Exception e) { 1178 loge("unable to send BLOCK_DISCOVERY response: " + e); 1179 } 1180 } 1181 break; 1182 case WifiP2pManager.DISCOVER_PEERS: 1183 if (mDiscoveryBlocked) { 1184 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 1185 WifiP2pManager.BUSY); 1186 break; 1187 } 1188 // do not send service discovery request while normal find operation. 1189 clearSupplicantServiceRequest(); 1190 if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) { 1191 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED); 1192 sendP2pDiscoveryChangedBroadcast(true); 1193 } else { 1194 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 1195 WifiP2pManager.ERROR); 1196 } 1197 break; 1198 case WifiMonitor.P2P_FIND_STOPPED_EVENT: 1199 sendP2pDiscoveryChangedBroadcast(false); 1200 break; 1201 case WifiP2pManager.STOP_DISCOVERY: 1202 if (mWifiNative.p2pStopFind()) { 1203 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED); 1204 } else { 1205 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, 1206 WifiP2pManager.ERROR); 1207 } 1208 break; 1209 case WifiP2pManager.DISCOVER_SERVICES: 1210 if (mDiscoveryBlocked) { 1211 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 1212 WifiP2pManager.BUSY); 1213 break; 1214 } 1215 if (DBG) logd(getName() + " discover services"); 1216 if (!updateSupplicantServiceRequest()) { 1217 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 1218 WifiP2pManager.NO_SERVICE_REQUESTS); 1219 break; 1220 } 1221 if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) { 1222 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_SUCCEEDED); 1223 } else { 1224 replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED, 1225 WifiP2pManager.ERROR); 1226 } 1227 break; 1228 case WifiMonitor.P2P_DEVICE_FOUND_EVENT: 1229 WifiP2pDevice device = (WifiP2pDevice) message.obj; 1230 if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break; 1231 mPeers.updateSupplicantDetails(device); 1232 sendPeersChangedBroadcast(); 1233 break; 1234 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 1235 device = (WifiP2pDevice) message.obj; 1236 // Gets current details for the one removed 1237 device = mPeers.remove(device.deviceAddress); 1238 if (device != null) { 1239 sendPeersChangedBroadcast(); 1240 } 1241 break; 1242 case WifiP2pManager.ADD_LOCAL_SERVICE: 1243 if (DBG) logd(getName() + " add service"); 1244 WifiP2pServiceInfo servInfo = (WifiP2pServiceInfo) message.obj; 1245 if (addLocalService(message.replyTo, servInfo)) { 1246 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_SUCCEEDED); 1247 } else { 1248 replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED); 1249 } 1250 break; 1251 case WifiP2pManager.REMOVE_LOCAL_SERVICE: 1252 if (DBG) logd(getName() + " remove service"); 1253 servInfo = (WifiP2pServiceInfo) message.obj; 1254 removeLocalService(message.replyTo, servInfo); 1255 replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_SUCCEEDED); 1256 break; 1257 case WifiP2pManager.CLEAR_LOCAL_SERVICES: 1258 if (DBG) logd(getName() + " clear service"); 1259 clearLocalServices(message.replyTo); 1260 replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_SUCCEEDED); 1261 break; 1262 case WifiP2pManager.ADD_SERVICE_REQUEST: 1263 if (DBG) logd(getName() + " add service request"); 1264 if (!addServiceRequest(message.replyTo, 1265 (WifiP2pServiceRequest) message.obj)) { 1266 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED); 1267 break; 1268 } 1269 replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_SUCCEEDED); 1270 break; 1271 case WifiP2pManager.REMOVE_SERVICE_REQUEST: 1272 if (DBG) logd(getName() + " remove service request"); 1273 removeServiceRequest(message.replyTo, (WifiP2pServiceRequest) message.obj); 1274 replyToMessage(message, WifiP2pManager.REMOVE_SERVICE_REQUEST_SUCCEEDED); 1275 break; 1276 case WifiP2pManager.CLEAR_SERVICE_REQUESTS: 1277 if (DBG) logd(getName() + " clear service request"); 1278 clearServiceRequests(message.replyTo); 1279 replyToMessage(message, WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED); 1280 break; 1281 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT: 1282 if (DBG) logd(getName() + " receive service response"); 1283 List<WifiP2pServiceResponse> sdRespList = 1284 (List<WifiP2pServiceResponse>) message.obj; 1285 for (WifiP2pServiceResponse resp : sdRespList) { 1286 WifiP2pDevice dev = 1287 mPeers.get(resp.getSrcDevice().deviceAddress); 1288 resp.setSrcDevice(dev); 1289 sendServiceResponse(resp); 1290 } 1291 break; 1292 case WifiP2pManager.DELETE_PERSISTENT_GROUP: 1293 if (DBG) logd(getName() + " delete persistent group"); 1294 mGroups.remove(message.arg1); 1295 replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED); 1296 break; 1297 case SET_MIRACAST_MODE: 1298 mWifiNative.setMiracastMode(message.arg1); 1299 break; 1300 case WifiP2pManager.START_LISTEN: 1301 if (DBG) logd(getName() + " start listen mode"); 1302 mWifiNative.p2pFlush(); 1303 if (mWifiNative.p2pExtListen(true, 500, 500)) { 1304 replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED); 1305 } else { 1306 replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED); 1307 } 1308 break; 1309 case WifiP2pManager.STOP_LISTEN: 1310 if (DBG) logd(getName() + " stop listen mode"); 1311 if (mWifiNative.p2pExtListen(false, 0, 0)) { 1312 replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED); 1313 } else { 1314 replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED); 1315 } 1316 mWifiNative.p2pFlush(); 1317 break; 1318 case WifiP2pManager.SET_CHANNEL: 1319 Bundle p2pChannels = (Bundle) message.obj; 1320 int lc = p2pChannels.getInt("lc", 0); 1321 int oc = p2pChannels.getInt("oc", 0); 1322 if (DBG) logd(getName() + " set listen and operating channel"); 1323 if (mWifiNative.p2pSetChannel(lc, oc)) { 1324 replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED); 1325 } else { 1326 replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED); 1327 } 1328 break; 1329 case WifiP2pManager.GET_HANDOVER_REQUEST: 1330 Bundle requestBundle = new Bundle(); 1331 requestBundle.putString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE, 1332 mWifiNative.getNfcHandoverRequest()); 1333 replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE, 1334 requestBundle); 1335 break; 1336 case WifiP2pManager.GET_HANDOVER_SELECT: 1337 Bundle selectBundle = new Bundle(); 1338 selectBundle.putString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE, 1339 mWifiNative.getNfcHandoverSelect()); 1340 replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE, 1341 selectBundle); 1342 break; 1343 default: 1344 return NOT_HANDLED; 1345 } 1346 return HANDLED; 1347 } 1348 1349 @Override 1350 public void exit() { 1351 sendP2pDiscoveryChangedBroadcast(false); 1352 sendP2pStateChangedBroadcast(false); 1353 mNetworkInfo.setIsAvailable(false); 1354 } 1355 } 1356 1357 class InactiveState extends State { 1358 @Override 1359 public void enter() { 1360 if (DBG) logd(getName()); 1361 mSavedPeerConfig.invalidate(); 1362 } 1363 1364 @Override 1365 public boolean processMessage(Message message) { 1366 if (DBG) logd(getName() + message.toString()); 1367 switch (message.what) { 1368 case WifiP2pManager.CONNECT: 1369 if (DBG) logd(getName() + " sending connect"); 1370 WifiP2pConfig config = (WifiP2pConfig) message.obj; 1371 if (isConfigInvalid(config)) { 1372 loge("Dropping connect requeset " + config); 1373 replyToMessage(message, WifiP2pManager.CONNECT_FAILED); 1374 break; 1375 } 1376 1377 mAutonomousGroup = false; 1378 mWifiNative.p2pStopFind(); 1379 if (reinvokePersistentGroup(config)) { 1380 transitionTo(mGroupNegotiationState); 1381 } else { 1382 transitionTo(mProvisionDiscoveryState); 1383 } 1384 mSavedPeerConfig = config; 1385 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); 1386 sendPeersChangedBroadcast(); 1387 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); 1388 break; 1389 case WifiP2pManager.STOP_DISCOVERY: 1390 if (mWifiNative.p2pStopFind()) { 1391 // When discovery stops in inactive state, flush to clear 1392 // state peer data 1393 mWifiNative.p2pFlush(); 1394 mServiceDiscReqId = null; 1395 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED); 1396 } else { 1397 replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, 1398 WifiP2pManager.ERROR); 1399 } 1400 break; 1401 case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT: 1402 config = (WifiP2pConfig) message.obj; 1403 if (isConfigInvalid(config)) { 1404 loge("Dropping GO neg request " + config); 1405 break; 1406 } 1407 mSavedPeerConfig = config; 1408 mAutonomousGroup = false; 1409 mJoinExistingGroup = false; 1410 transitionTo(mUserAuthorizingNegotiationRequestState); 1411 break; 1412 case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT: 1413 WifiP2pGroup group = (WifiP2pGroup) message.obj; 1414 WifiP2pDevice owner = group.getOwner(); 1415 1416 if (owner == null) { 1417 int id = group.getNetworkId(); 1418 if (id < 0) { 1419 loge("Ignored invitation from null owner"); 1420 break; 1421 } 1422 1423 String addr = mGroups.getOwnerAddr(id); 1424 if (addr != null) { 1425 group.setOwner(new WifiP2pDevice(addr)); 1426 owner = group.getOwner(); 1427 } else { 1428 loge("Ignored invitation from null owner"); 1429 break; 1430 } 1431 } 1432 1433 config = new WifiP2pConfig(); 1434 config.deviceAddress = group.getOwner().deviceAddress; 1435 1436 if (isConfigInvalid(config)) { 1437 loge("Dropping invitation request " + config); 1438 break; 1439 } 1440 mSavedPeerConfig = config; 1441 1442 // Check if we have the owner in peer list and use appropriate 1443 // wps method. Default is to use PBC. 1444 if ((owner = mPeers.get(owner.deviceAddress)) != null) { 1445 if (owner.wpsPbcSupported()) { 1446 mSavedPeerConfig.wps.setup = WpsInfo.PBC; 1447 } else if (owner.wpsKeypadSupported()) { 1448 mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; 1449 } else if (owner.wpsDisplaySupported()) { 1450 mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY; 1451 } 1452 } 1453 1454 mAutonomousGroup = false; 1455 mJoinExistingGroup = true; 1456 transitionTo(mUserAuthorizingInviteRequestState); 1457 break; 1458 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: 1459 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 1460 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 1461 // We let the supplicant handle the provision discovery response 1462 // and wait instead for the GO_NEGOTIATION_REQUEST_EVENT. 1463 // Handling provision discovery and issuing a p2p_connect before 1464 // group negotiation comes through causes issues 1465 break; 1466 case WifiP2pManager.CREATE_GROUP: 1467 mAutonomousGroup = true; 1468 int netId = message.arg1; 1469 boolean ret = false; 1470 if (netId == WifiP2pGroup.PERSISTENT_NET_ID) { 1471 // check if the go persistent group is present. 1472 netId = mGroups.getNetworkId(mThisDevice.deviceAddress); 1473 if (netId != -1) { 1474 ret = mWifiNative.p2pGroupAdd(netId); 1475 } else { 1476 ret = mWifiNative.p2pGroupAdd(true); 1477 } 1478 } else { 1479 ret = mWifiNative.p2pGroupAdd(false); 1480 } 1481 1482 if (ret) { 1483 replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED); 1484 transitionTo(mGroupNegotiationState); 1485 } else { 1486 replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, 1487 WifiP2pManager.ERROR); 1488 // remain at this state. 1489 } 1490 break; 1491 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 1492 mGroup = (WifiP2pGroup) message.obj; 1493 if (DBG) logd(getName() + " group started"); 1494 1495 // We hit this scenario when a persistent group is reinvoked 1496 if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) { 1497 mAutonomousGroup = false; 1498 deferMessage(message); 1499 transitionTo(mGroupNegotiationState); 1500 } else { 1501 loge("Unexpected group creation, remove " + mGroup); 1502 mWifiNative.p2pGroupRemove(mGroup.getInterface()); 1503 } 1504 break; 1505 case WifiP2pManager.START_LISTEN: 1506 if (DBG) logd(getName() + " start listen mode"); 1507 mWifiNative.p2pFlush(); 1508 if (mWifiNative.p2pExtListen(true, 500, 500)) { 1509 replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED); 1510 } else { 1511 replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED); 1512 } 1513 break; 1514 case WifiP2pManager.STOP_LISTEN: 1515 if (DBG) logd(getName() + " stop listen mode"); 1516 if (mWifiNative.p2pExtListen(false, 0, 0)) { 1517 replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED); 1518 } else { 1519 replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED); 1520 } 1521 mWifiNative.p2pFlush(); 1522 break; 1523 case WifiP2pManager.SET_CHANNEL: 1524 Bundle p2pChannels = (Bundle) message.obj; 1525 int lc = p2pChannels.getInt("lc", 0); 1526 int oc = p2pChannels.getInt("oc", 0); 1527 if (DBG) logd(getName() + " set listen and operating channel"); 1528 if (mWifiNative.p2pSetChannel(lc, oc)) { 1529 replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED); 1530 } else { 1531 replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED); 1532 } 1533 break; 1534 case WifiP2pManager.INITIATOR_REPORT_NFC_HANDOVER: 1535 String handoverSelect = null; 1536 1537 if (message.obj != null) { 1538 handoverSelect = ((Bundle) message.obj) 1539 .getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE); 1540 } 1541 1542 if (handoverSelect != null 1543 && mWifiNative.initiatorReportNfcHandover(handoverSelect)) { 1544 replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED); 1545 transitionTo(mGroupCreatingState); 1546 } else { 1547 replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED); 1548 } 1549 break; 1550 case WifiP2pManager.RESPONDER_REPORT_NFC_HANDOVER: 1551 String handoverRequest = null; 1552 1553 if (message.obj != null) { 1554 handoverRequest = ((Bundle) message.obj) 1555 .getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE); 1556 } 1557 1558 if (handoverRequest != null 1559 && mWifiNative.responderReportNfcHandover(handoverRequest)) { 1560 replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED); 1561 transitionTo(mGroupCreatingState); 1562 } else { 1563 replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED); 1564 } 1565 break; 1566 default: 1567 return NOT_HANDLED; 1568 } 1569 return HANDLED; 1570 } 1571 } 1572 1573 class GroupCreatingState extends State { 1574 @Override 1575 public void enter() { 1576 if (DBG) logd(getName()); 1577 sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT, 1578 ++sGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS); 1579 } 1580 1581 @Override 1582 public boolean processMessage(Message message) { 1583 if (DBG) logd(getName() + message.toString()); 1584 boolean ret = HANDLED; 1585 switch (message.what) { 1586 case GROUP_CREATING_TIMED_OUT: 1587 if (sGroupCreatingTimeoutIndex == message.arg1) { 1588 if (DBG) logd("Group negotiation timed out"); 1589 handleGroupCreationFailure(); 1590 transitionTo(mInactiveState); 1591 } 1592 break; 1593 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 1594 WifiP2pDevice device = (WifiP2pDevice) message.obj; 1595 if (!mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) { 1596 if (DBG) { 1597 logd("mSavedPeerConfig " + mSavedPeerConfig.deviceAddress 1598 + "device " + device.deviceAddress); 1599 } 1600 // Do the regular device lost handling 1601 ret = NOT_HANDLED; 1602 break; 1603 } 1604 // Do nothing 1605 if (DBG) logd("Add device to lost list " + device); 1606 mPeersLostDuringConnection.updateSupplicantDetails(device); 1607 break; 1608 case WifiP2pManager.DISCOVER_PEERS: 1609 // Discovery will break negotiation 1610 replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, 1611 WifiP2pManager.BUSY); 1612 break; 1613 case WifiP2pManager.CANCEL_CONNECT: 1614 // Do a supplicant p2p_cancel which only cancels an ongoing 1615 // group negotiation. This will fail for a pending provision 1616 // discovery or for a pending user action, but at the framework 1617 // level, we always treat cancel as succeeded and enter 1618 // an inactive state 1619 mWifiNative.p2pCancelConnect(); 1620 handleGroupCreationFailure(); 1621 transitionTo(mInactiveState); 1622 replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED); 1623 break; 1624 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT: 1625 // We hit this scenario when NFC handover is invoked. 1626 mAutonomousGroup = false; 1627 transitionTo(mGroupNegotiationState); 1628 break; 1629 default: 1630 ret = NOT_HANDLED; 1631 } 1632 return ret; 1633 } 1634 } 1635 1636 class UserAuthorizingNegotiationRequestState extends State { 1637 @Override 1638 public void enter() { 1639 if (DBG) logd(getName()); 1640 notifyInvitationReceived(); 1641 } 1642 1643 @Override 1644 public boolean processMessage(Message message) { 1645 if (DBG) logd(getName() + message.toString()); 1646 boolean ret = HANDLED; 1647 switch (message.what) { 1648 case PEER_CONNECTION_USER_ACCEPT: 1649 mWifiNative.p2pStopFind(); 1650 p2pConnectWithPinDisplay(mSavedPeerConfig); 1651 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); 1652 sendPeersChangedBroadcast(); 1653 transitionTo(mGroupNegotiationState); 1654 break; 1655 case PEER_CONNECTION_USER_REJECT: 1656 if (DBG) logd("User rejected negotiation " + mSavedPeerConfig); 1657 transitionTo(mInactiveState); 1658 break; 1659 default: 1660 return NOT_HANDLED; 1661 } 1662 return ret; 1663 } 1664 1665 @Override 1666 public void exit() { 1667 // TODO: dismiss dialog if not already done 1668 } 1669 } 1670 1671 class UserAuthorizingInviteRequestState extends State { 1672 @Override 1673 public void enter() { 1674 if (DBG) logd(getName()); 1675 notifyInvitationReceived(); 1676 } 1677 1678 @Override 1679 public boolean processMessage(Message message) { 1680 if (DBG) logd(getName() + message.toString()); 1681 boolean ret = HANDLED; 1682 switch (message.what) { 1683 case PEER_CONNECTION_USER_ACCEPT: 1684 mWifiNative.p2pStopFind(); 1685 if (!reinvokePersistentGroup(mSavedPeerConfig)) { 1686 // Do negotiation when persistence fails 1687 p2pConnectWithPinDisplay(mSavedPeerConfig); 1688 } 1689 mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED); 1690 sendPeersChangedBroadcast(); 1691 transitionTo(mGroupNegotiationState); 1692 break; 1693 case PEER_CONNECTION_USER_REJECT: 1694 if (DBG) logd("User rejected invitation " + mSavedPeerConfig); 1695 transitionTo(mInactiveState); 1696 break; 1697 default: 1698 return NOT_HANDLED; 1699 } 1700 return ret; 1701 } 1702 1703 @Override 1704 public void exit() { 1705 // TODO: dismiss dialog if not already done 1706 } 1707 } 1708 1709 class ProvisionDiscoveryState extends State { 1710 @Override 1711 public void enter() { 1712 if (DBG) logd(getName()); 1713 mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig); 1714 } 1715 1716 @Override 1717 public boolean processMessage(Message message) { 1718 if (DBG) logd(getName() + message.toString()); 1719 WifiP2pProvDiscEvent provDisc; 1720 WifiP2pDevice device; 1721 switch (message.what) { 1722 case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT: 1723 provDisc = (WifiP2pProvDiscEvent) message.obj; 1724 device = provDisc.device; 1725 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; 1726 1727 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { 1728 if (DBG) logd("Found a match " + mSavedPeerConfig); 1729 p2pConnectWithPinDisplay(mSavedPeerConfig); 1730 transitionTo(mGroupNegotiationState); 1731 } 1732 break; 1733 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 1734 provDisc = (WifiP2pProvDiscEvent) message.obj; 1735 device = provDisc.device; 1736 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; 1737 1738 if (mSavedPeerConfig.wps.setup == WpsInfo.KEYPAD) { 1739 if (DBG) logd("Found a match " + mSavedPeerConfig); 1740 // we already have the pin 1741 if (!TextUtils.isEmpty(mSavedPeerConfig.wps.pin)) { 1742 p2pConnectWithPinDisplay(mSavedPeerConfig); 1743 transitionTo(mGroupNegotiationState); 1744 } else { 1745 mJoinExistingGroup = false; 1746 transitionTo(mUserAuthorizingNegotiationRequestState); 1747 } 1748 } 1749 break; 1750 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 1751 provDisc = (WifiP2pProvDiscEvent) message.obj; 1752 device = provDisc.device; 1753 if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break; 1754 1755 if (mSavedPeerConfig.wps.setup == WpsInfo.DISPLAY) { 1756 if (DBG) logd("Found a match " + mSavedPeerConfig); 1757 mSavedPeerConfig.wps.pin = provDisc.pin; 1758 p2pConnectWithPinDisplay(mSavedPeerConfig); 1759 notifyInvitationSent(provDisc.pin, device.deviceAddress); 1760 transitionTo(mGroupNegotiationState); 1761 } 1762 break; 1763 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT: 1764 loge("provision discovery failed"); 1765 handleGroupCreationFailure(); 1766 transitionTo(mInactiveState); 1767 break; 1768 default: 1769 return NOT_HANDLED; 1770 } 1771 return HANDLED; 1772 } 1773 } 1774 1775 class GroupNegotiationState extends State { 1776 @Override 1777 public void enter() { 1778 if (DBG) logd(getName()); 1779 } 1780 1781 @Override 1782 public boolean processMessage(Message message) { 1783 if (DBG) logd(getName() + message.toString()); 1784 switch (message.what) { 1785 // We ignore these right now, since we get a GROUP_STARTED notification 1786 // afterwards 1787 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT: 1788 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT: 1789 if (DBG) logd(getName() + " go success"); 1790 break; 1791 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 1792 mGroup = (WifiP2pGroup) message.obj; 1793 if (DBG) logd(getName() + " group started"); 1794 1795 if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) { 1796 // update cache information and set network id to mGroup. 1797 updatePersistentNetworks(NO_RELOAD); 1798 String devAddr = mGroup.getOwner().deviceAddress; 1799 mGroup.setNetworkId(mGroups.getNetworkId(devAddr, 1800 mGroup.getNetworkName())); 1801 } 1802 1803 if (mGroup.isGroupOwner()) { 1804 // Setting an idle time out on GO causes issues with certain scenarios 1805 // on clients where it can be off-channel for longer and with the power 1806 // save modes used. 1807 // TODO: Verify multi-channel scenarios and supplicant behavior are 1808 // better before adding a time out in future 1809 // Set group idle timeout of 10 sec, to avoid GO beaconing incase of any 1810 // failure during 4-way Handshake. 1811 if (!mAutonomousGroup) { 1812 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 1813 GROUP_IDLE_TIME_S); 1814 } 1815 startDhcpServer(mGroup.getInterface()); 1816 } else { 1817 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S); 1818 startIpManager(mGroup.getInterface()); 1819 WifiP2pDevice groupOwner = mGroup.getOwner(); 1820 WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress); 1821 if (peer != null) { 1822 // update group owner details with peer details found at discovery 1823 groupOwner.updateSupplicantDetails(peer); 1824 mPeers.updateStatus(groupOwner.deviceAddress, 1825 WifiP2pDevice.CONNECTED); 1826 sendPeersChangedBroadcast(); 1827 } else { 1828 // A supplicant bug can lead to reporting an invalid 1829 // group owner address (all zeroes) at times. Avoid a 1830 // crash, but continue group creation since it is not 1831 // essential. 1832 logw("Unknown group owner " + groupOwner); 1833 } 1834 } 1835 transitionTo(mGroupCreatedState); 1836 break; 1837 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT: 1838 P2pStatus status = (P2pStatus) message.obj; 1839 if (status == P2pStatus.NO_COMMON_CHANNEL) { 1840 transitionTo(mFrequencyConflictState); 1841 break; 1842 } 1843 // continue with group removal handling 1844 case WifiMonitor.P2P_GROUP_REMOVED_EVENT: 1845 if (DBG) logd(getName() + " go failure"); 1846 handleGroupCreationFailure(); 1847 transitionTo(mInactiveState); 1848 break; 1849 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: 1850 // A group formation failure is always followed by 1851 // a group removed event. Flushing things at group formation 1852 // failure causes supplicant issues. Ignore right now. 1853 status = (P2pStatus) message.obj; 1854 if (status == P2pStatus.NO_COMMON_CHANNEL) { 1855 transitionTo(mFrequencyConflictState); 1856 break; 1857 } 1858 break; 1859 case WifiMonitor.P2P_INVITATION_RESULT_EVENT: 1860 status = (P2pStatus) message.obj; 1861 if (status == P2pStatus.SUCCESS) { 1862 // invocation was succeeded. 1863 // wait P2P_GROUP_STARTED_EVENT. 1864 break; 1865 } 1866 loge("Invitation result " + status); 1867 if (status == P2pStatus.UNKNOWN_P2P_GROUP) { 1868 // target device has already removed the credential. 1869 // So, remove this credential accordingly. 1870 int netId = mSavedPeerConfig.netId; 1871 if (netId >= 0) { 1872 if (DBG) logd("Remove unknown client from the list"); 1873 removeClientFromList(netId, mSavedPeerConfig.deviceAddress, true); 1874 } 1875 1876 // Reinvocation has failed, try group negotiation 1877 mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID; 1878 p2pConnectWithPinDisplay(mSavedPeerConfig); 1879 } else if (status == P2pStatus.INFORMATION_IS_CURRENTLY_UNAVAILABLE) { 1880 1881 // Devices setting persistent_reconnect to 0 in wpa_supplicant 1882 // always defer the invocation request and return 1883 // "information is currently unavailable" error. 1884 // So, try another way to connect for interoperability. 1885 mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID; 1886 p2pConnectWithPinDisplay(mSavedPeerConfig); 1887 } else if (status == P2pStatus.NO_COMMON_CHANNEL) { 1888 transitionTo(mFrequencyConflictState); 1889 } else { 1890 handleGroupCreationFailure(); 1891 transitionTo(mInactiveState); 1892 } 1893 break; 1894 default: 1895 return NOT_HANDLED; 1896 } 1897 return HANDLED; 1898 } 1899 } 1900 1901 class FrequencyConflictState extends State { 1902 private AlertDialog mFrequencyConflictDialog; 1903 @Override 1904 public void enter() { 1905 if (DBG) logd(getName()); 1906 notifyFrequencyConflict(); 1907 } 1908 1909 private void notifyFrequencyConflict() { 1910 logd("Notify frequency conflict"); 1911 Resources r = Resources.getSystem(); 1912 1913 AlertDialog dialog = new AlertDialog.Builder(mContext) 1914 .setMessage(r.getString(R.string.wifi_p2p_frequency_conflict_message, 1915 getDeviceName(mSavedPeerConfig.deviceAddress))) 1916 .setPositiveButton(r.getString(R.string.dlg_ok), new OnClickListener() { 1917 @Override 1918 public void onClick(DialogInterface dialog, int which) { 1919 sendMessage(DROP_WIFI_USER_ACCEPT); 1920 } 1921 }) 1922 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() { 1923 @Override 1924 public void onClick(DialogInterface dialog, int which) { 1925 sendMessage(DROP_WIFI_USER_REJECT); 1926 } 1927 }) 1928 .setOnCancelListener(new DialogInterface.OnCancelListener() { 1929 @Override 1930 public void onCancel(DialogInterface arg0) { 1931 sendMessage(DROP_WIFI_USER_REJECT); 1932 } 1933 }) 1934 .create(); 1935 dialog.setCanceledOnTouchOutside(false); 1936 1937 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 1938 WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes(); 1939 attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 1940 dialog.getWindow().setAttributes(attrs); 1941 dialog.show(); 1942 mFrequencyConflictDialog = dialog; 1943 } 1944 1945 @Override 1946 public boolean processMessage(Message message) { 1947 if (DBG) logd(getName() + message.toString()); 1948 switch (message.what) { 1949 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT: 1950 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT: 1951 loge(getName() + "group sucess during freq conflict!"); 1952 break; 1953 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 1954 loge(getName() + "group started after freq conflict, handle anyway"); 1955 deferMessage(message); 1956 transitionTo(mGroupNegotiationState); 1957 break; 1958 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT: 1959 case WifiMonitor.P2P_GROUP_REMOVED_EVENT: 1960 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT: 1961 // Ignore failures since we retry again 1962 break; 1963 case DROP_WIFI_USER_REJECT: 1964 // User rejected dropping wifi in favour of p2p 1965 handleGroupCreationFailure(); 1966 transitionTo(mInactiveState); 1967 break; 1968 case DROP_WIFI_USER_ACCEPT: 1969 // User accepted dropping wifi in favour of p2p 1970 if (mWifiChannel != null) { 1971 mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 1); 1972 } else { 1973 loge("DROP_WIFI_USER_ACCEPT message received when WifiChannel is null"); 1974 } 1975 mTemporarilyDisconnectedWifi = true; 1976 break; 1977 case DISCONNECT_WIFI_RESPONSE: 1978 // Got a response from wifistatemachine, retry p2p 1979 if (DBG) logd(getName() + "Wifi disconnected, retry p2p"); 1980 transitionTo(mInactiveState); 1981 sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig); 1982 break; 1983 default: 1984 return NOT_HANDLED; 1985 } 1986 return HANDLED; 1987 } 1988 1989 public void exit() { 1990 if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss(); 1991 } 1992 } 1993 1994 class GroupCreatedState extends State { 1995 @Override 1996 public void enter() { 1997 if (DBG) logd(getName()); 1998 // Once connected, peer config details are invalid 1999 mSavedPeerConfig.invalidate(); 2000 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); 2001 2002 updateThisDevice(WifiP2pDevice.CONNECTED); 2003 2004 // DHCP server has already been started if I am a group owner 2005 if (mGroup.isGroupOwner()) { 2006 setWifiP2pInfoOnGroupFormation( 2007 NetworkUtils.numericToInetAddress(SERVER_ADDRESS)); 2008 } 2009 2010 // In case of a negotiation group, connection changed is sent 2011 // after a client joins. For autonomous, send now 2012 if (mAutonomousGroup) { 2013 sendP2pConnectionChangedBroadcast(); 2014 } 2015 } 2016 2017 @Override 2018 public boolean processMessage(Message message) { 2019 if (DBG) logd(getName() + message.toString()); 2020 switch (message.what) { 2021 case WifiMonitor.AP_STA_CONNECTED_EVENT: 2022 WifiP2pDevice device = (WifiP2pDevice) message.obj; 2023 String deviceAddress = device.deviceAddress; 2024 // Clear timeout that was set when group was started. 2025 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0); 2026 if (deviceAddress != null) { 2027 if (mPeers.get(deviceAddress) != null) { 2028 mGroup.addClient(mPeers.get(deviceAddress)); 2029 } else { 2030 mGroup.addClient(deviceAddress); 2031 } 2032 mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED); 2033 if (DBG) logd(getName() + " ap sta connected"); 2034 sendPeersChangedBroadcast(); 2035 } else { 2036 loge("Connect on null device address, ignore"); 2037 } 2038 sendP2pConnectionChangedBroadcast(); 2039 break; 2040 case WifiMonitor.AP_STA_DISCONNECTED_EVENT: 2041 device = (WifiP2pDevice) message.obj; 2042 deviceAddress = device.deviceAddress; 2043 if (deviceAddress != null) { 2044 mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE); 2045 if (mGroup.removeClient(deviceAddress)) { 2046 if (DBG) logd("Removed client " + deviceAddress); 2047 if (!mAutonomousGroup && mGroup.isClientListEmpty()) { 2048 logd("Client list empty, remove non-persistent p2p group"); 2049 mWifiNative.p2pGroupRemove(mGroup.getInterface()); 2050 // We end up sending connection changed broadcast 2051 // when this happens at exit() 2052 } else { 2053 // Notify when a client disconnects from group 2054 sendP2pConnectionChangedBroadcast(); 2055 } 2056 } else { 2057 if (DBG) logd("Failed to remove client " + deviceAddress); 2058 for (WifiP2pDevice c : mGroup.getClientList()) { 2059 if (DBG) logd("client " + c.deviceAddress); 2060 } 2061 } 2062 sendPeersChangedBroadcast(); 2063 if (DBG) logd(getName() + " ap sta disconnected"); 2064 } else { 2065 loge("Disconnect on unknown device: " + device); 2066 } 2067 break; 2068 case IPM_PRE_DHCP_ACTION: 2069 mWifiNative.setP2pPowerSave(mGroup.getInterface(), false); 2070 mIpManager.completedPreDhcpAction(); 2071 break; 2072 case IPM_POST_DHCP_ACTION: 2073 mWifiNative.setP2pPowerSave(mGroup.getInterface(), true); 2074 break; 2075 case IPM_DHCP_RESULTS: 2076 mDhcpResults = (DhcpResults) message.obj; 2077 break; 2078 case IPM_PROVISIONING_SUCCESS: 2079 if (DBG) logd("mDhcpResults: " + mDhcpResults); 2080 setWifiP2pInfoOnGroupFormation(mDhcpResults.serverAddress); 2081 sendP2pConnectionChangedBroadcast(); 2082 try { 2083 final String ifname = mGroup.getInterface(); 2084 mNwService.addInterfaceToLocalNetwork( 2085 ifname, mDhcpResults.getRoutes(ifname)); 2086 } catch (RemoteException e) { 2087 loge("Failed to add iface to local network " + e); 2088 } 2089 break; 2090 case IPM_PROVISIONING_FAILURE: 2091 loge("IP provisioning failed"); 2092 mWifiNative.p2pGroupRemove(mGroup.getInterface()); 2093 break; 2094 case WifiP2pManager.REMOVE_GROUP: 2095 if (DBG) logd(getName() + " remove group"); 2096 if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) { 2097 transitionTo(mOngoingGroupRemovalState); 2098 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED); 2099 } else { 2100 handleGroupRemoved(); 2101 transitionTo(mInactiveState); 2102 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED, 2103 WifiP2pManager.ERROR); 2104 } 2105 break; 2106 case WifiMonitor.P2P_GROUP_REMOVED_EVENT: 2107 // We do not listen to NETWORK_DISCONNECTION_EVENT for group removal 2108 // handling since supplicant actually tries to reconnect after a temporary 2109 // disconnect until group idle time out. Eventually, a group removal event 2110 // will come when group has been removed. 2111 // 2112 // When there are connectivity issues during temporary disconnect, 2113 // the application will also just remove the group. 2114 // 2115 // Treating network disconnection as group removal causes race conditions 2116 // since supplicant would still maintain the group at that stage. 2117 if (DBG) logd(getName() + " group removed"); 2118 handleGroupRemoved(); 2119 transitionTo(mInactiveState); 2120 break; 2121 case WifiMonitor.P2P_DEVICE_LOST_EVENT: 2122 device = (WifiP2pDevice) message.obj; 2123 // Device loss for a connected device indicates 2124 // it is not in discovery any more 2125 if (mGroup.contains(device)) { 2126 if (DBG) logd("Add device to lost list " + device); 2127 mPeersLostDuringConnection.updateSupplicantDetails(device); 2128 return HANDLED; 2129 } 2130 // Do the regular device lost handling 2131 return NOT_HANDLED; 2132 case WifiStateMachine.CMD_DISABLE_P2P_REQ: 2133 sendMessage(WifiP2pManager.REMOVE_GROUP); 2134 deferMessage(message); 2135 break; 2136 // This allows any client to join the GO during the 2137 // WPS window 2138 case WifiP2pManager.START_WPS: 2139 WpsInfo wps = (WpsInfo) message.obj; 2140 if (wps == null) { 2141 replyToMessage(message, WifiP2pManager.START_WPS_FAILED); 2142 break; 2143 } 2144 boolean ret = true; 2145 if (wps.setup == WpsInfo.PBC) { 2146 ret = mWifiNative.startWpsPbc(mGroup.getInterface(), null); 2147 } else { 2148 if (wps.pin == null) { 2149 String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface()); 2150 try { 2151 Integer.parseInt(pin); 2152 notifyInvitationSent(pin, "any"); 2153 } catch (NumberFormatException ignore) { 2154 ret = false; 2155 } 2156 } else { 2157 ret = mWifiNative.startWpsPinKeypad(mGroup.getInterface(), 2158 wps.pin); 2159 } 2160 } 2161 replyToMessage(message, ret ? WifiP2pManager.START_WPS_SUCCEEDED : 2162 WifiP2pManager.START_WPS_FAILED); 2163 break; 2164 case WifiP2pManager.CONNECT: 2165 WifiP2pConfig config = (WifiP2pConfig) message.obj; 2166 if (isConfigInvalid(config)) { 2167 loge("Dropping connect requeset " + config); 2168 replyToMessage(message, WifiP2pManager.CONNECT_FAILED); 2169 break; 2170 } 2171 logd("Inviting device : " + config.deviceAddress); 2172 mSavedPeerConfig = config; 2173 if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) { 2174 mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED); 2175 sendPeersChangedBroadcast(); 2176 replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED); 2177 } else { 2178 replyToMessage(message, WifiP2pManager.CONNECT_FAILED, 2179 WifiP2pManager.ERROR); 2180 } 2181 // TODO: figure out updating the status to declined 2182 // when invitation is rejected 2183 break; 2184 case WifiMonitor.P2P_INVITATION_RESULT_EVENT: 2185 P2pStatus status = (P2pStatus) message.obj; 2186 if (status == P2pStatus.SUCCESS) { 2187 // invocation was succeeded. 2188 break; 2189 } 2190 loge("Invitation result " + status); 2191 if (status == P2pStatus.UNKNOWN_P2P_GROUP) { 2192 // target device has already removed the credential. 2193 // So, remove this credential accordingly. 2194 int netId = mGroup.getNetworkId(); 2195 if (netId >= 0) { 2196 if (DBG) logd("Remove unknown client from the list"); 2197 if (!removeClientFromList(netId, 2198 mSavedPeerConfig.deviceAddress, false)) { 2199 // not found the client on the list 2200 loge("Already removed the client, ignore"); 2201 break; 2202 } 2203 // try invitation. 2204 sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig); 2205 } 2206 } 2207 break; 2208 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: 2209 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 2210 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 2211 WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj; 2212 mSavedPeerConfig = new WifiP2pConfig(); 2213 mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress; 2214 if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) { 2215 mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD; 2216 } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) { 2217 mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY; 2218 mSavedPeerConfig.wps.pin = provDisc.pin; 2219 } else { 2220 mSavedPeerConfig.wps.setup = WpsInfo.PBC; 2221 } 2222 transitionTo(mUserAuthorizingJoinState); 2223 break; 2224 case WifiMonitor.P2P_GROUP_STARTED_EVENT: 2225 loge("Duplicate group creation event notice, ignore"); 2226 break; 2227 default: 2228 return NOT_HANDLED; 2229 } 2230 return HANDLED; 2231 } 2232 2233 public void exit() { 2234 updateThisDevice(WifiP2pDevice.AVAILABLE); 2235 resetWifiP2pInfo(); 2236 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null); 2237 sendP2pConnectionChangedBroadcast(); 2238 } 2239 } 2240 2241 class UserAuthorizingJoinState extends State { 2242 @Override 2243 public void enter() { 2244 if (DBG) logd(getName()); 2245 notifyInvitationReceived(); 2246 } 2247 2248 @Override 2249 public boolean processMessage(Message message) { 2250 if (DBG) logd(getName() + message.toString()); 2251 switch (message.what) { 2252 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT: 2253 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT: 2254 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT: 2255 // Ignore more client requests 2256 break; 2257 case PEER_CONNECTION_USER_ACCEPT: 2258 // Stop discovery to avoid failure due to channel switch 2259 mWifiNative.p2pStopFind(); 2260 if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { 2261 mWifiNative.startWpsPbc(mGroup.getInterface(), null); 2262 } else { 2263 mWifiNative.startWpsPinKeypad(mGroup.getInterface(), 2264 mSavedPeerConfig.wps.pin); 2265 } 2266 transitionTo(mGroupCreatedState); 2267 break; 2268 case PEER_CONNECTION_USER_REJECT: 2269 if (DBG) logd("User rejected incoming request"); 2270 transitionTo(mGroupCreatedState); 2271 break; 2272 default: 2273 return NOT_HANDLED; 2274 } 2275 return HANDLED; 2276 } 2277 2278 @Override 2279 public void exit() { 2280 // TODO: dismiss dialog if not already done 2281 } 2282 } 2283 2284 class OngoingGroupRemovalState extends State { 2285 @Override 2286 public void enter() { 2287 if (DBG) logd(getName()); 2288 } 2289 2290 @Override 2291 public boolean processMessage(Message message) { 2292 if (DBG) logd(getName() + message.toString()); 2293 switch (message.what) { 2294 // Group removal ongoing. Multiple calls 2295 // end up removing persisted network. Do nothing. 2296 case WifiP2pManager.REMOVE_GROUP: 2297 replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED); 2298 break; 2299 // Parent state will transition out of this state 2300 // when removal is complete 2301 default: 2302 return NOT_HANDLED; 2303 } 2304 return HANDLED; 2305 } 2306 } 2307 2308 @Override 2309 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2310 super.dump(fd, pw, args); 2311 pw.println("mWifiP2pInfo " + mWifiP2pInfo); 2312 pw.println("mGroup " + mGroup); 2313 pw.println("mSavedPeerConfig " + mSavedPeerConfig); 2314 pw.println(); 2315 } 2316 2317 private void sendP2pStateChangedBroadcast(boolean enabled) { 2318 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); 2319 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2320 if (enabled) { 2321 intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE, 2322 WifiP2pManager.WIFI_P2P_STATE_ENABLED); 2323 } else { 2324 intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE, 2325 WifiP2pManager.WIFI_P2P_STATE_DISABLED); 2326 } 2327 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2328 } 2329 2330 private void sendP2pDiscoveryChangedBroadcast(boolean started) { 2331 if (mDiscoveryStarted == started) return; 2332 mDiscoveryStarted = started; 2333 2334 if (DBG) logd("discovery change broadcast " + started); 2335 2336 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION); 2337 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2338 intent.putExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, started 2339 ? WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED : 2340 WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED); 2341 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2342 } 2343 2344 private void sendThisDeviceChangedBroadcast() { 2345 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); 2346 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2347 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice)); 2348 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2349 } 2350 2351 private void sendPeersChangedBroadcast() { 2352 final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); 2353 intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, new WifiP2pDeviceList(mPeers)); 2354 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2355 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 2356 } 2357 2358 private void sendP2pConnectionChangedBroadcast() { 2359 if (DBG) logd("sending p2p connection changed broadcast"); 2360 Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); 2361 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 2362 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 2363 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo)); 2364 intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); 2365 intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, new WifiP2pGroup(mGroup)); 2366 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2367 if (mWifiChannel != null) { 2368 mWifiChannel.sendMessage(WifiP2pServiceImpl.P2P_CONNECTION_CHANGED, 2369 new NetworkInfo(mNetworkInfo)); 2370 } else { 2371 loge("sendP2pConnectionChangedBroadcast(): WifiChannel is null"); 2372 } 2373 } 2374 2375 private void sendP2pPersistentGroupsChangedBroadcast() { 2376 if (DBG) logd("sending p2p persistent groups changed broadcast"); 2377 Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION); 2378 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2379 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 2380 } 2381 2382 private void startDhcpServer(String intf) { 2383 InterfaceConfiguration ifcg = null; 2384 try { 2385 ifcg = mNwService.getInterfaceConfig(intf); 2386 ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress( 2387 SERVER_ADDRESS), 24)); 2388 ifcg.setInterfaceUp(); 2389 mNwService.setInterfaceConfig(intf, ifcg); 2390 // This starts the dnsmasq server 2391 ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( 2392 Context.CONNECTIVITY_SERVICE); 2393 String[] tetheringDhcpRanges = cm.getTetheredDhcpRanges(); 2394 if (mNwService.isTetheringStarted()) { 2395 if (DBG) logd("Stop existing tethering and restart it"); 2396 mNwService.stopTethering(); 2397 } 2398 mNwService.tetherInterface(intf); 2399 mNwService.startTethering(tetheringDhcpRanges); 2400 } catch (Exception e) { 2401 loge("Error configuring interface " + intf + ", :" + e); 2402 return; 2403 } 2404 2405 logd("Started Dhcp server on " + intf); 2406 } 2407 2408 private void stopDhcpServer(String intf) { 2409 try { 2410 mNwService.untetherInterface(intf); 2411 for (String temp : mNwService.listTetheredInterfaces()) { 2412 logd("List all interfaces " + temp); 2413 if (temp.compareTo(intf) != 0) { 2414 logd("Found other tethering interfaces, so keep tethering alive"); 2415 return; 2416 } 2417 } 2418 mNwService.stopTethering(); 2419 } catch (Exception e) { 2420 loge("Error stopping Dhcp server" + e); 2421 return; 2422 } finally { 2423 logd("Stopped Dhcp server"); 2424 } 2425 } 2426 2427 private void notifyP2pEnableFailure() { 2428 Resources r = Resources.getSystem(); 2429 AlertDialog dialog = new AlertDialog.Builder(mContext) 2430 .setTitle(r.getString(R.string.wifi_p2p_dialog_title)) 2431 .setMessage(r.getString(R.string.wifi_p2p_failed_message)) 2432 .setPositiveButton(r.getString(R.string.ok), null) 2433 .create(); 2434 dialog.setCanceledOnTouchOutside(false); 2435 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 2436 WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes(); 2437 attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 2438 dialog.getWindow().setAttributes(attrs); 2439 dialog.show(); 2440 } 2441 2442 private void addRowToDialog(ViewGroup group, int stringId, String value) { 2443 Resources r = Resources.getSystem(); 2444 View row = LayoutInflater.from(mContext).inflate(R.layout.wifi_p2p_dialog_row, 2445 group, false); 2446 ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId)); 2447 ((TextView) row.findViewById(R.id.value)).setText(value); 2448 group.addView(row); 2449 } 2450 2451 private void notifyInvitationSent(String pin, String peerAddress) { 2452 Resources r = Resources.getSystem(); 2453 2454 final View textEntryView = LayoutInflater.from(mContext) 2455 .inflate(R.layout.wifi_p2p_dialog, null); 2456 2457 ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info); 2458 addRowToDialog(group, R.string.wifi_p2p_to_message, getDeviceName(peerAddress)); 2459 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, pin); 2460 2461 AlertDialog dialog = new AlertDialog.Builder(mContext) 2462 .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title)) 2463 .setView(textEntryView) 2464 .setPositiveButton(r.getString(R.string.ok), null) 2465 .create(); 2466 dialog.setCanceledOnTouchOutside(false); 2467 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 2468 WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes(); 2469 attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 2470 dialog.getWindow().setAttributes(attrs); 2471 dialog.show(); 2472 } 2473 2474 private void notifyInvitationReceived() { 2475 Resources r = Resources.getSystem(); 2476 final WpsInfo wps = mSavedPeerConfig.wps; 2477 final View textEntryView = LayoutInflater.from(mContext) 2478 .inflate(R.layout.wifi_p2p_dialog, null); 2479 2480 ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info); 2481 addRowToDialog(group, R.string.wifi_p2p_from_message, getDeviceName( 2482 mSavedPeerConfig.deviceAddress)); 2483 2484 final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin); 2485 2486 AlertDialog dialog = new AlertDialog.Builder(mContext) 2487 .setTitle(r.getString(R.string.wifi_p2p_invitation_to_connect_title)) 2488 .setView(textEntryView) 2489 .setPositiveButton(r.getString(R.string.accept), new OnClickListener() { 2490 public void onClick(DialogInterface dialog, int which) { 2491 if (wps.setup == WpsInfo.KEYPAD) { 2492 mSavedPeerConfig.wps.pin = pin.getText().toString(); 2493 } 2494 if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig); 2495 sendMessage(PEER_CONNECTION_USER_ACCEPT); 2496 } 2497 }) 2498 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() { 2499 @Override 2500 public void onClick(DialogInterface dialog, int which) { 2501 if (DBG) logd(getName() + " ignore connect"); 2502 sendMessage(PEER_CONNECTION_USER_REJECT); 2503 } 2504 }) 2505 .setOnCancelListener(new DialogInterface.OnCancelListener() { 2506 @Override 2507 public void onCancel(DialogInterface arg0) { 2508 if (DBG) logd(getName() + " ignore connect"); 2509 sendMessage(PEER_CONNECTION_USER_REJECT); 2510 } 2511 }) 2512 .create(); 2513 dialog.setCanceledOnTouchOutside(false); 2514 2515 // make the enter pin area or the display pin area visible 2516 switch (wps.setup) { 2517 case WpsInfo.KEYPAD: 2518 if (DBG) logd("Enter pin section visible"); 2519 textEntryView.findViewById(R.id.enter_pin_section).setVisibility(View.VISIBLE); 2520 break; 2521 case WpsInfo.DISPLAY: 2522 if (DBG) logd("Shown pin section visible"); 2523 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin); 2524 break; 2525 default: 2526 break; 2527 } 2528 2529 if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_APPLIANCE) 2530 == Configuration.UI_MODE_TYPE_APPLIANCE) { 2531 // For appliance devices, add a key listener which accepts. 2532 dialog.setOnKeyListener(new DialogInterface.OnKeyListener() { 2533 2534 @Override 2535 public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { 2536 // TODO: make the actual key come from a config value. 2537 if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) { 2538 sendMessage(PEER_CONNECTION_USER_ACCEPT); 2539 dialog.dismiss(); 2540 return true; 2541 } 2542 return false; 2543 } 2544 }); 2545 // TODO: add timeout for this dialog. 2546 // TODO: update UI in appliance mode to tell user what to do. 2547 } 2548 2549 dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 2550 WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes(); 2551 attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; 2552 dialog.getWindow().setAttributes(attrs); 2553 dialog.show(); 2554 } 2555 2556 /** 2557 * This method unifies the persisent group list, cleans up unused 2558 * networks and if required, updates corresponding broadcast receivers 2559 * @param boolean if true, reload the group list from scratch 2560 * and send broadcast message with fresh list 2561 */ 2562 private void updatePersistentNetworks(boolean reload) { 2563 if (reload) mGroups.clear(); 2564 2565 // Save in all cases, including when reload was requested, but 2566 // no network has been found. 2567 if (mWifiNative.p2pListNetworks(mGroups) || reload) { 2568 for (WifiP2pGroup group : mGroups.getGroupList()) { 2569 if (mThisDevice.deviceAddress.equals(group.getOwner().deviceAddress)) { 2570 group.setOwner(mThisDevice); 2571 } 2572 } 2573 mWifiNative.saveConfig(); 2574 sendP2pPersistentGroupsChangedBroadcast(); 2575 } 2576 } 2577 2578 /** 2579 * A config is valid if it has a peer address that has already been 2580 * discovered 2581 * @param WifiP2pConfig config to be validated 2582 * @return true if it is invalid, false otherwise 2583 */ 2584 private boolean isConfigInvalid(WifiP2pConfig config) { 2585 if (config == null) return true; 2586 if (TextUtils.isEmpty(config.deviceAddress)) return true; 2587 if (mPeers.get(config.deviceAddress) == null) return true; 2588 return false; 2589 } 2590 2591 private WifiP2pDevice fetchCurrentDeviceDetails(WifiP2pConfig config) { 2592 // Fetch & update group capability from supplicant on the device 2593 int gc = mWifiNative.getGroupCapability(config.deviceAddress); 2594 // TODO: The supplicant does not provide group capability changes as an event. 2595 // Having it pushed as an event would avoid polling for this information right 2596 // before a connection 2597 mPeers.updateGroupCapability(config.deviceAddress, gc); 2598 return mPeers.get(config.deviceAddress); 2599 } 2600 2601 /** 2602 * Start a p2p group negotiation and display pin if necessary 2603 * @param config for the peer 2604 */ 2605 private void p2pConnectWithPinDisplay(WifiP2pConfig config) { 2606 WifiP2pDevice dev = fetchCurrentDeviceDetails(config); 2607 2608 String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner()); 2609 try { 2610 Integer.parseInt(pin); 2611 notifyInvitationSent(pin, config.deviceAddress); 2612 } catch (NumberFormatException ignore) { 2613 // do nothing if p2pConnect did not return a pin 2614 } 2615 } 2616 2617 /** 2618 * Reinvoke a persistent group. 2619 * 2620 * @param config for the peer 2621 * @return true on success, false on failure 2622 */ 2623 private boolean reinvokePersistentGroup(WifiP2pConfig config) { 2624 WifiP2pDevice dev = fetchCurrentDeviceDetails(config); 2625 2626 boolean join = dev.isGroupOwner(); 2627 String ssid = mWifiNative.p2pGetSsid(dev.deviceAddress); 2628 if (DBG) logd("target ssid is " + ssid + " join:" + join); 2629 2630 if (join && dev.isGroupLimit()) { 2631 if (DBG) logd("target device reaches group limit."); 2632 2633 // if the target group has reached the limit, 2634 // try group formation. 2635 join = false; 2636 } else if (join) { 2637 int netId = mGroups.getNetworkId(dev.deviceAddress, ssid); 2638 if (netId >= 0) { 2639 // Skip WPS and start 4way handshake immediately. 2640 if (!mWifiNative.p2pGroupAdd(netId)) { 2641 return false; 2642 } 2643 return true; 2644 } 2645 } 2646 2647 if (!join && dev.isDeviceLimit()) { 2648 loge("target device reaches the device limit."); 2649 return false; 2650 } 2651 2652 if (!join && dev.isInvitationCapable()) { 2653 int netId = WifiP2pGroup.PERSISTENT_NET_ID; 2654 if (config.netId >= 0) { 2655 if (config.deviceAddress.equals(mGroups.getOwnerAddr(config.netId))) { 2656 netId = config.netId; 2657 } 2658 } else { 2659 netId = mGroups.getNetworkId(dev.deviceAddress); 2660 } 2661 if (netId < 0) { 2662 netId = getNetworkIdFromClientList(dev.deviceAddress); 2663 } 2664 if (DBG) logd("netId related with " + dev.deviceAddress + " = " + netId); 2665 if (netId >= 0) { 2666 // Invoke the persistent group. 2667 if (mWifiNative.p2pReinvoke(netId, dev.deviceAddress)) { 2668 // Save network id. It'll be used when an invitation 2669 // result event is received. 2670 config.netId = netId; 2671 return true; 2672 } else { 2673 loge("p2pReinvoke() failed, update networks"); 2674 updatePersistentNetworks(RELOAD); 2675 return false; 2676 } 2677 } 2678 } 2679 return false; 2680 } 2681 2682 /** 2683 * Return the network id of the group owner profile which has the p2p client with 2684 * the specified device address in it's client list. 2685 * If more than one persistent group of the same address is present in its client 2686 * lists, return the first one. 2687 * 2688 * @param deviceAddress p2p device address. 2689 * @return the network id. if not found, return -1. 2690 */ 2691 private int getNetworkIdFromClientList(String deviceAddress) { 2692 if (deviceAddress == null) return -1; 2693 2694 Collection<WifiP2pGroup> groups = mGroups.getGroupList(); 2695 for (WifiP2pGroup group : groups) { 2696 int netId = group.getNetworkId(); 2697 String[] p2pClientList = getClientList(netId); 2698 if (p2pClientList == null) continue; 2699 for (String client : p2pClientList) { 2700 if (deviceAddress.equalsIgnoreCase(client)) { 2701 return netId; 2702 } 2703 } 2704 } 2705 return -1; 2706 } 2707 2708 /** 2709 * Return p2p client list associated with the specified network id. 2710 * @param netId network id. 2711 * @return p2p client list. if not found, return null. 2712 */ 2713 private String[] getClientList(int netId) { 2714 String p2pClients = mWifiNative.getNetworkVariable(netId, "p2p_client_list"); 2715 if (p2pClients == null) { 2716 return null; 2717 } 2718 return p2pClients.split(" "); 2719 } 2720 2721 /** 2722 * Remove the specified p2p client from the specified profile. 2723 * @param netId network id of the profile. 2724 * @param addr p2p client address to be removed. 2725 * @param isRemovable if true, remove the specified profile if its client 2726 * list becomes empty. 2727 * @return whether removing the specified p2p client is successful or not. 2728 */ 2729 private boolean removeClientFromList(int netId, String addr, boolean isRemovable) { 2730 StringBuilder modifiedClientList = new StringBuilder(); 2731 String[] currentClientList = getClientList(netId); 2732 boolean isClientRemoved = false; 2733 if (currentClientList != null) { 2734 for (String client : currentClientList) { 2735 if (!client.equalsIgnoreCase(addr)) { 2736 modifiedClientList.append(" "); 2737 modifiedClientList.append(client); 2738 } else { 2739 isClientRemoved = true; 2740 } 2741 } 2742 } 2743 if (modifiedClientList.length() == 0 && isRemovable) { 2744 // the client list is empty. so remove it. 2745 if (DBG) logd("Remove unknown network"); 2746 mGroups.remove(netId); 2747 return true; 2748 } 2749 2750 if (!isClientRemoved) { 2751 // specified p2p client is not found. already removed. 2752 return false; 2753 } 2754 2755 if (DBG) logd("Modified client list: " + modifiedClientList); 2756 if (modifiedClientList.length() == 0) { 2757 modifiedClientList.append("\"\""); 2758 } 2759 mWifiNative.setNetworkVariable(netId, 2760 "p2p_client_list", modifiedClientList.toString()); 2761 mWifiNative.saveConfig(); 2762 return true; 2763 } 2764 2765 private void setWifiP2pInfoOnGroupFormation(InetAddress serverInetAddress) { 2766 mWifiP2pInfo.groupFormed = true; 2767 mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner(); 2768 mWifiP2pInfo.groupOwnerAddress = serverInetAddress; 2769 } 2770 2771 private void resetWifiP2pInfo() { 2772 mWifiP2pInfo.groupFormed = false; 2773 mWifiP2pInfo.isGroupOwner = false; 2774 mWifiP2pInfo.groupOwnerAddress = null; 2775 } 2776 2777 private String getDeviceName(String deviceAddress) { 2778 WifiP2pDevice d = mPeers.get(deviceAddress); 2779 if (d != null) { 2780 return d.deviceName; 2781 } 2782 //Treat the address as name if there is no match 2783 return deviceAddress; 2784 } 2785 2786 private String getPersistedDeviceName() { 2787 String deviceName = Settings.Global.getString(mContext.getContentResolver(), 2788 Settings.Global.WIFI_P2P_DEVICE_NAME); 2789 if (deviceName == null) { 2790 // We use the 4 digits of the ANDROID_ID to have a friendly 2791 // default that has low likelihood of collision with a peer 2792 String id = Settings.Secure.getString(mContext.getContentResolver(), 2793 Settings.Secure.ANDROID_ID); 2794 return "Android_" + id.substring(0, 4); 2795 } 2796 return deviceName; 2797 } 2798 2799 private boolean setAndPersistDeviceName(String devName) { 2800 if (devName == null) return false; 2801 2802 if (!mWifiNative.setDeviceName(devName)) { 2803 loge("Failed to set device name " + devName); 2804 return false; 2805 } 2806 2807 mThisDevice.deviceName = devName; 2808 mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName); 2809 2810 Settings.Global.putString(mContext.getContentResolver(), 2811 Settings.Global.WIFI_P2P_DEVICE_NAME, devName); 2812 sendThisDeviceChangedBroadcast(); 2813 return true; 2814 } 2815 2816 private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) { 2817 boolean success; 2818 2819 if (!wfdInfo.isWfdEnabled()) { 2820 success = mWifiNative.setWfdEnable(false); 2821 } else { 2822 success = 2823 mWifiNative.setWfdEnable(true) 2824 && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex()); 2825 } 2826 2827 if (!success) { 2828 loge("Failed to set wfd properties"); 2829 return false; 2830 } 2831 2832 mThisDevice.wfdInfo = wfdInfo; 2833 sendThisDeviceChangedBroadcast(); 2834 return true; 2835 } 2836 2837 private void initializeP2pSettings() { 2838 mWifiNative.setPersistentReconnect(true); 2839 mThisDevice.deviceName = getPersistedDeviceName(); 2840 mWifiNative.setDeviceName(mThisDevice.deviceName); 2841 // DIRECT-XY-DEVICENAME (XY is randomly generated) 2842 mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName); 2843 mWifiNative.setDeviceType(mThisDevice.primaryDeviceType); 2844 // Supplicant defaults to using virtual display with display 2845 // which refers to a remote display. Use physical_display 2846 mWifiNative.setConfigMethods("virtual_push_button physical_display keypad"); 2847 // STA has higher priority over P2P 2848 mWifiNative.setConcurrencyPriority("sta"); 2849 2850 mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress(); 2851 updateThisDevice(WifiP2pDevice.AVAILABLE); 2852 if (DBG) logd("DeviceAddress: " + mThisDevice.deviceAddress); 2853 2854 mClientInfoList.clear(); 2855 mWifiNative.p2pFlush(); 2856 mWifiNative.p2pServiceFlush(); 2857 mServiceTransactionId = 0; 2858 mServiceDiscReqId = null; 2859 2860 updatePersistentNetworks(RELOAD); 2861 } 2862 2863 private void updateThisDevice(int status) { 2864 mThisDevice.status = status; 2865 sendThisDeviceChangedBroadcast(); 2866 } 2867 2868 private void handleGroupCreationFailure() { 2869 resetWifiP2pInfo(); 2870 mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.FAILED, null, null); 2871 sendP2pConnectionChangedBroadcast(); 2872 2873 // Remove only the peer we failed to connect to so that other devices discovered 2874 // that have not timed out still remain in list for connection 2875 boolean peersChanged = mPeers.remove(mPeersLostDuringConnection); 2876 if (!TextUtils.isEmpty(mSavedPeerConfig.deviceAddress) 2877 && mPeers.remove(mSavedPeerConfig.deviceAddress) != null) { 2878 peersChanged = true; 2879 } 2880 if (peersChanged) { 2881 sendPeersChangedBroadcast(); 2882 } 2883 2884 mPeersLostDuringConnection.clear(); 2885 mServiceDiscReqId = null; 2886 sendMessage(WifiP2pManager.DISCOVER_PEERS); 2887 } 2888 2889 private void handleGroupRemoved() { 2890 if (mGroup.isGroupOwner()) { 2891 stopDhcpServer(mGroup.getInterface()); 2892 } else { 2893 if (DBG) logd("stop IpManager"); 2894 stopIpManager(); 2895 try { 2896 mNwService.removeInterfaceFromLocalNetwork(mGroup.getInterface()); 2897 } catch (RemoteException e) { 2898 loge("Failed to remove iface from local network " + e); 2899 } 2900 } 2901 2902 try { 2903 mNwService.clearInterfaceAddresses(mGroup.getInterface()); 2904 } catch (Exception e) { 2905 loge("Failed to clear addresses " + e); 2906 } 2907 2908 // Clear any timeout that was set. This is essential for devices 2909 // that reuse the main p2p interface for a created group. 2910 mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0); 2911 2912 boolean peersChanged = false; 2913 // Remove only peers part of the group, so that other devices discovered 2914 // that have not timed out still remain in list for connection 2915 for (WifiP2pDevice d : mGroup.getClientList()) { 2916 if (mPeers.remove(d)) peersChanged = true; 2917 } 2918 if (mPeers.remove(mGroup.getOwner())) peersChanged = true; 2919 if (mPeers.remove(mPeersLostDuringConnection)) peersChanged = true; 2920 if (peersChanged) { 2921 sendPeersChangedBroadcast(); 2922 } 2923 2924 mGroup = null; 2925 mPeersLostDuringConnection.clear(); 2926 mServiceDiscReqId = null; 2927 2928 if (mTemporarilyDisconnectedWifi) { 2929 if (mWifiChannel != null) { 2930 mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 0); 2931 } else { 2932 loge("handleGroupRemoved(): WifiChannel is null"); 2933 } 2934 mTemporarilyDisconnectedWifi = false; 2935 } 2936 } 2937 2938 private void replyToMessage(Message msg, int what) { 2939 // State machine initiated requests can have replyTo set to null 2940 // indicating there are no recipients, we ignore those reply actions 2941 if (msg.replyTo == null) return; 2942 Message dstMsg = obtainMessage(msg); 2943 dstMsg.what = what; 2944 mReplyChannel.replyToMessage(msg, dstMsg); 2945 } 2946 2947 private void replyToMessage(Message msg, int what, int arg1) { 2948 if (msg.replyTo == null) return; 2949 Message dstMsg = obtainMessage(msg); 2950 dstMsg.what = what; 2951 dstMsg.arg1 = arg1; 2952 mReplyChannel.replyToMessage(msg, dstMsg); 2953 } 2954 2955 private void replyToMessage(Message msg, int what, Object obj) { 2956 if (msg.replyTo == null) return; 2957 Message dstMsg = obtainMessage(msg); 2958 dstMsg.what = what; 2959 dstMsg.obj = obj; 2960 mReplyChannel.replyToMessage(msg, dstMsg); 2961 } 2962 2963 private Message obtainMessage(Message srcMsg) { 2964 // arg2 on the source message has a hash code that needs to 2965 // be retained in replies see WifiP2pManager for details 2966 Message msg = Message.obtain(); 2967 msg.arg2 = srcMsg.arg2; 2968 return msg; 2969 } 2970 2971 @Override 2972 protected void logd(String s) { 2973 Slog.d(TAG, s); 2974 } 2975 2976 @Override 2977 protected void loge(String s) { 2978 Slog.e(TAG, s); 2979 } 2980 2981 /** 2982 * Update service discovery request to wpa_supplicant. 2983 */ 2984 private boolean updateSupplicantServiceRequest() { 2985 clearSupplicantServiceRequest(); 2986 2987 StringBuffer sb = new StringBuffer(); 2988 for (ClientInfo c: mClientInfoList.values()) { 2989 int key; 2990 WifiP2pServiceRequest req; 2991 for (int i = 0; i < c.mReqList.size(); i++) { 2992 req = c.mReqList.valueAt(i); 2993 if (req != null) { 2994 sb.append(req.getSupplicantQuery()); 2995 } 2996 } 2997 } 2998 2999 if (sb.length() == 0) { 3000 return false; 3001 } 3002 3003 mServiceDiscReqId = mWifiNative.p2pServDiscReq("00:00:00:00:00:00", sb.toString()); 3004 if (mServiceDiscReqId == null) { 3005 return false; 3006 } 3007 return true; 3008 } 3009 3010 /** 3011 * Clear service discovery request in wpa_supplicant 3012 */ 3013 private void clearSupplicantServiceRequest() { 3014 if (mServiceDiscReqId == null) return; 3015 3016 mWifiNative.p2pServDiscCancelReq(mServiceDiscReqId); 3017 mServiceDiscReqId = null; 3018 } 3019 3020 private boolean addServiceRequest(Messenger m, WifiP2pServiceRequest req) { 3021 // TODO: We could track individual service adds separately and avoid 3022 // having to do update all service requests on every new request 3023 clearClientDeadChannels(); 3024 ClientInfo clientInfo = getClientInfo(m, true); 3025 if (clientInfo == null) { 3026 return false; 3027 } 3028 3029 ++mServiceTransactionId; 3030 //The Wi-Fi p2p spec says transaction id should be non-zero 3031 if (mServiceTransactionId == 0) ++mServiceTransactionId; 3032 req.setTransactionId(mServiceTransactionId); 3033 clientInfo.mReqList.put(mServiceTransactionId, req); 3034 3035 if (mServiceDiscReqId == null) { 3036 return true; 3037 } 3038 3039 return updateSupplicantServiceRequest(); 3040 } 3041 3042 private void removeServiceRequest(Messenger m, WifiP2pServiceRequest req) { 3043 ClientInfo clientInfo = getClientInfo(m, false); 3044 if (clientInfo == null) { 3045 return; 3046 } 3047 3048 // Application does not have transaction id information 3049 // go through stored requests to remove 3050 boolean removed = false; 3051 for (int i = 0; i < clientInfo.mReqList.size(); i++) { 3052 if (req.equals(clientInfo.mReqList.valueAt(i))) { 3053 removed = true; 3054 clientInfo.mReqList.removeAt(i); 3055 break; 3056 } 3057 } 3058 3059 if (!removed) return; 3060 3061 if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) { 3062 if (DBG) logd("remove client information from framework"); 3063 mClientInfoList.remove(clientInfo.mMessenger); 3064 } 3065 3066 if (mServiceDiscReqId == null) { 3067 return; 3068 } 3069 3070 updateSupplicantServiceRequest(); 3071 } 3072 3073 private void clearServiceRequests(Messenger m) { 3074 3075 ClientInfo clientInfo = getClientInfo(m, false); 3076 if (clientInfo == null) { 3077 return; 3078 } 3079 3080 if (clientInfo.mReqList.size() == 0) { 3081 return; 3082 } 3083 3084 clientInfo.mReqList.clear(); 3085 3086 if (clientInfo.mServList.size() == 0) { 3087 if (DBG) logd("remove channel information from framework"); 3088 mClientInfoList.remove(clientInfo.mMessenger); 3089 } 3090 3091 if (mServiceDiscReqId == null) { 3092 return; 3093 } 3094 3095 updateSupplicantServiceRequest(); 3096 } 3097 3098 private boolean addLocalService(Messenger m, WifiP2pServiceInfo servInfo) { 3099 clearClientDeadChannels(); 3100 ClientInfo clientInfo = getClientInfo(m, true); 3101 if (clientInfo == null) { 3102 return false; 3103 } 3104 3105 if (!clientInfo.mServList.add(servInfo)) { 3106 return false; 3107 } 3108 3109 if (!mWifiNative.p2pServiceAdd(servInfo)) { 3110 clientInfo.mServList.remove(servInfo); 3111 return false; 3112 } 3113 3114 return true; 3115 } 3116 3117 private void removeLocalService(Messenger m, WifiP2pServiceInfo servInfo) { 3118 ClientInfo clientInfo = getClientInfo(m, false); 3119 if (clientInfo == null) { 3120 return; 3121 } 3122 3123 mWifiNative.p2pServiceDel(servInfo); 3124 3125 clientInfo.mServList.remove(servInfo); 3126 if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) { 3127 if (DBG) logd("remove client information from framework"); 3128 mClientInfoList.remove(clientInfo.mMessenger); 3129 } 3130 } 3131 3132 private void clearLocalServices(Messenger m) { 3133 ClientInfo clientInfo = getClientInfo(m, false); 3134 if (clientInfo == null) { 3135 return; 3136 } 3137 3138 for (WifiP2pServiceInfo servInfo: clientInfo.mServList) { 3139 mWifiNative.p2pServiceDel(servInfo); 3140 } 3141 3142 clientInfo.mServList.clear(); 3143 if (clientInfo.mReqList.size() == 0) { 3144 if (DBG) logd("remove client information from framework"); 3145 mClientInfoList.remove(clientInfo.mMessenger); 3146 } 3147 } 3148 3149 private void clearClientInfo(Messenger m) { 3150 clearLocalServices(m); 3151 clearServiceRequests(m); 3152 } 3153 3154 /** 3155 * Send the service response to the WifiP2pManager.Channel. 3156 * @param WifiP2pServiceResponse response to service discovery 3157 */ 3158 private void sendServiceResponse(WifiP2pServiceResponse resp) { 3159 for (ClientInfo c : mClientInfoList.values()) { 3160 WifiP2pServiceRequest req = c.mReqList.get(resp.getTransactionId()); 3161 if (req != null) { 3162 Message msg = Message.obtain(); 3163 msg.what = WifiP2pManager.RESPONSE_SERVICE; 3164 msg.arg1 = 0; 3165 msg.arg2 = 0; 3166 msg.obj = resp; 3167 try { 3168 c.mMessenger.send(msg); 3169 } catch (RemoteException e) { 3170 if (DBG) logd("detect dead channel"); 3171 clearClientInfo(c.mMessenger); 3172 return; 3173 } 3174 } 3175 } 3176 } 3177 3178 /** 3179 * We don't get notifications of clients that have gone away. 3180 * We detect this actively when services are added and throw 3181 * them away. 3182 * 3183 * TODO: This can be done better with full async channels. 3184 */ 3185 private void clearClientDeadChannels() { 3186 ArrayList<Messenger> deadClients = new ArrayList<Messenger>(); 3187 3188 for (ClientInfo c : mClientInfoList.values()) { 3189 Message msg = Message.obtain(); 3190 msg.what = WifiP2pManager.PING; 3191 msg.arg1 = 0; 3192 msg.arg2 = 0; 3193 msg.obj = null; 3194 try { 3195 c.mMessenger.send(msg); 3196 } catch (RemoteException e) { 3197 if (DBG) logd("detect dead channel"); 3198 deadClients.add(c.mMessenger); 3199 } 3200 } 3201 3202 for (Messenger m : deadClients) { 3203 clearClientInfo(m); 3204 } 3205 } 3206 3207 /** 3208 * Return the specified ClientInfo. 3209 * @param m Messenger 3210 * @param createIfNotExist if true and the specified channel info does not exist, 3211 * create new client info. 3212 * @return the specified ClientInfo. 3213 */ 3214 private ClientInfo getClientInfo(Messenger m, boolean createIfNotExist) { 3215 ClientInfo clientInfo = mClientInfoList.get(m); 3216 3217 if (clientInfo == null && createIfNotExist) { 3218 if (DBG) logd("add a new client"); 3219 clientInfo = new ClientInfo(m); 3220 mClientInfoList.put(m, clientInfo); 3221 } 3222 3223 return clientInfo; 3224 } 3225 3226 /** 3227 * Enforces permissions on the caller who is requesting for P2p Peers 3228 * @param pkg Bundle containing the calling package string 3229 * @param uid of the caller 3230 * @return WifiP2pDeviceList the peer list 3231 */ 3232 private WifiP2pDeviceList getPeers(Bundle pkg, int uid) { 3233 String pkgName = pkg.getString(WifiP2pManager.CALLING_PACKAGE); 3234 boolean scanPermission = false; 3235 WifiPermissionsUtil wifiPermissionsUtil; 3236 // getPeers() is guaranteed to be invoked after Wifi Service is up 3237 // This ensures getInstance() will return a non-null object now 3238 if (mWifiInjector == null) { 3239 mWifiInjector = WifiInjector.getInstance(); 3240 } 3241 wifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil(); 3242 // Minimum Version to enforce location permission on apps build on the next 3243 // release. Bug 32288318 tracks updates to the version code. This code to check 3244 // version will serve as a place holder till the next release is available. 3245 try { 3246 scanPermission = wifiPermissionsUtil.canAccessScanResults(pkgName, 3247 uid, Build.VERSION_CODES.N + 2); 3248 } catch (SecurityException e) { 3249 Log.e(TAG, "Security Exception, cannot access peer list"); 3250 } 3251 if (scanPermission) { 3252 return new WifiP2pDeviceList(mPeers); 3253 } else { 3254 return new WifiP2pDeviceList(); 3255 } 3256 } 3257 } 3258 3259 /** 3260 * Information about a particular client and we track the service discovery requests 3261 * and the local services registered by the client. 3262 */ 3263 private class ClientInfo { 3264 3265 // A reference to WifiP2pManager.Channel handler. 3266 // The response of this request is notified to WifiP2pManager.Channel handler 3267 private Messenger mMessenger; 3268 3269 // A service discovery request list. 3270 private SparseArray<WifiP2pServiceRequest> mReqList; 3271 3272 // A local service information list. 3273 private List<WifiP2pServiceInfo> mServList; 3274 3275 private ClientInfo(Messenger m) { 3276 mMessenger = m; 3277 mReqList = new SparseArray(); 3278 mServList = new ArrayList<WifiP2pServiceInfo>(); 3279 } 3280 } 3281} 3282