Merge changes from topic "revert-3527440-JRJJTQBUFC" into main
* changes: Revert "Reject TetheringRequests that fuzzy-match existing ones" Revert "Stop tethering request only if fuzzy-matched to existing..."
This commit is contained in:
commit
99ef00112e
7 changed files with 137 additions and 886 deletions
|
|
@ -37,7 +37,6 @@ import android.os.Parcelable;
|
|||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
|
@ -1259,44 +1258,6 @@ public class TetheringManager {
|
|||
return sj.toString();
|
||||
}
|
||||
|
||||
@SuppressLint("UnflaggedApi")
|
||||
private static boolean supportsInterfaceName(int tetheringType) {
|
||||
// TODO: Check the interface name for TETHERING_WIFI and TETHERING_WIFI_P2P once
|
||||
// they're actually used.
|
||||
// Suppress lint for TETHERING_VIRTUAL since this method is only used internally.
|
||||
return tetheringType == TETHERING_VIRTUAL;
|
||||
}
|
||||
|
||||
private static boolean supportsConcurrentConnectivityScopes(int tetheringType) {
|
||||
// Currently, only WIFI supports simultaneous local and global connectivity.
|
||||
// This can't happen for REQUEST_TYPE_EXPLICIT requests, because
|
||||
// TetheringRequest.Builder will not allow building an explicit TetheringRequest
|
||||
// with TETHERING_WIFI and CONNECTIVITY_SCOPE_LOCAL, but when local-only hotspot
|
||||
// is running, there is a REQUEST_TYPE_IMPLICIT request in the serving request list.
|
||||
return tetheringType == TETHERING_WIFI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the other TetheringRequest "fuzzy" matches this one. This is used
|
||||
* internally to match tracked requests with external requests from API calls, and to reject
|
||||
* additional requests that the link layer has no capacity for.
|
||||
* @hide
|
||||
*/
|
||||
public boolean fuzzyMatches(final TetheringRequest other) {
|
||||
if (other == null) return false;
|
||||
final int type = getTetheringType();
|
||||
if (type != other.getTetheringType()) return false;
|
||||
if (supportsInterfaceName(type)
|
||||
&& !TextUtils.equals(getInterfaceName(), other.getInterfaceName())) {
|
||||
return false;
|
||||
}
|
||||
if (supportsConcurrentConnectivityScopes(type)
|
||||
&& getConnectivityScope() != other.getConnectivityScope()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
|
|
@ -1318,8 +1279,6 @@ public class TetheringManager {
|
|||
public boolean equalsIgnoreUidPackage(TetheringRequest otherRequest) {
|
||||
TetheringRequestParcel parcel = getParcel();
|
||||
TetheringRequestParcel otherParcel = otherRequest.getParcel();
|
||||
// Note: Changes here should also be reflected in fuzzyMatches(TetheringRequest) when
|
||||
// appropriate.
|
||||
return parcel.requestType == otherParcel.requestType
|
||||
&& parcel.tetheringType == otherParcel.tetheringType
|
||||
&& Objects.equals(parcel.localIPv4Address, otherParcel.localIPv4Address)
|
||||
|
|
|
|||
|
|
@ -415,6 +415,12 @@ public class IpServer extends StateMachineShim {
|
|||
return mIpv4PrefixRequest;
|
||||
}
|
||||
|
||||
/** The TetheringRequest the IpServer started with. */
|
||||
@Nullable
|
||||
public TetheringRequest getTetheringRequest() {
|
||||
return mTetheringRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest list of DHCP leases that was reported. Must be called on the IpServer looper
|
||||
* thread.
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ package com.android.networkstack.tethering;
|
|||
import static com.android.networkstack.tethering.util.TetheringUtils.createPlaceholderRequest;
|
||||
|
||||
import android.net.TetheringManager.TetheringRequest;
|
||||
import android.net.ip.IpServer;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -30,7 +28,6 @@ import com.android.internal.annotations.VisibleForTesting;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Helper class to keep track of tethering requests.
|
||||
|
|
@ -39,17 +36,29 @@ import java.util.Map;
|
|||
* layer to start.
|
||||
* 2) When the link layer is up, use {@link #getOrCreatePendingRequest(int)} to get a request to
|
||||
* start IP serving with.
|
||||
* 3) Remove pending request with {@link #removePendingRequest(TetheringRequest)}.
|
||||
* 3) Remove all pending requests with {@link #removeAllPendingRequests(int)}.
|
||||
* Note: This class is not thread-safe.
|
||||
* TODO: Add the pending IIntResultListeners at the same time as the pending requests, and
|
||||
* call them when we get the tether result.
|
||||
* TODO: Add support for multiple Bluetooth requests before the PAN service connects instead of
|
||||
* using a separate mPendingPanRequestListeners.
|
||||
* TODO: Add support for fuzzy-matched requests.
|
||||
*/
|
||||
public class RequestTracker {
|
||||
private static final String TAG = RequestTracker.class.getSimpleName();
|
||||
|
||||
@NonNull
|
||||
private final boolean mUseFuzzyMatching;
|
||||
private class PendingRequest {
|
||||
@NonNull
|
||||
private final TetheringRequest mTetheringRequest;
|
||||
|
||||
public RequestTracker(boolean useFuzzyMatching) {
|
||||
mUseFuzzyMatching = useFuzzyMatching;
|
||||
private PendingRequest(@NonNull TetheringRequest tetheringRequest) {
|
||||
mTetheringRequest = tetheringRequest;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
TetheringRequest getTetheringRequest() {
|
||||
return mTetheringRequest;
|
||||
}
|
||||
}
|
||||
|
||||
public enum AddResult {
|
||||
|
|
@ -60,51 +69,24 @@ public class RequestTracker {
|
|||
/**
|
||||
* Failure indicating that the request could not be added due to a request of the same type
|
||||
* with conflicting parameters already pending. If so, we must stop tethering for the
|
||||
* pending request before trying to add the result again. Only returned on V-.
|
||||
* pending request before trying to add the result again.
|
||||
*/
|
||||
FAILURE_DUPLICATE_REQUEST_RESTART,
|
||||
/**
|
||||
* Failure indicating that the request could not be added due to a fuzzy-matched request
|
||||
* already pending or serving. Only returned on B+.
|
||||
*/
|
||||
FAILURE_DUPLICATE_REQUEST_ERROR,
|
||||
FAILURE_CONFLICTING_PENDING_REQUEST
|
||||
}
|
||||
|
||||
/**
|
||||
* List of pending requests added by {@link #addPendingRequest(TetheringRequest)}
|
||||
* There can be only one per type, since we remove every request of the
|
||||
* same type when we add a request.
|
||||
* List of pending requests added by {@link #addPendingRequest(TetheringRequest)}. There can be
|
||||
* only one per type, since we remove every request of the same type when we add a request.
|
||||
*/
|
||||
private final List<TetheringRequest> mPendingRequests = new ArrayList<>();
|
||||
/**
|
||||
* List of serving requests added by
|
||||
* {@link #promoteRequestToServing(IpServer, TetheringRequest)}.
|
||||
*/
|
||||
private final Map<IpServer, TetheringRequest> mServingRequests = new ArrayMap<>();
|
||||
private final List<PendingRequest> mPendingRequests = new ArrayList<>();
|
||||
|
||||
@VisibleForTesting
|
||||
List<TetheringRequest> getPendingTetheringRequests() {
|
||||
return new ArrayList<>(mPendingRequests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pending request or fails with FAILURE_CONFLICTING_REQUEST_FAIL if the request
|
||||
* fuzzy-matches an existing request (either pending or serving).
|
||||
*/
|
||||
public AddResult addPendingRequestFuzzyMatched(@NonNull final TetheringRequest newRequest) {
|
||||
List<TetheringRequest> existingRequests = new ArrayList<>();
|
||||
existingRequests.addAll(mServingRequests.values());
|
||||
existingRequests.addAll(mPendingRequests);
|
||||
for (TetheringRequest request : existingRequests) {
|
||||
if (request.fuzzyMatches(newRequest)) {
|
||||
Log.i(TAG, "Cannot add pending request due to existing fuzzy-matched "
|
||||
+ "request: " + request);
|
||||
return AddResult.FAILURE_DUPLICATE_REQUEST_ERROR;
|
||||
}
|
||||
List<TetheringRequest> requests = new ArrayList<>();
|
||||
for (PendingRequest pendingRequest : mPendingRequests) {
|
||||
requests.add(pendingRequest.getTetheringRequest());
|
||||
}
|
||||
|
||||
mPendingRequests.add(newRequest);
|
||||
return AddResult.SUCCESS;
|
||||
return requests;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -113,12 +95,9 @@ public class RequestTracker {
|
|||
* layer comes up. The result of the add operation will be returned as an AddResult code.
|
||||
*/
|
||||
public AddResult addPendingRequest(@NonNull final TetheringRequest newRequest) {
|
||||
if (mUseFuzzyMatching) {
|
||||
return addPendingRequestFuzzyMatched(newRequest);
|
||||
}
|
||||
|
||||
// Check the existing requests to see if it is OK to add the new request.
|
||||
for (TetheringRequest existingRequest : mPendingRequests) {
|
||||
for (PendingRequest request : mPendingRequests) {
|
||||
TetheringRequest existingRequest = request.getTetheringRequest();
|
||||
if (existingRequest.getTetheringType() != newRequest.getTetheringType()) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -126,7 +105,7 @@ public class RequestTracker {
|
|||
// Can't add request if there's a request of the same type with different
|
||||
// parameters.
|
||||
if (!existingRequest.equalsIgnoreUidPackage(newRequest)) {
|
||||
return AddResult.FAILURE_DUPLICATE_REQUEST_RESTART;
|
||||
return AddResult.FAILURE_CONFLICTING_PENDING_REQUEST;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +113,7 @@ public class RequestTracker {
|
|||
// conflicting parameters above, so these would have been equivalent anyway (except for
|
||||
// UID).
|
||||
removeAllPendingRequests(newRequest.getTetheringType());
|
||||
mPendingRequests.add(newRequest);
|
||||
mPendingRequests.add(new PendingRequest(newRequest));
|
||||
return AddResult.SUCCESS;
|
||||
}
|
||||
|
||||
|
|
@ -166,8 +145,10 @@ public class RequestTracker {
|
|||
*/
|
||||
@Nullable
|
||||
public TetheringRequest getNextPendingRequest(int type) {
|
||||
for (TetheringRequest request : mPendingRequests) {
|
||||
if (request.getTetheringType() == type) return request;
|
||||
for (PendingRequest pendingRequest : mPendingRequests) {
|
||||
TetheringRequest tetheringRequest =
|
||||
pendingRequest.getTetheringRequest();
|
||||
if (tetheringRequest.getTetheringType() == type) return tetheringRequest;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -177,83 +158,7 @@ public class RequestTracker {
|
|||
*
|
||||
* @param type Tethering type
|
||||
*/
|
||||
public void removeAllPendingRequests(final int type) {
|
||||
mPendingRequests.removeIf(r -> r.getTetheringType() == type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a specific pending request.
|
||||
*
|
||||
* Note: For V-, this will be the same as removeAllPendingRequests to align with historical
|
||||
* behavior.
|
||||
*
|
||||
* @param request Request to be removed
|
||||
*/
|
||||
public void removePendingRequest(@NonNull TetheringRequest request) {
|
||||
if (!mUseFuzzyMatching) {
|
||||
// Remove all requests of the same type to match the historical behavior.
|
||||
removeAllPendingRequests(request.getTetheringType());
|
||||
return;
|
||||
}
|
||||
|
||||
mPendingRequests.removeIf(r -> r.equals(request));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a tethering request from the pending list and promotes it to serving with the
|
||||
* IpServer that is using it.
|
||||
* Note: If mUseFuzzyMatching is false, then the request will be removed from the pending list,
|
||||
* but it will not be added to serving list.
|
||||
*/
|
||||
public void promoteRequestToServing(@NonNull final IpServer ipServer,
|
||||
@NonNull final TetheringRequest tetheringRequest) {
|
||||
removePendingRequest(tetheringRequest);
|
||||
if (!mUseFuzzyMatching) return;
|
||||
mServingRequests.put(ipServer, tetheringRequest);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the serving request tied to the given IpServer, or null if there is none.
|
||||
* Note: If mUseFuzzyMatching is false, then this will always return null.
|
||||
*/
|
||||
@Nullable
|
||||
public TetheringRequest getServingRequest(@NonNull final IpServer ipServer) {
|
||||
return mServingRequests.get(ipServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the serving request tied to the given IpServer.
|
||||
* Note: If mUseFuzzyMatching is false, then this is a no-op since serving requests are unused
|
||||
* for that configuration.
|
||||
*/
|
||||
public void removeServingRequest(@NonNull final IpServer ipServer) {
|
||||
mServingRequests.remove(ipServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all serving requests of the given tethering type.
|
||||
*
|
||||
* @param type Tethering type
|
||||
*/
|
||||
public void removeAllServingRequests(final int type) {
|
||||
mServingRequests.entrySet().removeIf(e -> e.getValue().getTetheringType() == type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an existing (pending or serving) request that fuzzy matches the given request.
|
||||
* Optionally specify matchUid to only return requests with the same uid.
|
||||
*/
|
||||
public TetheringRequest findFuzzyMatchedRequest(
|
||||
@NonNull final TetheringRequest tetheringRequest, boolean matchUid) {
|
||||
List<TetheringRequest> allRequests = new ArrayList<>();
|
||||
allRequests.addAll(getPendingTetheringRequests());
|
||||
allRequests.addAll(mServingRequests.values());
|
||||
for (TetheringRequest request : allRequests) {
|
||||
if (!request.fuzzyMatches(tetheringRequest)) continue;
|
||||
if (matchUid && tetheringRequest.getUid() != request.getUid()) continue;
|
||||
return request;
|
||||
}
|
||||
return null;
|
||||
public void removeAllPendingRequests(int type) {
|
||||
mPendingRequests.removeIf(r -> r.getTetheringRequest().getTetheringType() == type);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ import static android.net.TetheringManager.TETHERING_WIFI;
|
|||
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
|
||||
import static android.net.TetheringManager.TETHERING_WIGIG;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_BLUETOOTH_SERVICE_PENDING;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_DUPLICATE_REQUEST;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
|
||||
|
|
@ -68,8 +67,6 @@ import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
|
|||
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
|
||||
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
|
||||
import static com.android.networkstack.tethering.RequestTracker.AddResult.FAILURE_DUPLICATE_REQUEST_ERROR;
|
||||
import static com.android.networkstack.tethering.RequestTracker.AddResult.FAILURE_DUPLICATE_REQUEST_RESTART;
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.TETHER_FORCE_USB_FUNCTIONS;
|
||||
import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE;
|
||||
import static com.android.networkstack.tethering.UpstreamNetworkMonitor.isCellular;
|
||||
|
|
@ -312,7 +309,7 @@ public class Tethering {
|
|||
mLooper = mDeps.makeTetheringLooper();
|
||||
mNotificationUpdater = mDeps.makeNotificationUpdater(mContext, mLooper);
|
||||
mTetheringMetrics = mDeps.makeTetheringMetrics(mContext);
|
||||
mRequestTracker = new RequestTracker(isTetheringWithSoftApConfigEnabled());
|
||||
mRequestTracker = new RequestTracker();
|
||||
|
||||
mTetherStates = new ArrayMap<>();
|
||||
mConnectedClientsTracker = new ConnectedClientsTracker();
|
||||
|
|
@ -463,7 +460,6 @@ public class Tethering {
|
|||
return mSettingsObserver;
|
||||
}
|
||||
|
||||
// TODO: Replace with SdkLevel.isAtLeastB() once the feature is fully implemented.
|
||||
boolean isTetheringWithSoftApConfigEnabled() {
|
||||
return SdkLevel.isAtLeastB() && Flags.tetheringWithSoftApConfig();
|
||||
}
|
||||
|
|
@ -708,16 +704,9 @@ public class Tethering {
|
|||
RequestTracker.AddResult result = mRequestTracker.addPendingRequest(request);
|
||||
// If tethering is already pending with a conflicting request, stop tethering before
|
||||
// starting.
|
||||
if (result == FAILURE_DUPLICATE_REQUEST_RESTART) {
|
||||
if (result == RequestTracker.AddResult.FAILURE_CONFLICTING_PENDING_REQUEST) {
|
||||
stopTetheringInternal(type); // Also removes the request from the tracker.
|
||||
mRequestTracker.addPendingRequest(request);
|
||||
} else if (result == FAILURE_DUPLICATE_REQUEST_ERROR) {
|
||||
// Reject any fuzzy matched request.
|
||||
// TODO: Add a CTS test to verify back-to-back start/stop calls succeed. This must
|
||||
// be for a non-Wifi type, since Wifi will reject the start calls if it hasn't
|
||||
// brought down the SoftAP yet.
|
||||
sendTetherResult(listener, TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.isExemptFromEntitlementCheck()) {
|
||||
|
|
@ -737,28 +726,39 @@ public class Tethering {
|
|||
});
|
||||
}
|
||||
|
||||
private boolean isTetheringTypePendingOrServing(final int type) {
|
||||
if (mRequestTracker.getNextPendingRequest(type) != null) return true;
|
||||
for (TetherState state : mTetherStates.values()) {
|
||||
// TODO: isCurrentlyServing only starts returning true once the IpServer has processed
|
||||
// the CMD_TETHER_REQUESTED. Ensure that we consider the request to be serving even when
|
||||
// that has not happened yet.
|
||||
if (state.isCurrentlyServing() && state.ipServer.interfaceType() == type) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void stopTetheringRequest(@NonNull final TetheringRequest request,
|
||||
@NonNull final IIntResultListener listener) {
|
||||
if (!isTetheringWithSoftApConfigEnabled()) return;
|
||||
final boolean hasNetworkSettings = hasCallingPermission(NETWORK_SETTINGS);
|
||||
mHandler.post(() -> {
|
||||
if (mRequestTracker.findFuzzyMatchedRequest(request, !hasNetworkSettings) != null) {
|
||||
final int type = request.getTetheringType();
|
||||
final int type = request.getTetheringType();
|
||||
if (isTetheringTypePendingOrServing(type)) {
|
||||
stopTetheringInternal(type);
|
||||
// TODO: We should send the success result after the waiting for tethering to
|
||||
// actually stop.
|
||||
sendTetherResult(listener, TETHER_ERROR_NO_ERROR);
|
||||
try {
|
||||
listener.onResult(TETHER_ERROR_NO_ERROR);
|
||||
} catch (RemoteException ignored) { }
|
||||
return;
|
||||
}
|
||||
|
||||
// Request doesn't match any active requests, ignore.
|
||||
sendTetherResult(listener, TETHER_ERROR_UNKNOWN_REQUEST);
|
||||
try {
|
||||
listener.onResult(TETHER_ERROR_UNKNOWN_REQUEST);
|
||||
} catch (RemoteException ignored) { }
|
||||
});
|
||||
}
|
||||
|
||||
void stopTetheringInternal(int type) {
|
||||
mRequestTracker.removeAllPendingRequests(type);
|
||||
mRequestTracker.removeAllServingRequests(type);
|
||||
|
||||
// Using a placeholder here is ok since none of the disable APIs use the request for
|
||||
// anything. We simply need the tethering type to know which link layer to poke for removal.
|
||||
|
|
@ -802,25 +802,21 @@ public class Tethering {
|
|||
// The result of Bluetooth tethering will be sent after the pan service connects.
|
||||
if (result == TETHER_ERROR_BLUETOOTH_SERVICE_PENDING) return;
|
||||
|
||||
sendTetherResultAndRemoveOnError(request, listener, result);
|
||||
sendTetherResult(listener, result, type);
|
||||
}
|
||||
|
||||
private void sendTetherResult(final IIntResultListener listener, final int result) {
|
||||
private void sendTetherResult(final IIntResultListener listener, final int result,
|
||||
final int type) {
|
||||
if (listener != null) {
|
||||
try {
|
||||
listener.onResult(result);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
} catch (RemoteException e) { }
|
||||
}
|
||||
}
|
||||
|
||||
private void sendTetherResultAndRemoveOnError(TetheringRequest request,
|
||||
final IIntResultListener listener, final int result) {
|
||||
sendTetherResult(listener, result);
|
||||
|
||||
// If changing tethering fail, remove corresponding request
|
||||
// no matter who trigger the start/stop.
|
||||
if (result != TETHER_ERROR_NO_ERROR) {
|
||||
mRequestTracker.removePendingRequest(request);
|
||||
final int type = request.getTetheringType();
|
||||
mRequestTracker.removeAllPendingRequests(type);
|
||||
mTetheringMetrics.updateErrorCode(type, result);
|
||||
mTetheringMetrics.sendReport(type);
|
||||
}
|
||||
|
|
@ -866,7 +862,8 @@ public class Tethering {
|
|||
// the service just to stop tethering since tethering is not started. Just remove
|
||||
// any pending request to enable tethering, and notify them that they have failed.
|
||||
if (mPendingPanRequestListener != null) {
|
||||
sendTetherResult(mPendingPanRequestListener, TETHER_ERROR_SERVICE_UNAVAIL);
|
||||
sendTetherResult(mPendingPanRequestListener, TETHER_ERROR_SERVICE_UNAVAIL,
|
||||
TETHERING_BLUETOOTH);
|
||||
}
|
||||
mPendingPanRequestListener = null;
|
||||
return TETHER_ERROR_NO_ERROR;
|
||||
|
|
@ -907,10 +904,7 @@ public class Tethering {
|
|||
if (mPendingPanRequestListener != null) {
|
||||
final int result = setBluetoothTetheringSettings(mBluetoothPan,
|
||||
true /* enable */);
|
||||
sendTetherResultAndRemoveOnError(
|
||||
mRequestTracker.getOrCreatePendingRequest(TETHERING_BLUETOOTH),
|
||||
mPendingPanRequestListener,
|
||||
result);
|
||||
sendTetherResult(mPendingPanRequestListener, result, TETHERING_BLUETOOTH);
|
||||
}
|
||||
mPendingPanRequestListener = null;
|
||||
});
|
||||
|
|
@ -924,10 +918,8 @@ public class Tethering {
|
|||
mIsConnected = false;
|
||||
|
||||
if (mPendingPanRequestListener != null) {
|
||||
sendTetherResultAndRemoveOnError(
|
||||
mRequestTracker.getOrCreatePendingRequest(TETHERING_BLUETOOTH),
|
||||
mPendingPanRequestListener,
|
||||
TETHER_ERROR_SERVICE_UNAVAIL);
|
||||
sendTetherResult(mPendingPanRequestListener, TETHER_ERROR_SERVICE_UNAVAIL,
|
||||
TETHERING_BLUETOOTH);
|
||||
}
|
||||
mPendingPanRequestListener = null;
|
||||
mBluetoothIfaceRequest = null;
|
||||
|
|
@ -1101,7 +1093,9 @@ public class Tethering {
|
|||
final int type = ifaceNameToType(iface);
|
||||
if (type == TETHERING_INVALID) {
|
||||
Log.e(TAG, "Ignoring call to legacy tether for unknown iface " + iface);
|
||||
sendTetherResult(listener, TETHER_ERROR_UNKNOWN_IFACE);
|
||||
try {
|
||||
listener.onResult(TETHER_ERROR_UNKNOWN_IFACE);
|
||||
} catch (RemoteException e) { }
|
||||
}
|
||||
|
||||
TetheringRequest request = mRequestTracker.getNextPendingRequest(type);
|
||||
|
|
@ -1138,7 +1132,9 @@ public class Tethering {
|
|||
// Do nothing
|
||||
break;
|
||||
}
|
||||
sendTetherResult(listener, result);
|
||||
try {
|
||||
listener.onResult(result);
|
||||
} catch (RemoteException e) { }
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1171,9 +1167,11 @@ public class Tethering {
|
|||
Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
|
||||
return TETHER_ERROR_UNAVAIL_IFACE;
|
||||
}
|
||||
mRequestTracker.promoteRequestToServing(tetherState.ipServer, request);
|
||||
// NOTE: If a CMD_TETHER_REQUESTED message is already in the IpServer's queue but not yet
|
||||
// processed, this will be a no-op and it will not return an error.
|
||||
//
|
||||
// This code cannot race with untether() because they both run on the handler thread.
|
||||
mRequestTracker.removeAllPendingRequests(request.getTetheringType());
|
||||
tetherState.ipServer.enable(request);
|
||||
if (request.getRequestType() == REQUEST_TYPE_PLACEHOLDER) {
|
||||
TerribleErrorLog.logTerribleError(TetheringStatsLog::write,
|
||||
|
|
@ -1193,7 +1191,10 @@ public class Tethering {
|
|||
return;
|
||||
}
|
||||
mHandler.post(() -> {
|
||||
sendTetherResult(listener, legacyUntetherInternal(iface));
|
||||
try {
|
||||
listener.onResult(legacyUntetherInternal(iface));
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -1208,7 +1209,7 @@ public class Tethering {
|
|||
Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
|
||||
return TETHER_ERROR_UNAVAIL_IFACE;
|
||||
}
|
||||
ensureIpServerUnwanted(tetherState.ipServer);
|
||||
tetherState.ipServer.unwanted();
|
||||
return TETHER_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
|
@ -1288,12 +1289,7 @@ public class Tethering {
|
|||
final TetherState tetherState = mTetherStates.valueAt(i);
|
||||
final int type = tetherState.ipServer.interfaceType();
|
||||
final String iface = mTetherStates.keyAt(i);
|
||||
// Note: serving requests are only populated on B+. B+ also uses the sync state
|
||||
// machine by default. This ensures that the serving request is (correctly) populated
|
||||
// after the IpServer enters the available state and before it enters the serving
|
||||
// state.
|
||||
final TetheringRequest request =
|
||||
mRequestTracker.getServingRequest(tetherState.ipServer);
|
||||
final TetheringRequest request = tetherState.ipServer.getTetheringRequest();
|
||||
final boolean includeSoftApConfig = request != null && cookie != null
|
||||
&& (cookie.uid == request.getUid() || cookie.hasSystemPrivilege);
|
||||
final TetheringInterface tetheringIface = new TetheringInterface(type, iface,
|
||||
|
|
@ -1615,7 +1611,7 @@ public class Tethering {
|
|||
|
||||
private void disableWifiIpServingCommon(int tetheringType, String ifname) {
|
||||
if (!TextUtils.isEmpty(ifname) && mTetherStates.containsKey(ifname)) {
|
||||
ensureIpServerUnwanted(mTetherStates.get(ifname).ipServer);
|
||||
mTetherStates.get(ifname).ipServer.unwanted();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1632,7 +1628,7 @@ public class Tethering {
|
|||
for (int i = 0; i < mTetherStates.size(); i++) {
|
||||
final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
|
||||
if (ipServer.interfaceType() == tetheringType) {
|
||||
ensureIpServerUnwanted(ipServer);
|
||||
ipServer.unwanted();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -1779,7 +1775,9 @@ public class Tethering {
|
|||
|
||||
void setUsbTethering(boolean enable, IIntResultListener listener) {
|
||||
mHandler.post(() -> {
|
||||
sendTetherResult(listener, setUsbTethering(enable));
|
||||
try {
|
||||
listener.onResult(setUsbTethering(enable));
|
||||
} catch (RemoteException e) { }
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -2906,9 +2904,6 @@ public class Tethering {
|
|||
tetherState.lastState = state;
|
||||
tetherState.lastError = lastError;
|
||||
} else {
|
||||
// Note: Even if an IpServer exists for this iface, it may be different from "who"
|
||||
// if a new IpServer fills the gap before the IpServer.STATE_UNAVAILABLE transition.
|
||||
// TODO: remove this comment once the sync state machine is enabled everywhere.
|
||||
if (DBG) Log.d(TAG, "got notification from stale iface " + iface);
|
||||
}
|
||||
|
||||
|
|
@ -2923,19 +2918,7 @@ public class Tethering {
|
|||
int which;
|
||||
switch (state) {
|
||||
case IpServer.STATE_UNAVAILABLE:
|
||||
which = TetherMainSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
|
||||
break;
|
||||
case IpServer.STATE_AVAILABLE:
|
||||
if (lastError != TETHER_ERROR_NO_ERROR) {
|
||||
// IpServer transitioned from an enabled state (STATE_TETHERED or
|
||||
// STATE_LOCAL_ONLY) back to STATE_AVAILABLE due to an error, so make sure
|
||||
// we remove the serving request from RequestTracker.
|
||||
// TODO: don't continue to use IpServers after they have hit an error, and
|
||||
// instead move them to STATE_UNAVAILABLE. This code can then
|
||||
// unconditionally remove the serving request whenever the IpServer enters
|
||||
// STATE_UNAVAILABLE.
|
||||
mRequestTracker.removeServingRequest(who);
|
||||
}
|
||||
which = TetherMainSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
|
||||
break;
|
||||
case IpServer.STATE_TETHERED:
|
||||
|
|
@ -3031,18 +3014,11 @@ public class Tethering {
|
|||
final TetherState tetherState = mTetherStates.get(iface);
|
||||
if (tetherState == null) return;
|
||||
|
||||
mRequestTracker.removeServingRequest(tetherState.ipServer);
|
||||
tetherState.ipServer.stop();
|
||||
mLog.i("removing IpServer for: " + iface);
|
||||
mTetherStates.remove(iface);
|
||||
}
|
||||
|
||||
private void ensureIpServerUnwanted(final IpServer ipServer) {
|
||||
mLog.i("unrequesting IpServer: " + ipServer);
|
||||
mRequestTracker.removeServingRequest(ipServer);
|
||||
ipServer.unwanted();
|
||||
}
|
||||
|
||||
private static String[] copy(String[] strarray) {
|
||||
return Arrays.copyOf(strarray, strarray.length);
|
||||
}
|
||||
|
|
@ -3050,7 +3026,9 @@ public class Tethering {
|
|||
void setPreferTestNetworks(final boolean prefer, IIntResultListener listener) {
|
||||
mHandler.post(() -> {
|
||||
mUpstreamNetworkMonitor.setPreferTestNetworks(prefer);
|
||||
sendTetherResult(listener, TETHER_ERROR_NO_ERROR);
|
||||
try {
|
||||
listener.onResult(TETHER_ERROR_NO_ERROR);
|
||||
} catch (RemoteException e) { }
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,22 +18,19 @@ package com.android.networkstack.tethering;
|
|||
|
||||
import static android.net.TetheringManager.TETHERING_USB;
|
||||
import static android.net.TetheringManager.TETHERING_WIFI;
|
||||
import static android.net.TetheringManager.TETHERING_VIRTUAL;
|
||||
|
||||
import static com.android.networkstack.tethering.util.TetheringUtils.createPlaceholderRequest;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.net.TetheringManager.TetheringRequest;
|
||||
import android.net.ip.IpServer;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.networkstack.tethering.RequestTracker.AddResult;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
|
|
@ -42,10 +39,13 @@ import org.junit.runner.RunWith;
|
|||
public class RequestTrackerTest {
|
||||
private RequestTracker mRequestTracker;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mRequestTracker = new RequestTracker();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoRequestsAdded_noPendingRequests() {
|
||||
mRequestTracker = new RequestTracker(false);
|
||||
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull();
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI))
|
||||
.isEqualTo(createPlaceholderRequest(TETHERING_WIFI));
|
||||
|
|
@ -53,7 +53,6 @@ public class RequestTrackerTest {
|
|||
|
||||
@Test
|
||||
public void testAddRequest_successResultAndBecomesNextPending() {
|
||||
mRequestTracker = new RequestTracker(false);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
|
||||
final AddResult result = mRequestTracker.addPendingRequest(request);
|
||||
|
|
@ -65,7 +64,6 @@ public class RequestTrackerTest {
|
|||
|
||||
@Test
|
||||
public void testAddRequest_equalRequestExists_successResultAndBecomesNextPending() {
|
||||
mRequestTracker = new RequestTracker(false);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
mRequestTracker.addPendingRequest(request);
|
||||
|
||||
|
|
@ -79,7 +77,6 @@ public class RequestTrackerTest {
|
|||
|
||||
@Test
|
||||
public void testAddRequest_equalButDifferentUidRequest_successResultAndBecomesNextPending() {
|
||||
mRequestTracker = new RequestTracker(false);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
request.setUid(1000);
|
||||
request.setPackageName("package");
|
||||
|
|
@ -97,8 +94,7 @@ public class RequestTrackerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAddRequest_conflictingPendingRequest_returnsFailureConflictingRequestRestart() {
|
||||
mRequestTracker = new RequestTracker(false);
|
||||
public void testAddConflictingRequest_returnsFailureConflictingPendingRequest() {
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
final TetheringRequest conflictingRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setExemptFromEntitlementCheck(true).build();
|
||||
|
|
@ -106,139 +102,13 @@ public class RequestTrackerTest {
|
|||
|
||||
final AddResult result = mRequestTracker.addPendingRequest(conflictingRequest);
|
||||
|
||||
assertThat(result).isEqualTo(AddResult.FAILURE_DUPLICATE_REQUEST_RESTART);
|
||||
assertThat(result).isEqualTo(AddResult.FAILURE_CONFLICTING_PENDING_REQUEST);
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request);
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRequest_noExistingRequestsFuzzyMatching_returnsSuccess() {
|
||||
mRequestTracker = new RequestTracker(true);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
|
||||
final AddResult result = mRequestTracker.addPendingRequest(request);
|
||||
|
||||
assertThat(result).isEqualTo(AddResult.SUCCESS);
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request);
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRequest_conflictingPendingRequestFuzzyMatching_returnsFailure() {
|
||||
mRequestTracker = new RequestTracker(true);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
final TetheringRequest conflictingRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setExemptFromEntitlementCheck(true).build();
|
||||
mRequestTracker.addPendingRequest(request);
|
||||
|
||||
final AddResult result = mRequestTracker.addPendingRequest(conflictingRequest);
|
||||
|
||||
assertThat(result).isEqualTo(AddResult.FAILURE_DUPLICATE_REQUEST_ERROR);
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request);
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRequest_conflictingServingRequestFuzzyMatching_returnsFailure() {
|
||||
mRequestTracker = new RequestTracker(true);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
final TetheringRequest conflictingRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setExemptFromEntitlementCheck(true).build();
|
||||
mRequestTracker.promoteRequestToServing(mock(IpServer.class), request);
|
||||
|
||||
final AddResult result = mRequestTracker.addPendingRequest(conflictingRequest);
|
||||
|
||||
assertThat(result).isEqualTo(AddResult.FAILURE_DUPLICATE_REQUEST_ERROR);
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull();
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI))
|
||||
.isEqualTo(createPlaceholderRequest(TETHERING_WIFI));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRequest_nonMatchingPendingRequestFuzzyMatching_returnsSuccess() {
|
||||
mRequestTracker = new RequestTracker(true);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_VIRTUAL).build();
|
||||
final TetheringRequest nonFuzzyMatched = new TetheringRequest.Builder(TETHERING_VIRTUAL)
|
||||
.setInterfaceName("iface")
|
||||
.build();
|
||||
mRequestTracker.addPendingRequest(request);
|
||||
|
||||
final AddResult result = mRequestTracker.addPendingRequest(nonFuzzyMatched);
|
||||
|
||||
assertThat(result).isEqualTo(AddResult.SUCCESS);
|
||||
// Next request is still the first, but verify RequestTracker contains the second request by
|
||||
// seeing if it rejects anything matching the second request
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_VIRTUAL)).isEqualTo(request);
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_VIRTUAL))
|
||||
.isEqualTo(request);
|
||||
assertThat(mRequestTracker.addPendingRequestFuzzyMatched(nonFuzzyMatched))
|
||||
.isEqualTo(AddResult.FAILURE_DUPLICATE_REQUEST_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRequest_nonMatchingServingRequestFuzzyMatching_returnsSuccess() {
|
||||
mRequestTracker = new RequestTracker(true);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_VIRTUAL).build();
|
||||
final TetheringRequest nonFuzzyMatched = new TetheringRequest.Builder(TETHERING_VIRTUAL)
|
||||
.setInterfaceName("iface")
|
||||
.build();
|
||||
mRequestTracker.promoteRequestToServing(mock(IpServer.class), request);
|
||||
|
||||
final AddResult result = mRequestTracker.addPendingRequest(nonFuzzyMatched);
|
||||
|
||||
assertThat(result).isEqualTo(AddResult.SUCCESS);
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_VIRTUAL))
|
||||
.isEqualTo(nonFuzzyMatched);
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_VIRTUAL))
|
||||
.isEqualTo(nonFuzzyMatched);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemovePendingRequest_removesAllPendingRequestsOfType() {
|
||||
mRequestTracker = new RequestTracker(false);
|
||||
final TetheringRequest request1 = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
request1.setUid(1000);
|
||||
request1.setPackageName("package");
|
||||
mRequestTracker.addPendingRequest(request1);
|
||||
final TetheringRequest request2 = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
request2.setUid(2000);
|
||||
request2.setPackageName("package2");
|
||||
|
||||
mRequestTracker.removePendingRequest(request2);
|
||||
|
||||
// Verify request1 isn't pending even though we tried to remove a different request
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull();
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI))
|
||||
.isEqualTo(createPlaceholderRequest(TETHERING_WIFI));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemovePendingRequest_fuzzyMatching_onlyTheEqualRequestIsRemoved() {
|
||||
mRequestTracker = new RequestTracker(true);
|
||||
final TetheringRequest request1 = new TetheringRequest.Builder(TETHERING_VIRTUAL).build();
|
||||
final TetheringRequest request2 = new TetheringRequest.Builder(TETHERING_VIRTUAL)
|
||||
.setInterfaceName("iface")
|
||||
.build();
|
||||
mRequestTracker.addPendingRequest(request1);
|
||||
mRequestTracker.addPendingRequest(request2);
|
||||
|
||||
mRequestTracker.removePendingRequest(request2);
|
||||
|
||||
// Verify request1 is still pending.
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_VIRTUAL)).isEqualTo(request1);
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_VIRTUAL))
|
||||
.isEqualTo(request1);
|
||||
assertThat(mRequestTracker.addPendingRequestFuzzyMatched(request1))
|
||||
.isEqualTo(AddResult.FAILURE_DUPLICATE_REQUEST_ERROR);
|
||||
// Verify we've removed request2 by checking if it can be added back without
|
||||
// FAILURE_CONFLICTING_REQUEST_FAIL.
|
||||
assertThat(mRequestTracker.addPendingRequestFuzzyMatched(request2))
|
||||
.isEqualTo(AddResult.SUCCESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveAllPendingRequests_noPendingRequestsLeft() {
|
||||
mRequestTracker = new RequestTracker(false);
|
||||
final TetheringRequest firstRequest = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
firstRequest.setUid(1000);
|
||||
firstRequest.setPackageName("package");
|
||||
|
|
@ -257,7 +127,6 @@ public class RequestTrackerTest {
|
|||
|
||||
@Test
|
||||
public void testRemoveAllPendingRequests_differentTypeExists_doesNotRemoveDifferentType() {
|
||||
mRequestTracker = new RequestTracker(false);
|
||||
final TetheringRequest differentType = new TetheringRequest.Builder(TETHERING_USB).build();
|
||||
mRequestTracker.addPendingRequest(differentType);
|
||||
|
||||
|
|
@ -267,61 +136,4 @@ public class RequestTrackerTest {
|
|||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_USB))
|
||||
.isEqualTo(differentType);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPromoteRequestToServing_requestIsntPendingAnymore() {
|
||||
mRequestTracker = new RequestTracker(false);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
mRequestTracker.addPendingRequest(request);
|
||||
|
||||
mRequestTracker.promoteRequestToServing(mock(IpServer.class), request);
|
||||
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull();
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI))
|
||||
.isEqualTo(createPlaceholderRequest(TETHERING_WIFI));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPromoteRequestToServing_fuzzyMatching_requestIsntPendingAnymore() {
|
||||
mRequestTracker = new RequestTracker(true);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
mRequestTracker.addPendingRequest(request);
|
||||
|
||||
mRequestTracker.promoteRequestToServing(mock(IpServer.class), request);
|
||||
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isNull();
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI))
|
||||
.isEqualTo(createPlaceholderRequest(TETHERING_WIFI));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveServingRequest_fuzzyMatching_requestCanBeAddedAgain() {
|
||||
mRequestTracker = new RequestTracker(true);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
mRequestTracker.addPendingRequest(request);
|
||||
IpServer ipServer = mock(IpServer.class);
|
||||
mRequestTracker.promoteRequestToServing(ipServer, request);
|
||||
|
||||
mRequestTracker.removeServingRequest(ipServer);
|
||||
|
||||
AddResult result = mRequestTracker.addPendingRequest(request);
|
||||
assertThat(result).isEqualTo(AddResult.SUCCESS);
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request);
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveAllServingRequests_fuzzyMatching_requestCanBeAddedAgain() {
|
||||
mRequestTracker = new RequestTracker(true);
|
||||
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
mRequestTracker.addPendingRequest(request);
|
||||
mRequestTracker.promoteRequestToServing(mock(IpServer.class), request);
|
||||
|
||||
mRequestTracker.removeAllServingRequests(TETHERING_WIFI);
|
||||
|
||||
AddResult result = mRequestTracker.addPendingRequest(request);
|
||||
assertThat(result).isEqualTo(AddResult.SUCCESS);
|
||||
assertThat(mRequestTracker.getNextPendingRequest(TETHERING_WIFI)).isEqualTo(request);
|
||||
assertThat(mRequestTracker.getOrCreatePendingRequest(TETHERING_WIFI)).isEqualTo(request);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,18 +50,15 @@ import static android.net.TetheringManager.TETHERING_USB;
|
|||
import static android.net.TetheringManager.TETHERING_VIRTUAL;
|
||||
import static android.net.TetheringManager.TETHERING_WIFI;
|
||||
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_DUPLICATE_REQUEST;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_REQUEST;
|
||||
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
|
||||
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
|
||||
import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
|
||||
import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
|
||||
import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR;
|
||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
|
||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
|
||||
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
|
||||
|
|
@ -96,7 +93,6 @@ import static org.junit.Assert.assertNotNull;
|
|||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assume.assumeFalse;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.ArgumentMatchers.notNull;
|
||||
|
|
@ -201,7 +197,6 @@ import androidx.test.runner.AndroidJUnit4;
|
|||
import com.android.internal.util.test.BroadcastInterceptingContext;
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.modules.utils.build.SdkLevel;
|
||||
import com.android.net.flags.Flags;
|
||||
import com.android.net.module.util.CollectionUtils;
|
||||
import com.android.net.module.util.InterfaceParams;
|
||||
import com.android.net.module.util.PrivateAddressCoordinator;
|
||||
|
|
@ -313,7 +308,8 @@ public class TetheringTest {
|
|||
@Mock private TetheringMetrics mTetheringMetrics;
|
||||
@Mock private PrivateAddressCoordinator.Dependencies mPrivateAddressCoordinatorDependencies;
|
||||
|
||||
private MockIpServerDependencies mIpServerDependencies;
|
||||
private final MockIpServerDependencies mIpServerDependencies =
|
||||
spy(new MockIpServerDependencies());
|
||||
private final MockTetheringDependencies mTetheringDependencies =
|
||||
new MockTetheringDependencies();
|
||||
|
||||
|
|
@ -400,9 +396,6 @@ public class TetheringTest {
|
|||
}
|
||||
|
||||
public class MockIpServerDependencies extends IpServer.Dependencies {
|
||||
|
||||
private int mOnDhcpServerCreatedResult = STATUS_SUCCESS;
|
||||
|
||||
@Override
|
||||
public DadProxy getDadProxy(
|
||||
Handler handler, InterfaceParams ifParams) {
|
||||
|
|
@ -444,7 +437,7 @@ public class TetheringTest {
|
|||
DhcpServerCallbacks cb) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
cb.onDhcpServerCreated(mOnDhcpServerCreatedResult, mDhcpServer);
|
||||
cb.onDhcpServerCreated(STATUS_SUCCESS, mDhcpServer);
|
||||
} catch (RemoteException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
|
@ -455,10 +448,6 @@ public class TetheringTest {
|
|||
IpNeighborMonitor.NeighborEventConsumer c) {
|
||||
return mIpNeighborMonitor;
|
||||
}
|
||||
|
||||
public void setOnDhcpServerCreatedResult(final int result) {
|
||||
mOnDhcpServerCreatedResult = result;
|
||||
}
|
||||
}
|
||||
|
||||
public class MockTetheringDependencies extends TetheringDependencies {
|
||||
|
|
@ -719,7 +708,6 @@ public class TetheringTest {
|
|||
|
||||
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)).thenReturn(true);
|
||||
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI_DIRECT)).thenReturn(true);
|
||||
mIpServerDependencies = spy(new MockIpServerDependencies());
|
||||
}
|
||||
|
||||
// In order to interact with syncSM from the test, tethering must be created in test thread.
|
||||
|
|
@ -2437,7 +2425,7 @@ public class TetheringTest {
|
|||
|
||||
@Test
|
||||
public void testSoftApConfigInTetheringEventCallback() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
assumeTrue(SdkLevel.isAtLeastV());
|
||||
when(mContext.checkCallingOrSelfPermission(NETWORK_SETTINGS))
|
||||
.thenReturn(PERMISSION_DENIED);
|
||||
when(mContext.checkCallingOrSelfPermission(NETWORK_STACK))
|
||||
|
|
@ -2494,12 +2482,14 @@ public class TetheringTest {
|
|||
// Enable wifi tethering
|
||||
mBinderCallingUid = TEST_CALLER_UID;
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, null);
|
||||
mLooper.dispatchAll();
|
||||
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
|
||||
mLooper.dispatchAll();
|
||||
// Netd "up" event should not trigger a state change callback in B+.
|
||||
callback.assertNoStateChangeCallback();
|
||||
if (SdkLevel.isAtLeastB()) {
|
||||
// Starting in B, ignore the interfaceStatusChanged
|
||||
callback.assertNoStateChangeCallback();
|
||||
}
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
mLooper.dispatchAll();
|
||||
// Verify we see Available -> Tethered states
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig},
|
||||
callback.pollTetherStatesChanged().availableList);
|
||||
|
|
@ -2517,15 +2507,20 @@ public class TetheringTest {
|
|||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED);
|
||||
|
||||
// Disable wifi tethering
|
||||
mTethering.stopTethering(TETHERING_WIFI);
|
||||
mLooper.dispatchAll();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME,
|
||||
mTethering.stopTethering(TETHERING_WIFI);
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_DISABLED);
|
||||
if (isAtLeastT()) {
|
||||
// After T, tethering doesn't support WIFI_AP_STATE_DISABLED with null interface name.
|
||||
callback.assertNoStateChangeCallback();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME,
|
||||
IFACE_IP_MODE_TETHERED);
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig},
|
||||
}
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithConfig},
|
||||
callback.pollTetherStatesChanged().availableList);
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig},
|
||||
differentCallback.pollTetherStatesChanged().availableList);
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig},
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithConfig},
|
||||
settingsCallback.pollTetherStatesChanged().availableList);
|
||||
mLooper.dispatchAll();
|
||||
callback.expectUpstreamChanged(NULL_NETWORK);
|
||||
|
|
@ -2533,332 +2528,6 @@ public class TetheringTest {
|
|||
callback.assertNoCallback();
|
||||
}
|
||||
|
||||
private boolean isTetheringWithSoftApConfigEnabled() {
|
||||
return SdkLevel.isAtLeastB() && Flags.tetheringWithSoftApConfig();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFuzzyMatchedWifiCannotBeAdded() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
initTetheringOnTestThread();
|
||||
TestTetheringEventCallback callback = new TestTetheringEventCallback();
|
||||
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid(
|
||||
WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build();
|
||||
final TetheringInterface wifiIfaceWithoutConfig = new TetheringInterface(
|
||||
TETHERING_WIFI, TEST_WLAN_IFNAME, null);
|
||||
final TetheringInterface wifiIfaceWithConfig = new TetheringInterface(
|
||||
TETHERING_WIFI, TEST_WLAN_IFNAME, softApConfig);
|
||||
|
||||
// Register callback before running any tethering.
|
||||
mTethering.registerTetheringEventCallback(callback);
|
||||
mLooper.dispatchAll();
|
||||
callback.expectTetheredClientChanged(Collections.emptyList());
|
||||
callback.expectUpstreamChanged(NULL_NETWORK);
|
||||
callback.expectConfigurationChanged(
|
||||
mTethering.getTetheringConfiguration().toStableParcelable());
|
||||
assertTetherStatesNotNullButEmpty(callback.pollTetherStatesChanged());
|
||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
|
||||
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
|
||||
initTetheringUpstream(upstreamState);
|
||||
|
||||
// Start wifi tethering but don't trigger the link layer event yet.
|
||||
mBinderCallingUid = TEST_CALLER_UID;
|
||||
final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig).build();
|
||||
tetheringRequest.setUid(TEST_CALLER_UID);
|
||||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
when(mWifiManager.startTetheredHotspot(null)).thenReturn(true);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
successListener.assertHasResult();
|
||||
|
||||
// Try starting wifi tethering with various fuzzy-matching requests and verify we get
|
||||
// TETHER_ERROR_DUPLICATE_REQUEST.
|
||||
|
||||
// Different static IP addresses
|
||||
final TetheringRequest differentIpAddr = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig)
|
||||
.setStaticIpv4Addresses(new LinkAddress("192.168.0.123/24"),
|
||||
new LinkAddress("192.168.0.42/24"))
|
||||
.build();
|
||||
differentIpAddr.setUid(TEST_CALLER_UID);
|
||||
ResultListener differentIpAddrListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
mTethering.startTethering(differentIpAddr, TEST_CALLER_PKG, differentIpAddrListener);
|
||||
mLooper.dispatchAll();
|
||||
verify(mWifiManager, times(1)).startTetheredHotspot(any());
|
||||
verify(mWifiManager, never()).stopSoftAp();
|
||||
differentIpAddrListener.assertHasResult();
|
||||
|
||||
// Different UID
|
||||
final TetheringRequest differentUid = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig).build();
|
||||
differentUid.setUid(TEST_CALLER_UID + 1);
|
||||
ResultListener differentUidListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
mTethering.startTethering(differentUid, TEST_CALLER_PKG, differentUidListener);
|
||||
mLooper.dispatchAll();
|
||||
differentUidListener.assertHasResult();
|
||||
verify(mWifiManager, times(1)).startTetheredHotspot(any());
|
||||
verify(mWifiManager, never()).stopSoftAp();
|
||||
|
||||
// Mock the link layer event to start IP serving and verify we still get
|
||||
// TETHER_ERROR_DUPLICATE_REQUEST even though the request is no longer pending and is
|
||||
// already serving.
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithoutConfig},
|
||||
callback.pollTetherStatesChanged().availableList);
|
||||
assertArrayEquals(new TetheringInterface[] {wifiIfaceWithConfig},
|
||||
callback.pollTetherStatesChanged().tetheredList);
|
||||
callback.expectUpstreamChanged(upstreamState.network);
|
||||
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STARTED);
|
||||
differentIpAddrListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
differentUidListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
mTethering.startTethering(differentIpAddr, TEST_CALLER_PKG, differentIpAddrListener);
|
||||
mTethering.startTethering(differentUid, TEST_CALLER_PKG, differentUidListener);
|
||||
mLooper.dispatchAll();
|
||||
differentIpAddrListener.assertHasResult();
|
||||
differentUidListener.assertHasResult();
|
||||
verify(mWifiManager, times(1)).startTetheredHotspot(any());
|
||||
verify(mWifiManager, never()).stopSoftAp();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFuzzyMatchedWifiCanBeAddedAfterIpServerStopped() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
when(mWifiManager.startTetheredHotspot(null)).thenReturn(true);
|
||||
initTetheringOnTestThread();
|
||||
|
||||
// Start wifi tethering and mock the ap state change.
|
||||
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid(
|
||||
WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build();
|
||||
final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig).build();
|
||||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
successListener.assertHasResult();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
|
||||
// Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST
|
||||
ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, failureListener);
|
||||
mLooper.dispatchAll();
|
||||
failureListener.assertHasResult();
|
||||
|
||||
// Trigger Netd callback to stop the IpServer
|
||||
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, false);
|
||||
|
||||
// We should be able to request the same Wifi again
|
||||
ResultListener successListener2 = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2);
|
||||
mLooper.dispatchAll();
|
||||
successListener2.assertHasResult();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFuzzyMatchedWifiCanBeAddedAfterIpServerUnwanted() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
when(mWifiManager.startTetheredHotspot(null)).thenReturn(true);
|
||||
initTetheringOnTestThread();
|
||||
|
||||
// Start wifi tethering and mock the ap state change.
|
||||
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid(
|
||||
WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build();
|
||||
final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig).build();
|
||||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
successListener.assertHasResult();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
|
||||
// Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST
|
||||
ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, failureListener);
|
||||
mLooper.dispatchAll();
|
||||
failureListener.assertHasResult();
|
||||
|
||||
// Trigger wifi ap state change to tell IpServer it's unwanted.
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_DISABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
|
||||
// We should be able to request the same Wifi again
|
||||
ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2);
|
||||
mLooper.dispatchAll();
|
||||
successListener2.assertHasResult();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFuzzyMatchedWifiCanBeAddedAfterIpServerError() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
when(mWifiManager.startTetheredHotspot(null)).thenReturn(true);
|
||||
initTetheringOnTestThread();
|
||||
|
||||
// Set up the DHCP server to fail creation.
|
||||
mIpServerDependencies.setOnDhcpServerCreatedResult(STATUS_UNKNOWN_ERROR);
|
||||
|
||||
// Start wifi tethering and mock the ap state change.
|
||||
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid(
|
||||
WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build();
|
||||
final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig).build();
|
||||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
successListener.assertHasResult();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
|
||||
// We should be able to request the same Wifi again since the DHCP server transitioned the
|
||||
// IpServer back to InitialState.
|
||||
ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2);
|
||||
mLooper.dispatchAll();
|
||||
successListener2.assertHasResult();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFuzzyMatchedWifiCanBeAddedAfterStoppingPendingRequest() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
when(mWifiManager.startTetheredHotspot(null)).thenReturn(true);
|
||||
initTetheringOnTestThread();
|
||||
|
||||
// Start wifi tethering but keep the request pending by not sending the ap state change.
|
||||
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid(
|
||||
WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build();
|
||||
final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig).build();
|
||||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
successListener.assertHasResult();
|
||||
|
||||
// Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST
|
||||
ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, failureListener);
|
||||
mLooper.dispatchAll();
|
||||
failureListener.assertHasResult();
|
||||
|
||||
// Stop Wifi tethering.
|
||||
mTethering.stopTethering(TETHERING_WIFI);
|
||||
|
||||
// We should be able to request the same Wifi again
|
||||
ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2);
|
||||
mLooper.dispatchAll();
|
||||
successListener2.assertHasResult();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFuzzyMatchedWifiCanBeAddedAfterStoppingServingRequest() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
when(mWifiManager.startTetheredHotspot(null)).thenReturn(true);
|
||||
initTetheringOnTestThread();
|
||||
|
||||
// Start wifi tethering and mock the ap state change.
|
||||
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder().setWifiSsid(
|
||||
WifiSsid.fromBytes("SoftApConfig".getBytes(StandardCharsets.UTF_8))).build();
|
||||
final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig).build();
|
||||
ResultListener successListener = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener);
|
||||
mLooper.dispatchAll();
|
||||
successListener.assertHasResult();
|
||||
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED, TEST_WLAN_IFNAME, IFACE_IP_MODE_TETHERED);
|
||||
|
||||
// Starting wifi again will cause TETHER_ERROR_DUPLICATE_REQUEST
|
||||
ResultListener failureListener = new ResultListener(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, failureListener);
|
||||
mLooper.dispatchAll();
|
||||
failureListener.assertHasResult();
|
||||
|
||||
// Stop Wifi tethering.
|
||||
mTethering.stopTethering(TETHERING_WIFI);
|
||||
|
||||
// We should be able to request the same Wifi again
|
||||
ResultListener successListener2 = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, successListener2);
|
||||
mLooper.dispatchAll();
|
||||
successListener2.assertHasResult();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStopTetheringWithMatchingRequest() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
when(mContext.checkCallingOrSelfPermission(NETWORK_SETTINGS)).thenReturn(PERMISSION_DENIED);
|
||||
initTetheringOnTestThread();
|
||||
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
|
||||
initTetheringUpstream(upstreamState);
|
||||
when(mWifiManager.startTetheredHotspot(null)).thenReturn(true);
|
||||
|
||||
// Enable wifi tethering.
|
||||
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder()
|
||||
.setSsid("SoftApConfig")
|
||||
.build();
|
||||
final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig).build();
|
||||
tetheringRequest.setUid(TEST_CALLER_UID);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, null);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
// Stop tethering with non-matching config. Should fail with TETHER_ERROR_UNKNOWN_REQUEST.
|
||||
SoftApConfiguration softApConfig2 = new SoftApConfiguration.Builder()
|
||||
.setSsid("SoftApConfig2")
|
||||
.build();
|
||||
IIntResultListener differentConfigListener = mock(IIntResultListener.class);
|
||||
mTethering.stopTetheringRequest(new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig2).build(), differentConfigListener);
|
||||
mLooper.dispatchAll();
|
||||
verify(differentConfigListener).onResult(eq(TETHER_ERROR_UNKNOWN_REQUEST));
|
||||
verify(mWifiManager, never()).stopSoftAp();
|
||||
|
||||
// Stop tethering with non-matching UID. Should fail with TETHER_ERROR_UNKNOWN_REQUEST.
|
||||
final TetheringRequest nonMatchingUid = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig).build();
|
||||
IIntResultListener nonMatchingUidListener = mock(IIntResultListener.class);
|
||||
nonMatchingUid.setUid(TEST_CALLER_UID_2);
|
||||
mTethering.stopTetheringRequest(nonMatchingUid, nonMatchingUidListener);
|
||||
mLooper.dispatchAll();
|
||||
verify(nonMatchingUidListener).onResult(eq(TETHER_ERROR_UNKNOWN_REQUEST));
|
||||
verify(mWifiManager, never()).stopSoftAp();
|
||||
|
||||
// Stop tethering with matching request. Should succeed now.
|
||||
IIntResultListener matchingListener = mock(IIntResultListener.class);
|
||||
mTethering.stopTetheringRequest(tetheringRequest, matchingListener);
|
||||
mLooper.dispatchAll();
|
||||
verify(matchingListener).onResult(eq(TETHER_ERROR_NO_ERROR));
|
||||
verify(mWifiManager).stopSoftAp();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStopTetheringWithSettingsPermission() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
initTetheringOnTestThread();
|
||||
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
|
||||
initTetheringUpstream(upstreamState);
|
||||
when(mWifiManager.startTetheredHotspot(null)).thenReturn(true);
|
||||
|
||||
// Enable wifi tethering.
|
||||
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder()
|
||||
.setSsid("SoftApConfig")
|
||||
.build();
|
||||
final TetheringRequest tetheringRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig).build();
|
||||
tetheringRequest.setUid(TEST_CALLER_UID);
|
||||
mTethering.startTethering(tetheringRequest, TEST_CALLER_PKG, null);
|
||||
mLooper.dispatchAll();
|
||||
|
||||
// Stop tethering with non-matching UID and Settings permission. Should succeed.
|
||||
final TetheringRequest nonMatchingUid = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig).build();
|
||||
IIntResultListener nonMatchingUidListener = mock(IIntResultListener.class);
|
||||
nonMatchingUid.setUid(TEST_CALLER_UID_2);
|
||||
when(mContext.checkCallingOrSelfPermission(NETWORK_SETTINGS))
|
||||
.thenReturn(PERMISSION_GRANTED);
|
||||
mTethering.stopTetheringRequest(nonMatchingUid, nonMatchingUidListener);
|
||||
mLooper.dispatchAll();
|
||||
verify(nonMatchingUidListener).onResult(eq(TETHER_ERROR_NO_ERROR));
|
||||
verify(mWifiManager).stopSoftAp();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReportFailCallbackIfOffloadNotSupported() throws Exception {
|
||||
initTetheringOnTestThread();
|
||||
|
|
@ -3125,8 +2794,7 @@ public class TetheringTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleStartTetheringLegacy() throws Exception {
|
||||
assumeFalse(isTetheringWithSoftApConfigEnabled());
|
||||
public void testMultipleStartTethering() throws Exception {
|
||||
initTetheringOnTestThread();
|
||||
final LinkAddress serverLinkAddr = new LinkAddress("192.168.20.1/24");
|
||||
final LinkAddress clientLinkAddr = new LinkAddress("192.168.20.42/24");
|
||||
|
|
@ -3907,7 +3575,6 @@ public class TetheringTest {
|
|||
@Test
|
||||
public void testStartBluetoothTetheringFailsWhenTheresAnExistingRequestWaitingForPanService()
|
||||
throws Exception {
|
||||
assumeFalse(isTetheringWithSoftApConfigEnabled());
|
||||
initTetheringOnTestThread();
|
||||
|
||||
mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import static android.net.TetheringManager.TETHERING_USB;
|
|||
import static android.net.TetheringManager.TETHERING_VIRTUAL;
|
||||
import static android.net.TetheringManager.TETHERING_WIFI;
|
||||
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_DUPLICATE_REQUEST;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
|
||||
|
|
@ -235,30 +234,6 @@ public class TetheringManagerTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartTetheringDuplicateRequestRejected() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
final TestTetheringEventCallback tetherEventCallback =
|
||||
mCtsTetheringUtils.registerTetheringEventCallback();
|
||||
try {
|
||||
tetherEventCallback.assumeWifiTetheringSupported(mContext);
|
||||
tetherEventCallback.expectNoTetheringActive();
|
||||
|
||||
final String[] wifiRegexs = mTM.getTetherableWifiRegexs();
|
||||
mCtsTetheringUtils.startWifiTethering(tetherEventCallback);
|
||||
mTetherChangeReceiver.expectTethering(true /* active */, wifiRegexs);
|
||||
|
||||
final StartTetheringCallback startTetheringCallback = new StartTetheringCallback();
|
||||
runAsShell(TETHER_PRIVILEGED, () -> {
|
||||
mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(),
|
||||
c -> c.run() /* executor */, startTetheringCallback);
|
||||
startTetheringCallback.expectTetheringFailed(TETHER_ERROR_DUPLICATE_REQUEST);
|
||||
});
|
||||
} finally {
|
||||
mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
|
||||
}
|
||||
}
|
||||
|
||||
private SoftApConfiguration createSoftApConfiguration(@NonNull String ssid) {
|
||||
SoftApConfiguration config;
|
||||
if (SdkLevel.isAtLeastT()) {
|
||||
|
|
@ -405,20 +380,17 @@ public class TetheringManagerTest {
|
|||
tetherEventCallback.assumeWifiTetheringSupported(mContext);
|
||||
tetherEventCallback.expectNoTetheringActive();
|
||||
|
||||
SoftApConfiguration softApConfig = isTetheringWithSoftApConfigEnabled()
|
||||
? createSoftApConfiguration("SSID") : null;
|
||||
SoftApConfiguration softApConfig = createSoftApConfiguration("SSID");
|
||||
final TetheringInterface tetheredIface =
|
||||
mCtsTetheringUtils.startWifiTethering(tetherEventCallback, softApConfig);
|
||||
|
||||
assertNotNull(tetheredIface);
|
||||
if (isTetheringWithSoftApConfigEnabled()) {
|
||||
assertEquals(softApConfig, tetheredIface.getSoftApConfiguration());
|
||||
}
|
||||
assertEquals(softApConfig, tetheredIface.getSoftApConfiguration());
|
||||
final String wifiTetheringIface = tetheredIface.getInterface();
|
||||
|
||||
mCtsTetheringUtils.stopWifiTethering(tetherEventCallback);
|
||||
|
||||
if (!SdkLevel.isAtLeastB()) {
|
||||
final String wifiTetheringIface = tetheredIface.getInterface();
|
||||
try {
|
||||
final int ret = runAsShell(TETHER_PRIVILEGED,
|
||||
() -> mTM.tether(wifiTetheringIface));
|
||||
|
|
@ -483,73 +455,25 @@ public class TetheringManagerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testStopTetheringRequestNoMatchFailure() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
final TestTetheringEventCallback tetherEventCallback =
|
||||
mCtsTetheringUtils.registerTetheringEventCallback();
|
||||
try {
|
||||
final StartTetheringCallback startTetheringCallback = new StartTetheringCallback();
|
||||
mTM.startTethering(new TetheringRequest.Builder(TETHERING_VIRTUAL).build(),
|
||||
c -> c.run(), startTetheringCallback);
|
||||
|
||||
// Stopping a non-matching request should have no effect
|
||||
TetheringRequest nonMatchingRequest = new TetheringRequest.Builder(TETHERING_VIRTUAL)
|
||||
.setInterfaceName("iface")
|
||||
.build();
|
||||
mCtsTetheringUtils.stopTethering(nonMatchingRequest, false /* success */);
|
||||
} finally {
|
||||
mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStopTetheringRequestMatchSuccess() throws Exception {
|
||||
public void testStopTetheringRequest() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
final TestTetheringEventCallback tetherEventCallback =
|
||||
mCtsTetheringUtils.registerTetheringEventCallback();
|
||||
try {
|
||||
tetherEventCallback.assumeWifiTetheringSupported(mContext);
|
||||
|
||||
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder()
|
||||
.setWifiSsid(WifiSsid.fromBytes("This is one config"
|
||||
.getBytes(StandardCharsets.UTF_8))).build();
|
||||
mCtsTetheringUtils.startWifiTethering(tetherEventCallback, softApConfig);
|
||||
// stopTethering without any tethering active should fail.
|
||||
TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI).build();
|
||||
mCtsTetheringUtils.stopTethering(request, false /* expectSuccess */);
|
||||
|
||||
// Stopping the active request should stop tethering.
|
||||
TetheringRequest request = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig)
|
||||
.build();
|
||||
mCtsTetheringUtils.stopTethering(request, true /* success */);
|
||||
tetherEventCallback.expectNoTetheringActive();
|
||||
} finally {
|
||||
mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
|
||||
}
|
||||
}
|
||||
// Start wifi tethering
|
||||
mCtsTetheringUtils.startWifiTethering(tetherEventCallback);
|
||||
|
||||
@Test
|
||||
public void testStopTetheringRequestFuzzyMatchSuccess() throws Exception {
|
||||
assumeTrue(isTetheringWithSoftApConfigEnabled());
|
||||
final TestTetheringEventCallback tetherEventCallback =
|
||||
mCtsTetheringUtils.registerTetheringEventCallback();
|
||||
try {
|
||||
tetherEventCallback.assumeWifiTetheringSupported(mContext);
|
||||
|
||||
SoftApConfiguration softApConfig = new SoftApConfiguration.Builder()
|
||||
.setWifiSsid(WifiSsid.fromBytes("This is one config"
|
||||
.getBytes(StandardCharsets.UTF_8))).build();
|
||||
mCtsTetheringUtils.startWifiTethering(tetherEventCallback, softApConfig);
|
||||
|
||||
// Stopping with a fuzzy matching request should stop tethering.
|
||||
final LinkAddress localAddr = new LinkAddress("192.168.24.5/24");
|
||||
final LinkAddress clientAddr = new LinkAddress("192.168.24.100/24");
|
||||
TetheringRequest fuzzyMatchingRequest = new TetheringRequest.Builder(TETHERING_WIFI)
|
||||
.setSoftApConfiguration(softApConfig)
|
||||
.setShouldShowEntitlementUi(true)
|
||||
.setStaticIpv4Addresses(localAddr, clientAddr)
|
||||
.build();
|
||||
mCtsTetheringUtils.stopTethering(fuzzyMatchingRequest, true /* success */);
|
||||
// stopTethering should succeed now that there's a request.
|
||||
mCtsTetheringUtils.stopTethering(request, true /* expectSuccess */);
|
||||
tetherEventCallback.expectNoTetheringActive();
|
||||
} finally {
|
||||
mCtsTetheringUtils.stopAllTethering();
|
||||
mCtsTetheringUtils.unregisterTetheringEventCallback(tetherEventCallback);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue