• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi.p2p;
18 
19 import 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                         int id = group.getNetworkId();
1363                         if (id < 0) {
1364                             loge("Ignored invitation from null owner");
1365                             break;
1366                         }
1367 
1368                         String addr = mGroups.getOwnerAddr(id);
1369                         if (addr != null) {
1370                             group.setOwner(new WifiP2pDevice(addr));
1371                             owner = group.getOwner();
1372                         } else {
1373                             loge("Ignored invitation from null owner");
1374                             break;
1375                         }
1376                     }
1377 
1378                     config = new WifiP2pConfig();
1379                     config.deviceAddress = group.getOwner().deviceAddress;
1380 
1381                     if (isConfigInvalid(config)) {
1382                         loge("Dropping invitation request " + config);
1383                         break;
1384                     }
1385                     mSavedPeerConfig = config;
1386 
1387                     //Check if we have the owner in peer list and use appropriate
1388                     //wps method. Default is to use PBC.
1389                     if ((owner = mPeers.get(owner.deviceAddress)) != null) {
1390                         if (owner.wpsPbcSupported()) {
1391                             mSavedPeerConfig.wps.setup = WpsInfo.PBC;
1392                         } else if (owner.wpsKeypadSupported()) {
1393                             mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
1394                         } else if (owner.wpsDisplaySupported()) {
1395                             mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
1396                         }
1397                     }
1398 
1399                     mAutonomousGroup = false;
1400                     mJoinExistingGroup = true;
1401                     transitionTo(mUserAuthorizingInviteRequestState);
1402                     break;
1403                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
1404                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
1405                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
1406                     //We let the supplicant handle the provision discovery response
1407                     //and wait instead for the GO_NEGOTIATION_REQUEST_EVENT.
1408                     //Handling provision discovery and issuing a p2p_connect before
1409                     //group negotiation comes through causes issues
1410                     break;
1411                 case WifiP2pManager.CREATE_GROUP:
1412                     mAutonomousGroup = true;
1413                     int netId = message.arg1;
1414                     boolean ret = false;
1415                     if (netId == WifiP2pGroup.PERSISTENT_NET_ID) {
1416                         // check if the go persistent group is present.
1417                         netId = mGroups.getNetworkId(mThisDevice.deviceAddress);
1418                         if (netId != -1) {
1419                             ret = mWifiNative.p2pGroupAdd(netId);
1420                         } else {
1421                             ret = mWifiNative.p2pGroupAdd(true);
1422                         }
1423                     } else {
1424                         ret = mWifiNative.p2pGroupAdd(false);
1425                     }
1426 
1427                     if (ret) {
1428                         replyToMessage(message, WifiP2pManager.CREATE_GROUP_SUCCEEDED);
1429                         transitionTo(mGroupNegotiationState);
1430                     } else {
1431                         replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED,
1432                                 WifiP2pManager.ERROR);
1433                         // remain at this state.
1434                     }
1435                     break;
1436                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1437                     mGroup = (WifiP2pGroup) message.obj;
1438                     if (DBG) logd(getName() + " group started");
1439 
1440                     // We hit this scenario when a persistent group is reinvoked
1441                     if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
1442                         mAutonomousGroup = false;
1443                         deferMessage(message);
1444                         transitionTo(mGroupNegotiationState);
1445                     } else {
1446                         loge("Unexpected group creation, remove " + mGroup);
1447                         mWifiNative.p2pGroupRemove(mGroup.getInterface());
1448                     }
1449                     break;
1450                 case WifiP2pManager.START_LISTEN:
1451                     if (DBG) logd(getName() + " start listen mode");
1452                     mWifiNative.p2pFlush();
1453                     if (mWifiNative.p2pExtListen(true, 500, 500)) {
1454                         replyToMessage(message, WifiP2pManager.START_LISTEN_SUCCEEDED);
1455                     } else {
1456                         replyToMessage(message, WifiP2pManager.START_LISTEN_FAILED);
1457                     }
1458                     break;
1459                 case WifiP2pManager.STOP_LISTEN:
1460                     if (DBG) logd(getName() + " stop listen mode");
1461                     if (mWifiNative.p2pExtListen(false, 0, 0)) {
1462                         replyToMessage(message, WifiP2pManager.STOP_LISTEN_SUCCEEDED);
1463                     } else {
1464                         replyToMessage(message, WifiP2pManager.STOP_LISTEN_FAILED);
1465                     }
1466                     mWifiNative.p2pFlush();
1467                     break;
1468                 case WifiP2pManager.SET_CHANNEL:
1469                     Bundle p2pChannels = (Bundle) message.obj;
1470                     int lc = p2pChannels.getInt("lc", 0);
1471                     int oc = p2pChannels.getInt("oc", 0);
1472                     if (DBG) logd(getName() + " set listen and operating channel");
1473                     if (mWifiNative.p2pSetChannel(lc, oc)) {
1474                         replyToMessage(message, WifiP2pManager.SET_CHANNEL_SUCCEEDED);
1475                     } else {
1476                         replyToMessage(message, WifiP2pManager.SET_CHANNEL_FAILED);
1477                     }
1478                     break;
1479                 case WifiP2pManager.INITIATOR_REPORT_NFC_HANDOVER:
1480                     String handoverSelect = null;
1481 
1482                     if (message.obj != null) {
1483                         handoverSelect = ((Bundle) message.obj)
1484                                 .getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE);
1485                     }
1486 
1487                     if (handoverSelect != null
1488                             && mWifiNative.initiatorReportNfcHandover(handoverSelect)) {
1489                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED);
1490                         transitionTo(mGroupCreatingState);
1491                     } else {
1492                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED);
1493                     }
1494                     break;
1495                 case WifiP2pManager.RESPONDER_REPORT_NFC_HANDOVER:
1496                     String handoverRequest = null;
1497 
1498                     if (message.obj != null) {
1499                         handoverRequest = ((Bundle) message.obj)
1500                                 .getString(WifiP2pManager.EXTRA_HANDOVER_MESSAGE);
1501                     }
1502 
1503                     if (handoverRequest != null
1504                             && mWifiNative.responderReportNfcHandover(handoverRequest)) {
1505                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_SUCCEEDED);
1506                         transitionTo(mGroupCreatingState);
1507                     } else {
1508                         replyToMessage(message, WifiP2pManager.REPORT_NFC_HANDOVER_FAILED);
1509                     }
1510                     break;
1511                 default:
1512                     return NOT_HANDLED;
1513             }
1514             return HANDLED;
1515         }
1516     }
1517 
1518     class GroupCreatingState extends State {
1519         @Override
enter()1520         public void enter() {
1521             if (DBG) logd(getName());
1522             sendMessageDelayed(obtainMessage(GROUP_CREATING_TIMED_OUT,
1523                     ++mGroupCreatingTimeoutIndex, 0), GROUP_CREATING_WAIT_TIME_MS);
1524         }
1525 
1526         @Override
processMessage(Message message)1527         public boolean processMessage(Message message) {
1528             if (DBG) logd(getName() + message.toString());
1529             boolean ret = HANDLED;
1530             switch (message.what) {
1531                case GROUP_CREATING_TIMED_OUT:
1532                     if (mGroupCreatingTimeoutIndex == message.arg1) {
1533                         if (DBG) logd("Group negotiation timed out");
1534                         handleGroupCreationFailure();
1535                         transitionTo(mInactiveState);
1536                     }
1537                     break;
1538                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
1539                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
1540                     if (!mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) {
1541                         if (DBG) {
1542                             logd("mSavedPeerConfig " + mSavedPeerConfig.deviceAddress +
1543                                 "device " + device.deviceAddress);
1544                         }
1545                         // Do the regular device lost handling
1546                         ret = NOT_HANDLED;
1547                         break;
1548                     }
1549                     // Do nothing
1550                     if (DBG) logd("Add device to lost list " + device);
1551                     mPeersLostDuringConnection.updateSupplicantDetails(device);
1552                     break;
1553                 case WifiP2pManager.DISCOVER_PEERS:
1554                     /* Discovery will break negotiation */
1555                     replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED,
1556                             WifiP2pManager.BUSY);
1557                     break;
1558                 case WifiP2pManager.CANCEL_CONNECT:
1559                     //Do a supplicant p2p_cancel which only cancels an ongoing
1560                     //group negotiation. This will fail for a pending provision
1561                     //discovery or for a pending user action, but at the framework
1562                     //level, we always treat cancel as succeeded and enter
1563                     //an inactive state
1564                     mWifiNative.p2pCancelConnect();
1565                     handleGroupCreationFailure();
1566                     transitionTo(mInactiveState);
1567                     replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_SUCCEEDED);
1568                     break;
1569                 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
1570                     // We hit this scenario when NFC handover is invoked.
1571                     mAutonomousGroup = false;
1572                     transitionTo(mGroupNegotiationState);
1573                     break;
1574                 default:
1575                     ret = NOT_HANDLED;
1576             }
1577             return ret;
1578         }
1579     }
1580 
1581     class UserAuthorizingNegotiationRequestState extends State {
1582         @Override
enter()1583         public void enter() {
1584             if (DBG) logd(getName());
1585             notifyInvitationReceived();
1586         }
1587 
1588         @Override
processMessage(Message message)1589         public boolean processMessage(Message message) {
1590             if (DBG) logd(getName() + message.toString());
1591             boolean ret = HANDLED;
1592             switch (message.what) {
1593                 case PEER_CONNECTION_USER_ACCEPT:
1594                     mWifiNative.p2pStopFind();
1595                     p2pConnectWithPinDisplay(mSavedPeerConfig);
1596                     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
1597                     sendPeersChangedBroadcast();
1598                     transitionTo(mGroupNegotiationState);
1599                    break;
1600                 case PEER_CONNECTION_USER_REJECT:
1601                     if (DBG) logd("User rejected negotiation " + mSavedPeerConfig);
1602                     transitionTo(mInactiveState);
1603                     break;
1604                 default:
1605                     return NOT_HANDLED;
1606             }
1607             return ret;
1608         }
1609 
1610         @Override
exit()1611         public void exit() {
1612             //TODO: dismiss dialog if not already done
1613         }
1614     }
1615 
1616     class UserAuthorizingInviteRequestState extends State {
1617         @Override
enter()1618         public void enter() {
1619             if (DBG) logd(getName());
1620             notifyInvitationReceived();
1621         }
1622 
1623         @Override
processMessage(Message message)1624         public boolean processMessage(Message message) {
1625             if (DBG) logd(getName() + message.toString());
1626             boolean ret = HANDLED;
1627             switch (message.what) {
1628                 case PEER_CONNECTION_USER_ACCEPT:
1629                     mWifiNative.p2pStopFind();
1630                     if (!reinvokePersistentGroup(mSavedPeerConfig)) {
1631                         // Do negotiation when persistence fails
1632                         p2pConnectWithPinDisplay(mSavedPeerConfig);
1633                     }
1634                     mPeers.updateStatus(mSavedPeerConfig.deviceAddress, WifiP2pDevice.INVITED);
1635                     sendPeersChangedBroadcast();
1636                     transitionTo(mGroupNegotiationState);
1637                    break;
1638                 case PEER_CONNECTION_USER_REJECT:
1639                     if (DBG) logd("User rejected invitation " + mSavedPeerConfig);
1640                     transitionTo(mInactiveState);
1641                     break;
1642                 default:
1643                     return NOT_HANDLED;
1644             }
1645             return ret;
1646         }
1647 
1648         @Override
exit()1649         public void exit() {
1650             //TODO: dismiss dialog if not already done
1651         }
1652     }
1653 
1654 
1655 
1656     class ProvisionDiscoveryState extends State {
1657         @Override
enter()1658         public void enter() {
1659             if (DBG) logd(getName());
1660             mWifiNative.p2pProvisionDiscovery(mSavedPeerConfig);
1661         }
1662 
1663         @Override
processMessage(Message message)1664         public boolean processMessage(Message message) {
1665             if (DBG) logd(getName() + message.toString());
1666             WifiP2pProvDiscEvent provDisc;
1667             WifiP2pDevice device;
1668             switch (message.what) {
1669                 case WifiMonitor.P2P_PROV_DISC_PBC_RSP_EVENT:
1670                     provDisc = (WifiP2pProvDiscEvent) message.obj;
1671                     device = provDisc.device;
1672                     if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1673 
1674                     if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
1675                         if (DBG) logd("Found a match " + mSavedPeerConfig);
1676                         p2pConnectWithPinDisplay(mSavedPeerConfig);
1677                         transitionTo(mGroupNegotiationState);
1678                     }
1679                     break;
1680                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
1681                     provDisc = (WifiP2pProvDiscEvent) message.obj;
1682                     device = provDisc.device;
1683                     if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1684 
1685                     if (mSavedPeerConfig.wps.setup == WpsInfo.KEYPAD) {
1686                         if (DBG) logd("Found a match " + mSavedPeerConfig);
1687                         /* we already have the pin */
1688                         if (!TextUtils.isEmpty(mSavedPeerConfig.wps.pin)) {
1689                             p2pConnectWithPinDisplay(mSavedPeerConfig);
1690                             transitionTo(mGroupNegotiationState);
1691                         } else {
1692                             mJoinExistingGroup = false;
1693                             transitionTo(mUserAuthorizingNegotiationRequestState);
1694                         }
1695                     }
1696                     break;
1697                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
1698                     provDisc = (WifiP2pProvDiscEvent) message.obj;
1699                     device = provDisc.device;
1700                     if (!device.deviceAddress.equals(mSavedPeerConfig.deviceAddress)) break;
1701 
1702                     if (mSavedPeerConfig.wps.setup == WpsInfo.DISPLAY) {
1703                         if (DBG) logd("Found a match " + mSavedPeerConfig);
1704                         mSavedPeerConfig.wps.pin = provDisc.pin;
1705                         p2pConnectWithPinDisplay(mSavedPeerConfig);
1706                         notifyInvitationSent(provDisc.pin, device.deviceAddress);
1707                         transitionTo(mGroupNegotiationState);
1708                     }
1709                     break;
1710                 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
1711                     loge("provision discovery failed");
1712                     handleGroupCreationFailure();
1713                     transitionTo(mInactiveState);
1714                     break;
1715                 default:
1716                     return NOT_HANDLED;
1717             }
1718             return HANDLED;
1719         }
1720     }
1721 
1722     class GroupNegotiationState extends State {
1723         @Override
enter()1724         public void enter() {
1725             if (DBG) logd(getName());
1726         }
1727 
1728         @Override
processMessage(Message message)1729         public boolean processMessage(Message message) {
1730             if (DBG) logd(getName() + message.toString());
1731             switch (message.what) {
1732                 // We ignore these right now, since we get a GROUP_STARTED notification
1733                 // afterwards
1734                 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
1735                 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
1736                     if (DBG) logd(getName() + " go success");
1737                     break;
1738                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1739                     mGroup = (WifiP2pGroup) message.obj;
1740                     if (DBG) logd(getName() + " group started");
1741 
1742                     if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
1743                         /*
1744                          * update cache information and set network id to mGroup.
1745                          */
1746                         updatePersistentNetworks(NO_RELOAD);
1747                         String devAddr = mGroup.getOwner().deviceAddress;
1748                         mGroup.setNetworkId(mGroups.getNetworkId(devAddr,
1749                                 mGroup.getNetworkName()));
1750                     }
1751 
1752                     if (mGroup.isGroupOwner()) {
1753                         /* Setting an idle time out on GO causes issues with certain scenarios
1754                          * on clients where it can be off-channel for longer and with the power
1755                          * save modes used.
1756                          *
1757                          * TODO: Verify multi-channel scenarios and supplicant behavior are
1758                          * better before adding a time out in future
1759                          */
1760                         //Set group idle timeout of 10 sec, to avoid GO beaconing incase of any
1761                         //failure during 4-way Handshake.
1762                         if (!mAutonomousGroup) {
1763                             mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
1764                         }
1765                         startDhcpServer(mGroup.getInterface());
1766                     } else {
1767                         mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
1768                         startIpManager(mGroup.getInterface());
1769                         WifiP2pDevice groupOwner = mGroup.getOwner();
1770                         WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
1771                         if (peer != null) {
1772                             // update group owner details with peer details found at discovery
1773                             groupOwner.updateSupplicantDetails(peer);
1774                             mPeers.updateStatus(groupOwner.deviceAddress, WifiP2pDevice.CONNECTED);
1775                             sendPeersChangedBroadcast();
1776                         } else {
1777                             // A supplicant bug can lead to reporting an invalid
1778                             // group owner address (all zeroes) at times. Avoid a
1779                             // crash, but continue group creation since it is not
1780                             // essential.
1781                             logw("Unknown group owner " + groupOwner);
1782                         }
1783                     }
1784                     transitionTo(mGroupCreatedState);
1785                     break;
1786                 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
1787                     P2pStatus status = (P2pStatus) message.obj;
1788                     if (status == P2pStatus.NO_COMMON_CHANNEL) {
1789                         transitionTo(mFrequencyConflictState);
1790                         break;
1791                     }
1792                     /* continue with group removal handling */
1793                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
1794                     if (DBG) logd(getName() + " go failure");
1795                     handleGroupCreationFailure();
1796                     transitionTo(mInactiveState);
1797                     break;
1798                 // A group formation failure is always followed by
1799                 // a group removed event. Flushing things at group formation
1800                 // failure causes supplicant issues. Ignore right now.
1801                 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
1802                     status = (P2pStatus) message.obj;
1803                     if (status == P2pStatus.NO_COMMON_CHANNEL) {
1804                         transitionTo(mFrequencyConflictState);
1805                         break;
1806                     }
1807                     break;
1808                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
1809                     status = (P2pStatus)message.obj;
1810                     if (status == P2pStatus.SUCCESS) {
1811                         // invocation was succeeded.
1812                         // wait P2P_GROUP_STARTED_EVENT.
1813                         break;
1814                     }
1815                     loge("Invitation result " + status);
1816                     if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
1817                         // target device has already removed the credential.
1818                         // So, remove this credential accordingly.
1819                         int netId = mSavedPeerConfig.netId;
1820                         if (netId >= 0) {
1821                             if (DBG) logd("Remove unknown client from the list");
1822                             removeClientFromList(netId, mSavedPeerConfig.deviceAddress, true);
1823                         }
1824 
1825                         // Reinvocation has failed, try group negotiation
1826                         mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID;
1827                         p2pConnectWithPinDisplay(mSavedPeerConfig);
1828                     } else if (status == P2pStatus.INFORMATION_IS_CURRENTLY_UNAVAILABLE) {
1829 
1830                         // Devices setting persistent_reconnect to 0 in wpa_supplicant
1831                         // always defer the invocation request and return
1832                         // "information is currently unable" error.
1833                         // So, try another way to connect for interoperability.
1834                         mSavedPeerConfig.netId = WifiP2pGroup.PERSISTENT_NET_ID;
1835                         p2pConnectWithPinDisplay(mSavedPeerConfig);
1836                     } else if (status == P2pStatus.NO_COMMON_CHANNEL) {
1837                         transitionTo(mFrequencyConflictState);
1838                     } else {
1839                         handleGroupCreationFailure();
1840                         transitionTo(mInactiveState);
1841                     }
1842                     break;
1843                 default:
1844                     return NOT_HANDLED;
1845             }
1846             return HANDLED;
1847         }
1848     }
1849 
1850     class FrequencyConflictState extends State {
1851         private AlertDialog mFrequencyConflictDialog;
1852         @Override
enter()1853         public void enter() {
1854             if (DBG) logd(getName());
1855             notifyFrequencyConflict();
1856         }
1857 
notifyFrequencyConflict()1858         private void notifyFrequencyConflict() {
1859             logd("Notify frequency conflict");
1860             Resources r = Resources.getSystem();
1861 
1862             AlertDialog dialog = new AlertDialog.Builder(mContext)
1863                 .setMessage(r.getString(R.string.wifi_p2p_frequency_conflict_message,
1864                         getDeviceName(mSavedPeerConfig.deviceAddress)))
1865                 .setPositiveButton(r.getString(R.string.dlg_ok), new OnClickListener() {
1866                         @Override
1867                         public void onClick(DialogInterface dialog, int which) {
1868                             sendMessage(DROP_WIFI_USER_ACCEPT);
1869                         }
1870                     })
1871                 .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
1872                         @Override
1873                         public void onClick(DialogInterface dialog, int which) {
1874                             sendMessage(DROP_WIFI_USER_REJECT);
1875                         }
1876                     })
1877                 .setOnCancelListener(new DialogInterface.OnCancelListener() {
1878                         @Override
1879                         public void onCancel(DialogInterface arg0) {
1880                             sendMessage(DROP_WIFI_USER_REJECT);
1881                         }
1882                     })
1883                 .create();
1884 
1885             dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
1886             WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
1887             attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
1888             dialog.getWindow().setAttributes(attrs);
1889             dialog.show();
1890             mFrequencyConflictDialog = dialog;
1891         }
1892 
1893         @Override
processMessage(Message message)1894         public boolean processMessage(Message message) {
1895             if (DBG) logd(getName() + message.toString());
1896             switch (message.what) {
1897                 case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
1898                 case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
1899                     loge(getName() + "group sucess during freq conflict!");
1900                     break;
1901                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
1902                     loge(getName() + "group started after freq conflict, handle anyway");
1903                     deferMessage(message);
1904                     transitionTo(mGroupNegotiationState);
1905                     break;
1906                 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
1907                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
1908                 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
1909                     // Ignore failures since we retry again
1910                     break;
1911                 case DROP_WIFI_USER_REJECT:
1912                     // User rejected dropping wifi in favour of p2p
1913                     handleGroupCreationFailure();
1914                     transitionTo(mInactiveState);
1915                     break;
1916                 case DROP_WIFI_USER_ACCEPT:
1917                     // User accepted dropping wifi in favour of p2p
1918                     mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 1);
1919                     mTemporarilyDisconnectedWifi = true;
1920                     break;
1921                 case DISCONNECT_WIFI_RESPONSE:
1922                     // Got a response from wifistatemachine, retry p2p
1923                     if (DBG) logd(getName() + "Wifi disconnected, retry p2p");
1924                     transitionTo(mInactiveState);
1925                     sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
1926                     break;
1927                 default:
1928                     return NOT_HANDLED;
1929             }
1930             return HANDLED;
1931         }
1932 
exit()1933         public void exit() {
1934             if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss();
1935         }
1936     }
1937 
1938     class GroupCreatedState extends State {
1939         @Override
enter()1940         public void enter() {
1941             if (DBG) logd(getName());
1942             // Once connected, peer config details are invalid
1943             mSavedPeerConfig.invalidate();
1944             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
1945 
1946             updateThisDevice(WifiP2pDevice.CONNECTED);
1947 
1948             //DHCP server has already been started if I am a group owner
1949             if (mGroup.isGroupOwner()) {
1950                 setWifiP2pInfoOnGroupFormation(NetworkUtils.numericToInetAddress(SERVER_ADDRESS));
1951             }
1952 
1953             // In case of a negotiation group, connection changed is sent
1954             // after a client joins. For autonomous, send now
1955             if (mAutonomousGroup) {
1956                 sendP2pConnectionChangedBroadcast();
1957             }
1958         }
1959 
1960         @Override
processMessage(Message message)1961         public boolean processMessage(Message message) {
1962             if (DBG) logd(getName() + message.toString());
1963             switch (message.what) {
1964                 case WifiMonitor.AP_STA_CONNECTED_EVENT:
1965                     WifiP2pDevice device = (WifiP2pDevice) message.obj;
1966                     String deviceAddress = device.deviceAddress;
1967                     // Clear timeout that was set when group was started.
1968                     mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
1969                     if (deviceAddress != null) {
1970                         if (mPeers.get(deviceAddress) != null) {
1971                             mGroup.addClient(mPeers.get(deviceAddress));
1972                         } else {
1973                             mGroup.addClient(deviceAddress);
1974                         }
1975                         mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
1976                         if (DBG) logd(getName() + " ap sta connected");
1977                         sendPeersChangedBroadcast();
1978                     } else {
1979                         loge("Connect on null device address, ignore");
1980                     }
1981                     sendP2pConnectionChangedBroadcast();
1982                     break;
1983                 case WifiMonitor.AP_STA_DISCONNECTED_EVENT:
1984                     device = (WifiP2pDevice) message.obj;
1985                     deviceAddress = device.deviceAddress;
1986                     if (deviceAddress != null) {
1987                         mPeers.updateStatus(deviceAddress, WifiP2pDevice.AVAILABLE);
1988                         if (mGroup.removeClient(deviceAddress)) {
1989                             if (DBG) logd("Removed client " + deviceAddress);
1990                             if (!mAutonomousGroup && mGroup.isClientListEmpty()) {
1991                                 logd("Client list empty, remove non-persistent p2p group");
1992                                 mWifiNative.p2pGroupRemove(mGroup.getInterface());
1993                                 // We end up sending connection changed broadcast
1994                                 // when this happens at exit()
1995                             } else {
1996                                 // Notify when a client disconnects from group
1997                                 sendP2pConnectionChangedBroadcast();
1998                             }
1999                         } else {
2000                             if (DBG) logd("Failed to remove client " + deviceAddress);
2001                             for (WifiP2pDevice c : mGroup.getClientList()) {
2002                                 if (DBG) logd("client " + c.deviceAddress);
2003                             }
2004                         }
2005                         sendPeersChangedBroadcast();
2006                         if (DBG) logd(getName() + " ap sta disconnected");
2007                     } else {
2008                         loge("Disconnect on unknown device: " + device);
2009                     }
2010                     break;
2011                 case IPM_PRE_DHCP_ACTION:
2012                     mWifiNative.setP2pPowerSave(mGroup.getInterface(), false);
2013                     mIpManager.completedPreDhcpAction();
2014                     break;
2015                 case IPM_POST_DHCP_ACTION:
2016                     mWifiNative.setP2pPowerSave(mGroup.getInterface(), true);
2017                     break;
2018                 case IPM_DHCP_RESULTS:
2019                     mDhcpResults = (DhcpResults) message.obj;
2020                     break;
2021                 case IPM_PROVISIONING_SUCCESS:
2022                     if (DBG) logd("mDhcpResults: " + mDhcpResults);
2023                     setWifiP2pInfoOnGroupFormation(mDhcpResults.serverAddress);
2024                     sendP2pConnectionChangedBroadcast();
2025                     try {
2026                         final String ifname = mGroup.getInterface();
2027                         mNwService.addInterfaceToLocalNetwork(
2028                                 ifname, mDhcpResults.getRoutes(ifname));
2029                     } catch (RemoteException e) {
2030                         loge("Failed to add iface to local network " + e);
2031                     }
2032                     break;
2033                 case IPM_PROVISIONING_FAILURE:
2034                     loge("IP provisioning failed");
2035                     mWifiNative.p2pGroupRemove(mGroup.getInterface());
2036                     break;
2037                 case WifiP2pManager.REMOVE_GROUP:
2038                     if (DBG) logd(getName() + " remove group");
2039                     if (mWifiNative.p2pGroupRemove(mGroup.getInterface())) {
2040                         transitionTo(mOngoingGroupRemovalState);
2041                         replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
2042                     } else {
2043                         handleGroupRemoved();
2044                         transitionTo(mInactiveState);
2045                         replyToMessage(message, WifiP2pManager.REMOVE_GROUP_FAILED,
2046                                 WifiP2pManager.ERROR);
2047                     }
2048                     break;
2049                 /* We do not listen to NETWORK_DISCONNECTION_EVENT for group removal
2050                  * handling since supplicant actually tries to reconnect after a temporary
2051                  * disconnect until group idle time out. Eventually, a group removal event
2052                  * will come when group has been removed.
2053                  *
2054                  * When there are connectivity issues during temporary disconnect, the application
2055                  * will also just remove the group.
2056                  *
2057                  * Treating network disconnection as group removal causes race conditions since
2058                  * supplicant would still maintain the group at that stage.
2059                  */
2060                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
2061                     if (DBG) logd(getName() + " group removed");
2062                     handleGroupRemoved();
2063                     transitionTo(mInactiveState);
2064                     break;
2065                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
2066                     device = (WifiP2pDevice) message.obj;
2067                     //Device loss for a connected device indicates it is not in discovery any more
2068                     if (mGroup.contains(device)) {
2069                         if (DBG) logd("Add device to lost list " + device);
2070                         mPeersLostDuringConnection.updateSupplicantDetails(device);
2071                         return HANDLED;
2072                     }
2073                     // Do the regular device lost handling
2074                     return NOT_HANDLED;
2075                 case WifiStateMachine.CMD_DISABLE_P2P_REQ:
2076                     sendMessage(WifiP2pManager.REMOVE_GROUP);
2077                     deferMessage(message);
2078                     break;
2079                     // This allows any client to join the GO during the
2080                     // WPS window
2081                 case WifiP2pManager.START_WPS:
2082                     WpsInfo wps = (WpsInfo) message.obj;
2083                     if (wps == null) {
2084                         replyToMessage(message, WifiP2pManager.START_WPS_FAILED);
2085                         break;
2086                     }
2087                     boolean ret = true;
2088                     if (wps.setup == WpsInfo.PBC) {
2089                         ret = mWifiNative.startWpsPbc(mGroup.getInterface(), null);
2090                     } else {
2091                         if (wps.pin == null) {
2092                             String pin = mWifiNative.startWpsPinDisplay(mGroup.getInterface());
2093                             try {
2094                                 Integer.parseInt(pin);
2095                                 notifyInvitationSent(pin, "any");
2096                             } catch (NumberFormatException ignore) {
2097                                 ret = false;
2098                             }
2099                         } else {
2100                             ret = mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
2101                                     wps.pin);
2102                         }
2103                     }
2104                     replyToMessage(message, ret ? WifiP2pManager.START_WPS_SUCCEEDED :
2105                             WifiP2pManager.START_WPS_FAILED);
2106                     break;
2107                 case WifiP2pManager.CONNECT:
2108                     WifiP2pConfig config = (WifiP2pConfig) message.obj;
2109                     if (isConfigInvalid(config)) {
2110                         loge("Dropping connect requeset " + config);
2111                         replyToMessage(message, WifiP2pManager.CONNECT_FAILED);
2112                         break;
2113                     }
2114                     logd("Inviting device : " + config.deviceAddress);
2115                     mSavedPeerConfig = config;
2116                     if (mWifiNative.p2pInvite(mGroup, config.deviceAddress)) {
2117                         mPeers.updateStatus(config.deviceAddress, WifiP2pDevice.INVITED);
2118                         sendPeersChangedBroadcast();
2119                         replyToMessage(message, WifiP2pManager.CONNECT_SUCCEEDED);
2120                     } else {
2121                         replyToMessage(message, WifiP2pManager.CONNECT_FAILED,
2122                                 WifiP2pManager.ERROR);
2123                     }
2124                     // TODO: figure out updating the status to declined when invitation is rejected
2125                     break;
2126                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
2127                     P2pStatus status = (P2pStatus)message.obj;
2128                     if (status == P2pStatus.SUCCESS) {
2129                         // invocation was succeeded.
2130                         break;
2131                     }
2132                     loge("Invitation result " + status);
2133                     if (status == P2pStatus.UNKNOWN_P2P_GROUP) {
2134                         // target device has already removed the credential.
2135                         // So, remove this credential accordingly.
2136                         int netId = mGroup.getNetworkId();
2137                         if (netId >= 0) {
2138                             if (DBG) logd("Remove unknown client from the list");
2139                             if (!removeClientFromList(netId,
2140                                     mSavedPeerConfig.deviceAddress, false)) {
2141                                 // not found the client on the list
2142                                 loge("Already removed the client, ignore");
2143                                 break;
2144                             }
2145                             // try invitation.
2146                             sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
2147                         }
2148                     }
2149                     break;
2150                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
2151                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
2152                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
2153                     WifiP2pProvDiscEvent provDisc = (WifiP2pProvDiscEvent) message.obj;
2154                     mSavedPeerConfig = new WifiP2pConfig();
2155                     mSavedPeerConfig.deviceAddress = provDisc.device.deviceAddress;
2156                     if (message.what == WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT) {
2157                         mSavedPeerConfig.wps.setup = WpsInfo.KEYPAD;
2158                     } else if (message.what == WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT) {
2159                         mSavedPeerConfig.wps.setup = WpsInfo.DISPLAY;
2160                         mSavedPeerConfig.wps.pin = provDisc.pin;
2161                     } else {
2162                         mSavedPeerConfig.wps.setup = WpsInfo.PBC;
2163                     }
2164                     transitionTo(mUserAuthorizingJoinState);
2165                     break;
2166                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
2167                     loge("Duplicate group creation event notice, ignore");
2168                     break;
2169                 default:
2170                     return NOT_HANDLED;
2171             }
2172             return HANDLED;
2173         }
2174 
exit()2175         public void exit() {
2176             updateThisDevice(WifiP2pDevice.AVAILABLE);
2177             resetWifiP2pInfo();
2178             mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
2179             sendP2pConnectionChangedBroadcast();
2180         }
2181     }
2182 
2183     class UserAuthorizingJoinState extends State {
2184         @Override
enter()2185         public void enter() {
2186             if (DBG) logd(getName());
2187             notifyInvitationReceived();
2188         }
2189 
2190         @Override
processMessage(Message message)2191         public boolean processMessage(Message message) {
2192             if (DBG) logd(getName() + message.toString());
2193             switch (message.what) {
2194                 case WifiMonitor.P2P_PROV_DISC_PBC_REQ_EVENT:
2195                 case WifiMonitor.P2P_PROV_DISC_ENTER_PIN_EVENT:
2196                 case WifiMonitor.P2P_PROV_DISC_SHOW_PIN_EVENT:
2197                     //Ignore more client requests
2198                     break;
2199                 case PEER_CONNECTION_USER_ACCEPT:
2200                     //Stop discovery to avoid failure due to channel switch
2201                     mWifiNative.p2pStopFind();
2202                     if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
2203                         mWifiNative.startWpsPbc(mGroup.getInterface(), null);
2204                     } else {
2205                         mWifiNative.startWpsPinKeypad(mGroup.getInterface(),
2206                                 mSavedPeerConfig.wps.pin);
2207                     }
2208                     transitionTo(mGroupCreatedState);
2209                     break;
2210                 case PEER_CONNECTION_USER_REJECT:
2211                     if (DBG) logd("User rejected incoming request");
2212                     transitionTo(mGroupCreatedState);
2213                     break;
2214                 default:
2215                     return NOT_HANDLED;
2216             }
2217             return HANDLED;
2218         }
2219 
2220         @Override
exit()2221         public void exit() {
2222             //TODO: dismiss dialog if not already done
2223         }
2224     }
2225 
2226     class OngoingGroupRemovalState extends State {
2227         @Override
enter()2228         public void enter() {
2229             if (DBG) logd(getName());
2230         }
2231 
2232         @Override
processMessage(Message message)2233         public boolean processMessage(Message message) {
2234             if (DBG) logd(getName() + message.toString());
2235             switch (message.what) {
2236                 // Group removal ongoing. Multiple calls
2237                 // end up removing persisted network. Do nothing.
2238                 case WifiP2pManager.REMOVE_GROUP:
2239                     replyToMessage(message, WifiP2pManager.REMOVE_GROUP_SUCCEEDED);
2240                     break;
2241                 // Parent state will transition out of this state
2242                 // when removal is complete
2243                 default:
2244                     return NOT_HANDLED;
2245             }
2246             return HANDLED;
2247         }
2248     }
2249 
2250     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2251     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2252         super.dump(fd, pw, args);
2253         pw.println("mWifiP2pInfo " + mWifiP2pInfo);
2254         pw.println("mGroup " + mGroup);
2255         pw.println("mSavedPeerConfig " + mSavedPeerConfig);
2256         pw.println();
2257     }
2258 
sendP2pStateChangedBroadcast(boolean enabled)2259     private void sendP2pStateChangedBroadcast(boolean enabled) {
2260         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
2261         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2262         if (enabled) {
2263             intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
2264                     WifiP2pManager.WIFI_P2P_STATE_ENABLED);
2265         } else {
2266             intent.putExtra(WifiP2pManager.EXTRA_WIFI_STATE,
2267                     WifiP2pManager.WIFI_P2P_STATE_DISABLED);
2268         }
2269         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2270     }
2271 
sendP2pDiscoveryChangedBroadcast(boolean started)2272     private void sendP2pDiscoveryChangedBroadcast(boolean started) {
2273         if (mDiscoveryStarted == started) return;
2274         mDiscoveryStarted = started;
2275 
2276         if (DBG) logd("discovery change broadcast " + started);
2277 
2278         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION);
2279         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2280         intent.putExtra(WifiP2pManager.EXTRA_DISCOVERY_STATE, started ?
2281                 WifiP2pManager.WIFI_P2P_DISCOVERY_STARTED :
2282                 WifiP2pManager.WIFI_P2P_DISCOVERY_STOPPED);
2283         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2284     }
2285 
sendThisDeviceChangedBroadcast()2286     private void sendThisDeviceChangedBroadcast() {
2287         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
2288         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2289         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE, new WifiP2pDevice(mThisDevice));
2290         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2291     }
2292 
sendPeersChangedBroadcast()2293     private void sendPeersChangedBroadcast() {
2294         final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
2295         intent.putExtra(WifiP2pManager.EXTRA_P2P_DEVICE_LIST, new WifiP2pDeviceList(mPeers));
2296         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2297         mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2298     }
2299 
sendP2pConnectionChangedBroadcast()2300     private void sendP2pConnectionChangedBroadcast() {
2301         if (DBG) logd("sending p2p connection changed broadcast");
2302         Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
2303         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
2304                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
2305         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo));
2306         intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo));
2307         intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, new WifiP2pGroup(mGroup));
2308         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2309         mWifiChannel.sendMessage(WifiP2pServiceImpl.P2P_CONNECTION_CHANGED,
2310                 new NetworkInfo(mNetworkInfo));
2311     }
2312 
sendP2pPersistentGroupsChangedBroadcast()2313     private void sendP2pPersistentGroupsChangedBroadcast() {
2314         if (DBG) logd("sending p2p persistent groups changed broadcast");
2315         Intent intent = new Intent(WifiP2pManager.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION);
2316         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2317         mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2318     }
2319 
startDhcpServer(String intf)2320     private void startDhcpServer(String intf) {
2321         InterfaceConfiguration ifcg = null;
2322         try {
2323             ifcg = mNwService.getInterfaceConfig(intf);
2324             ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(
2325                         SERVER_ADDRESS), 24));
2326             ifcg.setInterfaceUp();
2327             mNwService.setInterfaceConfig(intf, ifcg);
2328             /* This starts the dnsmasq server */
2329             ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
2330                     Context.CONNECTIVITY_SERVICE);
2331             String[] tetheringDhcpRanges = cm.getTetheredDhcpRanges();
2332             if (mNwService.isTetheringStarted()) {
2333                 if (DBG) logd("Stop existing tethering and restart it");
2334                 mNwService.stopTethering();
2335             }
2336             mNwService.tetherInterface(intf);
2337             mNwService.startTethering(tetheringDhcpRanges);
2338         } catch (Exception e) {
2339             loge("Error configuring interface " + intf + ", :" + e);
2340             return;
2341         }
2342 
2343         logd("Started Dhcp server on " + intf);
2344    }
2345 
stopDhcpServer(String intf)2346     private void stopDhcpServer(String intf) {
2347         try {
2348             mNwService.untetherInterface(intf);
2349             for (String temp : mNwService.listTetheredInterfaces()) {
2350                 logd("List all interfaces " + temp);
2351                 if (temp.compareTo(intf) != 0) {
2352                     logd("Found other tethering interfaces, so keep tethering alive");
2353                     return;
2354                 }
2355             }
2356             mNwService.stopTethering();
2357         } catch (Exception e) {
2358             loge("Error stopping Dhcp server" + e);
2359             return;
2360         } finally {
2361             logd("Stopped Dhcp server");
2362         }
2363     }
2364 
notifyP2pEnableFailure()2365     private void notifyP2pEnableFailure() {
2366         Resources r = Resources.getSystem();
2367         AlertDialog dialog = new AlertDialog.Builder(mContext)
2368             .setTitle(r.getString(R.string.wifi_p2p_dialog_title))
2369             .setMessage(r.getString(R.string.wifi_p2p_failed_message))
2370             .setPositiveButton(r.getString(R.string.ok), null)
2371             .create();
2372         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2373         WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
2374         attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
2375         dialog.getWindow().setAttributes(attrs);
2376         dialog.show();
2377     }
2378 
addRowToDialog(ViewGroup group, int stringId, String value)2379     private void addRowToDialog(ViewGroup group, int stringId, String value) {
2380         Resources r = Resources.getSystem();
2381         View row = LayoutInflater.from(mContext).inflate(R.layout.wifi_p2p_dialog_row,
2382                 group, false);
2383         ((TextView) row.findViewById(R.id.name)).setText(r.getString(stringId));
2384         ((TextView) row.findViewById(R.id.value)).setText(value);
2385         group.addView(row);
2386     }
2387 
notifyInvitationSent(String pin, String peerAddress)2388     private void notifyInvitationSent(String pin, String peerAddress) {
2389         Resources r = Resources.getSystem();
2390 
2391         final View textEntryView = LayoutInflater.from(mContext)
2392                 .inflate(R.layout.wifi_p2p_dialog, null);
2393 
2394         ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
2395         addRowToDialog(group, R.string.wifi_p2p_to_message, getDeviceName(peerAddress));
2396         addRowToDialog(group, R.string.wifi_p2p_show_pin_message, pin);
2397 
2398         AlertDialog dialog = new AlertDialog.Builder(mContext)
2399             .setTitle(r.getString(R.string.wifi_p2p_invitation_sent_title))
2400             .setView(textEntryView)
2401             .setPositiveButton(r.getString(R.string.ok), null)
2402             .create();
2403         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2404         WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
2405         attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
2406         dialog.getWindow().setAttributes(attrs);
2407         dialog.show();
2408     }
2409 
notifyInvitationReceived()2410     private void notifyInvitationReceived() {
2411         Resources r = Resources.getSystem();
2412         final WpsInfo wps = mSavedPeerConfig.wps;
2413         final View textEntryView = LayoutInflater.from(mContext)
2414                 .inflate(R.layout.wifi_p2p_dialog, null);
2415 
2416         ViewGroup group = (ViewGroup) textEntryView.findViewById(R.id.info);
2417         addRowToDialog(group, R.string.wifi_p2p_from_message, getDeviceName(
2418                 mSavedPeerConfig.deviceAddress));
2419 
2420         final EditText pin = (EditText) textEntryView.findViewById(R.id.wifi_p2p_wps_pin);
2421 
2422         AlertDialog dialog = new AlertDialog.Builder(mContext)
2423             .setTitle(r.getString(R.string.wifi_p2p_invitation_to_connect_title))
2424             .setView(textEntryView)
2425             .setPositiveButton(r.getString(R.string.accept), new OnClickListener() {
2426                         public void onClick(DialogInterface dialog, int which) {
2427                             if (wps.setup == WpsInfo.KEYPAD) {
2428                                 mSavedPeerConfig.wps.pin = pin.getText().toString();
2429                             }
2430                             if (DBG) logd(getName() + " accept invitation " + mSavedPeerConfig);
2431                             sendMessage(PEER_CONNECTION_USER_ACCEPT);
2432                         }
2433                     })
2434             .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
2435                         @Override
2436                         public void onClick(DialogInterface dialog, int which) {
2437                             if (DBG) logd(getName() + " ignore connect");
2438                             sendMessage(PEER_CONNECTION_USER_REJECT);
2439                         }
2440                     })
2441             .setOnCancelListener(new DialogInterface.OnCancelListener() {
2442                         @Override
2443                         public void onCancel(DialogInterface arg0) {
2444                             if (DBG) logd(getName() + " ignore connect");
2445                             sendMessage(PEER_CONNECTION_USER_REJECT);
2446                         }
2447                     })
2448             .create();
2449 
2450         //make the enter pin area or the display pin area visible
2451         switch (wps.setup) {
2452             case WpsInfo.KEYPAD:
2453                 if (DBG) logd("Enter pin section visible");
2454                 textEntryView.findViewById(R.id.enter_pin_section).setVisibility(View.VISIBLE);
2455                 break;
2456             case WpsInfo.DISPLAY:
2457                 if (DBG) logd("Shown pin section visible");
2458                 addRowToDialog(group, R.string.wifi_p2p_show_pin_message, wps.pin);
2459                 break;
2460             default:
2461                 break;
2462         }
2463 
2464         if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_APPLIANCE) ==
2465                 Configuration.UI_MODE_TYPE_APPLIANCE) {
2466             // For appliance devices, add a key listener which accepts.
2467             dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
2468 
2469                 @Override
2470                 public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
2471                     // TODO: make the actual key come from a config value.
2472                     if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
2473                         sendMessage(PEER_CONNECTION_USER_ACCEPT);
2474                         dialog.dismiss();
2475                         return true;
2476                     }
2477                     return false;
2478                 }
2479             });
2480             // TODO: add timeout for this dialog.
2481             // TODO: update UI in appliance mode to tell user what to do.
2482         }
2483 
2484         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
2485         WindowManager.LayoutParams attrs = dialog.getWindow().getAttributes();
2486         attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
2487         dialog.getWindow().setAttributes(attrs);
2488         dialog.show();
2489     }
2490 
2491     /**
2492      * Synchronize the persistent group list between
2493      * wpa_supplicant and mGroups.
2494      */
updatePersistentNetworks(boolean reload)2495     private void updatePersistentNetworks(boolean reload) {
2496         String listStr = mWifiNative.listNetworks();
2497         if (listStr == null) return;
2498 
2499         boolean isSaveRequired = false;
2500         String[] lines = listStr.split("\n");
2501         if (lines == null) return;
2502 
2503         if (reload) mGroups.clear();
2504 
2505         // Skip the first line, which is a header
2506         for (int i = 1; i < lines.length; i++) {
2507             String[] result = lines[i].split("\t");
2508             if (result == null || result.length < 4) {
2509                 continue;
2510             }
2511             // network-id | ssid | bssid | flags
2512             int netId = -1;
2513             String ssid = result[1];
2514             String bssid = result[2];
2515             String flags = result[3];
2516             try {
2517                 netId = Integer.parseInt(result[0]);
2518             } catch(NumberFormatException e) {
2519                 e.printStackTrace();
2520                 continue;
2521             }
2522 
2523             if (flags.indexOf("[CURRENT]") != -1) {
2524                 continue;
2525             }
2526             if (flags.indexOf("[P2P-PERSISTENT]") == -1) {
2527                 /*
2528                  * The unused profile is sometimes remained when the p2p group formation is failed.
2529                  * So, we clean up the p2p group here.
2530                  */
2531                 if (DBG) logd("clean up the unused persistent group. netId=" + netId);
2532                 mWifiNative.removeNetwork(netId);
2533                 isSaveRequired = true;
2534                 continue;
2535             }
2536 
2537             if (mGroups.contains(netId)) {
2538                 continue;
2539             }
2540 
2541             WifiP2pGroup group = new WifiP2pGroup();
2542             group.setNetworkId(netId);
2543             group.setNetworkName(ssid);
2544             String mode = mWifiNative.getNetworkVariable(netId, "mode");
2545             if (mode != null && mode.equals("3")) {
2546                 group.setIsGroupOwner(true);
2547             }
2548             if (bssid.equalsIgnoreCase(mThisDevice.deviceAddress)) {
2549                 group.setOwner(mThisDevice);
2550             } else {
2551                 WifiP2pDevice device = new WifiP2pDevice();
2552                 device.deviceAddress = bssid;
2553                 group.setOwner(device);
2554             }
2555             mGroups.add(group);
2556             isSaveRequired = true;
2557         }
2558 
2559         if (reload || isSaveRequired) {
2560             mWifiNative.saveConfig();
2561             sendP2pPersistentGroupsChangedBroadcast();
2562         }
2563     }
2564 
2565     /**
2566      * A config is valid if it has a peer address that has already been
2567      * discovered
2568      * @return true if it is invalid, false otherwise
2569      */
isConfigInvalid(WifiP2pConfig config)2570     private boolean isConfigInvalid(WifiP2pConfig config) {
2571         if (config == null) return true;
2572         if (TextUtils.isEmpty(config.deviceAddress)) return true;
2573         if (mPeers.get(config.deviceAddress) == null) return true;
2574         return false;
2575     }
2576 
2577     /* TODO: The supplicant does not provide group capability changes as an event.
2578      * Having it pushed as an event would avoid polling for this information right
2579      * before a connection
2580      */
fetchCurrentDeviceDetails(WifiP2pConfig config)2581     private WifiP2pDevice fetchCurrentDeviceDetails(WifiP2pConfig config) {
2582         /* Fetch & update group capability from supplicant on the device */
2583         int gc = mWifiNative.getGroupCapability(config.deviceAddress);
2584         mPeers.updateGroupCapability(config.deviceAddress, gc);
2585         return mPeers.get(config.deviceAddress);
2586     }
2587 
2588     /**
2589      * Start a p2p group negotiation and display pin if necessary
2590      * @param config for the peer
2591      */
p2pConnectWithPinDisplay(WifiP2pConfig config)2592     private void p2pConnectWithPinDisplay(WifiP2pConfig config) {
2593         WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
2594 
2595         String pin = mWifiNative.p2pConnect(config, dev.isGroupOwner());
2596         try {
2597             Integer.parseInt(pin);
2598             notifyInvitationSent(pin, config.deviceAddress);
2599         } catch (NumberFormatException ignore) {
2600             // do nothing if p2pConnect did not return a pin
2601         }
2602     }
2603 
2604     /**
2605      * Reinvoke a persistent group.
2606      *
2607      * @param config for the peer
2608      * @return true on success, false on failure
2609      */
reinvokePersistentGroup(WifiP2pConfig config)2610     private boolean reinvokePersistentGroup(WifiP2pConfig config) {
2611         WifiP2pDevice dev = fetchCurrentDeviceDetails(config);
2612 
2613         boolean join = dev.isGroupOwner();
2614         String ssid = mWifiNative.p2pGetSsid(dev.deviceAddress);
2615         if (DBG) logd("target ssid is " + ssid + " join:" + join);
2616 
2617         if (join && dev.isGroupLimit()) {
2618             if (DBG) logd("target device reaches group limit.");
2619 
2620             // if the target group has reached the limit,
2621             // try group formation.
2622             join = false;
2623         } else if (join) {
2624             int netId = mGroups.getNetworkId(dev.deviceAddress, ssid);
2625             if (netId >= 0) {
2626                 // Skip WPS and start 4way handshake immediately.
2627                 if (!mWifiNative.p2pGroupAdd(netId)) {
2628                     return false;
2629                 }
2630                 return true;
2631             }
2632         }
2633 
2634         if (!join && dev.isDeviceLimit()) {
2635             loge("target device reaches the device limit.");
2636             return false;
2637         }
2638 
2639         if (!join && dev.isInvitationCapable()) {
2640             int netId = WifiP2pGroup.PERSISTENT_NET_ID;
2641             if (config.netId >= 0) {
2642                 if (config.deviceAddress.equals(mGroups.getOwnerAddr(config.netId))) {
2643                     netId = config.netId;
2644                 }
2645             } else {
2646                 netId = mGroups.getNetworkId(dev.deviceAddress);
2647             }
2648             if (netId < 0) {
2649                 netId = getNetworkIdFromClientList(dev.deviceAddress);
2650             }
2651             if (DBG) logd("netId related with " + dev.deviceAddress + " = " + netId);
2652             if (netId >= 0) {
2653                 // Invoke the persistent group.
2654                 if (mWifiNative.p2pReinvoke(netId, dev.deviceAddress)) {
2655                     // Save network id. It'll be used when an invitation result event is received.
2656                     config.netId = netId;
2657                     return true;
2658                 } else {
2659                     loge("p2pReinvoke() failed, update networks");
2660                     updatePersistentNetworks(RELOAD);
2661                     return false;
2662                 }
2663             }
2664         }
2665 
2666         return false;
2667     }
2668 
2669     /**
2670      * Return the network id of the group owner profile which has the p2p client with
2671      * the specified device address in it's client list.
2672      * If more than one persistent group of the same address is present in its client
2673      * lists, return the first one.
2674      *
2675      * @param deviceAddress p2p device address.
2676      * @return the network id. if not found, return -1.
2677      */
getNetworkIdFromClientList(String deviceAddress)2678     private int getNetworkIdFromClientList(String deviceAddress) {
2679         if (deviceAddress == null) return -1;
2680 
2681         Collection<WifiP2pGroup> groups = mGroups.getGroupList();
2682         for (WifiP2pGroup group : groups) {
2683             int netId = group.getNetworkId();
2684             String[] p2pClientList = getClientList(netId);
2685             if (p2pClientList == null) continue;
2686             for (String client : p2pClientList) {
2687                 if (deviceAddress.equalsIgnoreCase(client)) {
2688                     return netId;
2689                 }
2690             }
2691         }
2692         return -1;
2693     }
2694 
2695     /**
2696      * Return p2p client list associated with the specified network id.
2697      * @param netId network id.
2698      * @return p2p client list. if not found, return null.
2699      */
getClientList(int netId)2700     private String[] getClientList(int netId) {
2701         String p2pClients = mWifiNative.getNetworkVariable(netId, "p2p_client_list");
2702         if (p2pClients == null) {
2703             return null;
2704         }
2705         return p2pClients.split(" ");
2706     }
2707 
2708     /**
2709      * Remove the specified p2p client from the specified profile.
2710      * @param netId network id of the profile.
2711      * @param addr p2p client address to be removed.
2712      * @param isRemovable if true, remove the specified profile if its client list becomes empty.
2713      * @return whether removing the specified p2p client is successful or not.
2714      */
removeClientFromList(int netId, String addr, boolean isRemovable)2715     private boolean removeClientFromList(int netId, String addr, boolean isRemovable) {
2716         StringBuilder modifiedClientList =  new StringBuilder();
2717         String[] currentClientList = getClientList(netId);
2718         boolean isClientRemoved = false;
2719         if (currentClientList != null) {
2720             for (String client : currentClientList) {
2721                 if (!client.equalsIgnoreCase(addr)) {
2722                     modifiedClientList.append(" ");
2723                     modifiedClientList.append(client);
2724                 } else {
2725                     isClientRemoved = true;
2726                 }
2727             }
2728         }
2729         if (modifiedClientList.length() == 0 && isRemovable) {
2730             // the client list is empty. so remove it.
2731             if (DBG) logd("Remove unknown network");
2732             mGroups.remove(netId);
2733             return true;
2734         }
2735 
2736         if (!isClientRemoved) {
2737             // specified p2p client is not found. already removed.
2738             return false;
2739         }
2740 
2741         if (DBG) logd("Modified client list: " + modifiedClientList);
2742         if (modifiedClientList.length() == 0) {
2743             modifiedClientList.append("\"\"");
2744         }
2745         mWifiNative.setNetworkVariable(netId,
2746                 "p2p_client_list", modifiedClientList.toString());
2747         mWifiNative.saveConfig();
2748         return true;
2749     }
2750 
setWifiP2pInfoOnGroupFormation(InetAddress serverInetAddress)2751     private void setWifiP2pInfoOnGroupFormation(InetAddress serverInetAddress) {
2752         mWifiP2pInfo.groupFormed = true;
2753         mWifiP2pInfo.isGroupOwner = mGroup.isGroupOwner();
2754         mWifiP2pInfo.groupOwnerAddress = serverInetAddress;
2755     }
2756 
resetWifiP2pInfo()2757     private void resetWifiP2pInfo() {
2758         mWifiP2pInfo.groupFormed = false;
2759         mWifiP2pInfo.isGroupOwner = false;
2760         mWifiP2pInfo.groupOwnerAddress = null;
2761     }
2762 
getDeviceName(String deviceAddress)2763     private String getDeviceName(String deviceAddress) {
2764         WifiP2pDevice d = mPeers.get(deviceAddress);
2765         if (d != null) {
2766                 return d.deviceName;
2767         }
2768         //Treat the address as name if there is no match
2769         return deviceAddress;
2770     }
2771 
getPersistedDeviceName()2772     private String getPersistedDeviceName() {
2773         String deviceName = Settings.Global.getString(mContext.getContentResolver(),
2774                 Settings.Global.WIFI_P2P_DEVICE_NAME);
2775         if (deviceName == null) {
2776             /* We use the 4 digits of the ANDROID_ID to have a friendly
2777              * default that has low likelihood of collision with a peer */
2778             String id = Settings.Secure.getString(mContext.getContentResolver(),
2779                     Settings.Secure.ANDROID_ID);
2780             return "Android_" + id.substring(0,4);
2781         }
2782         return deviceName;
2783     }
2784 
setAndPersistDeviceName(String devName)2785     private boolean setAndPersistDeviceName(String devName) {
2786         if (devName == null) return false;
2787 
2788         if (!mWifiNative.setDeviceName(devName)) {
2789             loge("Failed to set device name " + devName);
2790             return false;
2791         }
2792 
2793         mThisDevice.deviceName = devName;
2794         mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
2795 
2796         Settings.Global.putString(mContext.getContentResolver(),
2797                 Settings.Global.WIFI_P2P_DEVICE_NAME, devName);
2798         sendThisDeviceChangedBroadcast();
2799         return true;
2800     }
2801 
setWfdInfo(WifiP2pWfdInfo wfdInfo)2802     private boolean setWfdInfo(WifiP2pWfdInfo wfdInfo) {
2803         boolean success;
2804 
2805         if (!wfdInfo.isWfdEnabled()) {
2806             success = mWifiNative.setWfdEnable(false);
2807         } else {
2808             success =
2809                 mWifiNative.setWfdEnable(true)
2810                 && mWifiNative.setWfdDeviceInfo(wfdInfo.getDeviceInfoHex());
2811         }
2812 
2813         if (!success) {
2814             loge("Failed to set wfd properties");
2815             return false;
2816         }
2817 
2818         mThisDevice.wfdInfo = wfdInfo;
2819         sendThisDeviceChangedBroadcast();
2820         return true;
2821     }
2822 
initializeP2pSettings()2823     private void initializeP2pSettings() {
2824         mWifiNative.setPersistentReconnect(true);
2825         mThisDevice.deviceName = getPersistedDeviceName();
2826         mWifiNative.setDeviceName(mThisDevice.deviceName);
2827         // DIRECT-XY-DEVICENAME (XY is randomly generated)
2828         mWifiNative.setP2pSsidPostfix("-" + mThisDevice.deviceName);
2829         mWifiNative.setDeviceType(mThisDevice.primaryDeviceType);
2830         // Supplicant defaults to using virtual display with display
2831         // which refers to a remote display. Use physical_display
2832         mWifiNative.setConfigMethods("virtual_push_button physical_display keypad");
2833         // STA has higher priority over P2P
2834         mWifiNative.setConcurrencyPriority("sta");
2835 
2836         mThisDevice.deviceAddress = mWifiNative.p2pGetDeviceAddress();
2837         updateThisDevice(WifiP2pDevice.AVAILABLE);
2838         if (DBG) logd("DeviceAddress: " + mThisDevice.deviceAddress);
2839 
2840         mClientInfoList.clear();
2841         mWifiNative.p2pFlush();
2842         mWifiNative.p2pServiceFlush();
2843         mServiceTransactionId = 0;
2844         mServiceDiscReqId = null;
2845 
2846         updatePersistentNetworks(RELOAD);
2847     }
2848 
updateThisDevice(int status)2849     private void updateThisDevice(int status) {
2850         mThisDevice.status = status;
2851         sendThisDeviceChangedBroadcast();
2852     }
2853 
handleGroupCreationFailure()2854     private void handleGroupCreationFailure() {
2855         resetWifiP2pInfo();
2856         mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.FAILED, null, null);
2857         sendP2pConnectionChangedBroadcast();
2858 
2859         // Remove only the peer we failed to connect to so that other devices discovered
2860         // that have not timed out still remain in list for connection
2861         boolean peersChanged = mPeers.remove(mPeersLostDuringConnection);
2862         if (TextUtils.isEmpty(mSavedPeerConfig.deviceAddress) == false &&
2863                 mPeers.remove(mSavedPeerConfig.deviceAddress) != null) {
2864             peersChanged = true;
2865         }
2866         if (peersChanged) {
2867             sendPeersChangedBroadcast();
2868         }
2869 
2870         mPeersLostDuringConnection.clear();
2871         mServiceDiscReqId = null;
2872         sendMessage(WifiP2pManager.DISCOVER_PEERS);
2873     }
2874 
handleGroupRemoved()2875     private void handleGroupRemoved() {
2876         if (mGroup.isGroupOwner()) {
2877             stopDhcpServer(mGroup.getInterface());
2878         } else {
2879             if (DBG) logd("stop IpManager");
2880             stopIpManager();
2881             try {
2882                 mNwService.removeInterfaceFromLocalNetwork(mGroup.getInterface());
2883             } catch (RemoteException e) {
2884                 loge("Failed to remove iface from local network " + e);
2885             }
2886         }
2887 
2888         try {
2889             mNwService.clearInterfaceAddresses(mGroup.getInterface());
2890         } catch (Exception e) {
2891             loge("Failed to clear addresses " + e);
2892         }
2893 
2894         // Clear any timeout that was set. This is essential for devices
2895         // that reuse the main p2p interface for a created group.
2896         mWifiNative.setP2pGroupIdle(mGroup.getInterface(), 0);
2897 
2898         boolean peersChanged = false;
2899         // Remove only peers part of the group, so that other devices discovered
2900         // that have not timed out still remain in list for connection
2901         for (WifiP2pDevice d : mGroup.getClientList()) {
2902             if (mPeers.remove(d)) peersChanged = true;
2903         }
2904         if (mPeers.remove(mGroup.getOwner())) peersChanged = true;
2905         if (mPeers.remove(mPeersLostDuringConnection)) peersChanged = true;
2906         if (peersChanged) {
2907             sendPeersChangedBroadcast();
2908         }
2909 
2910         mGroup = null;
2911         mPeersLostDuringConnection.clear();
2912         mServiceDiscReqId = null;
2913 
2914         if (mTemporarilyDisconnectedWifi) {
2915             mWifiChannel.sendMessage(WifiP2pServiceImpl.DISCONNECT_WIFI_REQUEST, 0);
2916             mTemporarilyDisconnectedWifi = false;
2917         }
2918     }
2919 
2920     //State machine initiated requests can have replyTo set to null indicating
2921     //there are no recipients, we ignore those reply actions
replyToMessage(Message msg, int what)2922     private void replyToMessage(Message msg, int what) {
2923         if (msg.replyTo == null) return;
2924         Message dstMsg = obtainMessage(msg);
2925         dstMsg.what = what;
2926         mReplyChannel.replyToMessage(msg, dstMsg);
2927     }
2928 
replyToMessage(Message msg, int what, int arg1)2929     private void replyToMessage(Message msg, int what, int arg1) {
2930         if (msg.replyTo == null) return;
2931         Message dstMsg = obtainMessage(msg);
2932         dstMsg.what = what;
2933         dstMsg.arg1 = arg1;
2934         mReplyChannel.replyToMessage(msg, dstMsg);
2935     }
2936 
replyToMessage(Message msg, int what, Object obj)2937     private void replyToMessage(Message msg, int what, Object obj) {
2938         if (msg.replyTo == null) return;
2939         Message dstMsg = obtainMessage(msg);
2940         dstMsg.what = what;
2941         dstMsg.obj = obj;
2942         mReplyChannel.replyToMessage(msg, dstMsg);
2943     }
2944 
2945     /* arg2 on the source message has a hash code that needs to be retained in replies
2946      * see WifiP2pManager for details */
obtainMessage(Message srcMsg)2947     private Message obtainMessage(Message srcMsg) {
2948         Message msg = Message.obtain();
2949         msg.arg2 = srcMsg.arg2;
2950         return msg;
2951     }
2952 
2953     @Override
logd(String s)2954     protected void logd(String s) {
2955         Slog.d(TAG, s);
2956     }
2957 
2958     @Override
loge(String s)2959     protected void loge(String s) {
2960         Slog.e(TAG, s);
2961     }
2962 
2963     /**
2964      * Update service discovery request to wpa_supplicant.
2965      */
updateSupplicantServiceRequest()2966     private boolean updateSupplicantServiceRequest() {
2967         clearSupplicantServiceRequest();
2968 
2969         StringBuffer sb = new StringBuffer();
2970         for (ClientInfo c: mClientInfoList.values()) {
2971             int key;
2972             WifiP2pServiceRequest req;
2973             for (int i=0; i < c.mReqList.size(); i++) {
2974                 req = c.mReqList.valueAt(i);
2975                 if (req != null) {
2976                     sb.append(req.getSupplicantQuery());
2977                 }
2978             }
2979         }
2980 
2981         if (sb.length() == 0) {
2982             return false;
2983         }
2984 
2985         mServiceDiscReqId = mWifiNative.p2pServDiscReq("00:00:00:00:00:00", sb.toString());
2986         if (mServiceDiscReqId == null) {
2987             return false;
2988         }
2989         return true;
2990     }
2991 
2992     /**
2993      * Clear service discovery request in wpa_supplicant
2994      */
clearSupplicantServiceRequest()2995     private void clearSupplicantServiceRequest() {
2996         if (mServiceDiscReqId == null) return;
2997 
2998         mWifiNative.p2pServDiscCancelReq(mServiceDiscReqId);
2999         mServiceDiscReqId = null;
3000     }
3001 
3002     /* TODO: We could track individual service adds separately and avoid
3003      * having to do update all service requests on every new request
3004      */
addServiceRequest(Messenger m, WifiP2pServiceRequest req)3005     private boolean addServiceRequest(Messenger m, WifiP2pServiceRequest req) {
3006         clearClientDeadChannels();
3007         ClientInfo clientInfo = getClientInfo(m, true);
3008         if (clientInfo == null) {
3009             return false;
3010         }
3011 
3012         ++mServiceTransactionId;
3013         //The Wi-Fi p2p spec says transaction id should be non-zero
3014         if (mServiceTransactionId == 0) ++mServiceTransactionId;
3015         req.setTransactionId(mServiceTransactionId);
3016         clientInfo.mReqList.put(mServiceTransactionId, req);
3017 
3018         if (mServiceDiscReqId == null) {
3019             return true;
3020         }
3021 
3022         return updateSupplicantServiceRequest();
3023     }
3024 
removeServiceRequest(Messenger m, WifiP2pServiceRequest req)3025     private void removeServiceRequest(Messenger m, WifiP2pServiceRequest req) {
3026         ClientInfo clientInfo = getClientInfo(m, false);
3027         if (clientInfo == null) {
3028             return;
3029         }
3030 
3031         //Application does not have transaction id information
3032         //go through stored requests to remove
3033         boolean removed = false;
3034         for (int i=0; i<clientInfo.mReqList.size(); i++) {
3035             if (req.equals(clientInfo.mReqList.valueAt(i))) {
3036                 removed = true;
3037                 clientInfo.mReqList.removeAt(i);
3038                 break;
3039             }
3040         }
3041 
3042         if (!removed) return;
3043 
3044         if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
3045             if (DBG) logd("remove client information from framework");
3046             mClientInfoList.remove(clientInfo.mMessenger);
3047         }
3048 
3049         if (mServiceDiscReqId == null) {
3050             return;
3051         }
3052 
3053         updateSupplicantServiceRequest();
3054     }
3055 
clearServiceRequests(Messenger m)3056     private void clearServiceRequests(Messenger m) {
3057 
3058         ClientInfo clientInfo = getClientInfo(m, false);
3059         if (clientInfo == null) {
3060             return;
3061         }
3062 
3063         if (clientInfo.mReqList.size() == 0) {
3064             return;
3065         }
3066 
3067         clientInfo.mReqList.clear();
3068 
3069         if (clientInfo.mServList.size() == 0) {
3070             if (DBG) logd("remove channel information from framework");
3071             mClientInfoList.remove(clientInfo.mMessenger);
3072         }
3073 
3074         if (mServiceDiscReqId == null) {
3075             return;
3076         }
3077 
3078         updateSupplicantServiceRequest();
3079     }
3080 
addLocalService(Messenger m, WifiP2pServiceInfo servInfo)3081     private boolean addLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
3082         clearClientDeadChannels();
3083         ClientInfo clientInfo = getClientInfo(m, true);
3084         if (clientInfo == null) {
3085             return false;
3086         }
3087 
3088         if (!clientInfo.mServList.add(servInfo)) {
3089             return false;
3090         }
3091 
3092         if (!mWifiNative.p2pServiceAdd(servInfo)) {
3093             clientInfo.mServList.remove(servInfo);
3094             return false;
3095         }
3096 
3097         return true;
3098     }
3099 
removeLocalService(Messenger m, WifiP2pServiceInfo servInfo)3100     private void removeLocalService(Messenger m, WifiP2pServiceInfo servInfo) {
3101         ClientInfo clientInfo = getClientInfo(m, false);
3102         if (clientInfo == null) {
3103             return;
3104         }
3105 
3106         mWifiNative.p2pServiceDel(servInfo);
3107 
3108         clientInfo.mServList.remove(servInfo);
3109         if (clientInfo.mReqList.size() == 0 && clientInfo.mServList.size() == 0) {
3110             if (DBG) logd("remove client information from framework");
3111             mClientInfoList.remove(clientInfo.mMessenger);
3112         }
3113     }
3114 
clearLocalServices(Messenger m)3115     private void clearLocalServices(Messenger m) {
3116         ClientInfo clientInfo = getClientInfo(m, false);
3117         if (clientInfo == null) {
3118             return;
3119         }
3120 
3121         for (WifiP2pServiceInfo servInfo: clientInfo.mServList) {
3122             mWifiNative.p2pServiceDel(servInfo);
3123         }
3124 
3125         clientInfo.mServList.clear();
3126         if (clientInfo.mReqList.size() == 0) {
3127             if (DBG) logd("remove client information from framework");
3128             mClientInfoList.remove(clientInfo.mMessenger);
3129         }
3130     }
3131 
clearClientInfo(Messenger m)3132     private void clearClientInfo(Messenger m) {
3133         clearLocalServices(m);
3134         clearServiceRequests(m);
3135     }
3136 
3137     /**
3138      * Send the service response to the WifiP2pManager.Channel.
3139      *
3140      * @param resp
3141      */
sendServiceResponse(WifiP2pServiceResponse resp)3142     private void sendServiceResponse(WifiP2pServiceResponse resp) {
3143         for (ClientInfo c : mClientInfoList.values()) {
3144             WifiP2pServiceRequest req = c.mReqList.get(resp.getTransactionId());
3145             if (req != null) {
3146                 Message msg = Message.obtain();
3147                 msg.what = WifiP2pManager.RESPONSE_SERVICE;
3148                 msg.arg1 = 0;
3149                 msg.arg2 = 0;
3150                 msg.obj = resp;
3151                 try {
3152                     c.mMessenger.send(msg);
3153                 } catch (RemoteException e) {
3154                     if (DBG) logd("detect dead channel");
3155                     clearClientInfo(c.mMessenger);
3156                     return;
3157                 }
3158             }
3159         }
3160     }
3161 
3162     /**
3163      * We dont get notifications of clients that have gone away.
3164      * We detect this actively when services are added and throw
3165      * them away.
3166      *
3167      * TODO: This can be done better with full async channels.
3168      */
clearClientDeadChannels()3169     private void clearClientDeadChannels() {
3170         ArrayList<Messenger> deadClients = new ArrayList<Messenger>();
3171 
3172         for (ClientInfo c : mClientInfoList.values()) {
3173             Message msg = Message.obtain();
3174             msg.what = WifiP2pManager.PING;
3175             msg.arg1 = 0;
3176             msg.arg2 = 0;
3177             msg.obj = null;
3178             try {
3179                 c.mMessenger.send(msg);
3180             } catch (RemoteException e) {
3181                 if (DBG) logd("detect dead channel");
3182                 deadClients.add(c.mMessenger);
3183             }
3184         }
3185 
3186         for (Messenger m : deadClients) {
3187             clearClientInfo(m);
3188         }
3189     }
3190 
3191     /**
3192      * Return the specified ClientInfo.
3193      * @param m Messenger
3194      * @param createIfNotExist if true and the specified channel info does not exist,
3195      * create new client info.
3196      * @return the specified ClientInfo.
3197      */
getClientInfo(Messenger m, boolean createIfNotExist)3198     private ClientInfo getClientInfo(Messenger m, boolean createIfNotExist) {
3199         ClientInfo clientInfo = mClientInfoList.get(m);
3200 
3201         if (clientInfo == null && createIfNotExist) {
3202             if (DBG) logd("add a new client");
3203             clientInfo = new ClientInfo(m);
3204             mClientInfoList.put(m, clientInfo);
3205         }
3206 
3207         return clientInfo;
3208     }
3209 
3210     }
3211 
3212     /**
3213      * Information about a particular client and we track the service discovery requests
3214      * and the local services registered by the client.
3215      */
3216     private class ClientInfo {
3217 
3218         /*
3219          * A reference to WifiP2pManager.Channel handler.
3220          * The response of this request is notified to WifiP2pManager.Channel handler
3221          */
3222         private Messenger mMessenger;
3223 
3224         /*
3225          * A service discovery request list.
3226          */
3227         private SparseArray<WifiP2pServiceRequest> mReqList;
3228 
3229         /*
3230          * A local service information list.
3231          */
3232         private List<WifiP2pServiceInfo> mServList;
3233 
ClientInfo(Messenger m)3234         private ClientInfo(Messenger m) {
3235             mMessenger = m;
3236             mReqList = new SparseArray();
3237             mServList = new ArrayList<WifiP2pServiceInfo>();
3238         }
3239     }
3240 }
3241