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