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