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