Home | History | Annotate | Download | only in p2p
      1 /*
      2  * Copyright (C) 2008 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.net.wifi.p2p.WifiP2pConfig;
     20 import android.net.wifi.p2p.WifiP2pDevice;
     21 import android.net.wifi.p2p.WifiP2pGroup;
     22 import android.net.wifi.p2p.WifiP2pProvDiscEvent;
     23 import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
     24 import android.os.Handler;
     25 import android.os.Message;
     26 import android.util.ArraySet;
     27 import android.util.Log;
     28 import android.util.SparseArray;
     29 
     30 import com.android.internal.annotations.VisibleForTesting;
     31 import com.android.internal.util.Protocol;
     32 import com.android.server.wifi.WifiInjector;
     33 import com.android.server.wifi.p2p.WifiP2pServiceImpl.P2pStatus;
     34 
     35 import java.util.HashMap;
     36 import java.util.List;
     37 import java.util.Map;
     38 import java.util.Set;
     39 
     40 /**
     41  * Listens for events from the wpa_supplicant, and passes them on
     42  * to the {@link WifiP2pServiceImpl} for handling.
     43  *
     44  * @hide
     45  */
     46 public class WifiP2pMonitor {
     47     private static final String TAG = "WifiP2pMonitor";
     48 
     49     /* Supplicant events reported to a state machine */
     50     private static final int BASE = Protocol.BASE_WIFI_MONITOR;
     51 
     52     /* Connection to supplicant established */
     53     public static final int SUP_CONNECTION_EVENT                 = BASE + 1;
     54     /* Connection to supplicant lost */
     55     public static final int SUP_DISCONNECTION_EVENT              = BASE + 2;
     56 
     57     /* P2P events */
     58     public static final int P2P_DEVICE_FOUND_EVENT               = BASE + 21;
     59     public static final int P2P_DEVICE_LOST_EVENT                = BASE + 22;
     60     public static final int P2P_GO_NEGOTIATION_REQUEST_EVENT     = BASE + 23;
     61     public static final int P2P_GO_NEGOTIATION_SUCCESS_EVENT     = BASE + 25;
     62     public static final int P2P_GO_NEGOTIATION_FAILURE_EVENT     = BASE + 26;
     63     public static final int P2P_GROUP_FORMATION_SUCCESS_EVENT    = BASE + 27;
     64     public static final int P2P_GROUP_FORMATION_FAILURE_EVENT    = BASE + 28;
     65     public static final int P2P_GROUP_STARTED_EVENT              = BASE + 29;
     66     public static final int P2P_GROUP_REMOVED_EVENT              = BASE + 30;
     67     public static final int P2P_INVITATION_RECEIVED_EVENT        = BASE + 31;
     68     public static final int P2P_INVITATION_RESULT_EVENT          = BASE + 32;
     69     public static final int P2P_PROV_DISC_PBC_REQ_EVENT          = BASE + 33;
     70     public static final int P2P_PROV_DISC_PBC_RSP_EVENT          = BASE + 34;
     71     public static final int P2P_PROV_DISC_ENTER_PIN_EVENT        = BASE + 35;
     72     public static final int P2P_PROV_DISC_SHOW_PIN_EVENT         = BASE + 36;
     73     public static final int P2P_FIND_STOPPED_EVENT               = BASE + 37;
     74     public static final int P2P_SERV_DISC_RESP_EVENT             = BASE + 38;
     75     public static final int P2P_PROV_DISC_FAILURE_EVENT          = BASE + 39;
     76 
     77     /* hostap events */
     78     public static final int AP_STA_DISCONNECTED_EVENT            = BASE + 41;
     79     public static final int AP_STA_CONNECTED_EVENT               = BASE + 42;
     80 
     81 
     82     private final WifiInjector mWifiInjector;
     83     private boolean mVerboseLoggingEnabled = false;
     84     private boolean mConnected = false;
     85 
     86     public WifiP2pMonitor(WifiInjector wifiInjector) {
     87         mWifiInjector = wifiInjector;
     88     }
     89 
     90     void enableVerboseLogging(int verbose) {
     91         if (verbose > 0) {
     92             mVerboseLoggingEnabled = true;
     93         } else {
     94             mVerboseLoggingEnabled = false;
     95         }
     96     }
     97 
     98     // TODO(b/27569474) remove support for multiple handlers for the same event
     99     private final Map<String, SparseArray<Set<Handler>>> mHandlerMap = new HashMap<>();
    100 
    101     /**
    102      * Registers a callback handler for the provided event.
    103      */
    104     public synchronized void registerHandler(String iface, int what, Handler handler) {
    105         SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface);
    106         if (ifaceHandlers == null) {
    107             ifaceHandlers = new SparseArray<>();
    108             mHandlerMap.put(iface, ifaceHandlers);
    109         }
    110         Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(what);
    111         if (ifaceWhatHandlers == null) {
    112             ifaceWhatHandlers = new ArraySet<>();
    113             ifaceHandlers.put(what, ifaceWhatHandlers);
    114         }
    115         ifaceWhatHandlers.add(handler);
    116     }
    117 
    118     private final Map<String, Boolean> mMonitoringMap = new HashMap<>();
    119     private boolean isMonitoring(String iface) {
    120         Boolean val = mMonitoringMap.get(iface);
    121         if (val == null) {
    122             return false;
    123         } else {
    124             return val.booleanValue();
    125         }
    126     }
    127 
    128     /**
    129      * Enable/Disable monitoring for the provided iface.
    130      *
    131      * @param iface Name of the iface.
    132      * @param enabled true to enable, false to disable.
    133      */
    134     @VisibleForTesting
    135     public void setMonitoring(String iface, boolean enabled) {
    136         mMonitoringMap.put(iface, enabled);
    137     }
    138 
    139     private void setMonitoringNone() {
    140         for (String iface : mMonitoringMap.keySet()) {
    141             setMonitoring(iface, false);
    142         }
    143     }
    144 
    145     /**
    146      * Wait for wpa_supplicant's control interface to be ready.
    147      *
    148      * TODO: Add unit tests for these once we remove the legacy code.
    149      */
    150     private boolean ensureConnectedLocked() {
    151         if (mConnected) {
    152             return true;
    153         }
    154         if (mVerboseLoggingEnabled) Log.d(TAG, "connecting to supplicant");
    155         int connectTries = 0;
    156         while (true) {
    157             mConnected = mWifiInjector.getWifiP2pNative().connectToSupplicant();
    158             if (mConnected) {
    159                 return true;
    160             }
    161             if (connectTries++ < 50) {
    162                 try {
    163                     Thread.sleep(100);
    164                 } catch (InterruptedException ignore) {
    165                 }
    166             } else {
    167                 return false;
    168             }
    169         }
    170     }
    171 
    172     /**
    173      * Start Monitoring for wpa_supplicant events.
    174      *
    175      * @param iface Name of iface.
    176      * TODO: Add unit tests for these once we remove the legacy code.
    177      */
    178     public synchronized void startMonitoring(String iface) {
    179         if (ensureConnectedLocked()) {
    180             setMonitoring(iface, true);
    181             broadcastSupplicantConnectionEvent(iface);
    182         } else {
    183             boolean originalMonitoring = isMonitoring(iface);
    184             setMonitoring(iface, true);
    185             broadcastSupplicantDisconnectionEvent(iface);
    186             setMonitoring(iface, originalMonitoring);
    187             Log.e(TAG, "startMonitoring(" + iface + ") failed!");
    188         }
    189     }
    190 
    191     /**
    192      * Stop Monitoring for wpa_supplicant events.
    193      *
    194      * @param iface Name of iface.
    195      * TODO: Add unit tests for these once we remove the legacy code.
    196      */
    197     public synchronized void stopMonitoring(String iface) {
    198         if (mVerboseLoggingEnabled) Log.d(TAG, "stopMonitoring(" + iface + ")");
    199         setMonitoring(iface, true);
    200         broadcastSupplicantDisconnectionEvent(iface);
    201         setMonitoring(iface, false);
    202     }
    203 
    204     /**
    205      * Stop Monitoring for wpa_supplicant events.
    206      *
    207      * TODO: Add unit tests for these once we remove the legacy code.
    208      */
    209     public synchronized void stopAllMonitoring() {
    210         mConnected = false;
    211         setMonitoringNone();
    212     }
    213 
    214     /**
    215      * Similar functions to Handler#sendMessage that send the message to the registered handler
    216      * for the given interface and message what.
    217      * All of these should be called with the WifiMonitor class lock
    218      */
    219     private void sendMessage(String iface, int what) {
    220         sendMessage(iface, Message.obtain(null, what));
    221     }
    222 
    223     private void sendMessage(String iface, int what, Object obj) {
    224         sendMessage(iface, Message.obtain(null, what, obj));
    225     }
    226 
    227     private void sendMessage(String iface, int what, int arg1) {
    228         sendMessage(iface, Message.obtain(null, what, arg1, 0));
    229     }
    230 
    231     private void sendMessage(String iface, int what, int arg1, int arg2) {
    232         sendMessage(iface, Message.obtain(null, what, arg1, arg2));
    233     }
    234 
    235     private void sendMessage(String iface, int what, int arg1, int arg2, Object obj) {
    236         sendMessage(iface, Message.obtain(null, what, arg1, arg2, obj));
    237     }
    238 
    239     private void sendMessage(String iface, Message message) {
    240         SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface);
    241         if (iface != null && ifaceHandlers != null) {
    242             if (isMonitoring(iface)) {
    243                 Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(message.what);
    244                 if (ifaceWhatHandlers != null) {
    245                     for (Handler handler : ifaceWhatHandlers) {
    246                         if (handler != null) {
    247                             sendMessage(handler, Message.obtain(message));
    248                         }
    249                     }
    250                 }
    251             } else {
    252                 if (mVerboseLoggingEnabled) {
    253                     Log.d(TAG, "Dropping event because (" + iface + ") is stopped");
    254                 }
    255             }
    256         } else {
    257             if (mVerboseLoggingEnabled) {
    258                 Log.d(TAG, "Sending to all monitors because there's no matching iface");
    259             }
    260             for (Map.Entry<String, SparseArray<Set<Handler>>> entry : mHandlerMap.entrySet()) {
    261                 if (isMonitoring(entry.getKey())) {
    262                     Set<Handler> ifaceWhatHandlers = entry.getValue().get(message.what);
    263                     for (Handler handler : ifaceWhatHandlers) {
    264                         if (handler != null) {
    265                             sendMessage(handler, Message.obtain(message));
    266                         }
    267                     }
    268                 }
    269             }
    270         }
    271 
    272         message.recycle();
    273     }
    274 
    275     private void sendMessage(Handler handler, Message message) {
    276         message.setTarget(handler);
    277         message.sendToTarget();
    278     }
    279 
    280     /**
    281      * Broadcast the connection to wpa_supplicant event to all the handlers registered for
    282      * this event.
    283      *
    284      * @param iface Name of iface on which this occurred.
    285      */
    286     public void broadcastSupplicantConnectionEvent(String iface) {
    287         sendMessage(iface, SUP_CONNECTION_EVENT);
    288     }
    289 
    290     /**
    291      * Broadcast the loss of connection to wpa_supplicant event to all the handlers registered for
    292      * this event.
    293      *
    294      * @param iface Name of iface on which this occurred.
    295      */
    296     public void broadcastSupplicantDisconnectionEvent(String iface) {
    297         sendMessage(iface, SUP_DISCONNECTION_EVENT);
    298     }
    299 
    300     /**
    301      * Broadcast new p2p device discovered event to all handlers registered for this event.
    302      *
    303      * @param iface Name of iface on which this occurred.
    304      * @param device Device that has been discovered during recent scan.
    305      */
    306     public void broadcastP2pDeviceFound(String iface, WifiP2pDevice device) {
    307         if (device != null) {
    308             sendMessage(iface, P2P_DEVICE_FOUND_EVENT, device);
    309         }
    310     }
    311 
    312     /**
    313      * Broadcast p2p device lost event to all handlers registered for this event.
    314      *
    315      * @param iface Name of iface on which this occurred.
    316      * @param device Device that has been lost in recent scan.
    317      */
    318     public void broadcastP2pDeviceLost(String iface, WifiP2pDevice device) {
    319         if (device != null) {
    320             sendMessage(iface, P2P_DEVICE_LOST_EVENT, device);
    321         }
    322     }
    323 
    324     /**
    325      * Broadcast scan termination event to all handlers registered for this event.
    326      *
    327      * @param iface Name of iface on which this occurred.
    328      */
    329     public void broadcastP2pFindStopped(String iface) {
    330         sendMessage(iface, P2P_FIND_STOPPED_EVENT);
    331     }
    332 
    333     /**
    334      * Broadcast group owner negotiation request event to all handlers registered for this event.
    335      *
    336      * @param iface Name of iface on which this occurred.
    337      * @param config P2p configuration.
    338      */
    339     public void broadcastP2pGoNegotiationRequest(String iface, WifiP2pConfig config) {
    340         if (config != null) {
    341             sendMessage(iface, P2P_GO_NEGOTIATION_REQUEST_EVENT, config);
    342         }
    343     }
    344 
    345     /**
    346      * Broadcast group owner negotiation success event to all handlers registered for this event.
    347      *
    348      * @param iface Name of iface on which this occurred.
    349      */
    350     public void broadcastP2pGoNegotiationSuccess(String iface) {
    351         sendMessage(iface, P2P_GO_NEGOTIATION_SUCCESS_EVENT);
    352     }
    353 
    354     /**
    355      * Broadcast group owner negotiation failure event to all handlers registered for this event.
    356      *
    357      * @param iface Name of iface on which this occurred.
    358      * @param reason Failure reason.
    359      */
    360     public void broadcastP2pGoNegotiationFailure(String iface, P2pStatus reason) {
    361         sendMessage(iface, P2P_GO_NEGOTIATION_FAILURE_EVENT, reason);
    362     }
    363 
    364     /**
    365      * Broadcast group formation success event to all handlers registered for this event.
    366      *
    367      * @param iface Name of iface on which this occurred.
    368      */
    369     public void broadcastP2pGroupFormationSuccess(String iface) {
    370         sendMessage(iface, P2P_GROUP_FORMATION_SUCCESS_EVENT);
    371     }
    372 
    373     /**
    374      * Broadcast group formation failure event to all handlers registered for this event.
    375      *
    376      * @param iface Name of iface on which this occurred.
    377      * @param reason Failure reason.
    378      */
    379     public void broadcastP2pGroupFormationFailure(String iface, String reason) {
    380         P2pStatus err = P2pStatus.UNKNOWN;
    381         if (reason.equals("FREQ_CONFLICT")) {
    382             err = P2pStatus.NO_COMMON_CHANNEL;
    383         }
    384         sendMessage(iface, P2P_GROUP_FORMATION_FAILURE_EVENT, err);
    385     }
    386 
    387     /**
    388      * Broadcast group started event to all handlers registered for this event.
    389      *
    390      * @param iface Name of iface on which this occurred.
    391      * @param group Started group.
    392      */
    393     public void broadcastP2pGroupStarted(String iface, WifiP2pGroup group) {
    394         if (group != null) {
    395             sendMessage(iface, P2P_GROUP_STARTED_EVENT, group);
    396         }
    397     }
    398 
    399     /**
    400      * Broadcast group removed event to all handlers registered for this event.
    401      *
    402      * @param iface Name of iface on which this occurred.
    403      * @param group Removed group.
    404      */
    405     public void broadcastP2pGroupRemoved(String iface, WifiP2pGroup group) {
    406         if (group != null) {
    407             sendMessage(iface, P2P_GROUP_REMOVED_EVENT, group);
    408         }
    409     }
    410 
    411     /**
    412      * Broadcast invitation received event to all handlers registered for this event.
    413      *
    414      * @param iface Name of iface on which this occurred.
    415      * @param group Group to which invitation has been received.
    416      */
    417     public void broadcastP2pInvitationReceived(String iface, WifiP2pGroup group) {
    418         if (group != null) {
    419             sendMessage(iface, P2P_INVITATION_RECEIVED_EVENT, group);
    420         }
    421     }
    422 
    423     /**
    424      * Broadcast invitation result event to all handlers registered for this event.
    425      *
    426      * @param iface Name of iface on which this occurred.
    427      * @param result Result of invitation.
    428      */
    429     public void broadcastP2pInvitationResult(String iface, P2pStatus result) {
    430         sendMessage(iface, P2P_INVITATION_RESULT_EVENT, result);
    431     }
    432 
    433     /**
    434      * Broadcast PB discovery request event to all handlers registered for this event.
    435      *
    436      * @param iface Name of iface on which this occurred.
    437      * @param event Provision discovery request event.
    438      */
    439     public void broadcastP2pProvisionDiscoveryPbcRequest(String iface, WifiP2pProvDiscEvent event) {
    440         if (event != null) {
    441             sendMessage(iface, P2P_PROV_DISC_PBC_REQ_EVENT, event);
    442         }
    443     }
    444 
    445     /**
    446      * Broadcast PB discovery response event to all handlers registered for this event.
    447      *
    448      * @param iface Name of iface on which this occurred.
    449      * @param event Provision discovery response event.
    450      */
    451     public void broadcastP2pProvisionDiscoveryPbcResponse(
    452             String iface, WifiP2pProvDiscEvent event) {
    453         if (event != null) {
    454             sendMessage(iface, P2P_PROV_DISC_PBC_RSP_EVENT, event);
    455         }
    456     }
    457 
    458     /**
    459      * Broadcast PIN discovery request event to all handlers registered for this event.
    460      *
    461      * @param iface Name of iface on which this occurred.
    462      * @param event Provision discovery request event.
    463      */
    464     public void broadcastP2pProvisionDiscoveryEnterPin(String iface, WifiP2pProvDiscEvent event) {
    465         if (event != null) {
    466             sendMessage(iface, P2P_PROV_DISC_ENTER_PIN_EVENT, event);
    467         }
    468     }
    469 
    470     /**
    471      * Broadcast PIN discovery response event to all handlers registered for this event.
    472      *
    473      * @param iface Name of iface on which this occurred.
    474      * @param event Provision discovery response event.
    475      */
    476     public void broadcastP2pProvisionDiscoveryShowPin(String iface, WifiP2pProvDiscEvent event) {
    477         if (event != null) {
    478             sendMessage(iface, P2P_PROV_DISC_SHOW_PIN_EVENT, event);
    479         }
    480     }
    481 
    482     /**
    483      * Broadcast P2P discovery failure event to all handlers registered for this event.
    484      *
    485      * @param iface Name of iface on which this occurred.
    486      */
    487     public void broadcastP2pProvisionDiscoveryFailure(String iface) {
    488         sendMessage(iface, P2P_PROV_DISC_FAILURE_EVENT);
    489     }
    490 
    491     /**
    492      * Broadcast service discovery response event to all handlers registered for this event.
    493      *
    494      * @param iface Name of iface on which this occurred.
    495      * @param services List of discovered services.
    496      */
    497     public void broadcastP2pServiceDiscoveryResponse(
    498             String iface, List<WifiP2pServiceResponse> services) {
    499         sendMessage(iface, P2P_SERV_DISC_RESP_EVENT, services);
    500     }
    501 
    502     /**
    503      * Broadcast AP STA connection event.
    504      *
    505      * @param iface Name of iface on which this occurred.
    506      */
    507     public void broadcastP2pApStaConnected(String iface, WifiP2pDevice device) {
    508         sendMessage(iface, AP_STA_CONNECTED_EVENT, device);
    509     }
    510 
    511     /**
    512      * Broadcast AP STA disconnection event.
    513      *
    514      * @param iface Name of iface on which this occurred.
    515      */
    516     public void broadcastP2pApStaDisconnected(String iface, WifiP2pDevice device) {
    517         sendMessage(iface, AP_STA_DISCONNECTED_EVENT, device);
    518     }
    519 }
    520