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