summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/WifiServiceImpl.java122
1 files changed, 109 insertions, 13 deletions
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index ce9784d2e..4e8bbd9c2 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -203,12 +203,12 @@ public class WifiServiceImpl extends IWifiManager.Stub {
private WifiPermissionsUtil mWifiPermissionsUtil;
- private final ConcurrentHashMap<String, Integer> mIfaceIpModes;
-
@GuardedBy("mLocalOnlyHotspotRequests")
private final HashMap<Integer, LocalOnlyHotspotRequestInfo> mLocalOnlyHotspotRequests;
@GuardedBy("mLocalOnlyHotspotRequests")
private WifiConfiguration mLocalOnlyHotspotConfig = null;
+ @GuardedBy("mLocalOnlyHotspotRequests")
+ private final ConcurrentHashMap<String, Integer> mIfaceIpModes;
/**
* Callback for use with LocalOnlyHotspot to unregister requesting applications upon death.
@@ -856,12 +856,65 @@ public class WifiServiceImpl extends IWifiManager.Stub {
// NETWORK_STACK is a signature only permission.
enforceNetworkStackPermission();
- Integer previousMode = mIfaceIpModes.put(ifaceName, mode);
- Slog.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode
- + " previous mode= " + previousMode);
+ // hand off the work to our handler thread
+ mClientHandler.post(() -> {
+ updateInterfaceIpStateInternal(ifaceName, mode);
+ });
+ }
- // TODO: check the mode when startLOHS comes in in case it is already active
- // TODO: if mode == LOCAL_ONLY, trigger onStarted callbacks
+ private void updateInterfaceIpStateInternal(String ifaceName, int mode) {
+ // update interface IP state related to tethering and hotspot
+ synchronized (mLocalOnlyHotspotRequests) {
+ // update the mode tracker here - we clear out state below
+ Integer previousMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
+ if (ifaceName != null) {
+ previousMode = mIfaceIpModes.put(ifaceName, mode);
+ }
+ Slog.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode
+ + " previous mode= " + previousMode);
+
+ switch (mode) {
+ case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
+ // first make sure we have registered requests.. otherwise clean up
+ if (mLocalOnlyHotspotRequests.isEmpty()) {
+ // we don't have requests... stop the hotspot
+ stopSoftAp();
+ updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+ return;
+ }
+ // LOHS is ready to go! Call our registered requestors!
+ sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked();
+ break;
+ case WifiManager.IFACE_IP_MODE_TETHERED:
+ // we have tethered an interface. we don't really act on this now other than if
+ // we have LOHS requests, and this is an issue. return incompatible mode for
+ // onFailed for the registered requestors since this can result from a race
+ // between a tether request and a hotspot request (tethering wins).
+ sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
+ LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE);
+ mLocalOnlyHotspotRequests.clear();
+ break;
+ case WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR:
+ // there was an error setting up the hotspot... trigger onFailed for the
+ // registered LOHS requestors
+ sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
+ LocalOnlyHotspotCallback.ERROR_GENERIC);
+ mLocalOnlyHotspotRequests.clear();
+ updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
+ break;
+ case WifiManager.IFACE_IP_MODE_UNSPECIFIED:
+ if (ifaceName == null) {
+ // interface name is null, this is due to softap teardown. clear all
+ // entries for now.
+ // TODO: Deal with individual interfaces when we receive updates for them
+ mIfaceIpModes.clear();
+ return;
+ }
+ break;
+ default:
+ mLog.trace("updateInterfaceIpStateInternal: unknown mode %").c(mode).flush();
+ }
+ }
}
/**
@@ -953,6 +1006,9 @@ public class WifiServiceImpl extends IWifiManager.Stub {
// holding the required lock: send message to requestors and clear the list
sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
errorToReport);
+ // also need to clear interface ip state - send null for now since we don't know
+ // what interface (and we have one anyway)
+ updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
}
return;
}
@@ -960,8 +1016,18 @@ public class WifiServiceImpl extends IWifiManager.Stub {
if (currentState == WIFI_AP_STATE_DISABLING || currentState == WIFI_AP_STATE_DISABLED) {
// softap is shutting down or is down... let requestors know via the onStopped call
synchronized (mLocalOnlyHotspotRequests) {
- // holding the required lock: send message to requestors and clear the list
- sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked();
+ // if we are currently in hotspot mode, then trigger onStopped for registered
+ // requestors, otherwise something odd happened and we should clear state
+ if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)) {
+ // holding the required lock: send message to requestors and clear the list
+ sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked();
+ } else {
+ // LOHS not active: report an error (still holding the required lock)
+ sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(ERROR_GENERIC);
+ }
+ // also clear interface ip state - send null for now since we don't know what
+ // interface (and we only have one anyway)
+ updateInterfaceIpState(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
}
return;
}
@@ -1078,10 +1144,40 @@ public class WifiServiceImpl extends IWifiManager.Stub {
// check current mode to see if we can start localOnlyHotspot
boolean apDisabled =
mWifiStateMachine.syncGetWifiApState() == WifiManager.WIFI_AP_STATE_DISABLED;
- if (!apDisabled) {
- // Tethering is enabled, cannot start LocalOnlyHotspot
- mLog.trace("Cannot start localOnlyHotspot when WiFi Tethering is active.");
- return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
+
+ synchronized (mLocalOnlyHotspotRequests) {
+ if (!apDisabled && mLocalOnlyHotspotRequests.isEmpty()) {
+ // Tethering is enabled, cannot start LocalOnlyHotspot
+ mLog.trace("Cannot start localOnlyHotspot when WiFi Tethering is active.");
+ return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
+ }
+
+ // does this caller already have a request?
+ LocalOnlyHotspotRequestInfo request = mLocalOnlyHotspotRequests.get(uid);
+ if (request != null) {
+ mLog.trace("caller already has an active request");
+ throw new IllegalStateException(
+ "Caller already has an active LocalOnlyHotspot request");
+ }
+
+ // now create the new LOHS request info object
+ request = new LocalOnlyHotspotRequestInfo(binder, messenger,
+ new LocalOnlyRequestorCallback());
+ // TODO: move this below when start is implemented
+ mLocalOnlyHotspotRequests.put(uid, request);
+
+ // check if LOHS is already active, if so, record the request and trigger the callback
+ if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)) {
+ try {
+ Slog.d(TAG, "LOHS already up, send started");
+ request.sendHotspotStartedMessage(mLocalOnlyHotspotConfig);
+ // TODO: move this return value out of the try when start is implemented
+ return LocalOnlyHotspotCallback.REQUEST_REGISTERED;
+ } catch (RemoteException e) {
+ mLocalOnlyHotspotRequests.remove(uid);
+ return LocalOnlyHotspotCallback.ERROR_GENERIC;
+ }
+ }
}
throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");