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