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