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