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.Context;
21 import android.content.DialogInterface;
22 import android.content.DialogInterface.OnClickListener;
23 import android.content.Intent;
24 import android.content.pm.PackageManager;
25 import android.content.res.Configuration;
26 import android.content.res.Resources;
27 import android.net.ConnectivityManager;
28 import android.net.DhcpResults;
29 import android.net.InterfaceConfiguration;
30 import android.net.LinkAddress;
31 import android.net.LinkProperties;
32 import android.net.NetworkInfo;
33 import android.net.NetworkUtils;
34 import android.net.ip.IpManager;
35 import android.net.wifi.WpsInfo;
36 import android.net.wifi.p2p.IWifiP2pManager;
37 import android.net.wifi.p2p.WifiP2pConfig;
38 import android.net.wifi.p2p.WifiP2pDevice;
39 import android.net.wifi.p2p.WifiP2pDeviceList;
40 import android.net.wifi.p2p.WifiP2pGroup;
41 import android.net.wifi.p2p.WifiP2pGroupList;
42 import android.net.wifi.p2p.WifiP2pGroupList.GroupDeleteListener;
43 import android.net.wifi.p2p.WifiP2pInfo;
44 import android.net.wifi.p2p.WifiP2pManager;
45 import android.net.wifi.p2p.WifiP2pProvDiscEvent;
46 import android.net.wifi.p2p.WifiP2pWfdInfo;
47 import android.net.wifi.p2p.nsd.WifiP2pServiceInfo;
48 import android.net.wifi.p2p.nsd.WifiP2pServiceRequest;
49 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
50 import android.os.Binder;
51 import android.os.Bundle;
52 import android.os.Handler;
53 import android.os.HandlerThread;
54 import android.os.IBinder;
55 import android.os.INetworkManagementService;
56 import android.os.Looper;
57 import android.os.Message;
58 import android.os.Messenger;
59 import android.os.RemoteException;
60 import android.os.ServiceManager;
61 import android.os.UserHandle;
62 import android.provider.Settings;
63 import android.text.TextUtils;
64 import android.util.Slog;
65 import android.util.SparseArray;
66 import android.view.KeyEvent;
67 import android.view.LayoutInflater;
68 import android.view.View;
69 import android.view.ViewGroup;
70 import android.view.WindowManager;
71 import android.widget.EditText;
72 import android.widget.TextView;
73 
74 import com.android.internal.R;
75 import com.android.internal.util.AsyncChannel;
76 import com.android.internal.util.Protocol;
77 import com.android.internal.util.State;
78 import com.android.internal.util.StateMachine;
79 import com.android.server.wifi.WifiMonitor;
80 import com.android.server.wifi.WifiNative;
81 import com.android.server.wifi.WifiStateMachine;
82 
83 import java.io.FileDescriptor;
84 import java.io.PrintWriter;
85 import java.net.InetAddress;
86 import java.util.ArrayList;
87 import java.util.Collection;
88 import java.util.HashMap;
89 import java.util.List;
90 
91 
92 /**
93  * WifiP2pService includes a state machine to perform Wi-Fi p2p operations. Applications
94  * communicate with this service to issue device discovery and connectivity requests
95  * through the WifiP2pManager interface. The state machine communicates with the wifi
96  * driver through wpa_supplicant and handles the event responses through WifiMonitor.
97  *
98  * Note that the term Wifi when used without a p2p suffix refers to the client mode
99  * of Wifi operation
100  * @hide
101  */
102 public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
103     private static final String TAG = "WifiP2pService";
104     private static final boolean DBG = false;
105     private static final String NETWORKTYPE = "WIFI_P2P";
106 
107     private Context mContext;
108 
109     INetworkManagementService mNwService;
110     private IpManager mIpManager;
111     private DhcpResults mDhcpResults;
112 
113     private P2pStateMachine mP2pStateMachine;
114     private AsyncChannel mReplyChannel = new AsyncChannel();
115     private AsyncChannel mWifiChannel;
116 
117     private static final Boolean JOIN_GROUP = true;
118     private static final Boolean FORM_GROUP = false;
119 
120     private static final Boolean RELOAD = true;
121     private static final Boolean NO_RELOAD = false;
122 
123     /* Two minutes comes from the wpa_supplicant setting */
124     private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000;
125     private static int mGroupCreatingTimeoutIndex = 0;
126 
127     private static final int DISABLE_P2P_WAIT_TIME_MS = 5 * 1000;
128     private static int mDisableP2pTimeoutIndex = 0;
129 
130     /* Set a two minute discover timeout to avoid STA scans from being blocked */
131     private static final int DISCOVER_TIMEOUT_S = 120;
132 
133     /* Idle time after a peer is gone when the group is torn down */
134     private static final int GROUP_IDLE_TIME_S = 10;
135 
136     private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE;
137 
138     /* Delayed message to timeout group creation */
139     public static final int GROUP_CREATING_TIMED_OUT        =   BASE + 1;
140 
141     /* User accepted a peer request */
142     private static final int PEER_CONNECTION_USER_ACCEPT    =   BASE + 2;
143     /* User rejected a peer request */
144     private static final int PEER_CONNECTION_USER_REJECT    =   BASE + 3;
145     /* User wants to disconnect wifi in favour of p2p */
146     private static final int DROP_WIFI_USER_ACCEPT          =   BASE + 4;
147     /* User wants to keep his wifi connection and drop p2p */
148     private static final int DROP_WIFI_USER_REJECT          =   BASE + 5;
149     /* Delayed message to timeout p2p disable */
150     public static final int DISABLE_P2P_TIMED_OUT           =   BASE + 6;
151 
152 
153     /* Commands to the WifiStateMachine */
154     public static final int P2P_CONNECTION_CHANGED          =   BASE + 11;
155 
156     /* These commands are used to temporarily disconnect wifi when we detect
157      * a frequency conflict which would make it impossible to have with p2p
158      * and wifi active at the same time.
159      *
160      * If the user chooses to disable wifi temporarily, we keep wifi disconnected
161      * until the p2p connection is done and terminated at which point we will
162      * bring back wifi up
163      *
164      * DISCONNECT_WIFI_REQUEST
165      *      msg.arg1 = 1 enables temporary disconnect and 0 disables it.
166      */
167     public static final int DISCONNECT_WIFI_REQUEST         =   BASE + 12;
168     public static final int DISCONNECT_WIFI_RESPONSE        =   BASE + 13;
169 
170     public static final int SET_MIRACAST_MODE               =   BASE + 14;
171 
172     // During dhcp (and perhaps other times) we can't afford to drop packets
173     // but Discovery will switch our channel enough we will.
174     //   msg.arg1 = ENABLED for blocking, DISABLED for resumed.
175     //   msg.arg2 = msg to send when blocked
176     //   msg.obj  = StateMachine to send to when blocked
177     public static final int BLOCK_DISCOVERY                 =   BASE + 15;
178 
179     // Messages for interaction with IpManager.
180     private static final int IPM_PRE_DHCP_ACTION            =   BASE + 30;
181     private static final int IPM_POST_DHCP_ACTION           =   BASE + 31;
182     private static final int IPM_DHCP_RESULTS               =   BASE + 32;
183     private static final int IPM_PROVISIONING_SUCCESS       =   BASE + 33;
184     private static final int IPM_PROVISIONING_FAILURE       =   BASE + 34;
185 
186     public static final int ENABLED                         = 1;
187     public static final int DISABLED                        = 0;
188 
189     private final boolean mP2pSupported;
190 
191     private WifiP2pDevice mThisDevice = new WifiP2pDevice();
192 
193     /* When a group has been explicitly created by an app, we persist the group
194      * even after all clients have been disconnected until an explicit remove
195      * is invoked */
196     private boolean mAutonomousGroup;
197 
198     /* Invitation to join an existing p2p group */
199     private boolean mJoinExistingGroup;
200 
201     /* Track whether we are in p2p discovery. This is used to avoid sending duplicate
202      * broadcasts
203      */
204     private boolean mDiscoveryStarted;
205     /* Track whether servcice/peer discovery is blocked in favor of other wifi actions
206      * (notably dhcp)
207      */
208     private boolean mDiscoveryBlocked;
209 
210     /*
211      * remember if we were in a scan when it had to be stopped
212      */
213     private boolean mDiscoveryPostponed = false;
214 
215     private NetworkInfo mNetworkInfo;
216 
217     private boolean mTemporarilyDisconnectedWifi = false;
218 
219     /* The transaction Id of service discovery request */
220     private byte mServiceTransactionId = 0;
221 
222     /* Service discovery request ID of wpa_supplicant.
223      * null means it's not set yet. */
224     private String mServiceDiscReqId;
225 
226     /* clients(application) information list. */
227     private HashMap<Messenger, ClientInfo> mClientInfoList = new HashMap<Messenger, ClientInfo>();
228 
229     /* Is chosen as a unique address to avoid conflict with
230        the ranges defined in Tethering.java */
231     private static final String SERVER_ADDRESS = "192.168.49.1";
232 
233     /**
234      * Error code definition.
235      * see the Table.8 in the WiFi Direct specification for the detail.
236      */
237     public static enum P2pStatus {
238         /* Success. */
239         SUCCESS,
240 
241         /* The target device is currently unavailable. */
242         INFORMATION_IS_CURRENTLY_UNAVAILABLE,
243 
244         /* Protocol error. */
245         INCOMPATIBLE_PARAMETERS,
246 
247         /* The target device reached the limit of the number of the connectable device.
248          * For example, device limit or group limit is set. */
249         LIMIT_REACHED,
250 
251         /* Protocol error. */
252         INVALID_PARAMETER,
253 
254         /* Unable to accommodate request. */
255         UNABLE_TO_ACCOMMODATE_REQUEST,
256 
257         /* Previous protocol error, or disruptive behavior. */
258         PREVIOUS_PROTOCOL_ERROR,
259 
260         /* There is no common channels the both devices can use. */
261         NO_COMMON_CHANNEL,
262 
263         /* Unknown p2p group. For example, Device A tries to invoke the previous persistent group,
264          *  but device B has removed the specified credential already. */
265         UNKNOWN_P2P_GROUP,
266 
267         /* Both p2p devices indicated an intent of 15 in group owner negotiation. */
268         BOTH_GO_INTENT_15,
269 
270         /* Incompatible provisioning method. */
271         INCOMPATIBLE_PROVISIONING_METHOD,
272 
273         /* Rejected by user */
274         REJECTED_BY_USER,
275 
276         /* Unknown error */
277         UNKNOWN;
278 
valueOf(int error)279         public static P2pStatus valueOf(int error) {
280             switch(error) {
281             case 0 :
282                 return SUCCESS;
283             case 1:
284                 return INFORMATION_IS_CURRENTLY_UNAVAILABLE;
285             case 2:
286                 return INCOMPATIBLE_PARAMETERS;
287             case 3:
288                 return LIMIT_REACHED;
289             case 4:
290                 return INVALID_PARAMETER;
291             case 5:
292                 return UNABLE_TO_ACCOMMODATE_REQUEST;
293             case 6:
294                 return PREVIOUS_PROTOCOL_ERROR;
295             case 7:
296                 return NO_COMMON_CHANNEL;
297             case 8:
298                 return UNKNOWN_P2P_GROUP;
299             case 9:
300                 return BOTH_GO_INTENT_15;
301             case 10:
302                 return INCOMPATIBLE_PROVISIONING_METHOD;
303             case 11:
304                 return REJECTED_BY_USER;
305             default:
306                 return UNKNOWN;
307             }
308         }
309     }
310 
311     /**
312      * Handles client connections
313      */
314     private class ClientHandler extends Handler {
315 
ClientHandler(android.os.Looper looper)316         ClientHandler(android.os.Looper looper) {
317             super(looper);
318         }
319 
320         @Override
handleMessage(Message msg)321         public void handleMessage(Message msg) {
322             switch (msg.what) {
323               case WifiP2pManager.SET_DEVICE_NAME:
324               case WifiP2pManager.SET_WFD_INFO:
325               case WifiP2pManager.DISCOVER_PEERS:
326               case WifiP2pManager.STOP_DISCOVERY:
327               case WifiP2pManager.CONNECT:
328               case WifiP2pManager.CANCEL_CONNECT:
329               case WifiP2pManager.CREATE_GROUP:
330               case WifiP2pManager.REMOVE_GROUP:
331               case WifiP2pManager.START_LISTEN:
332               case WifiP2pManager.STOP_LISTEN:
333               case WifiP2pManager.SET_CHANNEL:
334               case WifiP2pManager.START_WPS:
335               case WifiP2pManager.ADD_LOCAL_SERVICE:
336               case WifiP2pManager.REMOVE_LOCAL_SERVICE:
337               case WifiP2pManager.CLEAR_LOCAL_SERVICES:
338               case WifiP2pManager.DISCOVER_SERVICES:
339               case WifiP2pManager.ADD_SERVICE_REQUEST:
340               case WifiP2pManager.REMOVE_SERVICE_REQUEST:
341               case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
342               case WifiP2pManager.REQUEST_PEERS:
343               case WifiP2pManager.REQUEST_CONNECTION_INFO:
344               case WifiP2pManager.REQUEST_GROUP_INFO:
345               case WifiP2pManager.DELETE_PERSISTENT_GROUP:
346               case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
347                 mP2pStateMachine.sendMessage(Message.obtain(msg));
348                 break;
349               default:
350                 Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
351                 break;
352             }
353         }
354     }
355     private ClientHandler mClientHandler;
356 
WifiP2pServiceImpl(Context context)357     public WifiP2pServiceImpl(Context context) {
358         mContext = context;
359 
360         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, "");
361 
362         mP2pSupported = mContext.getPackageManager().hasSystemFeature(
363                 PackageManager.FEATURE_WIFI_DIRECT);
364 
365         mThisDevice.primaryDeviceType = mContext.getResources().getString(
366                 com.android.internal.R.string.config_wifi_p2p_device_type);
367 
368         HandlerThread wifiP2pThread = new HandlerThread("WifiP2pService");
369         wifiP2pThread.start();
370         mClientHandler = new ClientHandler(wifiP2pThread.getLooper());
371 
372         mP2pStateMachine = new P2pStateMachine(TAG, wifiP2pThread.getLooper(), mP2pSupported);
373         mP2pStateMachine.start();
374     }
375 
connectivityServiceReady()376     public void connectivityServiceReady() {
377         IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
378         mNwService = INetworkManagementService.Stub.asInterface(b);
379     }
380 
enforceAccessPermission()381     private void enforceAccessPermission() {
382         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
383                 "WifiP2pService");
384     }
385 
enforceChangePermission()386     private void enforceChangePermission() {
387         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
388                 "WifiP2pService");
389     }
390 
enforceConnectivityInternalPermission()391     private void enforceConnectivityInternalPermission() {
392         mContext.enforceCallingOrSelfPermission(
393                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
394                 "WifiP2pService");
395     }
396 
checkConnectivityInternalPermission()397     private int checkConnectivityInternalPermission() {
398         return mContext.checkCallingOrSelfPermission(
399                 android.Manifest.permission.CONNECTIVITY_INTERNAL);
400     }
401 
checkLocationHardwarePermission()402     private int checkLocationHardwarePermission() {
403         return mContext.checkCallingOrSelfPermission(
404                 android.Manifest.permission.LOCATION_HARDWARE);
405     }
406 
enforceConnectivityInternalOrLocationHardwarePermission()407     private void enforceConnectivityInternalOrLocationHardwarePermission() {
408         if (checkConnectivityInternalPermission() != PackageManager.PERMISSION_GRANTED
409                 && checkLocationHardwarePermission() != PackageManager.PERMISSION_GRANTED) {
410             enforceConnectivityInternalPermission();
411         }
412     }
413 
stopIpManager()414     private void stopIpManager() {
415         if (mIpManager != null) {
416             mIpManager.stop();
417             mIpManager = null;
418         }
419         mDhcpResults = null;
420     }
421 
startIpManager(String ifname)422     private void startIpManager(String ifname) {
423         stopIpManager();
424 
425         mIpManager = new IpManager(mContext, ifname,
426                 new IpManager.Callback() {
427                     @Override
428                     public void onPreDhcpAction() {
429                         mP2pStateMachine.sendMessage(IPM_PRE_DHCP_ACTION);
430                     }
431                     @Override
432                     public void onPostDhcpAction() {
433                         mP2pStateMachine.sendMessage(IPM_POST_DHCP_ACTION);
434                     }
435                     @Override
436                     public void onNewDhcpResults(DhcpResults dhcpResults) {
437                         mP2pStateMachine.sendMessage(IPM_DHCP_RESULTS, dhcpResults);
438                     }
439                     @Override
440                     public void onProvisioningSuccess(LinkProperties newLp) {
441                         mP2pStateMachine.sendMessage(IPM_PROVISIONING_SUCCESS);
442                     }
443                     @Override
444                     public void onProvisioningFailure(LinkProperties newLp) {
445                         mP2pStateMachine.sendMessage(IPM_PROVISIONING_FAILURE);
446                     }
447                 },
448                 mNwService);
449 
450         final IpManager.ProvisioningConfiguration config =
451                 mIpManager.buildProvisioningConfiguration()
452                           .withoutIPv6()
453                           .withoutIpReachabilityMonitor()
454                           .withPreDhcpAction(30 * 1000)
455                           .withProvisioningTimeoutMs(36 * 1000)
456                           .build();
457         mIpManager.startProvisioning(config);
458     }
459 
460     /**
461      * Get a reference to handler. This is used by a client to establish
462      * an AsyncChannel communication with WifiP2pService
463      */
getMessenger()464     public Messenger getMessenger() {
465         enforceAccessPermission();
466         enforceChangePermission();
467         return new Messenger(mClientHandler);
468     }
469 
470     /**
471      * Get a reference to handler. This is used by a WifiStateMachine to establish
472      * an AsyncChannel communication with P2pStateMachine
473      * @hide
474      */
getP2pStateMachineMessenger()475     public Messenger getP2pStateMachineMessenger() {
476         enforceConnectivityInternalOrLocationHardwarePermission();
477         enforceAccessPermission();
478         enforceChangePermission();
479         return new Messenger(mP2pStateMachine.getHandler());
480     }
481 
482     /** This is used to provide information to drivers to optimize performance depending
483      * on the current mode of operation.
484      * 0 - disabled
485      * 1 - source operation
486      * 2 - sink operation
487      *
488      * As an example, the driver could reduce the channel dwell time during scanning
489      * when acting as a source or sink to minimize impact on miracast.
490      */
setMiracastMode(int mode)491     public void setMiracastMode(int mode) {
492         enforceConnectivityInternalPermission();
493         mP2pStateMachine.sendMessage(SET_MIRACAST_MODE, mode);
494     }
495 
496     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)497     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
498         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
499                 != PackageManager.PERMISSION_GRANTED) {
500             pw.println("Permission Denial: can't dump WifiP2pService from from pid="
501                     + Binder.getCallingPid()
502                     + ", uid=" + Binder.getCallingUid());
503             return;
504         }
505         mP2pStateMachine.dump(fd, pw, args);
506         pw.println("mAutonomousGroup " + mAutonomousGroup);
507         pw.println("mJoinExistingGroup " + mJoinExistingGroup);
508         pw.println("mDiscoveryStarted " + mDiscoveryStarted);
509         pw.println("mNetworkInfo " + mNetworkInfo);
510         pw.println("mTemporarilyDisconnectedWifi " + mTemporarilyDisconnectedWifi);
511         pw.println("mServiceDiscReqId " + mServiceDiscReqId);
512         pw.println();
513 
514         final IpManager ipManager = mIpManager;
515         if (ipManager != null) {
516             pw.println("mIpManager:");
517             ipManager.dump(fd, pw, args);
518         }
519     }
520 
521 
522     /**
523      * Handles interaction with WifiStateMachine
524      */
525     private class P2pStateMachine extends StateMachine {
526 
527         private DefaultState mDefaultState = new DefaultState();
528         private P2pNotSupportedState mP2pNotSupportedState = new P2pNotSupportedState();
529         private P2pDisablingState mP2pDisablingState = new P2pDisablingState();
530         private P2pDisabledState mP2pDisabledState = new P2pDisabledState();
531         private P2pEnablingState mP2pEnablingState = new P2pEnablingState();
532         private P2pEnabledState mP2pEnabledState = new P2pEnabledState();
533         // Inactive is when p2p is enabled with no connectivity
534         private InactiveState mInactiveState = new InactiveState();
535         private GroupCreatingState mGroupCreatingState = new GroupCreatingState();
536         private UserAuthorizingInviteRequestState mUserAuthorizingInviteRequestState
537                 = new UserAuthorizingInviteRequestState();
538         private UserAuthorizingNegotiationRequestState mUserAuthorizingNegotiationRequestState
539                 = new UserAuthorizingNegotiationRequestState();
540         private ProvisionDiscoveryState mProvisionDiscoveryState = new ProvisionDiscoveryState();
541         private GroupNegotiationState mGroupNegotiationState = new GroupNegotiationState();
542         private FrequencyConflictState mFrequencyConflictState = new FrequencyConflictState();
543 
544         private GroupCreatedState mGroupCreatedState = new GroupCreatedState();
545         private UserAuthorizingJoinState mUserAuthorizingJoinState = new UserAuthorizingJoinState();
546         private OngoingGroupRemovalState mOngoingGroupRemovalState = new OngoingGroupRemovalState();
547 
548         private WifiNative mWifiNative = WifiNative.getP2pNativeInterface();
549         private WifiMonitor mWifiMonitor = WifiMonitor.getInstance();
550         private final WifiP2pDeviceList mPeers = new WifiP2pDeviceList();
551         /* During a connection, supplicant can tell us that a device was lost. From a supplicant's
552          * perspective, the discovery stops during connection and it purges device since it does
553          * not get latest updates about the device without being in discovery state.
554          *
555          * From the framework perspective, the device is still there since we are connecting or
556          * connected to it. so we keep these devices in a separate list, so that they are removed
557          * when connection is cancelled or lost
558          */
559         private final WifiP2pDeviceList mPeersLostDuringConnection = new WifiP2pDeviceList();
560         private final WifiP2pGroupList mGroups = new WifiP2pGroupList(null,
561                 new GroupDeleteListener() {
562             @Override
563             public void onDeleteGroup(int netId) {
564                 if (DBG) logd("called onDeleteGroup() netId=" + netId);
565                 mWifiNative.removeNetwork(netId);
566                 mWifiNative.saveConfig();
567                 sendP2pPersistentGroupsChangedBroadcast();
568             }
569         });
570         private final WifiP2pInfo mWifiP2pInfo = new WifiP2pInfo();
571         private WifiP2pGroup mGroup;
572 
573         // Saved WifiP2pConfig for an ongoing peer connection. This will never be null.
574         // The deviceAddress will be an empty string when the device is inactive
575         // or if it is connected without any ongoing join request
576         private WifiP2pConfig mSavedPeerConfig = new WifiP2pConfig();
577 
P2pStateMachine(String name, Looper looper, boolean p2pSupported)578         P2pStateMachine(String name, Looper looper, boolean p2pSupported) {
579             super(name, looper);
580 
581             addState(mDefaultState);
582                 addState(mP2pNotSupportedState, mDefaultState);
583                 addState(mP2pDisablingState, mDefaultState);
584                 addState(mP2pDisabledState, mDefaultState);
585                 addState(mP2pEnablingState, mDefaultState);
586                 addState(mP2pEnabledState, mDefaultState);
587                     addState(mInactiveState, mP2pEnabledState);
588                     addState(mGroupCreatingState, mP2pEnabledState);
589                         addState(mUserAuthorizingInviteRequestState, mGroupCreatingState);
590                         addState(mUserAuthorizingNegotiationRequestState, mGroupCreatingState);
591                         addState(mProvisionDiscoveryState, mGroupCreatingState);
592                         addState(mGroupNegotiationState, mGroupCreatingState);
593                         addState(mFrequencyConflictState, mGroupCreatingState);
594                     addState(mGroupCreatedState, mP2pEnabledState);
595                         addState(mUserAuthorizingJoinState, mGroupCreatedState);
596                         addState(mOngoingGroupRemovalState, mGroupCreatedState);
597 
598             if (p2pSupported) {
599                 setInitialState(mP2pDisabledState);
600             } else {
601                 setInitialState(mP2pNotSupportedState);
602             }
603             setLogRecSize(50);
604             setLogOnlyTransitions(true);
605 
606             String interfaceName = mWifiNative.getInterfaceName();
607             mWifiMonitor.registerHandler(interfaceName,
608                     WifiMonitor.AP_STA_CONNECTED_EVENT, getHandler());
609             mWifiMonitor.registerHandler(interfaceName,
610                     WifiMonitor.AP_STA_DISCONNECTED_EVENT, getHandler());
611             mWifiMonitor.registerHandler(interfaceName,
612                     WifiMonitor.AUTHENTICATION_FAILURE_EVENT, getHandler());
613             mWifiMonitor.registerHandler(interfaceName,
614                     WifiMonitor.NETWORK_CONNECTION_EVENT, getHandler());
615             mWifiMonitor.registerHandler(interfaceName,
616                     WifiMonitor.NETWORK_DISCONNECTION_EVENT, getHandler());
617             mWifiMonitor.registerHandler(interfaceName,
618                     WifiMonitor.P2P_DEVICE_FOUND_EVENT, getHandler());
619             mWifiMonitor.registerHandler(interfaceName,
620                     WifiMonitor.P2P_DEVICE_LOST_EVENT, getHandler());
621             mWifiMonitor.registerHandler(interfaceName,
622                     WifiMonitor.P2P_FIND_STOPPED_EVENT, getHandler());
623             mWifiMonitor.registerHandler(interfaceName,
624                     WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT, getHandler());
625             mWifiMonitor.registerHandler(interfaceName,
626                     WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT, getHandler());
627             mWifiMonitor.registerHandler(interfaceName,
628                     WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT, getHandler());
629             mWifiMonitor.registerHandler(interfaceName,
630                     WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT, getHandler());
631             mWifiMonitor.registerHandler(interfaceName,
632                     WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT, getHandler());
633             mWifiMonitor.registerHandler(interfaceName,
634                     WifiMonitor.P2P_GROUP_REMOVED_EVENT, getHandler());
635             mWifiMonitor.registerHandler(interfaceName,
636                     WifiMonitor.P2P_GROUP_STARTED_EVENT, getHandler());
637             mWifiMonitor.registerHandler(interfaceName,
638                     WifiMonitor.P2P_INVITATION_RECEIVED_EVENT, getHandler());
639             mWifiMonitor.registerHandler(interfaceName,
640                     WifiMonitor.P2P_INVITATION_RESULT_EVENT, getHandler());
641             mWifiMonitor.registerHandler(interfaceName,
642                     WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT, getHandler());
643             mWifiMonitor.registerHandler(interfaceName,
644                     WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT, getHandler());
645             mWifiMonitor.registerHandler(interfaceName,
646                     WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT, getHandler());
647             mWifiMonitor.registerHandler(interfaceName,
648                     WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT, getHandler());
649             mWifiMonitor.registerHandler(interfaceName,
650                     WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT, getHandler());
651             mWifiMonitor.registerHandler(interfaceName,
652                     WifiMonitor.P2P_SERV_DISC_RESP_EVENT, getHandler());
653             mWifiMonitor.registerHandler(interfaceName,
654                     WifiMonitor.SCAN_RESULTS_EVENT, getHandler());
655             mWifiMonitor.registerHandler(interfaceName,
656                     WifiMonitor.SUP_CONNECTION_EVENT, getHandler());
657             mWifiMonitor.registerHandler(interfaceName,
658                     WifiMonitor.SUP_DISCONNECTION_EVENT, getHandler());
659             mWifiMonitor.registerHandler(interfaceName,
660                     WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, getHandler());
661             mWifiMonitor.registerHandler(interfaceName,
662                     WifiMonitor.WPS_FAIL_EVENT, getHandler());
663             mWifiMonitor.registerHandler(interfaceName,
664                     WifiMonitor.WPS_OVERLAP_EVENT, getHandler());
665             mWifiMonitor.registerHandler(interfaceName,
666                     WifiMonitor.WPS_SUCCESS_EVENT, getHandler());
667             mWifiMonitor.registerHandler(interfaceName,
668                     WifiMonitor.WPS_TIMEOUT_EVENT, getHandler());
669         }
670 
671     class DefaultState extends State {
672         @Override
processMessage(Message message)673         public boolean processMessage(Message message) {
674             if (DBG) logd(getName() + message.toString());
675             switch (message.what) {
676                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
677                     if (message.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
678                         if (DBG) logd("Full connection with WifiStateMachine established");
679                         mWifiChannel = (AsyncChannel) message.obj;
680                     } else {
681                         loge("Full connection failure, error = " + message.arg1);
682                         mWifiChannel = null;
683                     }
684                     break;
685 
686                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
687                     if (message.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
688                         loge("Send failed, client connection lost");
689                     } else {
690                         loge("Client connection lost with reason: " + message.arg1);
691                     }
692                     mWifiChannel = null;
693                     break;
694 
695                 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
696                     AsyncChannel ac = new AsyncChannel();
697                     ac.connect(mContext, getHandler(), message.replyTo);
698                     break;
699                 case BLOCK_DISCOVERY:
700                     mDiscoveryBlocked = (message.arg1 == ENABLED ? true : false);
701                     // always reset this - we went to a state that doesn't support discovery so
702                     // it would have stopped regardless
703                     mDiscoveryPostponed = false;
704                     if (mDiscoveryBlocked) {
705                         try {
706                             StateMachine m = (StateMachine)message.obj;
707                             m.sendMessage(message.arg2);
708                         } catch (Exception e) {
709                             loge("unable to send BLOCK_DISCOVERY response: " + e);
710                         }
711                     }
712                     break;
713                 case WifiP2pManager.DISCOVER_PEERS:
714                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
715                             WifiP2pManager.BUSY);
716                     break;
717                 case WifiP2pManager.STOP_DISCOVERY:
718                     replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
719                             WifiP2pManager.BUSY);
720                     break;
721                 case WifiP2pManager.DISCOVER_SERVICES:
722                     replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
723                             WifiP2pManager.BUSY);
724                     break;
725                 case WifiP2pManager.CONNECT:
726                     replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
727                             WifiP2pManager.BUSY);
728                     break;
729                 case WifiP2pManager.CANCEL_CONNECT:
730                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
731                             WifiP2pManager.BUSY);
732                     break;
733                 case WifiP2pManager.CREATE_GROUP:
734                     replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
735                             WifiP2pManager.BUSY);
736                     break;
737                 case WifiP2pManager.REMOVE_GROUP:
738                     replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
739                             WifiP2pManager.BUSY);
740                     break;
741                 case WifiP2pManager.ADD_LOCAL_SERVICE:
742                     replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
743                             WifiP2pManager.BUSY);
744                     break;
745                 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
746                     replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
747                             WifiP2pManager.BUSY);
748                     break;
749                 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
750                     replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED,
751                             WifiP2pManager.BUSY);
752                     break;
753                 case WifiP2pManager.ADD_SERVICE_REQUEST:
754                     replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED,
755                             WifiP2pManager.BUSY);
756                     break;
757                 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
758                     replyToMessage(message,
759                             WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED,
760                             WifiP2pManager.BUSY);
761                     break;
762                 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
763                     replyToMessage(message,
764                             WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED,
765                             WifiP2pManager.BUSY);
766                     break;
767                 case WifiP2pManager.SET_DEVICE_NAME:
768                     replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
769                             WifiP2pManager.BUSY);
770                     break;
771                 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
772                     replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
773                             WifiP2pManager.BUSY);
774                     break;
775                 case WifiP2pManager.SET_WFD_INFO:
776                     replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
777                             WifiP2pManager.BUSY);
778                     break;
779                 case WifiP2pManager.REQUEST_PEERS:
780                     replyToMessage(message, WifiP2pManager.RESPONSE_PEERS,
781                             new WifiP2pDeviceList(mPeers));
782                     break;
783                 case WifiP2pManager.REQUEST_CONNECTION_INFO:
784                     replyToMessage(message, WifiP2pManager.RESPONSE_CONNECTION_INFO,
785                             new WifiP2pInfo(mWifiP2pInfo));
786                     break;
787                 case WifiP2pManager.REQUEST_GROUP_INFO:
788                     replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO,
789                             mGroup != null ? new WifiP2pGroup(mGroup) : null);
790                     break;
791                 case WifiP2pManager.REQUEST_PERSISTENT_GROUP_INFO:
792                     replyToMessage(message, WifiP2pManager.RESPONSE_PERSISTENT_GROUP_INFO,
793                             new WifiP2pGroupList(mGroups, null));
794                     break;
795                 case WifiP2pManager.START_WPS:
796                     replyToMessage(message, WifiP2pManager.START_WPS_FAILED,
797                         WifiP2pManager.BUSY);
798                     break;
799                 case WifiP2pManager.GET_HANDOVER_REQUEST:
800                 case WifiP2pManager.GET_HANDOVER_SELECT:
801                     replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE, null);
802                     break;
803                 case WifiP2pManager.INITIATOR_REPORT_NFC_HANDOVER:
804                 case WifiP2pManager.RESPONDER_REPORT_NFC_HANDOVER:
805                     replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED,
806                             WifiP2pManager.BUSY);
807                     break;
808                     // Ignore
809                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
810                 case WifiMonitor.SCAN_RESULTS_EVENT:
811                 case WifiMonitor.SUP_CONNECTION_EVENT:
812                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
813                 case WifiMonitor.NETWORK_CONNECTION_EVENT:
814                 case WifiMonitor.NETWORK_DISCONNECTION_EVENT:
815                 case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT:
816                 case WifiMonitor.AUTHENTICATION_FAILURE_EVENT:
817                 case WifiMonitor.WPS_SUCCESS_EVENT:
818                 case WifiMonitor.WPS_FAIL_EVENT:
819                 case WifiMonitor.WPS_OVERLAP_EVENT:
820                 case WifiMonitor.WPS_TIMEOUT_EVENT:
821                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
822                 case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
823                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
824                 case WifiMonitor.P2P_FIND_STOPPED_EVENT:
825                 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
826                 case PEER_CONNECTION_USER_ACCEPT:
827                 case PEER_CONNECTION_USER_REJECT:
828                 case DISCONNECT_WIFI_RESPONSE:
829                 case DROP_WIFI_USER_ACCEPT:
830                 case DROP_WIFI_USER_REJECT:
831                 case GROUP_CREATING_TIMED_OUT:
832                 case DISABLE_P2P_TIMED_OUT:
833                 case IPM_PRE_DHCP_ACTION:
834                 case IPM_POST_DHCP_ACTION:
835                 case IPM_DHCP_RESULTS:
836                 case IPM_PROVISIONING_SUCCESS:
837                 case IPM_PROVISIONING_FAILURE:
838                 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
839                 case SET_MIRACAST_MODE:
840                 case WifiP2pManager.START_LISTEN:
841                 case WifiP2pManager.STOP_LISTEN:
842                 case WifiP2pManager.SET_CHANNEL:
843                 case WifiStateMachine.CMD_ENABLE_P2P:
844                     // Enable is lazy and has no response
845                     break;
846                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
847                     // If we end up handling in default, p2p is not enabled
848                     mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
849                     break;
850                     /* unexpected group created, remove */
851                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
852                     mGroup = (WifiP2pGroup) message.obj;
853                     loge("Unexpected group creation, remove " + mGroup);
854                     mWifiNative.p2pGroupRemove(mGroup.getInterface());
855                     break;
856                 // A group formation failure is always followed by
857                 // a group removed event. Flushing things at group formation
858                 // failure causes supplicant issues. Ignore right now.
859                 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
860                     break;
861                 default:
862                     loge("Unhandled message " + message);
863                     return NOT_HANDLED;
864             }
865             return HANDLED;
866         }
867     }
868 
869     class P2pNotSupportedState extends State {
870         @Override
processMessage(Message message)871         public boolean processMessage(Message message) {
872             switch (message.what) {
873                case WifiP2pManager.DISCOVER_PEERS:
874                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
875                             WifiP2pManager.P2P_UNSUPPORTED);
876                     break;
877                 case WifiP2pManager.STOP_DISCOVERY:
878                     replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
879                             WifiP2pManager.P2P_UNSUPPORTED);
880                     break;
881                 case WifiP2pManager.DISCOVER_SERVICES:
882                     replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
883                             WifiP2pManager.P2P_UNSUPPORTED);
884                     break;
885                 case WifiP2pManager.CONNECT:
886                     replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
887                             WifiP2pManager.P2P_UNSUPPORTED);
888                     break;
889                 case WifiP2pManager.CANCEL_CONNECT:
890                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED,
891                             WifiP2pManager.P2P_UNSUPPORTED);
892                     break;
893                case WifiP2pManager.CREATE_GROUP:
894                     replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
895                             WifiP2pManager.P2P_UNSUPPORTED);
896                     break;
897                 case WifiP2pManager.REMOVE_GROUP:
898                     replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
899                             WifiP2pManager.P2P_UNSUPPORTED);
900                     break;
901                 case WifiP2pManager.ADD_LOCAL_SERVICE:
902                     replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED,
903                             WifiP2pManager.P2P_UNSUPPORTED);
904                     break;
905                 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
906                     replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_FAILED,
907                             WifiP2pManager.P2P_UNSUPPORTED);
908                     break;
909                 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
910                     replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_FAILED,
911                             WifiP2pManager.P2P_UNSUPPORTED);
912                     break;
913                 case WifiP2pManager.ADD_SERVICE_REQUEST:
914                     replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED,
915                             WifiP2pManager.P2P_UNSUPPORTED);
916                     break;
917                 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
918                     replyToMessage(message,
919                             WifiP2pManager.REMOVE_SERVICE_REQUEST_FAILED,
920                             WifiP2pManager.P2P_UNSUPPORTED);
921                     break;
922                 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
923                     replyToMessage(message,
924                             WifiP2pManager.CLEAR_SERVICE_REQUESTS_FAILED,
925                             WifiP2pManager.P2P_UNSUPPORTED);
926                     break;
927                 case WifiP2pManager.SET_DEVICE_NAME:
928                     replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
929                             WifiP2pManager.P2P_UNSUPPORTED);
930                     break;
931                 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
932                     replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP,
933                             WifiP2pManager.P2P_UNSUPPORTED);
934                     break;
935                 case WifiP2pManager.SET_WFD_INFO:
936                     replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
937                             WifiP2pManager.P2P_UNSUPPORTED);
938                     break;
939                 case WifiP2pManager.START_WPS:
940                     replyToMessage(message, WifiP2pManager.START_WPS_FAILED,
941                             WifiP2pManager.P2P_UNSUPPORTED);
942                     break;
943                 case WifiP2pManager.START_LISTEN:
944                     replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED,
945                             WifiP2pManager.P2P_UNSUPPORTED);
946                     break;
947                 case WifiP2pManager.STOP_LISTEN:
948                     replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED,
949                             WifiP2pManager.P2P_UNSUPPORTED);
950                     break;
951 
952                 default:
953                     return NOT_HANDLED;
954             }
955             return HANDLED;
956         }
957     }
958 
959     class P2pDisablingState extends State {
960         @Override
enter()961         public void enter() {
962             if (DBG) logd(getName());
963             sendMessageDelayed(obtainMessage(DISABLE_P2P_TIMED_OUT,
964                     ++mDisableP2pTimeoutIndex, 0), DISABLE_P2P_WAIT_TIME_MS);
965         }
966 
967         @Override
processMessage(Message message)968         public boolean processMessage(Message message) {
969             if (DBG) logd(getName() + message.toString());
970             switch (message.what) {
971                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
972                     if (DBG) logd("p2p socket connection lost");
973                     transitionTo(mP2pDisabledState);
974                     break;
975                 case WifiStateMachine.CMD_ENABLE_P2P:
976                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
977                     deferMessage(message);
978                     break;
979                 case DISABLE_P2P_TIMED_OUT:
980                     if (mDisableP2pTimeoutIndex == message.arg1) {
981                         loge("P2p disable timed out");
982                         transitionTo(mP2pDisabledState);
983                     }
984                     break;
985                 default:
986                     return NOT_HANDLED;
987             }
988             return HANDLED;
989         }
990 
991         @Override
exit()992         public void exit() {
993             mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
994         }
995     }
996 
997     class P2pDisabledState extends State {
998        @Override
enter()999         public void enter() {
1000             if (DBG) logd(getName());
1001         }
1002 
1003         @Override
processMessage(Message message)1004         public boolean processMessage(Message message) {
1005             if (DBG) logd(getName() + message.toString());
1006             switch (message.what) {
1007                 case WifiStateMachine.CMD_ENABLE_P2P:
1008                     try {
1009                         mNwService.setInterfaceUp(mWifiNative.getInterfaceName());
1010                     } catch (RemoteException re) {
1011                         loge("Unable to change interface settings: " + re);
1012                     } catch (IllegalStateException ie) {
1013                         loge("Unable to change interface settings: " + ie);
1014                     }
1015                     mWifiMonitor.startMonitoring(mWifiNative.getInterfaceName());
1016                     transitionTo(mP2pEnablingState);
1017                     break;
1018                 default:
1019                     return NOT_HANDLED;
1020             }
1021             return HANDLED;
1022         }
1023     }
1024 
1025     class P2pEnablingState extends State {
1026         @Override
enter()1027         public void enter() {
1028             if (DBG) logd(getName());
1029         }
1030 
1031         @Override
processMessage(Message message)1032         public boolean processMessage(Message message) {
1033             if (DBG) logd(getName() + message.toString());
1034             switch (message.what) {
1035                 case WifiMonitor.SUP_CONNECTION_EVENT:
1036                     if (DBG) logd("P2p socket connection successful");
1037                     transitionTo(mInactiveState);
1038                     break;
1039                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
1040                     loge("P2p socket connection failed");
1041                     transitionTo(mP2pDisabledState);
1042                     break;
1043                 case WifiStateMachine.CMD_ENABLE_P2P:
1044                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
1045                     deferMessage(message);
1046                     break;
1047                 default:
1048                     return NOT_HANDLED;
1049             }
1050             return HANDLED;
1051         }
1052     }
1053 
1054     class P2pEnabledState extends State {
1055         @Override
enter()1056         public void enter() {
1057             if (DBG) logd(getName());
1058             sendP2pStateChangedBroadcast(true);
1059             mNetworkInfo.setIsAvailable(true);
1060             sendP2pConnectionChangedBroadcast();
1061             initializeP2pSettings();
1062         }
1063 
1064         @Override
processMessage(Message message)1065         public boolean processMessage(Message message) {
1066             if (DBG) logd(getName() + message.toString());
1067             switch (message.what) {
1068                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
1069                     loge("Unexpected loss of p2p socket connection");
1070                     transitionTo(mP2pDisabledState);
1071                     break;
1072                 case WifiStateMachine.CMD_ENABLE_P2P:
1073                     //Nothing to do
1074                     break;
1075                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
1076                     if (mPeers.clear()) {
1077                         sendPeersChangedBroadcast();
1078                     }
1079                     if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
1080 
1081                     mWifiMonitor.stopMonitoring(mWifiNative.getInterfaceName());
1082                     transitionTo(mP2pDisablingState);
1083                     break;
1084                 case WifiP2pManager.SET_DEVICE_NAME:
1085                 {
1086                     WifiP2pDevice d = (WifiP2pDevice) message.obj;
1087                     if (d != null && setAndPersistDeviceName(d.deviceName)) {
1088                         if (DBG) logd("set device name " + d.deviceName);
1089                         replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_SUCCEEDED);
1090                     } else {
1091                         replyToMessage(message, WifiP2pManager.SET_DEVICE_NAME_FAILED,
1092                                 WifiP2pManager.ERROR);
1093                     }
1094                     break;
1095                 }
1096                 case WifiP2pManager.SET_WFD_INFO:
1097                 {
1098                     WifiP2pWfdInfo d = (WifiP2pWfdInfo) message.obj;
1099                     if (d != null && setWfdInfo(d)) {
1100                         replyToMessage(message, WifiP2pManager.SET_WFD_INFO_SUCCEEDED);
1101                     } else {
1102                         replyToMessage(message, WifiP2pManager.SET_WFD_INFO_FAILED,
1103                                 WifiP2pManager.ERROR);
1104                     }
1105                     break;
1106                 }
1107                 case BLOCK_DISCOVERY:
1108                     boolean blocked = (message.arg1 == ENABLED ? true : false);
1109                     if (mDiscoveryBlocked == blocked) break;
1110                     mDiscoveryBlocked = blocked;
1111                     if (blocked && mDiscoveryStarted) {
1112                         mWifiNative.p2pStopFind();
1113                         mDiscoveryPostponed = true;
1114                     }
1115                     if (!blocked && mDiscoveryPostponed) {
1116                         mDiscoveryPostponed = false;
1117                         mWifiNative.p2pFind(DISCOVER_TIMEOUT_S);
1118                     }
1119                     if (blocked) {
1120                         try {
1121                             StateMachine m = (StateMachine)message.obj;
1122                             m.sendMessage(message.arg2);
1123                         } catch (Exception e) {
1124                             loge("unable to send BLOCK_DISCOVERY response: " + e);
1125                         }
1126                     }
1127                     break;
1128                 case WifiP2pManager.DISCOVER_PEERS:
1129                     if (mDiscoveryBlocked) {
1130                         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
1131                                 WifiP2pManager.BUSY);
1132                         break;
1133                     }
1134                     // do not send service discovery request while normal find operation.
1135                     clearSupplicantServiceRequest();
1136                     if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
1137                         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED);
1138                         sendP2pDiscoveryChangedBroadcast(true);
1139                     } else {
1140                         replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
1141                                 WifiP2pManager.ERROR);
1142                     }
1143                     break;
1144                 case WifiMonitor.P2P_FIND_STOPPED_EVENT:
1145                     sendP2pDiscoveryChangedBroadcast(false);
1146                     break;
1147                 case WifiP2pManager.STOP_DISCOVERY:
1148                     if (mWifiNative.p2pStopFind()) {
1149                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
1150                     } else {
1151                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
1152                                 WifiP2pManager.ERROR);
1153                     }
1154                     break;
1155                 case WifiP2pManager.DISCOVER_SERVICES:
1156                     if (mDiscoveryBlocked) {
1157                         replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
1158                                 WifiP2pManager.BUSY);
1159                         break;
1160                     }
1161                     if (DBG) logd(getName() + " discover services");
1162                     if (!updateSupplicantServiceRequest()) {
1163                         replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
1164                                 WifiP2pManager.NO_SERVICE_REQUESTS);
1165                         break;
1166                     }
1167                     if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) {
1168                         replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_SUCCEEDED);
1169                     } else {
1170                         replyToMessage(message, WifiP2pManager.DISCOVER_SERVICES_FAILED,
1171                                 WifiP2pManager.ERROR);
1172                     }
1173                     break;
1174                 case WifiMonitor.P2P_DEVICE_FOUND_EVENT:
1175                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
1176                     if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break;
1177                     mPeers.updateSupplicantDetails(device);
1178                     sendPeersChangedBroadcast();
1179                     break;
1180                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
1181                     device = (WifiP2pDevice) message.obj;
1182                     // Gets current details for the one removed
1183                     device = mPeers.remove(device.deviceAddress);
1184                     if (device != null) {
1185                         sendPeersChangedBroadcast();
1186                     }
1187                     break;
1188                 case WifiP2pManager.ADD_LOCAL_SERVICE:
1189                     if (DBG) logd(getName() + " add service");
1190                     WifiP2pServiceInfo servInfo = (WifiP2pServiceInfo)message.obj;
1191                     if (addLocalService(message.replyTo, servInfo)) {
1192                         replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_SUCCEEDED);
1193                     } else {
1194                         replyToMessage(message, WifiP2pManager.ADD_LOCAL_SERVICE_FAILED);
1195                     }
1196                     break;
1197                 case WifiP2pManager.REMOVE_LOCAL_SERVICE:
1198                     if (DBG) logd(getName() + " remove service");
1199                     servInfo = (WifiP2pServiceInfo)message.obj;
1200                     removeLocalService(message.replyTo, servInfo);
1201                     replyToMessage(message, WifiP2pManager.REMOVE_LOCAL_SERVICE_SUCCEEDED);
1202                     break;
1203                 case WifiP2pManager.CLEAR_LOCAL_SERVICES:
1204                     if (DBG) logd(getName() + " clear service");
1205                     clearLocalServices(message.replyTo);
1206                     replyToMessage(message, WifiP2pManager.CLEAR_LOCAL_SERVICES_SUCCEEDED);
1207                     break;
1208                 case WifiP2pManager.ADD_SERVICE_REQUEST:
1209                     if (DBG) logd(getName() + " add service request");
1210                     if (!addServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj)) {
1211                         replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_FAILED);
1212                         break;
1213                     }
1214                     replyToMessage(message, WifiP2pManager.ADD_SERVICE_REQUEST_SUCCEEDED);
1215                     break;
1216                 case WifiP2pManager.REMOVE_SERVICE_REQUEST:
1217                     if (DBG) logd(getName() + " remove service request");
1218                     removeServiceRequest(message.replyTo, (WifiP2pServiceRequest)message.obj);
1219                     replyToMessage(message, WifiP2pManager.REMOVE_SERVICE_REQUEST_SUCCEEDED);
1220                     break;
1221                 case WifiP2pManager.CLEAR_SERVICE_REQUESTS:
1222                     if (DBG) logd(getName() + " clear service request");
1223                     clearServiceRequests(message.replyTo);
1224                     replyToMessage(message, WifiP2pManager.CLEAR_SERVICE_REQUESTS_SUCCEEDED);
1225                     break;
1226                 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
1227                     if (DBG) logd(getName() + " receive service response");
1228                     List<WifiP2pServiceResponse> sdRespList =
1229                         (List<WifiP2pServiceResponse>) message.obj;
1230                     for (WifiP2pServiceResponse resp : sdRespList) {
1231                         WifiP2pDevice dev =
1232                             mPeers.get(resp.getSrcDevice().deviceAddress);
1233                         resp.setSrcDevice(dev);
1234                         sendServiceResponse(resp);
1235                     }
1236                     break;
1237                 case WifiP2pManager.DELETE_PERSISTENT_GROUP:
1238                    if (DBG) logd(getName() + " delete persistent group");
1239                    mGroups.remove(message.arg1);
1240                    replyToMessage(message, WifiP2pManager.DELETE_PERSISTENT_GROUP_SUCCEEDED);
1241                    break;
1242                 case SET_MIRACAST_MODE:
1243                     mWifiNative.setMiracastMode(message.arg1);
1244                     break;
1245                 case WifiP2pManager.START_LISTEN:
1246                     if (DBG) logd(getName() + " start listen mode");
1247                     mWifiNative.p2pFlush();
1248                     if (mWifiNative.p2pExtListen(true, 500, 500)) {
1249                         replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
1250                     } else {
1251                         replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
1252                     }
1253                     break;
1254                 case WifiP2pManager.STOP_LISTEN:
1255                     if (DBG) logd(getName() + " stop listen mode");
1256                     if (mWifiNative.p2pExtListen(false, 0, 0)) {
1257                         replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
1258                     } else {
1259                         replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
1260                     }
1261                     mWifiNative.p2pFlush();
1262                     break;
1263                 case WifiP2pManager.SET_CHANNEL:
1264                     Bundle p2pChannels = (Bundle) message.obj;
1265                     int lc = p2pChannels.getInt("lc", 0);
1266                     int oc = p2pChannels.getInt("oc", 0);
1267                     if (DBG) logd(getName() + " set listen and operating channel");
1268                     if (mWifiNative.p2pSetChannel(lc, oc)) {
1269                         replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
1270                     } else {
1271                         replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
1272                     }
1273                     break;
1274                 case WifiP2pManager.GET_HANDOVER_REQUEST:
1275                     Bundle requestBundle = new Bundle();
1276                     requestBundle.putString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE,
1277                             mWifiNative.getNfcHandoverRequest());
1278                     replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE,
1279                             requestBundle);
1280                     break;
1281                 case WifiP2pManager.GET_HANDOVER_SELECT:
1282                     Bundle selectBundle = new Bundle();
1283                     selectBundle.putString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE,
1284                             mWifiNative.getNfcHandoverSelect());
1285                     replyToMessage(message, WifiP2pManager.RESPONSE_GET_HANDOVER_MESSAGE,
1286                             selectBundle);
1287                     break;
1288                 default:
1289                    return NOT_HANDLED;
1290             }
1291             return HANDLED;
1292         }
1293 
1294         @Override
exit()1295         public void exit() {
1296             sendP2pDiscoveryChangedBroadcast(false);
1297             sendP2pStateChangedBroadcast(false);
1298             mNetworkInfo.setIsAvailable(false);
1299         }
1300     }
1301 
1302     class InactiveState extends State {
1303         @Override
enter()1304         public void enter() {
1305             if (DBG) logd(getName());
1306             mSavedPeerConfig.invalidate();
1307         }
1308 
1309         @Override
processMessage(Message message)1310         public boolean processMessage(Message message) {
1311             if (DBG) logd(getName() + message.toString());
1312             switch (message.what) {
1313                 case WifiP2pManager.CONNECT:
1314                     if (DBG) logd(getName() + " sending connect");
1315                     WifiP2pConfig config = (WifiP2pConfig) message.obj;
1316                     if (isConfigInvalid(config)) {
1317                         loge("Dropping connect requeset " + config);
1318                         replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
1319                         break;
1320                     }
1321 
1322                     mAutonomousGroup = false;
1323                     mWifiNative.p2pStopFind();
1324                     if (reinvokePersistentGroup(config)) {
1325                         transitionTo(mGroupNegotiationState);
1326                     } else {
1327                         transitionTo(mProvisionDiscoveryState);
1328                     }
1329                     mSavedPeerConfig = config;
1330                     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
1331                     sendPeersChangedBroadcast();
1332                     replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
1333                     break;
1334                 case WifiP2pManager.STOP_DISCOVERY:
1335                     if (mWifiNative.p2pStopFind()) {
1336                         // When discovery stops in inactive state, flush to clear
1337                         // state peer data
1338                         mWifiNative.p2pFlush();
1339                         mServiceDiscReqId = null;
1340                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED);
1341                     } else {
1342                         replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED,
1343                                 WifiP2pManager.ERROR);
1344                     }
1345                     break;
1346                 case WifiMonitor.P2P_GO_NEGOTIATION_REQUEST_EVENT:
1347                     config = (WifiP2pConfig) message.obj;
1348                     if (isConfigInvalid(config)) {
1349                         loge("Dropping GO neg request " + config);
1350                         break;
1351                     }
1352                     mSavedPeerConfig = config;
1353                     mAutonomousGroup = false;
1354                     mJoinExistingGroup = false;
1355                     transitionTo(mUserAuthorizingNegotiationRequestState);
1356                     break;
1357                 case WifiMonitor.P2P_INVITATION_RECEIVED_EVENT:
1358                     WifiP2pGroup group = (WifiP2pGroup) message.obj;
1359                     WifiP2pDevice owner = group.getOwner();
1360 
1361                     if (owner == null) {
1362                         loge("Ignored invitation from null owner");
1363                         break;
1364                     }
1365 
1366                     config = new WifiP2pConfig();
1367                     config.deviceAddress = group.getOwner().deviceAddress;
1368 
1369                     if (isConfigInvalid(config)) {
1370                         loge("Dropping invitation request " + config);
1371                         break;
1372                     }
1373                     mSavedPeerConfig = config;
1374 
1375                     //Check if we have the owner in peer list and use appropriate
1376                     //wps method. Default is to use PBC.
1377                     if ((owner = mPeers.get(owner.deviceAddress)) != null) {
1378                         if (owner.wpsPbcSupported()) {
1379                             mSavedPeerConfig.wps.setup = WpsInfo.PBC;
1380                         } else if (owner.wpsKeypadSupported()) {
1381                             mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
1382                         } else if (owner.wpsDisplaySupported()) {
1383                             mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
1384                         }
1385                     }
1386 
1387                     mAutonomousGroup = false;
1388                     mJoinExistingGroup = true;
1389                     transitionTo(mUserAuthorizingInviteRequestState);
1390                     break;
1391                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
1392                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
1393                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
1394                     //We let the supplicant handle the provision discovery response
1395                     //and wait instead for the GO_NEGOTIATION_REQUEST_EVENT.
1396                     //Handling provision discovery and issuing a p2p_connect before
1397                     //group negotiation comes through causes issues
1398                     break;
1399                 case WifiP2pManager.CREATE_GROUP:
1400                     mAutonomousGroup = true;
1401                     int netId = message.arg1;
1402                     boolean ret = false;
1403                     if (netId == WifiP2pGroup.PERSISTENT_NET_ID) {
1404                         // check if the go persistent group is present.
1405                         netId = mGroups.getNetworkId(mThisDevice.deviceAddress);
1406                         if (netId != -1) {
1407                             ret = mWifiNative.p2pGroupAdd(netId);
1408                         } else {
1409                             ret = mWifiNative.p2pGroupAdd(true);
1410                         }
1411                     } else {
1412                         ret = mWifiNative.p2pGroupAdd(false);
1413                     }
1414 
1415                     if (ret) {
1416                         replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED);
1417                         transitionTo(mGroupNegotiationState);
1418                     } else {
1419                         replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
1420                                 WifiP2pManager.ERROR);
1421                         // remain at this state.
1422                     }
1423                     break;
1424                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1425                     mGroup = (WifiP2pGroup) message.obj;
1426                     if (DBG) logd(getName() + " group started");
1427 
1428                     // We hit this scenario when a persistent group is reinvoked
1429                     if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
1430                         mAutonomousGroup = false;
1431                         deferMessage(message);
1432                         transitionTo(mGroupNegotiationState);
1433                     } else {
1434                         loge("Unexpected group creation, remove " + mGroup);
1435                         mWifiNative.p2pGroupRemove(mGroup.getInterface());
1436                     }
1437                     break;
1438                 case WifiP2pManager.START_LISTEN:
1439                     if (DBG) logd(getName() + " start listen mode");
1440                     mWifiNative.p2pFlush();
1441                     if (mWifiNative.p2pExtListen(true, 500, 500)) {
1442                         replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
1443                     } else {
1444                         replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
1445                     }
1446                     break;
1447                 case WifiP2pManager.STOP_LISTEN:
1448                     if (DBG) logd(getName() + " stop listen mode");
1449                     if (mWifiNative.p2pExtListen(false, 0, 0)) {
1450                         replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
1451                     } else {
1452                         replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
1453                     }
1454                     mWifiNative.p2pFlush();
1455                     break;
1456                 case WifiP2pManager.SET_CHANNEL:
1457                     Bundle p2pChannels = (Bundle) message.obj;
1458                     int lc = p2pChannels.getInt("lc", 0);
1459                     int oc = p2pChannels.getInt("oc", 0);
1460                     if (DBG) logd(getName() + " set listen and operating channel");
1461                     if (mWifiNative.p2pSetChannel(lc, oc)) {
1462                         replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
1463                     } else {
1464                         replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
1465                     }
1466                     break;
1467                 case WifiP2pManager.INITIATOR_REPORT_NFC_HANDOVER:
1468                     String handoverSelect = null;
1469 
1470                     if (message.obj != null) {
1471                         handoverSelect = ((Bundle) message.obj)
1472                                 .getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE);
1473                     }
1474 
1475                     if (handoverSelect != null
1476                             && mWifiNative.initiatorReportNfcHandover(handoverSelect)) {
1477                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED);
1478                         transitionTo(mGroupCreatingState);
1479                     } else {
1480                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED);
1481                     }
1482                     break;
1483                 case WifiP2pManager.RESPONDER_REPORT_NFC_HANDOVER:
1484                     String handoverRequest = null;
1485 
1486                     if (message.obj != null) {
1487                         handoverRequest = ((Bundle) message.obj)
1488                                 .getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE);
1489                     }
1490 
1491                     if (handoverRequest != null
1492                             && mWifiNative.responderReportNfcHandover(handoverRequest)) {
1493                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED);
1494                         transitionTo(mGroupCreatingState);
1495                     } else {
1496                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED);
1497                     }
1498                     break;
1499                 default:
1500                     return NOT_HANDLED;
1501             }
1502             return HANDLED;
1503         }
1504     }
1505 
1506     class GroupCreatingState extends State {
1507         @Override
enter()1508         public void enter() {
1509             if (DBG) logd(getName());
1510             sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT,
1511                     ++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS);
1512         }
1513 
1514         @Override
processMessage(Message message)1515         public boolean processMessage(Message message) {
1516             if (DBG) logd(getName() + message.toString());
1517             boolean ret = HANDLED;
1518             switch (message.what) {
1519                case GROUP_CREATING_TIMED_OUT:
1520                     if (mGroupCreatingTimeoutIndex == message.arg1) {
1521                         if (DBG) logd("Group negotiation timed out");
1522                         handleGroupCreationFailure();
1523                         transitionTo(mInactiveState);
1524                     }
1525                     break;
1526                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
1527                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
1528                     if (!mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) {
1529                         if (DBG) {
1530                             logd("mSavedPeerConfig " + mSavedPeerConfig.deviceAddress +
1531                                 "device " + device.deviceAddress);
1532                         }
1533                         // Do the regular device lost handling
1534                         ret = NOT_HANDLED;
1535                         break;
1536                     }
1537                     // Do nothing
1538                     if (DBG) logd("Add device to lost list " + device);
1539                     mPeersLostDuringConnection.updateSupplicantDetails(device);
1540                     break;
1541                 case WifiP2pManager.DISCOVER_PEERS:
1542                     /* Discovery will break negotiation */
1543                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
1544                             WifiP2pManager.BUSY);
1545                     break;
1546                 case WifiP2pManager.CANCEL_CONNECT:
1547                     //Do a supplicant p2p_cancel which only cancels an ongoing
1548                     //group negotiation. This will fail for a pending provision
1549                     //discovery or for a pending user action, but at the framework
1550                     //level, we always treat cancel as succeeded and enter
1551                     //an inactive state
1552                     mWifiNative.p2pCancelConnect();
1553                     handleGroupCreationFailure();
1554                     transitionTo(mInactiveState);
1555                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED);
1556                     break;
1557                 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
1558                     // We hit this scenario when NFC handover is invoked.
1559                     mAutonomousGroup = false;
1560                     transitionTo(mGroupNegotiationState);
1561                     break;
1562                 default:
1563                     ret = NOT_HANDLED;
1564             }
1565             return ret;
1566         }
1567     }
1568 
1569     class UserAuthorizingNegotiationRequestState extends State {
1570         @Override
enter()1571         public void enter() {
1572             if (DBG) logd(getName());
1573             notifyInvitationReceived();
1574         }
1575 
1576         @Override
processMessage(Message message)1577         public boolean processMessage(Message message) {
1578             if (DBG) logd(getName() + message.toString());
1579             boolean ret = HANDLED;
1580             switch (message.what) {
1581                 case PEER_CONNECTION_USER_ACCEPT:
1582                     mWifiNative.p2pStopFind();
1583                     p2pConnectWithPinDisplay(mSavedPeerConfig);
1584                     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
1585                     sendPeersChangedBroadcast();
1586                     transitionTo(mGroupNegotiationState);
1587                    break;
1588                 case PEER_CONNECTION_USER_REJECT:
1589                     if (DBG) logd("User rejected negotiation " + mSavedPeerConfig);
1590                     transitionTo(mInactiveState);
1591                     break;
1592                 default:
1593                     return NOT_HANDLED;
1594             }
1595             return ret;
1596         }
1597 
1598         @Override
exit()1599         public void exit() {
1600             //TODO: dismiss dialog if not already done
1601         }
1602     }
1603 
1604     class UserAuthorizingInviteRequestState extends State {
1605         @Override
enter()1606         public void enter() {
1607             if (DBG) logd(getName());
1608             notifyInvitationReceived();
1609         }
1610 
1611         @Override
processMessage(Message message)1612         public boolean processMessage(Message message) {
1613             if (DBG) logd(getName() + message.toString());
1614             boolean ret = HANDLED;
1615             switch (message.what) {
1616                 case PEER_CONNECTION_USER_ACCEPT:
1617                     mWifiNative.p2pStopFind();
1618                     if (!reinvokePersistentGroup(mSavedPeerConfig)) {
1619                         // Do negotiation when persistence fails
1620                         p2pConnectWithPinDisplay(mSavedPeerConfig);
1621                     }
1622                     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
1623                     sendPeersChangedBroadcast();
1624                     transitionTo(mGroupNegotiationState);
1625                    break;
1626                 case PEER_CONNECTION_USER_REJECT:
1627                     if (DBG) logd("User rejected invitation " + mSavedPeerConfig);
1628                     transitionTo(mInactiveState);
1629                     break;
1630                 default:
1631                     return NOT_HANDLED;
1632             }
1633             return ret;
1634         }
1635 
1636         @Override
exit()1637         public void exit() {
1638             //TODO: dismiss dialog if not already done
1639         }
1640     }
1641 
1642 
1643 
1644     class ProvisionDiscoveryState extends State {
1645         @Override
enter()1646         public void enter() {
1647             if (DBG) logd(getName());
1648             mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig);
1649         }
1650 
1651         @Override
processMessage(Message message)1652         public boolean processMessage(Message message) {
1653             if (DBG) logd(getName() + message.toString());
1654             WifiP2pProvDiscEvent provDisc;
1655             WifiP2pDevice device;
1656             switch (message.what) {
1657                 case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT:
1658                     provDisc = (WifiP2pProvDiscEvent) message.obj;
1659                     device = provDisc.device;
1660                     if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1661 
1662                     if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
1663                         if (DBG) logd("Found a match " + mSavedPeerConfig);
1664                         p2pConnectWithPinDisplay(mSavedPeerConfig);
1665                         transitionTo(mGroupNegotiationState);
1666                     }
1667                     break;
1668                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
1669                     provDisc = (WifiP2pProvDiscEvent) message.obj;
1670                     device = provDisc.device;
1671                     if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1672 
1673                     if (mSavedPeerConfig.wps.setup == WpsInfo.KEYPAD) {
1674                         if (DBG) logd("Found a match " + mSavedPeerConfig);
1675                         /* we already have the pin */
1676                         if (!TextUtils.isEmpty(mSavedPeerConfig.wps.pin)) {
1677                             p2pConnectWithPinDisplay(mSavedPeerConfig);
1678                             transitionTo(mGroupNegotiationState);
1679                         } else {
1680                             mJoinExistingGroup = false;
1681                             transitionTo(mUserAuthorizingNegotiationRequestState);
1682                         }
1683                     }
1684                     break;
1685                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
1686                     provDisc = (WifiP2pProvDiscEvent) message.obj;
1687                     device = provDisc.device;
1688                     if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1689 
1690                     if (mSavedPeerConfig.wps.setup == WpsInfo.DISPLAY) {
1691                         if (DBG) logd("Found a match " + mSavedPeerConfig);
1692                         mSavedPeerConfig.wps.pin = provDisc.pin;
1693                         p2pConnectWithPinDisplay(mSavedPeerConfig);
1694                         notifyInvitationSent(provDisc.pin, device.deviceAddress);
1695                         transitionTo(mGroupNegotiationState);
1696                     }
1697                     break;
1698                 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
1699                     loge("provision discovery failed");
1700                     handleGroupCreationFailure();
1701                     transitionTo(mInactiveState);
1702                     break;
1703                 default:
1704                     return NOT_HANDLED;
1705             }
1706             return HANDLED;
1707         }
1708     }
1709 
1710     class GroupNegotiationState extends State {
1711         @Override
enter()1712         public void enter() {
1713             if (DBG) logd(getName());
1714         }
1715 
1716         @Override
processMessage(Message message)1717         public boolean processMessage(Message message) {
1718             if (DBG) logd(getName() + message.toString());
1719             switch (message.what) {
1720                 // We ignore these right now, since we get a GROUP_STARTED notification
1721                 // afterwards
1722                 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
1723                 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
1724                     if (DBG) logd(getName() + " go success");
1725                     break;
1726                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1727                     mGroup = (WifiP2pGroup) message.obj;
1728                     if (DBG) logd(getName() + " group started");
1729 
1730                     if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
1731                         /*
1732                          * update cache information and set network id to mGroup.
1733                          */
1734                         updatePersistentNetworks(NO_RELOAD);
1735                         String devAddr = mGroup.getOwner().deviceAddress;
1736                         mGroup.setNetworkId(mGroups.getNetworkId(devAddr,
1737                                 mGroup.getNetworkName()));
1738                     }
1739 
1740                     if (mGroup.isGroupOwner()) {
1741                         /* Setting an idle time out on GO causes issues with certain scenarios
1742                          * on clients where it can be off-channel for longer and with the power
1743                          * save modes used.
1744                          *
1745                          * TODO: Verify multi-channel scenarios and supplicant behavior are
1746                          * better before adding a time out in future
1747                          */
1748                         //Set group idle timeout of 10 sec, to avoid GO beaconing incase of any
1749                         //failure during 4-way Handshake.
1750                         if (!mAutonomousGroup) {
1751                             mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
1752                         }
1753                         startDhcpServer(mGroup.getInterface());
1754                     } else {
1755                         mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
1756                         startIpManager(mGroup.getInterface());
1757                         WifiP2pDevice groupOwner = mGroup.getOwner();
1758                         WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
1759                         if (peer != null) {
1760                             // update group owner details with peer details found at discovery
1761                             groupOwner.updateSupplicantDetails(peer);
1762                             mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
1763                             sendPeersChangedBroadcast();
1764                         } else {
1765                             // A supplicant bug can lead to reporting an invalid
1766                             // group owner address (all zeroes) at times. Avoid a
1767                             // crash, but continue group creation since it is not
1768                             // essential.
1769                             logw("Unknown group owner " + groupOwner);
1770                         }
1771                     }
1772                     transitionTo(mGroupCreatedState);
1773                     break;
1774                 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
1775                     P2pStatus status = (P2pStatus) message.obj;
1776                     if (status == P2pStatus.NO_COMMON_CHANNEL) {
1777                         transitionTo(mFrequencyConflictState);
1778                         break;
1779                     }
1780                     /* continue with group removal handling */
1781                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
1782                     if (DBG) logd(getName() + " go failure");
1783                     handleGroupCreationFailure();
1784                     transitionTo(mInactiveState);
1785                     break;
1786                 // A group formation failure is always followed by
1787                 // a group removed event. Flushing things at group formation
1788                 // failure causes supplicant issues. Ignore right now.
1789                 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
1790                     status = (P2pStatus) message.obj;
1791                     if (status == P2pStatus.NO_COMMON_CHANNEL) {
1792                         transitionTo(mFrequencyConflictState);
1793                         break;
1794                     }
1795                     break;
1796                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
1797                     status = (P2pStatus)message.obj;
1798                     if (status == P2pStatus.SUCCESS) {
1799                         // invocation was succeeded.
1800                         // wait P2P_GROUP_STARTED_EVENT.
1801                         break;
1802                     }
1803                     loge("Invitation result " + status);
1804                     if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
1805                         // target device has already removed the credential.
1806                         // So, remove this credential accordingly.
1807                         int netId = mSavedPeerConfig.netId;
1808                         if (netId >= 0) {
1809                             if (DBG) logd("Remove unknown client from the list");
1810                             removeClientFromList(netId, mSavedPeerConfig.deviceAddress, true);
1811                         }
1812 
1813                         // Reinvocation has failed, try group negotiation
1814                         mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID;
1815                         p2pConnectWithPinDisplay(mSavedPeerConfig);
1816                     } else if (status == P2pStatus.INFORMATION_IS_CURRENTLY_UNAVAILABLE) {
1817 
1818                         // Devices setting persistent_reconnect to 0 in wpa_supplicant
1819                         // always defer the invocation request and return
1820                         // "information is currently unable" error.
1821                         // So, try another way to connect for interoperability.
1822                         mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID;
1823                         p2pConnectWithPinDisplay(mSavedPeerConfig);
1824                     } else if (status == P2pStatus.NO_COMMON_CHANNEL) {
1825                         transitionTo(mFrequencyConflictState);
1826                     } else {
1827                         handleGroupCreationFailure();
1828                         transitionTo(mInactiveState);
1829                     }
1830                     break;
1831                 default:
1832                     return NOT_HANDLED;
1833             }
1834             return HANDLED;
1835         }
1836     }
1837 
1838     class FrequencyConflictState extends State {
1839         private AlertDialog mFrequencyConflictDialog;
1840         @Override
enter()1841         public void enter() {
1842             if (DBG) logd(getName());
1843             notifyFrequencyConflict();
1844         }
1845 
notifyFrequencyConflict()1846         private void notifyFrequencyConflict() {
1847             logd("Notify frequency conflict");
1848             Resources r = Resources.getSystem();
1849 
1850             AlertDialog dialog = new AlertDialog.Builder(mContext)
1851                 .setMessage(r.getString(R.string.wifi_p2p_frequency_conflict_message,
1852                         getDeviceName(mSavedPeerConfig.deviceAddress)))
1853                 .setPositiveButton(r.getString(R.string.dlg_ok), new OnClickListener() {
1854                         @Override
1855                         public void onClick(DialogInterface dialog, int which) {
1856                             sendMessage(DROP_WIFI_USER_ACCEPT);
1857                         }
1858                     })
1859                 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
1860                         @Override
1861                         public void onClick(DialogInterface dialog, int which) {
1862                             sendMessage(DROP_WIFI_USER_REJECT);
1863                         }
1864                     })
1865                 .setOnCancelListener(new DialogInterface.OnCancelListener() {
1866                         @Override
1867                         public void onCancel(DialogInterface arg0) {
1868                             sendMessage(DROP_WIFI_USER_REJECT);
1869                         }
1870                     })
1871                 .create();
1872 
1873             dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1874             WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
1875             attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
1876             dialog.getWindow().setAttributes(attrs);
1877             dialog.show();
1878             mFrequencyConflictDialog = dialog;
1879         }
1880 
1881         @Override
processMessage(Message message)1882         public boolean processMessage(Message message) {
1883             if (DBG) logd(getName() + message.toString());
1884             switch (message.what) {
1885                 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
1886                 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
1887                     loge(getName() + "group sucess during freq conflict!");
1888                     break;
1889                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1890                     loge(getName() + "group started after freq conflict, handle anyway");
1891                     deferMessage(message);
1892                     transitionTo(mGroupNegotiationState);
1893                     break;
1894                 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
1895                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
1896                 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
1897                     // Ignore failures since we retry again
1898                     break;
1899                 case DROP_WIFI_USER_REJECT:
1900                     // User rejected dropping wifi in favour of p2p
1901                     handleGroupCreationFailure();
1902                     transitionTo(mInactiveState);
1903                     break;
1904                 case DROP_WIFI_USER_ACCEPT:
1905                     // User accepted dropping wifi in favour of p2p
1906                     mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 1);
1907                     mTemporarilyDisconnectedWifi = true;
1908                     break;
1909                 case DISCONNECT_WIFI_RESPONSE:
1910                     // Got a response from wifistatemachine, retry p2p
1911                     if (DBG) logd(getName() + "Wifi disconnected, retry p2p");
1912                     transitionTo(mInactiveState);
1913                     sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
1914                     break;
1915                 default:
1916                     return NOT_HANDLED;
1917             }
1918             return HANDLED;
1919         }
1920 
exit()1921         public void exit() {
1922             if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss();
1923         }
1924     }
1925 
1926     class GroupCreatedState extends State {
1927         @Override
enter()1928         public void enter() {
1929             if (DBG) logd(getName());
1930             // Once connected, peer config details are invalid
1931             mSavedPeerConfig.invalidate();
1932             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
1933 
1934             updateThisDevice(WifiP2pDevice.CONNECTED);
1935 
1936             //DHCP server has already been started if I am a group owner
1937             if (mGroup.isGroupOwner()) {
1938                 setWifiP2pInfoOnGroupFormation(NetworkUtils.numericToInetAddress(SERVER_ADDRESS));
1939             }
1940 
1941             // In case of a negotiation group, connection changed is sent
1942             // after a client joins. For autonomous, send now
1943             if (mAutonomousGroup) {
1944                 sendP2pConnectionChangedBroadcast();
1945             }
1946         }
1947 
1948         @Override
processMessage(Message message)1949         public boolean processMessage(Message message) {
1950             if (DBG) logd(getName() + message.toString());
1951             switch (message.what) {
1952                 case WifiMonitor.AP_STA_CONNECTED_EVENT:
1953                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
1954                     String deviceAddress = device.deviceAddress;
1955                     // Clear timeout that was set when group was started.
1956                     mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
1957                     if (deviceAddress != null) {
1958                         if (mPeers.get(deviceAddress) != null) {
1959                             mGroup.addClient(mPeers.get(deviceAddress));
1960                         } else {
1961                             mGroup.addClient(deviceAddress);
1962                         }
1963                         mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
1964                         if (DBG) logd(getName() + " ap sta connected");
1965                         sendPeersChangedBroadcast();
1966                     } else {
1967                         loge("Connect on null device address, ignore");
1968                     }
1969                     sendP2pConnectionChangedBroadcast();
1970                     break;
1971                 case WifiMonitor.AP_STA_DISCONNECTED_EVENT:
1972                     device = (WifiP2pDevice) message.obj;
1973                     deviceAddress = device.deviceAddress;
1974                     if (deviceAddress != null) {
1975                         mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
1976                         if (mGroup.removeClient(deviceAddress)) {
1977                             if (DBG) logd("Removed client " + deviceAddress);
1978                             if (!mAutonomousGroup && mGroup.isClientListEmpty()) {
1979                                 logd("Client list empty, remove non-persistent p2p group");
1980                                 mWifiNative.p2pGroupRemove(mGroup.getInterface());
1981                                 // We end up sending connection changed broadcast
1982                                 // when this happens at exit()
1983                             } else {
1984                                 // Notify when a client disconnects from group
1985                                 sendP2pConnectionChangedBroadcast();
1986                             }
1987                         } else {
1988                             if (DBG) logd("Failed to remove client " + deviceAddress);
1989                             for (WifiP2pDevice c : mGroup.getClientList()) {
1990                                 if (DBG) logd("client " + c.deviceAddress);
1991                             }
1992                         }
1993                         sendPeersChangedBroadcast();
1994                         if (DBG) logd(getName() + " ap sta disconnected");
1995                     } else {
1996                         loge("Disconnect on unknown device: " + device);
1997                     }
1998                     break;
1999                 case IPM_PRE_DHCP_ACTION:
2000                     mWifiNative.setP2pPowerSave(mGroup.getInterface(), false);
2001                     mIpManager.completedPreDhcpAction();
2002                     break;
2003                 case IPM_POST_DHCP_ACTION:
2004                     mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
2005                     break;
2006                 case IPM_DHCP_RESULTS:
2007                     mDhcpResults = (DhcpResults) message.obj;
2008                     break;
2009                 case IPM_PROVISIONING_SUCCESS:
2010                     if (DBG) logd("mDhcpResults: " + mDhcpResults);
2011                     setWifiP2pInfoOnGroupFormation(mDhcpResults.serverAddress);
2012                     sendP2pConnectionChangedBroadcast();
2013                     try {
2014                         final String ifname = mGroup.getInterface();
2015                         mNwService.addInterfaceToLocalNetwork(
2016                                 ifname, mDhcpResults.getRoutes(ifname));
2017                     } catch (RemoteException e) {
2018                         loge("Failed to add iface to local network " + e);
2019                     }
2020                     break;
2021                 case IPM_PROVISIONING_FAILURE:
2022                     loge("IP provisioning failed");
2023                     mWifiNative.p2pGroupRemove(mGroup.getInterface());
2024                     break;
2025                 case WifiP2pManager.REMOVE_GROUP:
2026                     if (DBG) logd(getName() + " remove group");
2027                     if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) {
2028                         transitionTo(mOngoingGroupRemovalState);
2029                         replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
2030                     } else {
2031                         handleGroupRemoved();
2032                         transitionTo(mInactiveState);
2033                         replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
2034                                 WifiP2pManager.ERROR);
2035                     }
2036                     break;
2037                 /* We do not listen to NETWORK_DISCONNECTION_EVENT for group removal
2038                  * handling since supplicant actually tries to reconnect after a temporary
2039                  * disconnect until group idle time out. Eventually, a group removal event
2040                  * will come when group has been removed.
2041                  *
2042                  * When there are connectivity issues during temporary disconnect, the application
2043                  * will also just remove the group.
2044                  *
2045                  * Treating network disconnection as group removal causes race conditions since
2046                  * supplicant would still maintain the group at that stage.
2047                  */
2048                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
2049                     if (DBG) logd(getName() + " group removed");
2050                     handleGroupRemoved();
2051                     transitionTo(mInactiveState);
2052                     break;
2053                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
2054                     device = (WifiP2pDevice) message.obj;
2055                     //Device loss for a connected device indicates it is not in discovery any more
2056                     if (mGroup.contains(device)) {
2057                         if (DBG) logd("Add device to lost list " + device);
2058                         mPeersLostDuringConnection.updateSupplicantDetails(device);
2059                         return HANDLED;
2060                     }
2061                     // Do the regular device lost handling
2062                     return NOT_HANDLED;
2063                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
2064                     sendMessage(WifiP2pManager.REMOVE_GROUP);
2065                     deferMessage(message);
2066                     break;
2067                     // This allows any client to join the GO during the
2068                     // WPS window
2069                 case WifiP2pManager.START_WPS:
2070                     WpsInfo wps = (WpsInfo) message.obj;
2071                     if (wps == null) {
2072                         replyToMessage(message, WifiP2pManager.START_WPS_FAILED);
2073                         break;
2074                     }
2075                     boolean ret = true;
2076                     if (wps.setup == WpsInfo.PBC) {
2077                         ret = mWifiNative.startWpsPbc(mGroup.getInterface(), null);
2078                     } else {
2079                         if (wps.pin == null) {
2080                             String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface());
2081                             try {
2082                                 Integer.parseInt(pin);
2083                                 notifyInvitationSent(pin, "any");
2084                             } catch (NumberFormatException ignore) {
2085                                 ret = false;
2086                             }
2087                         } else {
2088                             ret = mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
2089                                     wps.pin);
2090                         }
2091                     }
2092                     replyToMessage(message, ret ? WifiP2pManager.START_WPS_SUCCEEDED :
2093                             WifiP2pManager.START_WPS_FAILED);
2094                     break;
2095                 case WifiP2pManager.CONNECT:
2096                     WifiP2pConfig config = (WifiP2pConfig) message.obj;
2097                     if (isConfigInvalid(config)) {
2098                         loge("Dropping connect requeset " + config);
2099                         replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
2100                         break;
2101                     }
2102                     logd("Inviting device : " + config.deviceAddress);
2103                     mSavedPeerConfig = config;
2104                     if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
2105                         mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
2106                         sendPeersChangedBroadcast();
2107                         replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
2108                     } else {
2109                         replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
2110                                 WifiP2pManager.ERROR);
2111                     }
2112                     // TODO: figure out updating the status to declined when invitation is rejected
2113                     break;
2114                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
2115                     P2pStatus status = (P2pStatus)message.obj;
2116                     if (status == P2pStatus.SUCCESS) {
2117                         // invocation was succeeded.
2118                         break;
2119                     }
2120                     loge("Invitation result " + status);
2121                     if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
2122                         // target device has already removed the credential.
2123                         // So, remove this credential accordingly.
2124                         int netId = mGroup.getNetworkId();
2125                         if (netId >= 0) {
2126                             if (DBG) logd("Remove unknown client from the list");
2127                             if (!removeClientFromList(netId,
2128                                     mSavedPeerConfig.deviceAddress, false)) {
2129                                 // not found the client on the list
2130                                 loge("Already removed the client, ignore");
2131                                 break;
2132                             }
2133                             // try invitation.
2134                             sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
2135                         }
2136                     }
2137                     break;
2138                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
2139                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
2140                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
2141                     WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;
2142                     mSavedPeerConfig = new WifiP2pConfig();
2143                     mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress;
2144                     if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) {
2145                         mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
2146                     } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) {
2147                         mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
2148                         mSavedPeerConfig.wps.pin = provDisc.pin;
2149                     } else {
2150                         mSavedPeerConfig.wps.setup = WpsInfo.PBC;
2151                     }
2152                     transitionTo(mUserAuthorizingJoinState);
2153                     break;
2154                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
2155                     loge("Duplicate group creation event notice, ignore");
2156                     break;
2157                 default:
2158                     return NOT_HANDLED;
2159             }
2160             return HANDLED;
2161         }
2162 
exit()2163         public void exit() {
2164             updateThisDevice(WifiP2pDevice.AVAILABLE);
2165             resetWifiP2pInfo();
2166             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
2167             sendP2pConnectionChangedBroadcast();
2168         }
2169     }
2170 
2171     class UserAuthorizingJoinState extends State {
2172         @Override
enter()2173         public void enter() {
2174             if (DBG) logd(getName());
2175             notifyInvitationReceived();
2176         }
2177 
2178         @Override
processMessage(Message message)2179         public boolean processMessage(Message message) {
2180             if (DBG) logd(getName() + message.toString());
2181             switch (message.what) {
2182                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
2183                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
2184                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
2185                     //Ignore more client requests
2186                     break;
2187                 case PEER_CONNECTION_USER_ACCEPT:
2188                     //Stop discovery to avoid failure due to channel switch
2189                     mWifiNative.p2pStopFind();
2190                     if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
2191                         mWifiNative.startWpsPbc(mGroup.getInterface(), null);
2192                     } else {
2193                         mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
2194                                 mSavedPeerConfig.wps.pin);
2195                     }
2196                     transitionTo(mGroupCreatedState);
2197                     break;
2198                 case PEER_CONNECTION_USER_REJECT:
2199                     if (DBG) logd("User rejected incoming request");
2200                     transitionTo(mGroupCreatedState);
2201                     break;
2202                 default:
2203                     return NOT_HANDLED;
2204             }
2205             return HANDLED;
2206         }
2207 
2208         @Override
exit()2209         public void exit() {
2210             //TODO: dismiss dialog if not already done
2211         }
2212     }
2213 
2214     class OngoingGroupRemovalState extends State {
2215         @Override
enter()2216         public void enter() {
2217             if (DBG) logd(getName());
2218         }
2219 
2220         @Override
processMessage(Message message)2221         public boolean processMessage(Message message) {
2222             if (DBG) logd(getName() + message.toString());
2223             switch (message.what) {
2224                 // Group removal ongoing. Multiple calls
2225                 // end up removing persisted network. Do nothing.
2226                 case WifiP2pManager.REMOVE_GROUP:
2227                     replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
2228                     break;
2229                 // Parent state will transition out of this state
2230                 // when removal is complete
2231                 default:
2232                     return NOT_HANDLED;
2233             }
2234             return HANDLED;
2235         }
2236     }
2237 
2238     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2239     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2240         super.dump(fd, pw, args);
2241         pw.println("mWifiP2pInfo " + mWifiP2pInfo);
2242         pw.println("mGroup " + mGroup);
2243         pw.println("mSavedPeerConfig " + mSavedPeerConfig);
2244         pw.println();
2245     }
2246 
sendP2pStateChangedBroadcast(boolean enabled)2247     private void sendP2pStateChangedBroadcast(boolean enabled) {
2248         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
2249         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2250         if (enabled) {
2251             intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
2252                     WifiP2pManager.WIFI_P2P_STATE_ENABLED);
2253         } else {
2254             intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
2255                     WifiP2pManager.WIFI_P2P_STATE_DISABLED);
2256         }
2257         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2258     }
2259 
sendP2pDiscoveryChangedBroadcast(boolean started)2260     private void sendP2pDiscoveryChangedBroadcast(boolean started) {
2261         if (mDiscoveryStarted == started) return;
2262         mDiscoveryStarted = started;
2263 
2264         if (DBG) logd("discovery change broadcast " + started);
2265 
2266         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
2267         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2268         intent.putExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, started ?
2269                 WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED :
2270                 WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED);
2271         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2272     }
2273 
sendThisDeviceChangedBroadcast()2274     private void sendThisDeviceChangedBroadcast() {
2275         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
2276         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2277         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice));
2278         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2279     }
2280 
sendPeersChangedBroadcast()2281     private void sendPeersChangedBroadcast() {
2282         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
2283         intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, new WifiP2pDeviceList(mPeers));
2284         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2285         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2286     }
2287 
sendP2pConnectionChangedBroadcast()2288     private void sendP2pConnectionChangedBroadcast() {
2289         if (DBG) logd("sending p2p connection changed broadcast");
2290         Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
2291         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
2292                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
2293         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo));
2294         intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
2295         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, new WifiP2pGroup(mGroup));
2296         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2297         mWifiChannel.sendMessage(WifiP2pServiceImpl.P2P_CONNECTION_CHANGED,
2298                 new NetworkInfo(mNetworkInfo));
2299     }
2300 
sendP2pPersistentGroupsChangedBroadcast()2301     private void sendP2pPersistentGroupsChangedBroadcast() {
2302         if (DBG) logd("sending p2p persistent groups changed broadcast");
2303         Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);
2304         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2305         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2306     }
2307 
startDhcpServer(String intf)2308     private void startDhcpServer(String intf) {
2309         InterfaceConfiguration ifcg = null;
2310         try {
2311             ifcg = mNwService.getInterfaceConfig(intf);
2312             ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(
2313                         SERVER_ADDRESS), 24));
2314             ifcg.setInterfaceUp();
2315             mNwService.setInterfaceConfig(intf, ifcg);
2316             /* This starts the dnsmasq server */
2317             ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
2318                     Context.CONNECTIVITY_SERVICE);
2319             String[] tetheringDhcpRanges = cm.getTetheredDhcpRanges();
2320             if (mNwService.isTetheringStarted()) {
2321                 if (DBG) logd("Stop existing tethering and restart it");
2322                 mNwService.stopTethering();
2323             }
2324             mNwService.tetherInterface(intf);
2325             mNwService.startTethering(tetheringDhcpRanges);
2326         } catch (Exception e) {
2327             loge("Error configuring interface " + intf + ", :" + e);
2328             return;
2329         }
2330 
2331         logd("Started Dhcp server on " + intf);
2332    }
2333 
stopDhcpServer(String intf)2334     private void stopDhcpServer(String intf) {
2335         try {
2336             mNwService.untetherInterface(intf);
2337             for (String temp : mNwService.listTetheredInterfaces()) {
2338                 logd("List all interfaces " + temp);
2339                 if (temp.compareTo(intf) != 0) {
2340                     logd("Found other tethering interfaces, so keep tethering alive");
2341                     return;
2342                 }
2343             }
2344             mNwService.stopTethering();
2345         } catch (Exception e) {
2346             loge("Error stopping Dhcp server" + e);
2347             return;
2348         } finally {
2349             logd("Stopped Dhcp server");
2350         }
2351     }
2352 
notifyP2pEnableFailure()2353     private void notifyP2pEnableFailure() {
2354         Resources r = Resources.getSystem();
2355         AlertDialog dialog = new AlertDialog.Builder(mContext)
2356             .setTitle(r.getString(R.string.wifi_p2p_dialog_title))
2357             .setMessage(r.getString(R.string.wifi_p2p_failed_message))
2358             .setPositiveButton(r.getString(R.string.ok), null)
2359             .create();
2360         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2361         WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
2362         attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
2363         dialog.getWindow().setAttributes(attrs);
2364         dialog.show();
2365     }
2366 
addRowToDialog(ViewGroup group, int stringId, String value)2367     private void addRowToDialog(ViewGroup group, int stringId, String value) {
2368         Resources r = Resources.getSystem();
2369         View row = LayoutInflater.from(mContext).inflate(R.layout.wifi_p2p_dialog_row,
2370                 group, false);
2371         ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId));
2372         ((TextView) row.findViewById(R.id.value)).setText(value);
2373         group.addView(row);
2374     }
2375 
notifyInvitationSent(String pin, String peerAddress)2376     private void notifyInvitationSent(String pin, String peerAddress) {
2377         Resources r = Resources.getSystem();
2378 
2379         final View textEntryView = LayoutInflater.from(mContext)
2380                 .inflate(R.layout.wifi_p2p_dialog, null);
2381 
2382         ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
2383         addRowToDialog(group, R.string.wifi_p2p_to_message, getDeviceName(peerAddress));
2384         addRowToDialog(group, R.string.wifi_p2p_show_pin_message, pin);
2385 
2386         AlertDialog dialog = new AlertDialog.Builder(mContext)
2387             .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title))
2388             .setView(textEntryView)
2389             .setPositiveButton(r.getString(R.string.ok), null)
2390             .create();
2391         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2392         WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
2393         attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
2394         dialog.getWindow().setAttributes(attrs);
2395         dialog.show();
2396     }
2397 
notifyInvitationReceived()2398     private void notifyInvitationReceived() {
2399         Resources r = Resources.getSystem();
2400         final WpsInfo wps = mSavedPeerConfig.wps;
2401         final View textEntryView = LayoutInflater.from(mContext)
2402                 .inflate(R.layout.wifi_p2p_dialog, null);
2403 
2404         ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
2405         addRowToDialog(group, R.string.wifi_p2p_from_message, getDeviceName(
2406                 mSavedPeerConfig.deviceAddress));
2407 
2408         final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin);
2409 
2410         AlertDialog dialog = new AlertDialog.Builder(mContext)
2411             .setTitle(r.getString(R.string.wifi_p2p_invitation_to_connect_title))
2412             .setView(textEntryView)
2413             .setPositiveButton(r.getString(R.string.accept), new OnClickListener() {
2414                         public void onClick(DialogInterface dialog, int which) {
2415                             if (wps.setup == WpsInfo.KEYPAD) {
2416                                 mSavedPeerConfig.wps.pin = pin.getText().toString();
2417                             }
2418                             if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig);
2419                             sendMessage(PEER_CONNECTION_USER_ACCEPT);
2420                         }
2421                     })
2422             .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
2423                         @Override
2424                         public void onClick(DialogInterface dialog, int which) {
2425                             if (DBG) logd(getName() + " ignore connect");
2426                             sendMessage(PEER_CONNECTION_USER_REJECT);
2427                         }
2428                     })
2429             .setOnCancelListener(new DialogInterface.OnCancelListener() {
2430                         @Override
2431                         public void onCancel(DialogInterface arg0) {
2432                             if (DBG) logd(getName() + " ignore connect");
2433                             sendMessage(PEER_CONNECTION_USER_REJECT);
2434                         }
2435                     })
2436             .create();
2437 
2438         //make the enter pin area or the display pin area visible
2439         switch (wps.setup) {
2440             case WpsInfo.KEYPAD:
2441                 if (DBG) logd("Enter pin section visible");
2442                 textEntryView.findViewById(R.id.enter_pin_section).setVisibility(View.VISIBLE);
2443                 break;
2444             case WpsInfo.DISPLAY:
2445                 if (DBG) logd("Shown pin section visible");
2446                 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin);
2447                 break;
2448             default:
2449                 break;
2450         }
2451 
2452         if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_APPLIANCE) ==
2453                 Configuration.UI_MODE_TYPE_APPLIANCE) {
2454             // For appliance devices, add a key listener which accepts.
2455             dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
2456 
2457                 @Override
2458                 public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
2459                     // TODO: make the actual key come from a config value.
2460                     if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
2461                         sendMessage(PEER_CONNECTION_USER_ACCEPT);
2462                         dialog.dismiss();
2463                         return true;
2464                     }
2465                     return false;
2466                 }
2467             });
2468             // TODO: add timeout for this dialog.
2469             // TODO: update UI in appliance mode to tell user what to do.
2470         }
2471 
2472         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2473         WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
2474         attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
2475         dialog.getWindow().setAttributes(attrs);
2476         dialog.show();
2477     }
2478 
2479     /**
2480      * Synchronize the persistent group list between
2481      * wpa_supplicant and mGroups.
2482      */
updatePersistentNetworks(boolean reload)2483     private void updatePersistentNetworks(boolean reload) {
2484         String listStr = mWifiNative.listNetworks();
2485         if (listStr == null) return;
2486 
2487         boolean isSaveRequired = false;
2488         String[] lines = listStr.split("\n");
2489         if (lines == null) return;
2490 
2491         if (reload) mGroups.clear();
2492 
2493         // Skip the first line, which is a header
2494         for (int i = 1; i < lines.length; i++) {
2495             String[] result = lines[i].split("\t");
2496             if (result == null || result.length < 4) {
2497                 continue;
2498             }
2499             // network-id | ssid | bssid | flags
2500             int netId = -1;
2501             String ssid = result[1];
2502             String bssid = result[2];
2503             String flags = result[3];
2504             try {
2505                 netId = Integer.parseInt(result[0]);
2506             } catch(NumberFormatException e) {
2507                 e.printStackTrace();
2508                 continue;
2509             }
2510 
2511             if (flags.indexOf("[CURRENT]") != -1) {
2512                 continue;
2513             }
2514             if (flags.indexOf("[P2P-PERSISTENT]") == -1) {
2515                 /*
2516                  * The unused profile is sometimes remained when the p2p group formation is failed.
2517                  * So, we clean up the p2p group here.
2518                  */
2519                 if (DBG) logd("clean up the unused persistent group. netId=" + netId);
2520                 mWifiNative.removeNetwork(netId);
2521                 isSaveRequired = true;
2522                 continue;
2523             }
2524 
2525             if (mGroups.contains(netId)) {
2526                 continue;
2527             }
2528 
2529             WifiP2pGroup group = new WifiP2pGroup();
2530             group.setNetworkId(netId);
2531             group.setNetworkName(ssid);
2532             String mode = mWifiNative.getNetworkVariable(netId, "mode");
2533             if (mode != null && mode.equals("3")) {
2534                 group.setIsGroupOwner(true);
2535             }
2536             if (bssid.equalsIgnoreCase(mThisDevice.deviceAddress)) {
2537                 group.setOwner(mThisDevice);
2538             } else {
2539                 WifiP2pDevice device = new WifiP2pDevice();
2540                 device.deviceAddress = bssid;
2541                 group.setOwner(device);
2542             }
2543             mGroups.add(group);
2544             isSaveRequired = true;
2545         }
2546 
2547         if (reload || isSaveRequired) {
2548             mWifiNative.saveConfig();
2549             sendP2pPersistentGroupsChangedBroadcast();
2550         }
2551     }
2552 
2553     /**
2554      * A config is valid if it has a peer address that has already been
2555      * discovered
2556      * @return true if it is invalid, false otherwise
2557      */
isConfigInvalid(WifiP2pConfig config)2558     private boolean isConfigInvalid(WifiP2pConfig config) {
2559         if (config == null) return true;
2560         if (TextUtils.isEmpty(config.deviceAddress)) return true;
2561         if (mPeers.get(config.deviceAddress) == null) return true;
2562         return false;
2563     }
2564 
2565     /* TODO: The supplicant does not provide group capability changes as an event.
2566      * Having it pushed as an event would avoid polling for this information right
2567      * before a connection
2568      */
fetchCurrentDeviceDetails(WifiP2pConfig config)2569     private WifiP2pDevice fetchCurrentDeviceDetails(WifiP2pConfig config) {
2570         /* Fetch & update group capability from supplicant on the device */
2571         int gc = mWifiNative.getGroupCapability(config.deviceAddress);
2572         mPeers.updateGroupCapability(config.deviceAddress, gc);
2573         return mPeers.get(config.deviceAddress);
2574     }
2575 
2576     /**
2577      * Start a p2p group negotiation and display pin if necessary
2578      * @param config for the peer
2579      */
p2pConnectWithPinDisplay(WifiP2pConfig config)2580     private void p2pConnectWithPinDisplay(WifiP2pConfig config) {
2581         WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
2582 
2583         String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner());
2584         try {
2585             Integer.parseInt(pin);
2586             notifyInvitationSent(pin, config.deviceAddress);
2587         } catch (NumberFormatException ignore) {
2588             // do nothing if p2pConnect did not return a pin
2589         }
2590     }
2591 
2592     /**
2593      * Reinvoke a persistent group.
2594      *
2595      * @param config for the peer
2596      * @return true on success, false on failure
2597      */
reinvokePersistentGroup(WifiP2pConfig config)2598     private boolean reinvokePersistentGroup(WifiP2pConfig config) {
2599         WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
2600 
2601         boolean join = dev.isGroupOwner();
2602         String ssid = mWifiNative.p2pGetSsid(dev.deviceAddress);
2603         if (DBG) logd("target ssid is " + ssid + " join:" + join);
2604 
2605         if (join && dev.isGroupLimit()) {
2606             if (DBG) logd("target device reaches group limit.");
2607 
2608             // if the target group has reached the limit,
2609             // try group formation.
2610             join = false;
2611         } else if (join) {
2612             int netId = mGroups.getNetworkId(dev.deviceAddress, ssid);
2613             if (netId >= 0) {
2614                 // Skip WPS and start 4way handshake immediately.
2615                 if (!mWifiNative.p2pGroupAdd(netId)) {
2616                     return false;
2617                 }
2618                 return true;
2619             }
2620         }
2621 
2622         if (!join && dev.isDeviceLimit()) {
2623             loge("target device reaches the device limit.");
2624             return false;
2625         }
2626 
2627         if (!join && dev.isInvitationCapable()) {
2628             int netId = WifiP2pGroup.PERSISTENT_NET_ID;
2629             if (config.netId >= 0) {
2630                 if (config.deviceAddress.equals(mGroups.getOwnerAddr(config.netId))) {
2631                     netId = config.netId;
2632                 }
2633             } else {
2634                 netId = mGroups.getNetworkId(dev.deviceAddress);
2635             }
2636             if (netId < 0) {
2637                 netId = getNetworkIdFromClientList(dev.deviceAddress);
2638             }
2639             if (DBG) logd("netId related with " + dev.deviceAddress + " = " + netId);
2640             if (netId >= 0) {
2641                 // Invoke the persistent group.
2642                 if (mWifiNative.p2pReinvoke(netId, dev.deviceAddress)) {
2643                     // Save network id. It'll be used when an invitation result event is received.
2644                     config.netId = netId;
2645                     return true;
2646                 } else {
2647                     loge("p2pReinvoke() failed, update networks");
2648                     updatePersistentNetworks(RELOAD);
2649                     return false;
2650                 }
2651             }
2652         }
2653 
2654         return false;
2655     }
2656 
2657     /**
2658      * Return the network id of the group owner profile which has the p2p client with
2659      * the specified device address in it's client list.
2660      * If more than one persistent group of the same address is present in its client
2661      * lists, return the first one.
2662      *
2663      * @param deviceAddress p2p device address.
2664      * @return the network id. if not found, return -1.
2665      */
getNetworkIdFromClientList(String deviceAddress)2666     private int getNetworkIdFromClientList(String deviceAddress) {
2667         if (deviceAddress == null) return -1;
2668 
2669         Collection<WifiP2pGroup> groups = mGroups.getGroupList();
2670         for (WifiP2pGroup group : groups) {
2671             int netId = group.getNetworkId();
2672             String[] p2pClientList = getClientList(netId);
2673             if (p2pClientList == null) continue;
2674             for (String client : p2pClientList) {
2675                 if (deviceAddress.equalsIgnoreCase(client)) {
2676                     return netId;
2677                 }
2678             }
2679         }
2680         return -1;
2681     }
2682 
2683     /**
2684      * Return p2p client list associated with the specified network id.
2685      * @param netId network id.
2686      * @return p2p client list. if not found, return null.
2687      */
getClientList(int netId)2688     private String[] getClientList(int netId) {
2689         String p2pClients = mWifiNative.getNetworkVariable(netId, "p2p_client_list");
2690         if (p2pClients == null) {
2691             return null;
2692         }
2693         return p2pClients.split(" ");
2694     }
2695 
2696     /**
2697      * Remove the specified p2p client from the specified profile.
2698      * @param netId network id of the profile.
2699      * @param addr p2p client address to be removed.
2700      * @param isRemovable if true, remove the specified profile if its client list becomes empty.
2701      * @return whether removing the specified p2p client is successful or not.
2702      */
removeClientFromList(int netId, String addr, boolean isRemovable)2703     private boolean removeClientFromList(int netId, String addr, boolean isRemovable) {
2704         StringBuilder modifiedClientList =  new StringBuilder();
2705         String[] currentClientList = getClientList(netId);
2706         boolean isClientRemoved = false;
2707         if (currentClientList != null) {
2708             for (String client : currentClientList) {
2709                 if (!client.equalsIgnoreCase(addr)) {
2710                     modifiedClientList.append(" ");
2711                     modifiedClientList.append(client);
2712                 } else {
2713                     isClientRemoved = true;
2714                 }
2715             }
2716         }
2717         if (modifiedClientList.length() == 0 && isRemovable) {
2718             // the client list is empty. so remove it.
2719             if (DBG) logd("Remove unknown network");
2720             mGroups.remove(netId);
2721             return true;
2722         }
2723 
2724         if (!isClientRemoved) {
2725             // specified p2p client is not found. already removed.
2726             return false;
2727         }
2728 
2729         if (DBG) logd("Modified client list: " + modifiedClientList);
2730         if (modifiedClientList.length() == 0) {
2731             modifiedClientList.append("\"\"");
2732         }
2733         mWifiNative.setNetworkVariable(netId,
2734                 "p2p_client_list", modifiedClientList.toString());
2735         mWifiNative.saveConfig();
2736         return true;
2737     }
2738 
setWifiP2pInfoOnGroupFormation(InetAddress serverInetAddress)2739     private void setWifiP2pInfoOnGroupFormation(InetAddress serverInetAddress) {
2740         mWifiP2pInfo.groupFormed = true;
2741         mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner();
2742         mWifiP2pInfo.groupOwnerAddress = serverInetAddress;
2743     }
2744 
resetWifiP2pInfo()2745     private void resetWifiP2pInfo() {
2746         mWifiP2pInfo.groupFormed = false;
2747         mWifiP2pInfo.isGroupOwner = false;
2748         mWifiP2pInfo.groupOwnerAddress = null;
2749     }
2750 
getDeviceName(String deviceAddress)2751     private String getDeviceName(String deviceAddress) {
2752         WifiP2pDevice d = mPeers.get(deviceAddress);
2753         if (d != null) {
2754                 return d.deviceName;
2755         }
2756         //Treat the address as name if there is no match
2757         return deviceAddress;
2758     }
2759 
getPersistedDeviceName()2760     private String getPersistedDeviceName() {
2761         String deviceName = Settings.Global.getString(mContext.getContentResolver(),
2762                 Settings.Global.WIFI_P2P_DEVICE_NAME);
2763         if (deviceName == null) {
2764             /* We use the 4 digits of the ANDROID_ID to have a friendly
2765              * default that has low likelihood of collision with a peer */
2766             String id = Settings.Secure.getString(mContext.getContentResolver(),
2767                     Settings.Secure.ANDROID_ID);
2768             return "Android_" + id.substring(0,4);
2769         }
2770         return deviceName;
2771     }
2772 
setAndPersistDeviceName(String devName)2773     private boolean setAndPersistDeviceName(String devName) {
2774         if (devName == null) return false;
2775 
2776         if (!mWifiNative.setDeviceName(devName)) {
2777             loge("Failed to set device name " + devName);
2778             return false;
2779         }
2780 
2781         mThisDevice.deviceName = devName;
2782         mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
2783 
2784         Settings.Global.putString(mContext.getContentResolver(),
2785                 Settings.Global.WIFI_P2P_DEVICE_NAME, devName);
2786         sendThisDeviceChangedBroadcast();
2787         return true;
2788     }
2789 
setWfdInfo(WifiP2pWfdInfo wfdInfo)2790     private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) {
2791         boolean success;
2792 
2793         if (!wfdInfo.isWfdEnabled()) {
2794             success = mWifiNative.setWfdEnable(false);
2795         } else {
2796             success =
2797                 mWifiNative.setWfdEnable(true)
2798                 && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex());
2799         }
2800 
2801         if (!success) {
2802             loge("Failed to set wfd properties");
2803             return false;
2804         }
2805 
2806         mThisDevice.wfdInfo = wfdInfo;
2807         sendThisDeviceChangedBroadcast();
2808         return true;
2809     }
2810 
initializeP2pSettings()2811     private void initializeP2pSettings() {
2812         mWifiNative.setPersistentReconnect(true);
2813         mThisDevice.deviceName = getPersistedDeviceName();
2814         mWifiNative.setDeviceName(mThisDevice.deviceName);
2815         // DIRECT-XY-DEVICENAME (XY is randomly generated)
2816         mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
2817         mWifiNative.setDeviceType(mThisDevice.primaryDeviceType);
2818         // Supplicant defaults to using virtual display with display
2819         // which refers to a remote display. Use physical_display
2820         mWifiNative.setConfigMethods("virtual_push_button physical_display keypad");
2821         // STA has higher priority over P2P
2822         mWifiNative.setConcurrencyPriority("sta");
2823 
2824         mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress();
2825         updateThisDevice(WifiP2pDevice.AVAILABLE);
2826         if (DBG) logd("DeviceAddress: " + mThisDevice.deviceAddress);
2827 
2828         mClientInfoList.clear();
2829         mWifiNative.p2pFlush();
2830         mWifiNative.p2pServiceFlush();
2831         mServiceTransactionId = 0;
2832         mServiceDiscReqId = null;
2833 
2834         updatePersistentNetworks(RELOAD);
2835     }
2836 
updateThisDevice(int status)2837     private void updateThisDevice(int status) {
2838         mThisDevice.status = status;
2839         sendThisDeviceChangedBroadcast();
2840     }
2841 
handleGroupCreationFailure()2842     private void handleGroupCreationFailure() {
2843         resetWifiP2pInfo();
2844         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.FAILED, null, null);
2845         sendP2pConnectionChangedBroadcast();
2846 
2847         // Remove only the peer we failed to connect to so that other devices discovered
2848         // that have not timed out still remain in list for connection
2849         boolean peersChanged = mPeers.remove(mPeersLostDuringConnection);
2850         if (TextUtils.isEmpty(mSavedPeerConfig.deviceAddress) == false &&
2851                 mPeers.remove(mSavedPeerConfig.deviceAddress) != null) {
2852             peersChanged = true;
2853         }
2854         if (peersChanged) {
2855             sendPeersChangedBroadcast();
2856         }
2857 
2858         mPeersLostDuringConnection.clear();
2859         mServiceDiscReqId = null;
2860         sendMessage(WifiP2pManager.DISCOVER_PEERS);
2861     }
2862 
handleGroupRemoved()2863     private void handleGroupRemoved() {
2864         if (mGroup.isGroupOwner()) {
2865             stopDhcpServer(mGroup.getInterface());
2866         } else {
2867             if (DBG) logd("stop IpManager");
2868             stopIpManager();
2869             try {
2870                 mNwService.removeInterfaceFromLocalNetwork(mGroup.getInterface());
2871             } catch (RemoteException e) {
2872                 loge("Failed to remove iface from local network " + e);
2873             }
2874         }
2875 
2876         try {
2877             mNwService.clearInterfaceAddresses(mGroup.getInterface());
2878         } catch (Exception e) {
2879             loge("Failed to clear addresses " + e);
2880         }
2881 
2882         // Clear any timeout that was set. This is essential for devices
2883         // that reuse the main p2p interface for a created group.
2884         mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
2885 
2886         boolean peersChanged = false;
2887         // Remove only peers part of the group, so that other devices discovered
2888         // that have not timed out still remain in list for connection
2889         for (WifiP2pDevice d : mGroup.getClientList()) {
2890             if (mPeers.remove(d)) peersChanged = true;
2891         }
2892         if (mPeers.remove(mGroup.getOwner())) peersChanged = true;
2893         if (mPeers.remove(mPeersLostDuringConnection)) peersChanged = true;
2894         if (peersChanged) {
2895             sendPeersChangedBroadcast();
2896         }
2897 
2898         mGroup = null;
2899         mPeersLostDuringConnection.clear();
2900         mServiceDiscReqId = null;
2901 
2902         if (mTemporarilyDisconnectedWifi) {
2903             mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 0);
2904             mTemporarilyDisconnectedWifi = false;
2905         }
2906     }
2907 
2908     //State machine initiated requests can have replyTo set to null indicating
2909     //there are no recipients, we ignore those reply actions
replyToMessage(Message msg, int what)2910     private void replyToMessage(Message msg, int what) {
2911         if (msg.replyTo == null) return;
2912         Message dstMsg = obtainMessage(msg);
2913         dstMsg.what = what;
2914         mReplyChannel.replyToMessage(msg, dstMsg);
2915     }
2916 
replyToMessage(Message msg, int what, int arg1)2917     private void replyToMessage(Message msg, int what, int arg1) {
2918         if (msg.replyTo == null) return;
2919         Message dstMsg = obtainMessage(msg);
2920         dstMsg.what = what;
2921         dstMsg.arg1 = arg1;
2922         mReplyChannel.replyToMessage(msg, dstMsg);
2923     }
2924 
replyToMessage(Message msg, int what, Object obj)2925     private void replyToMessage(Message msg, int what, Object obj) {
2926         if (msg.replyTo == null) return;
2927         Message dstMsg = obtainMessage(msg);
2928         dstMsg.what = what;
2929         dstMsg.obj = obj;
2930         mReplyChannel.replyToMessage(msg, dstMsg);
2931     }
2932 
2933     /* arg2 on the source message has a hash code that needs to be retained in replies
2934      * see WifiP2pManager for details */
obtainMessage(Message srcMsg)2935     private Message obtainMessage(Message srcMsg) {
2936         Message msg = Message.obtain();
2937         msg.arg2 = srcMsg.arg2;
2938         return msg;
2939     }
2940 
2941     @Override
logd(String s)2942     protected void logd(String s) {
2943         Slog.d(TAG, s);
2944     }
2945 
2946     @Override
loge(String s)2947     protected void loge(String s) {
2948         Slog.e(TAG, s);
2949     }
2950 
2951     /**
2952      * Update service discovery request to wpa_supplicant.
2953      */
updateSupplicantServiceRequest()2954     private boolean updateSupplicantServiceRequest() {
2955         clearSupplicantServiceRequest();
2956 
2957         StringBuffer sb = new StringBuffer();
2958         for (ClientInfo c: mClientInfoList.values()) {
2959             int key;
2960             WifiP2pServiceRequest req;
2961             for (int i=0; i < c.mReqList.size(); i++) {
2962                 req = c.mReqList.valueAt(i);
2963                 if (req != null) {
2964                     sb.append(req.getSupplicantQuery());
2965                 }
2966             }
2967         }
2968 
2969         if (sb.length() == 0) {
2970             return false;
2971         }
2972 
2973         mServiceDiscReqId = mWifiNative.p2pServDiscReq("00:00:00:00:00:00", sb.toString());
2974         if (mServiceDiscReqId == null) {
2975             return false;
2976         }
2977         return true;
2978     }
2979 
2980     /**
2981      * Clear service discovery request in wpa_supplicant
2982      */
clearSupplicantServiceRequest()2983     private void clearSupplicantServiceRequest() {
2984         if (mServiceDiscReqId == null) return;
2985 
2986         mWifiNative.p2pServDiscCancelReq(mServiceDiscReqId);
2987         mServiceDiscReqId = null;
2988     }
2989 
2990     /* TODO: We could track individual service adds separately and avoid
2991      * having to do update all service requests on every new request
2992      */
addServiceRequest(Messenger m, WifiP2pServiceRequest req)2993     private boolean addServiceRequest(Messenger m, WifiP2pServiceRequest req) {
2994         clearClientDeadChannels();
2995         ClientInfo clientInfo = getClientInfo(m, true);
2996         if (clientInfo == null) {
2997             return false;
2998         }
2999 
3000         ++mServiceTransactionId;
3001         //The Wi-Fi p2p spec says transaction id should be non-zero
3002         if (mServiceTransactionId == 0) ++mServiceTransactionId;
3003         req.setTransactionId(mServiceTransactionId);
3004         clientInfo.mReqList.put(mServiceTransactionId, req);
3005 
3006         if (mServiceDiscReqId == null) {
3007             return true;
3008         }
3009 
3010         return updateSupplicantServiceRequest();
3011     }
3012 
removeServiceRequest(Messenger m, WifiP2pServiceRequest req)3013     private void removeServiceRequest(Messenger m, WifiP2pServiceRequest req) {
3014         ClientInfo clientInfo = getClientInfo(m, false);
3015         if (clientInfo == null) {
3016             return;
3017         }
3018 
3019         //Application does not have transaction id information
3020         //go through stored requests to remove
3021         boolean removed = false;
3022         for (int i=0; i<clientInfo.mReqList.size(); i++) {
3023             if (req.equals(clientInfo.mReqList.valueAt(i))) {
3024                 removed = true;
3025                 clientInfo.mReqList.removeAt(i);
3026                 break;
3027             }
3028         }
3029 
3030         if (!removed) return;
3031 
3032         if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
3033             if (DBG) logd("remove client information from framework");
3034             mClientInfoList.remove(clientInfo.mMessenger);
3035         }
3036 
3037         if (mServiceDiscReqId == null) {
3038             return;
3039         }
3040 
3041         updateSupplicantServiceRequest();
3042     }
3043 
clearServiceRequests(Messenger m)3044     private void clearServiceRequests(Messenger m) {
3045 
3046         ClientInfo clientInfo = getClientInfo(m, false);
3047         if (clientInfo == null) {
3048             return;
3049         }
3050 
3051         if (clientInfo.mReqList.size() == 0) {
3052             return;
3053         }
3054 
3055         clientInfo.mReqList.clear();
3056 
3057         if (clientInfo.mServList.size() == 0) {
3058             if (DBG) logd("remove channel information from framework");
3059             mClientInfoList.remove(clientInfo.mMessenger);
3060         }
3061 
3062         if (mServiceDiscReqId == null) {
3063             return;
3064         }
3065 
3066         updateSupplicantServiceRequest();
3067     }
3068 
addLocalService(Messenger m, WifiP2pServiceInfo servInfo)3069     private boolean addLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
3070         clearClientDeadChannels();
3071         ClientInfo clientInfo = getClientInfo(m, true);
3072         if (clientInfo == null) {
3073             return false;
3074         }
3075 
3076         if (!clientInfo.mServList.add(servInfo)) {
3077             return false;
3078         }
3079 
3080         if (!mWifiNative.p2pServiceAdd(servInfo)) {
3081             clientInfo.mServList.remove(servInfo);
3082             return false;
3083         }
3084 
3085         return true;
3086     }
3087 
removeLocalService(Messenger m, WifiP2pServiceInfo servInfo)3088     private void removeLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
3089         ClientInfo clientInfo = getClientInfo(m, false);
3090         if (clientInfo == null) {
3091             return;
3092         }
3093 
3094         mWifiNative.p2pServiceDel(servInfo);
3095 
3096         clientInfo.mServList.remove(servInfo);
3097         if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
3098             if (DBG) logd("remove client information from framework");
3099             mClientInfoList.remove(clientInfo.mMessenger);
3100         }
3101     }
3102 
clearLocalServices(Messenger m)3103     private void clearLocalServices(Messenger m) {
3104         ClientInfo clientInfo = getClientInfo(m, false);
3105         if (clientInfo == null) {
3106             return;
3107         }
3108 
3109         for (WifiP2pServiceInfo servInfo: clientInfo.mServList) {
3110             mWifiNative.p2pServiceDel(servInfo);
3111         }
3112 
3113         clientInfo.mServList.clear();
3114         if (clientInfo.mReqList.size() == 0) {
3115             if (DBG) logd("remove client information from framework");
3116             mClientInfoList.remove(clientInfo.mMessenger);
3117         }
3118     }
3119 
clearClientInfo(Messenger m)3120     private void clearClientInfo(Messenger m) {
3121         clearLocalServices(m);
3122         clearServiceRequests(m);
3123     }
3124 
3125     /**
3126      * Send the service response to the WifiP2pManager.Channel.
3127      *
3128      * @param resp
3129      */
sendServiceResponse(WifiP2pServiceResponse resp)3130     private void sendServiceResponse(WifiP2pServiceResponse resp) {
3131         for (ClientInfo c : mClientInfoList.values()) {
3132             WifiP2pServiceRequest req = c.mReqList.get(resp.getTransactionId());
3133             if (req != null) {
3134                 Message msg = Message.obtain();
3135                 msg.what = WifiP2pManager.RESPONSE_SERVICE;
3136                 msg.arg1 = 0;
3137                 msg.arg2 = 0;
3138                 msg.obj = resp;
3139                 try {
3140                     c.mMessenger.send(msg);
3141                 } catch (RemoteException e) {
3142                     if (DBG) logd("detect dead channel");
3143                     clearClientInfo(c.mMessenger);
3144                     return;
3145                 }
3146             }
3147         }
3148     }
3149 
3150     /**
3151      * We dont get notifications of clients that have gone away.
3152      * We detect this actively when services are added and throw
3153      * them away.
3154      *
3155      * TODO: This can be done better with full async channels.
3156      */
clearClientDeadChannels()3157     private void clearClientDeadChannels() {
3158         ArrayList<Messenger> deadClients = new ArrayList<Messenger>();
3159 
3160         for (ClientInfo c : mClientInfoList.values()) {
3161             Message msg = Message.obtain();
3162             msg.what = WifiP2pManager.PING;
3163             msg.arg1 = 0;
3164             msg.arg2 = 0;
3165             msg.obj = null;
3166             try {
3167                 c.mMessenger.send(msg);
3168             } catch (RemoteException e) {
3169                 if (DBG) logd("detect dead channel");
3170                 deadClients.add(c.mMessenger);
3171             }
3172         }
3173 
3174         for (Messenger m : deadClients) {
3175             clearClientInfo(m);
3176         }
3177     }
3178 
3179     /**
3180      * Return the specified ClientInfo.
3181      * @param m Messenger
3182      * @param createIfNotExist if true and the specified channel info does not exist,
3183      * create new client info.
3184      * @return the specified ClientInfo.
3185      */
getClientInfo(Messenger m, boolean createIfNotExist)3186     private ClientInfo getClientInfo(Messenger m, boolean createIfNotExist) {
3187         ClientInfo clientInfo = mClientInfoList.get(m);
3188 
3189         if (clientInfo == null && createIfNotExist) {
3190             if (DBG) logd("add a new client");
3191             clientInfo = new ClientInfo(m);
3192             mClientInfoList.put(m, clientInfo);
3193         }
3194 
3195         return clientInfo;
3196     }
3197 
3198     }
3199 
3200     /**
3201      * Information about a particular client and we track the service discovery requests
3202      * and the local services registered by the client.
3203      */
3204     private class ClientInfo {
3205 
3206         /*
3207          * A reference to WifiP2pManager.Channel handler.
3208          * The response of this request is notified to WifiP2pManager.Channel handler
3209          */
3210         private Messenger mMessenger;
3211 
3212         /*
3213          * A service discovery request list.
3214          */
3215         private SparseArray<WifiP2pServiceRequest> mReqList;
3216 
3217         /*
3218          * A local service information list.
3219          */
3220         private List<WifiP2pServiceInfo> mServList;
3221 
ClientInfo(Messenger m)3222         private ClientInfo(Messenger m) {
3223             mMessenger = m;
3224             mReqList = new SparseArray();
3225             mServList = new ArrayList<WifiP2pServiceInfo>();
3226         }
3227     }
3228 }
3229