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