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