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