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