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