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