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