blob: a0a26674cbf38147b60cf5148e8091c1bcb77ff1 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi.p2p;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pGroup;
import android.net.wifi.p2p.WifiP2pProvDiscEvent;
import android.net.wifi.p2p.nsd.WifiP2pServiceResponse;
import android.os.Handler;
import android.os.Message;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Protocol;
import com.android.server.wifi.p2p.WifiP2pServiceImpl.P2pStatus;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Listens for events from the wpa_supplicant, and passes them on
* to the {@link WifiP2pServiceImpl} for handling.
*/
public class WifiP2pMonitor {
private static final String TAG = "WifiP2pMonitor";
/* Supplicant events reported to a state machine */
private static final int BASE = Protocol.BASE_WIFI_MONITOR;
/* Connection to supplicant established */
public static final int SUP_CONNECTION_EVENT = BASE + 1;
/* Connection to supplicant lost */
public static final int SUP_DISCONNECTION_EVENT = BASE + 2;
/* P2P events */
public static final int P2P_DEVICE_FOUND_EVENT = BASE + 21;
public static final int P2P_DEVICE_LOST_EVENT = BASE + 22;
public static final int P2P_GO_NEGOTIATION_REQUEST_EVENT = BASE + 23;
public static final int P2P_GO_NEGOTIATION_SUCCESS_EVENT = BASE + 25;
public static final int P2P_GO_NEGOTIATION_FAILURE_EVENT = BASE + 26;
public static final int P2P_GROUP_FORMATION_SUCCESS_EVENT = BASE + 27;
public static final int P2P_GROUP_FORMATION_FAILURE_EVENT = BASE + 28;
public static final int P2P_GROUP_STARTED_EVENT = BASE + 29;
public static final int P2P_GROUP_REMOVED_EVENT = BASE + 30;
public static final int P2P_INVITATION_RECEIVED_EVENT = BASE + 31;
public static final int P2P_INVITATION_RESULT_EVENT = BASE + 32;
public static final int P2P_PROV_DISC_PBC_REQ_EVENT = BASE + 33;
public static final int P2P_PROV_DISC_PBC_RSP_EVENT = BASE + 34;
public static final int P2P_PROV_DISC_ENTER_PIN_EVENT = BASE + 35;
public static final int P2P_PROV_DISC_SHOW_PIN_EVENT = BASE + 36;
public static final int P2P_FIND_STOPPED_EVENT = BASE + 37;
public static final int P2P_SERV_DISC_RESP_EVENT = BASE + 38;
public static final int P2P_PROV_DISC_FAILURE_EVENT = BASE + 39;
/* hostap events */
public static final int AP_STA_DISCONNECTED_EVENT = BASE + 41;
public static final int AP_STA_CONNECTED_EVENT = BASE + 42;
private boolean mVerboseLoggingEnabled = false;
/**
* Enable verbose logging for all sub modules.
*/
public void enableVerboseLogging(int verbose) {
mVerboseLoggingEnabled = verbose > 0;
}
private final Map<String, SparseArray<Set<Handler>>> mHandlerMap = new HashMap<>();
/**
* Registers a callback handler for the provided event.
*/
public synchronized void registerHandler(String iface, int what, Handler handler) {
SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface);
if (ifaceHandlers == null) {
ifaceHandlers = new SparseArray<>();
mHandlerMap.put(iface, ifaceHandlers);
}
Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(what);
if (ifaceWhatHandlers == null) {
ifaceWhatHandlers = new ArraySet<>();
ifaceHandlers.put(what, ifaceWhatHandlers);
}
ifaceWhatHandlers.add(handler);
}
private final Map<String, Boolean> mMonitoringMap = new HashMap<>();
private boolean isMonitoring(String iface) {
Boolean val = mMonitoringMap.get(iface);
if (val == null) {
return false;
} else {
return val.booleanValue();
}
}
/**
* Enable/Disable monitoring for the provided iface.
*
* @param iface Name of the iface.
* @param enabled true to enable, false to disable.
*/
@VisibleForTesting
public void setMonitoring(String iface, boolean enabled) {
mMonitoringMap.put(iface, enabled);
}
/**
* Start Monitoring for wpa_supplicant events.
*
* @param iface Name of iface.
* TODO: Add unit tests for these once we remove the legacy code.
*/
public synchronized void startMonitoring(String iface) {
setMonitoring(iface, true);
broadcastSupplicantConnectionEvent(iface);
}
/**
* Stop Monitoring for wpa_supplicant events.
*
* @param iface Name of iface.
* TODO: Add unit tests for these once we remove the legacy code.
*/
public synchronized void stopMonitoring(String iface) {
if (mVerboseLoggingEnabled) Log.d(TAG, "stopMonitoring(" + iface + ")");
setMonitoring(iface, true);
broadcastSupplicantDisconnectionEvent(iface);
setMonitoring(iface, false);
}
/**
* Similar functions to Handler#sendMessage that send the message to the registered handler
* for the given interface and message what.
* All of these should be called with the WifiMonitor class lock
*/
private void sendMessage(String iface, int what) {
sendMessage(iface, Message.obtain(null, what));
}
private void sendMessage(String iface, int what, Object obj) {
sendMessage(iface, Message.obtain(null, what, obj));
}
private void sendMessage(String iface, int what, int arg1) {
sendMessage(iface, Message.obtain(null, what, arg1, 0));
}
private void sendMessage(String iface, int what, int arg1, int arg2) {
sendMessage(iface, Message.obtain(null, what, arg1, arg2));
}
private void sendMessage(String iface, int what, int arg1, int arg2, Object obj) {
sendMessage(iface, Message.obtain(null, what, arg1, arg2, obj));
}
private void sendMessage(String iface, Message message) {
SparseArray<Set<Handler>> ifaceHandlers = mHandlerMap.get(iface);
if (iface != null && ifaceHandlers != null) {
if (isMonitoring(iface)) {
Set<Handler> ifaceWhatHandlers = ifaceHandlers.get(message.what);
if (ifaceWhatHandlers != null) {
for (Handler handler : ifaceWhatHandlers) {
if (handler != null) {
sendMessage(handler, Message.obtain(message));
}
}
}
} else {
if (mVerboseLoggingEnabled) {
Log.d(TAG, "Dropping event because (" + iface + ") is stopped");
}
}
} else {
if (mVerboseLoggingEnabled) {
Log.d(TAG, "Sending to all monitors because there's no matching iface");
}
for (Map.Entry<String, SparseArray<Set<Handler>>> entry : mHandlerMap.entrySet()) {
if (isMonitoring(entry.getKey())) {
Set<Handler> ifaceWhatHandlers = entry.getValue().get(message.what);
for (Handler handler : ifaceWhatHandlers) {
if (handler != null) {
sendMessage(handler, Message.obtain(message));
}
}
}
}
}
message.recycle();
}
private void sendMessage(Handler handler, Message message) {
message.setTarget(handler);
message.sendToTarget();
}
/**
* Broadcast the connection to wpa_supplicant event to all the handlers registered for
* this event.
*
* @param iface Name of iface on which this occurred.
*/
public void broadcastSupplicantConnectionEvent(String iface) {
sendMessage(iface, SUP_CONNECTION_EVENT);
}
/**
* Broadcast the loss of connection to wpa_supplicant event to all the handlers registered for
* this event.
*
* @param iface Name of iface on which this occurred.
*/
public void broadcastSupplicantDisconnectionEvent(String iface) {
sendMessage(iface, SUP_DISCONNECTION_EVENT);
}
/**
* Broadcast new p2p device discovered event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param device Device that has been discovered during recent scan.
*/
public void broadcastP2pDeviceFound(String iface, WifiP2pDevice device) {
if (device != null) {
sendMessage(iface, P2P_DEVICE_FOUND_EVENT, device);
}
}
/**
* Broadcast p2p device lost event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param device Device that has been lost in recent scan.
*/
public void broadcastP2pDeviceLost(String iface, WifiP2pDevice device) {
if (device != null) {
sendMessage(iface, P2P_DEVICE_LOST_EVENT, device);
}
}
/**
* Broadcast scan termination event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
*/
public void broadcastP2pFindStopped(String iface) {
sendMessage(iface, P2P_FIND_STOPPED_EVENT);
}
/**
* Broadcast group owner negotiation request event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param config P2p configuration.
*/
public void broadcastP2pGoNegotiationRequest(String iface, WifiP2pConfig config) {
if (config != null) {
sendMessage(iface, P2P_GO_NEGOTIATION_REQUEST_EVENT, config);
}
}
/**
* Broadcast group owner negotiation success event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
*/
public void broadcastP2pGoNegotiationSuccess(String iface) {
sendMessage(iface, P2P_GO_NEGOTIATION_SUCCESS_EVENT);
}
/**
* Broadcast group owner negotiation failure event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param reason Failure reason.
*/
public void broadcastP2pGoNegotiationFailure(String iface, P2pStatus reason) {
sendMessage(iface, P2P_GO_NEGOTIATION_FAILURE_EVENT, reason);
}
/**
* Broadcast group formation success event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
*/
public void broadcastP2pGroupFormationSuccess(String iface) {
sendMessage(iface, P2P_GROUP_FORMATION_SUCCESS_EVENT);
}
/**
* Broadcast group formation failure event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param reason Failure reason.
*/
public void broadcastP2pGroupFormationFailure(String iface, String reason) {
P2pStatus err = P2pStatus.UNKNOWN;
if (reason.equals("FREQ_CONFLICT")) {
err = P2pStatus.NO_COMMON_CHANNEL;
}
sendMessage(iface, P2P_GROUP_FORMATION_FAILURE_EVENT, err);
}
/**
* Broadcast group started event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param group Started group.
*/
public void broadcastP2pGroupStarted(String iface, WifiP2pGroup group) {
if (group != null) {
sendMessage(iface, P2P_GROUP_STARTED_EVENT, group);
}
}
/**
* Broadcast group removed event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param group Removed group.
*/
public void broadcastP2pGroupRemoved(String iface, WifiP2pGroup group) {
if (group != null) {
sendMessage(iface, P2P_GROUP_REMOVED_EVENT, group);
}
}
/**
* Broadcast invitation received event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param group Group to which invitation has been received.
*/
public void broadcastP2pInvitationReceived(String iface, WifiP2pGroup group) {
if (group != null) {
sendMessage(iface, P2P_INVITATION_RECEIVED_EVENT, group);
}
}
/**
* Broadcast invitation result event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param result Result of invitation.
*/
public void broadcastP2pInvitationResult(String iface, P2pStatus result) {
sendMessage(iface, P2P_INVITATION_RESULT_EVENT, result);
}
/**
* Broadcast PB discovery request event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param event Provision discovery request event.
*/
public void broadcastP2pProvisionDiscoveryPbcRequest(String iface, WifiP2pProvDiscEvent event) {
if (event != null) {
sendMessage(iface, P2P_PROV_DISC_PBC_REQ_EVENT, event);
}
}
/**
* Broadcast PB discovery response event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param event Provision discovery response event.
*/
public void broadcastP2pProvisionDiscoveryPbcResponse(
String iface, WifiP2pProvDiscEvent event) {
if (event != null) {
sendMessage(iface, P2P_PROV_DISC_PBC_RSP_EVENT, event);
}
}
/**
* Broadcast PIN discovery request event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param event Provision discovery request event.
*/
public void broadcastP2pProvisionDiscoveryEnterPin(String iface, WifiP2pProvDiscEvent event) {
if (event != null) {
sendMessage(iface, P2P_PROV_DISC_ENTER_PIN_EVENT, event);
}
}
/**
* Broadcast PIN discovery response event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param event Provision discovery response event.
*/
public void broadcastP2pProvisionDiscoveryShowPin(String iface, WifiP2pProvDiscEvent event) {
if (event != null) {
sendMessage(iface, P2P_PROV_DISC_SHOW_PIN_EVENT, event);
}
}
/**
* Broadcast P2P discovery failure event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
*/
public void broadcastP2pProvisionDiscoveryFailure(String iface) {
sendMessage(iface, P2P_PROV_DISC_FAILURE_EVENT);
}
/**
* Broadcast service discovery response event to all handlers registered for this event.
*
* @param iface Name of iface on which this occurred.
* @param services List of discovered services.
*/
public void broadcastP2pServiceDiscoveryResponse(
String iface, List<WifiP2pServiceResponse> services) {
sendMessage(iface, P2P_SERV_DISC_RESP_EVENT, services);
}
/**
* Broadcast AP STA connection event.
*
* @param iface Name of iface on which this occurred.
*/
public void broadcastP2pApStaConnected(String iface, WifiP2pDevice device) {
sendMessage(iface, AP_STA_CONNECTED_EVENT, device);
}
/**
* Broadcast AP STA disconnection event.
*
* @param iface Name of iface on which this occurred.
*/
public void broadcastP2pApStaDisconnected(String iface, WifiP2pDevice device) {
sendMessage(iface, AP_STA_DISCONNECTED_EVENT, device);
}
}