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