WifiP2pMonitor.java revision 163f9765f9e4c3f868b1e0d630b6adeaa115fb4a
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
17package com.android.server.wifi.p2p;
18
19import android.net.wifi.p2p.WifiP2pConfig;
20import android.net.wifi.p2p.WifiP2pDevice;
21import android.net.wifi.p2p.WifiP2pGroup;
22import android.net.wifi.p2p.WifiP2pProvDiscEvent;
23import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
24import android.os.Handler;
25import android.os.Message;
26import android.util.ArraySet;
27import android.util.Log;
28import android.util.SparseArray;
29
30import com.android.internal.annotations.VisibleForTesting;
31import com.android.internal.util.Protocol;
32import com.android.server.wifi.WifiInjector;
33import com.android.server.wifi.p2p.WifiP2pServiceImpl.P2pStatus;
34
35import java.util.HashMap;
36import java.util.List;
37import java.util.Map;
38import 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 */
46public 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++ < 5) {
162                try {
163                    Thread.sleep(1000);
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                boolean firstHandler = true;
244                Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(message.what);
245                if (ifaceWhatHandlers != null) {
246                    for (Handler handler : ifaceWhatHandlers) {
247                        if (firstHandler) {
248                            firstHandler = false;
249                            sendMessage(handler, message);
250                        } else {
251                            sendMessage(handler, Message.obtain(message));
252                        }
253                    }
254                }
255            } else {
256                if (mVerboseLoggingEnabled) {
257                    Log.d(TAG, "Dropping event because (" + iface + ") is stopped");
258                }
259            }
260        } else {
261            if (mVerboseLoggingEnabled) {
262                Log.d(TAG, "Sending to all monitors because there's no matching iface");
263            }
264            boolean firstHandler = true;
265            for (Map.Entry<String, SparseArray<Set<Handler>>> entry : mHandlerMap.entrySet()) {
266                if (isMonitoring(entry.getKey())) {
267                    Set<Handler> ifaceWhatHandlers = entry.getValue().get(message.what);
268                    for (Handler handler : ifaceWhatHandlers) {
269                        if (firstHandler) {
270                            firstHandler = false;
271                            sendMessage(handler, message);
272                        } else {
273                            sendMessage(handler, Message.obtain(message));
274                        }
275                    }
276                }
277            }
278        }
279    }
280
281    private void sendMessage(Handler handler, Message message) {
282        if (handler != null) {
283            message.setTarget(handler);
284            message.sendToTarget();
285        }
286    }
287
288    /**
289     * Broadcast the connection to wpa_supplicant event to all the handlers registered for
290     * this event.
291     *
292     * @param iface Name of iface on which this occurred.
293     */
294    public void broadcastSupplicantConnectionEvent(String iface) {
295        sendMessage(iface, SUP_CONNECTION_EVENT);
296    }
297
298    /**
299     * Broadcast the loss of connection to wpa_supplicant event to all the handlers registered for
300     * this event.
301     *
302     * @param iface Name of iface on which this occurred.
303     */
304    public void broadcastSupplicantDisconnectionEvent(String iface) {
305        sendMessage(iface, SUP_DISCONNECTION_EVENT);
306    }
307
308    /**
309     * Broadcast new p2p device discovered event to all handlers registered for this event.
310     *
311     * @param iface Name of iface on which this occurred.
312     * @param device Device that has been discovered during recent scan.
313     */
314    public void broadcastP2pDeviceFound(String iface, WifiP2pDevice device) {
315        if (device != null) {
316            sendMessage(iface, P2P_DEVICE_FOUND_EVENT, device);
317        }
318    }
319
320    /**
321     * Broadcast p2p device lost event to all handlers registered for this event.
322     *
323     * @param iface Name of iface on which this occurred.
324     * @param device Device that has been lost in recent scan.
325     */
326    public void broadcastP2pDeviceLost(String iface, WifiP2pDevice device) {
327        if (device != null) {
328            sendMessage(iface, P2P_DEVICE_LOST_EVENT, device);
329        }
330    }
331
332    /**
333     * Broadcast scan termination event to all handlers registered for this event.
334     *
335     * @param iface Name of iface on which this occurred.
336     */
337    public void broadcastP2pFindStopped(String iface) {
338        sendMessage(iface, P2P_FIND_STOPPED_EVENT);
339    }
340
341    /**
342     * Broadcast group owner negotiation request event to all handlers registered for this event.
343     *
344     * @param iface Name of iface on which this occurred.
345     * @param config P2p configuration.
346     */
347    public void broadcastP2pGoNegotiationRequest(String iface, WifiP2pConfig config) {
348        if (config != null) {
349            sendMessage(iface, P2P_GO_NEGOTIATION_REQUEST_EVENT, config);
350        }
351    }
352
353    /**
354     * Broadcast group owner negotiation success event to all handlers registered for this event.
355     *
356     * @param iface Name of iface on which this occurred.
357     */
358    public void broadcastP2pGoNegotiationSuccess(String iface) {
359        sendMessage(iface, P2P_GO_NEGOTIATION_SUCCESS_EVENT);
360    }
361
362    /**
363     * Broadcast group owner negotiation failure event to all handlers registered for this event.
364     *
365     * @param iface Name of iface on which this occurred.
366     * @param reason Failure reason.
367     */
368    public void broadcastP2pGoNegotiationFailure(String iface, P2pStatus reason) {
369        sendMessage(iface, P2P_GO_NEGOTIATION_FAILURE_EVENT, reason);
370    }
371
372    /**
373     * Broadcast group formation success event to all handlers registered for this event.
374     *
375     * @param iface Name of iface on which this occurred.
376     */
377    public void broadcastP2pGroupFormationSuccess(String iface) {
378        sendMessage(iface, P2P_GROUP_FORMATION_SUCCESS_EVENT);
379    }
380
381    /**
382     * Broadcast group formation failure event to all handlers registered for this event.
383     *
384     * @param iface Name of iface on which this occurred.
385     * @param reason Failure reason.
386     */
387    public void broadcastP2pGroupFormationFailure(String iface, String reason) {
388        P2pStatus err = P2pStatus.UNKNOWN;
389        if (reason.equals("FREQ_CONFLICT")) {
390            err = P2pStatus.NO_COMMON_CHANNEL;
391        }
392        sendMessage(iface, P2P_GROUP_FORMATION_FAILURE_EVENT, err);
393    }
394
395    /**
396     * Broadcast group started event to all handlers registered for this event.
397     *
398     * @param iface Name of iface on which this occurred.
399     * @param group Started group.
400     */
401    public void broadcastP2pGroupStarted(String iface, WifiP2pGroup group) {
402        if (group != null) {
403            sendMessage(iface, P2P_GROUP_STARTED_EVENT, group);
404        }
405    }
406
407    /**
408     * Broadcast group removed event to all handlers registered for this event.
409     *
410     * @param iface Name of iface on which this occurred.
411     * @param group Removed group.
412     */
413    public void broadcastP2pGroupRemoved(String iface, WifiP2pGroup group) {
414        if (group != null) {
415            sendMessage(iface, P2P_GROUP_REMOVED_EVENT, group);
416        }
417    }
418
419    /**
420     * Broadcast invitation received event to all handlers registered for this event.
421     *
422     * @param iface Name of iface on which this occurred.
423     * @param group Group to which invitation has been received.
424     */
425    public void broadcastP2pInvitationReceived(String iface, WifiP2pGroup group) {
426        if (group != null) {
427            sendMessage(iface, P2P_INVITATION_RECEIVED_EVENT, group);
428        }
429    }
430
431    /**
432     * Broadcast invitation result event to all handlers registered for this event.
433     *
434     * @param iface Name of iface on which this occurred.
435     * @param result Result of invitation.
436     */
437    public void broadcastP2pInvitationResult(String iface, P2pStatus result) {
438        sendMessage(iface, P2P_INVITATION_RESULT_EVENT, result);
439    }
440
441    /**
442     * Broadcast PB discovery request event to all handlers registered for this event.
443     *
444     * @param iface Name of iface on which this occurred.
445     * @param event Provision discovery request event.
446     */
447    public void broadcastP2pProvisionDiscoveryPbcRequest(String iface, WifiP2pProvDiscEvent event) {
448        if (event != null) {
449            sendMessage(iface, P2P_PROV_DISC_PBC_REQ_EVENT, event);
450        }
451    }
452
453    /**
454     * Broadcast PB discovery response event to all handlers registered for this event.
455     *
456     * @param iface Name of iface on which this occurred.
457     * @param event Provision discovery response event.
458     */
459    public void broadcastP2pProvisionDiscoveryPbcResponse(
460            String iface, WifiP2pProvDiscEvent event) {
461        if (event != null) {
462            sendMessage(iface, P2P_PROV_DISC_PBC_RSP_EVENT, event);
463        }
464    }
465
466    /**
467     * Broadcast PIN discovery request event to all handlers registered for this event.
468     *
469     * @param iface Name of iface on which this occurred.
470     * @param event Provision discovery request event.
471     */
472    public void broadcastP2pProvisionDiscoveryEnterPin(String iface, WifiP2pProvDiscEvent event) {
473        if (event != null) {
474            sendMessage(iface, P2P_PROV_DISC_ENTER_PIN_EVENT, event);
475        }
476    }
477
478    /**
479     * Broadcast PIN discovery response event to all handlers registered for this event.
480     *
481     * @param iface Name of iface on which this occurred.
482     * @param event Provision discovery response event.
483     */
484    public void broadcastP2pProvisionDiscoveryShowPin(String iface, WifiP2pProvDiscEvent event) {
485        if (event != null) {
486            sendMessage(iface, P2P_PROV_DISC_SHOW_PIN_EVENT, event);
487        }
488    }
489
490    /**
491     * Broadcast P2P discovery failure event to all handlers registered for this event.
492     *
493     * @param iface Name of iface on which this occurred.
494     */
495    public void broadcastP2pProvisionDiscoveryFailure(String iface) {
496        sendMessage(iface, P2P_PROV_DISC_FAILURE_EVENT);
497    }
498
499    /**
500     * Broadcast service discovery response event to all handlers registered for this event.
501     *
502     * @param iface Name of iface on which this occurred.
503     * @param services List of discovered services.
504     */
505    public void broadcastP2pServiceDiscoveryResponse(
506            String iface, List<WifiP2pServiceResponse> services) {
507        sendMessage(iface, P2P_SERV_DISC_RESP_EVENT, services);
508    }
509}
510