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++ < 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