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