Allow callers of startTethering to choose local-only mode.
This is useful for OEMs that want to use RNDIS or NCM as a local-only link that is directly connected to some other host. This can be used to implement USB tethering using NCM, which currently only supports local-only mode. Bug: 175090447 Test: TetheringIntegrationTests:EthernetTetheringTest#testLocalOnlyTethering Change-Id: I0ffaa46e4640e5b235340a15d25909106ceb0c07
This commit is contained in:
@@ -27,6 +27,8 @@ package android.net {
|
|||||||
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
|
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
|
||||||
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
|
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
|
||||||
field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
|
field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
|
||||||
|
field public static final int CONNECTIVITY_SCOPE_GLOBAL = 1; // 0x1
|
||||||
|
field public static final int CONNECTIVITY_SCOPE_LOCAL = 2; // 0x2
|
||||||
field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
|
field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
|
||||||
field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
|
field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
|
||||||
field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
|
field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
|
||||||
@@ -72,6 +74,7 @@ package android.net {
|
|||||||
public static interface TetheringManager.TetheringEventCallback {
|
public static interface TetheringManager.TetheringEventCallback {
|
||||||
method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
|
method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
|
||||||
method public default void onError(@NonNull String, int);
|
method public default void onError(@NonNull String, int);
|
||||||
|
method public default void onLocalOnlyInterfacesChanged(@NonNull java.util.List<java.lang.String>);
|
||||||
method public default void onOffloadStatusChanged(int);
|
method public default void onOffloadStatusChanged(int);
|
||||||
method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
|
method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
|
||||||
method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
|
method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
|
||||||
@@ -81,6 +84,7 @@ package android.net {
|
|||||||
|
|
||||||
public static class TetheringManager.TetheringRequest {
|
public static class TetheringManager.TetheringRequest {
|
||||||
method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
|
method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
|
||||||
|
method public int getConnectivityScope();
|
||||||
method @Nullable public android.net.LinkAddress getLocalIpv4Address();
|
method @Nullable public android.net.LinkAddress getLocalIpv4Address();
|
||||||
method public boolean getShouldShowEntitlementUi();
|
method public boolean getShouldShowEntitlementUi();
|
||||||
method public int getTetheringType();
|
method public int getTetheringType();
|
||||||
@@ -90,6 +94,7 @@ package android.net {
|
|||||||
public static class TetheringManager.TetheringRequest.Builder {
|
public static class TetheringManager.TetheringRequest.Builder {
|
||||||
ctor public TetheringManager.TetheringRequest.Builder(int);
|
ctor public TetheringManager.TetheringRequest.Builder(int);
|
||||||
method @NonNull public android.net.TetheringManager.TetheringRequest build();
|
method @NonNull public android.net.TetheringManager.TetheringRequest build();
|
||||||
|
method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setConnectivityScope(int);
|
||||||
method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
|
method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
|
||||||
method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
|
method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
|
||||||
method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
|
method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
|
||||||
|
|||||||
@@ -556,6 +556,28 @@ public class TetheringManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that this tethering connection will provide connectivity beyond this device (e.g.,
|
||||||
|
* global Internet access).
|
||||||
|
*/
|
||||||
|
public static final int CONNECTIVITY_SCOPE_GLOBAL = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that this tethering connection will only provide local connectivity.
|
||||||
|
*/
|
||||||
|
public static final int CONNECTIVITY_SCOPE_LOCAL = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connectivity scopes for {@link TetheringRequest.Builder#setConnectivityScope}.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef(prefix = "CONNECTIVITY_SCOPE_", value = {
|
||||||
|
CONNECTIVITY_SCOPE_GLOBAL,
|
||||||
|
CONNECTIVITY_SCOPE_LOCAL,
|
||||||
|
})
|
||||||
|
public @interface ConnectivityScope {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use with {@link #startTethering} to specify additional parameters when starting tethering.
|
* Use with {@link #startTethering} to specify additional parameters when starting tethering.
|
||||||
*/
|
*/
|
||||||
@@ -579,6 +601,7 @@ public class TetheringManager {
|
|||||||
mBuilderParcel.staticClientAddress = null;
|
mBuilderParcel.staticClientAddress = null;
|
||||||
mBuilderParcel.exemptFromEntitlementCheck = false;
|
mBuilderParcel.exemptFromEntitlementCheck = false;
|
||||||
mBuilderParcel.showProvisioningUi = true;
|
mBuilderParcel.showProvisioningUi = true;
|
||||||
|
mBuilderParcel.connectivityScope = getDefaultConnectivityScope(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -624,7 +647,21 @@ public class TetheringManager {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build {@link TetheringRequest] with the currently set configuration. */
|
/**
|
||||||
|
* Sets the connectivity scope to be provided by this tethering downstream.
|
||||||
|
*/
|
||||||
|
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
|
||||||
|
@NonNull
|
||||||
|
public Builder setConnectivityScope(@ConnectivityScope int scope) {
|
||||||
|
if (!checkConnectivityScope(mBuilderParcel.tetheringType, scope)) {
|
||||||
|
throw new IllegalArgumentException("Invalid connectivity scope " + scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
mBuilderParcel.connectivityScope = scope;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Build {@link TetheringRequest} with the currently set configuration. */
|
||||||
@NonNull
|
@NonNull
|
||||||
public TetheringRequest build() {
|
public TetheringRequest build() {
|
||||||
return new TetheringRequest(mBuilderParcel);
|
return new TetheringRequest(mBuilderParcel);
|
||||||
@@ -655,6 +692,12 @@ public class TetheringManager {
|
|||||||
return mRequestParcel.tetheringType;
|
return mRequestParcel.tetheringType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get connectivity type */
|
||||||
|
@ConnectivityScope
|
||||||
|
public int getConnectivityScope() {
|
||||||
|
return mRequestParcel.connectivityScope;
|
||||||
|
}
|
||||||
|
|
||||||
/** Check if exempt from entitlement check. */
|
/** Check if exempt from entitlement check. */
|
||||||
public boolean isExemptFromEntitlementCheck() {
|
public boolean isExemptFromEntitlementCheck() {
|
||||||
return mRequestParcel.exemptFromEntitlementCheck;
|
return mRequestParcel.exemptFromEntitlementCheck;
|
||||||
@@ -678,6 +721,26 @@ public class TetheringManager {
|
|||||||
new IpPrefix(clientAddress.toString()));
|
new IpPrefix(clientAddress.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the default connectivity scope for the given tethering type. Usually this is
|
||||||
|
* CONNECTIVITY_SCOPE_GLOBAL, except for NCM which for historical reasons defaults to local.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static @ConnectivityScope int getDefaultConnectivityScope(int tetheringType) {
|
||||||
|
return tetheringType != TETHERING_NCM
|
||||||
|
? CONNECTIVITY_SCOPE_GLOBAL
|
||||||
|
: CONNECTIVITY_SCOPE_LOCAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the requested connectivity scope is allowed.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
private static boolean checkConnectivityScope(int type, int scope) {
|
||||||
|
if (scope == CONNECTIVITY_SCOPE_GLOBAL) return true;
|
||||||
|
return type == TETHERING_USB || type == TETHERING_ETHERNET || type == TETHERING_NCM;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a TetheringRequestParcel from the configuration
|
* Get a TetheringRequestParcel from the configuration
|
||||||
* @hide
|
* @hide
|
||||||
@@ -939,6 +1002,15 @@ public class TetheringManager {
|
|||||||
*/
|
*/
|
||||||
default void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {}
|
default void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when there was a change in the list of local-only interfaces.
|
||||||
|
*
|
||||||
|
* <p>This will be called immediately after the callback is registered, and may be called
|
||||||
|
* multiple times later upon changes.
|
||||||
|
* @param interfaces The list of 0 or more String of active local-only interface names.
|
||||||
|
*/
|
||||||
|
default void onLocalOnlyInterfacesChanged(@NonNull List<String> interfaces) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when an error occurred configuring tethering.
|
* Called when an error occurred configuring tethering.
|
||||||
*
|
*
|
||||||
@@ -1045,6 +1117,7 @@ public class TetheringManager {
|
|||||||
private final HashMap<String, Integer> mErrorStates = new HashMap<>();
|
private final HashMap<String, Integer> mErrorStates = new HashMap<>();
|
||||||
private String[] mLastTetherableInterfaces = null;
|
private String[] mLastTetherableInterfaces = null;
|
||||||
private String[] mLastTetheredInterfaces = null;
|
private String[] mLastTetheredInterfaces = null;
|
||||||
|
private String[] mLastLocalOnlyInterfaces = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpstreamChanged(Network network) throws RemoteException {
|
public void onUpstreamChanged(Network network) throws RemoteException {
|
||||||
@@ -1082,6 +1155,14 @@ public class TetheringManager {
|
|||||||
Collections.unmodifiableList(Arrays.asList(mLastTetheredInterfaces)));
|
Collections.unmodifiableList(Arrays.asList(mLastTetheredInterfaces)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private synchronized void maybeSendLocalOnlyIfacesChangedCallback(
|
||||||
|
final TetherStatesParcel newStates) {
|
||||||
|
if (Arrays.equals(mLastLocalOnlyInterfaces, newStates.localOnlyList)) return;
|
||||||
|
mLastLocalOnlyInterfaces = newStates.localOnlyList.clone();
|
||||||
|
callback.onLocalOnlyInterfacesChanged(
|
||||||
|
Collections.unmodifiableList(Arrays.asList(mLastLocalOnlyInterfaces)));
|
||||||
|
}
|
||||||
|
|
||||||
// Called immediately after the callbacks are registered.
|
// Called immediately after the callbacks are registered.
|
||||||
@Override
|
@Override
|
||||||
public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
|
public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
|
||||||
@@ -1092,6 +1173,7 @@ public class TetheringManager {
|
|||||||
sendRegexpsChanged(parcel.config);
|
sendRegexpsChanged(parcel.config);
|
||||||
maybeSendTetherableIfacesChangedCallback(parcel.states);
|
maybeSendTetherableIfacesChangedCallback(parcel.states);
|
||||||
maybeSendTetheredIfacesChangedCallback(parcel.states);
|
maybeSendTetheredIfacesChangedCallback(parcel.states);
|
||||||
|
maybeSendLocalOnlyIfacesChangedCallback(parcel.states);
|
||||||
callback.onClientsChanged(parcel.tetheredClients);
|
callback.onClientsChanged(parcel.tetheredClients);
|
||||||
callback.onOffloadStatusChanged(parcel.offloadStatus);
|
callback.onOffloadStatusChanged(parcel.offloadStatus);
|
||||||
});
|
});
|
||||||
@@ -1122,6 +1204,7 @@ public class TetheringManager {
|
|||||||
sendErrorCallbacks(states);
|
sendErrorCallbacks(states);
|
||||||
maybeSendTetherableIfacesChangedCallback(states);
|
maybeSendTetherableIfacesChangedCallback(states);
|
||||||
maybeSendTetheredIfacesChangedCallback(states);
|
maybeSendTetheredIfacesChangedCallback(states);
|
||||||
|
maybeSendLocalOnlyIfacesChangedCallback(states);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,4 +28,5 @@ parcelable TetheringRequestParcel {
|
|||||||
LinkAddress staticClientAddress;
|
LinkAddress staticClientAddress;
|
||||||
boolean exemptFromEntitlementCheck;
|
boolean exemptFromEntitlementCheck;
|
||||||
boolean showProvisioningUi;
|
boolean showProvisioningUi;
|
||||||
|
int connectivityScope;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1426,7 +1426,7 @@ public class IpServer extends StateMachine {
|
|||||||
break;
|
break;
|
||||||
case CMD_INTERFACE_DOWN:
|
case CMD_INTERFACE_DOWN:
|
||||||
transitionTo(mUnavailableState);
|
transitionTo(mUnavailableState);
|
||||||
mLog.i("Untethered (interface down) and restarting" + mIfaceName);
|
mLog.i("Untethered (interface down) and restarting " + mIfaceName);
|
||||||
mCallback.requestEnableTethering(mInterfaceType, true /* enabled */);
|
mCallback.requestEnableTethering(mInterfaceType, true /* enabled */);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -162,7 +162,8 @@ public class TetheringUtils {
|
|||||||
&& Objects.equals(request.localIPv4Address, otherRequest.localIPv4Address)
|
&& Objects.equals(request.localIPv4Address, otherRequest.localIPv4Address)
|
||||||
&& Objects.equals(request.staticClientAddress, otherRequest.staticClientAddress)
|
&& Objects.equals(request.staticClientAddress, otherRequest.staticClientAddress)
|
||||||
&& request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck
|
&& request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck
|
||||||
&& request.showProvisioningUi == otherRequest.showProvisioningUi;
|
&& request.showProvisioningUi == otherRequest.showProvisioningUi
|
||||||
|
&& request.connectivityScope == otherRequest.connectivityScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get inet6 address for all nodes given scope ID. */
|
/** Get inet6 address for all nodes given scope ID. */
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
|
|||||||
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
|
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
|
||||||
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
|
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
|
||||||
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
|
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
|
||||||
|
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
|
||||||
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
|
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
|
||||||
import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
|
import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
|
||||||
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
|
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
|
||||||
@@ -90,6 +91,7 @@ import android.net.TetherStatesParcel;
|
|||||||
import android.net.TetheredClient;
|
import android.net.TetheredClient;
|
||||||
import android.net.TetheringCallbackStartedParcel;
|
import android.net.TetheringCallbackStartedParcel;
|
||||||
import android.net.TetheringConfigurationParcel;
|
import android.net.TetheringConfigurationParcel;
|
||||||
|
import android.net.TetheringManager.TetheringRequest;
|
||||||
import android.net.TetheringRequestParcel;
|
import android.net.TetheringRequestParcel;
|
||||||
import android.net.ip.IpServer;
|
import android.net.ip.IpServer;
|
||||||
import android.net.shared.NetdUtils;
|
import android.net.shared.NetdUtils;
|
||||||
@@ -731,7 +733,7 @@ public class Tethering {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
maybeTrackNewInterfaceLocked(iface, TETHERING_ETHERNET);
|
maybeTrackNewInterfaceLocked(iface, TETHERING_ETHERNET);
|
||||||
changeInterfaceState(iface, IpServer.STATE_TETHERED);
|
changeInterfaceState(iface, getRequestedState(TETHERING_ETHERNET));
|
||||||
mConfiguredEthernetIface = iface;
|
mConfiguredEthernetIface = iface;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -748,10 +750,10 @@ public class Tethering {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tether(String iface, final IIntResultListener listener) {
|
void tether(String iface, int requestedState, final IIntResultListener listener) {
|
||||||
mHandler.post(() -> {
|
mHandler.post(() -> {
|
||||||
try {
|
try {
|
||||||
listener.onResult(tether(iface, IpServer.STATE_TETHERED));
|
listener.onResult(tether(iface, requestedState));
|
||||||
} catch (RemoteException e) { }
|
} catch (RemoteException e) { }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -855,6 +857,22 @@ public class Tethering {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getRequestedState(int type) {
|
||||||
|
final TetheringRequestParcel request = mActiveTetheringRequests.get(type);
|
||||||
|
|
||||||
|
// The request could have been deleted before we had a chance to complete it.
|
||||||
|
// If so, assume that the scope is the default scope for this tethering type.
|
||||||
|
// This likely doesn't matter - if the request has been deleted, then tethering is
|
||||||
|
// likely going to be stopped soon anyway.
|
||||||
|
final int connectivityScope = (request != null)
|
||||||
|
? request.connectivityScope
|
||||||
|
: TetheringRequest.getDefaultConnectivityScope(type);
|
||||||
|
|
||||||
|
return connectivityScope == CONNECTIVITY_SCOPE_LOCAL
|
||||||
|
? IpServer.STATE_LOCAL_ONLY
|
||||||
|
: IpServer.STATE_TETHERED;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Figure out how to update for local hotspot mode interfaces.
|
// TODO: Figure out how to update for local hotspot mode interfaces.
|
||||||
private void sendTetherStateChangedBroadcast() {
|
private void sendTetherStateChangedBroadcast() {
|
||||||
if (!isTetheringSupported()) return;
|
if (!isTetheringSupported()) return;
|
||||||
@@ -994,9 +1012,11 @@ public class Tethering {
|
|||||||
mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_USB);
|
mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_USB);
|
||||||
} else if (usbConfigured && rndisEnabled) {
|
} else if (usbConfigured && rndisEnabled) {
|
||||||
// Tether if rndis is enabled and usb is configured.
|
// Tether if rndis is enabled and usb is configured.
|
||||||
tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
|
final int state = getRequestedState(TETHERING_USB);
|
||||||
|
tetherMatchingInterfaces(state, TETHERING_USB);
|
||||||
} else if (usbConnected && ncmEnabled) {
|
} else if (usbConnected && ncmEnabled) {
|
||||||
tetherMatchingInterfaces(IpServer.STATE_LOCAL_ONLY, TETHERING_NCM);
|
final int state = getRequestedState(TETHERING_NCM);
|
||||||
|
tetherMatchingInterfaces(state, TETHERING_NCM);
|
||||||
}
|
}
|
||||||
mRndisEnabled = usbConfigured && rndisEnabled;
|
mRndisEnabled = usbConfigured && rndisEnabled;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ public class TetheringService extends Service {
|
|||||||
IIntResultListener listener) {
|
IIntResultListener listener) {
|
||||||
if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
|
if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
|
||||||
|
|
||||||
mTethering.tether(iface, listener);
|
mTethering.tether(iface, IpServer.STATE_TETHERED, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -19,7 +19,14 @@ package android.net;
|
|||||||
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
|
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
|
||||||
import static android.Manifest.permission.NETWORK_SETTINGS;
|
import static android.Manifest.permission.NETWORK_SETTINGS;
|
||||||
import static android.Manifest.permission.TETHER_PRIVILEGED;
|
import static android.Manifest.permission.TETHER_PRIVILEGED;
|
||||||
|
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
|
||||||
|
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
|
||||||
import static android.net.TetheringManager.TETHERING_ETHERNET;
|
import static android.net.TetheringManager.TETHERING_ETHERNET;
|
||||||
|
import static android.system.OsConstants.IPPROTO_ICMPV6;
|
||||||
|
|
||||||
|
import static com.android.net.module.util.ConnectivityUtils.isIPv6ULA;
|
||||||
|
import static com.android.net.module.util.NetworkStackConstants.ETHER_TYPE_IPV6;
|
||||||
|
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -50,6 +57,10 @@ import androidx.test.InstrumentationRegistry;
|
|||||||
import androidx.test.filters.MediumTest;
|
import androidx.test.filters.MediumTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.net.module.util.Struct;
|
||||||
|
import com.android.net.module.util.structs.EthernetHeader;
|
||||||
|
import com.android.net.module.util.structs.Icmpv6Header;
|
||||||
|
import com.android.net.module.util.structs.Ipv6Header;
|
||||||
import com.android.testutils.HandlerUtils;
|
import com.android.testutils.HandlerUtils;
|
||||||
import com.android.testutils.TapPacketReader;
|
import com.android.testutils.TapPacketReader;
|
||||||
|
|
||||||
@@ -60,6 +71,7 @@ import org.junit.runner.RunWith;
|
|||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.net.InterfaceAddress;
|
import java.net.InterfaceAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
@@ -229,6 +241,82 @@ public class EthernetTetheringTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isRouterAdvertisement(byte[] pkt) {
|
||||||
|
if (pkt == null) return false;
|
||||||
|
|
||||||
|
ByteBuffer buf = ByteBuffer.wrap(pkt);
|
||||||
|
|
||||||
|
final EthernetHeader ethHdr = Struct.parse(EthernetHeader.class, buf);
|
||||||
|
if (ethHdr.etherType != ETHER_TYPE_IPV6) return false;
|
||||||
|
|
||||||
|
final Ipv6Header ipv6Hdr = Struct.parse(Ipv6Header.class, buf);
|
||||||
|
if (ipv6Hdr.nextHeader != (byte) IPPROTO_ICMPV6) return false;
|
||||||
|
|
||||||
|
final Icmpv6Header icmpv6Hdr = Struct.parse(Icmpv6Header.class, buf);
|
||||||
|
return icmpv6Hdr.type == (short) ICMPV6_ROUTER_ADVERTISEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void expectRouterAdvertisement(TapPacketReader reader, String iface,
|
||||||
|
long timeoutMs) {
|
||||||
|
final long deadline = SystemClock.uptimeMillis() + timeoutMs;
|
||||||
|
do {
|
||||||
|
byte[] pkt = reader.popPacket(timeoutMs);
|
||||||
|
if (isRouterAdvertisement(pkt)) return;
|
||||||
|
timeoutMs = deadline - SystemClock.uptimeMillis();
|
||||||
|
} while (timeoutMs > 0);
|
||||||
|
fail("Did not receive router advertisement on " + iface + " after "
|
||||||
|
+ timeoutMs + "ms idle");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void expectLocalOnlyAddresses(String iface) throws Exception {
|
||||||
|
final List<InterfaceAddress> interfaceAddresses =
|
||||||
|
NetworkInterface.getByName(iface).getInterfaceAddresses();
|
||||||
|
|
||||||
|
boolean foundIpv6Ula = false;
|
||||||
|
for (InterfaceAddress ia : interfaceAddresses) {
|
||||||
|
final InetAddress addr = ia.getAddress();
|
||||||
|
if (isIPv6ULA(addr)) {
|
||||||
|
foundIpv6Ula = true;
|
||||||
|
}
|
||||||
|
final int prefixlen = ia.getNetworkPrefixLength();
|
||||||
|
final LinkAddress la = new LinkAddress(addr, prefixlen);
|
||||||
|
if (la.isIpv6() && la.isGlobalPreferred()) {
|
||||||
|
fail("Found global IPv6 address on local-only interface: " + interfaceAddresses);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue("Did not find IPv6 ULA on local-only interface " + iface,
|
||||||
|
foundIpv6Ula);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLocalOnlyTethering() throws Exception {
|
||||||
|
assumeFalse(mEm.isAvailable());
|
||||||
|
|
||||||
|
mEm.setIncludeTestInterfaces(true);
|
||||||
|
|
||||||
|
mTestIface = createTestInterface();
|
||||||
|
|
||||||
|
final String iface = mTetheredInterfaceRequester.getInterface();
|
||||||
|
assertEquals("TetheredInterfaceCallback for unexpected interface",
|
||||||
|
mTestIface.getInterfaceName(), iface);
|
||||||
|
|
||||||
|
final TetheringRequest request = new TetheringRequest.Builder(TETHERING_ETHERNET)
|
||||||
|
.setConnectivityScope(CONNECTIVITY_SCOPE_LOCAL).build();
|
||||||
|
mTetheringEventCallback = enableEthernetTethering(iface, request);
|
||||||
|
mTetheringEventCallback.awaitInterfaceLocalOnly();
|
||||||
|
|
||||||
|
// makePacketReader only works after tethering is started, because until then the interface
|
||||||
|
// does not have an IP address, and unprivileged apps cannot see interfaces without IP
|
||||||
|
// addresses. This shouldn't be flaky because the TAP interface will buffer all packets even
|
||||||
|
// before the reader is started.
|
||||||
|
FileDescriptor fd = mTestIface.getFileDescriptor().getFileDescriptor();
|
||||||
|
mTapPacketReader = makePacketReader(fd, getMTU(mTestIface));
|
||||||
|
|
||||||
|
expectRouterAdvertisement(mTapPacketReader, iface, 2000 /* timeoutMs */);
|
||||||
|
expectLocalOnlyAddresses(iface);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isAdbOverNetwork() {
|
private boolean isAdbOverNetwork() {
|
||||||
// If adb TCP port opened, this test may running by adb over network.
|
// If adb TCP port opened, this test may running by adb over network.
|
||||||
return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1)
|
return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1)
|
||||||
@@ -257,10 +345,13 @@ public class EthernetTetheringTest {
|
|||||||
private final TetheringManager mTm;
|
private final TetheringManager mTm;
|
||||||
private final CountDownLatch mTetheringStartedLatch = new CountDownLatch(1);
|
private final CountDownLatch mTetheringStartedLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch mTetheringStoppedLatch = new CountDownLatch(1);
|
private final CountDownLatch mTetheringStoppedLatch = new CountDownLatch(1);
|
||||||
|
private final CountDownLatch mLocalOnlyStartedLatch = new CountDownLatch(1);
|
||||||
|
private final CountDownLatch mLocalOnlyStoppedLatch = new CountDownLatch(1);
|
||||||
private final CountDownLatch mClientConnectedLatch = new CountDownLatch(1);
|
private final CountDownLatch mClientConnectedLatch = new CountDownLatch(1);
|
||||||
private final String mIface;
|
private final String mIface;
|
||||||
|
|
||||||
private volatile boolean mInterfaceWasTethered = false;
|
private volatile boolean mInterfaceWasTethered = false;
|
||||||
|
private volatile boolean mInterfaceWasLocalOnly = false;
|
||||||
private volatile boolean mUnregistered = false;
|
private volatile boolean mUnregistered = false;
|
||||||
private volatile Collection<TetheredClient> mClients = null;
|
private volatile Collection<TetheredClient> mClients = null;
|
||||||
|
|
||||||
@@ -279,7 +370,6 @@ public class EthernetTetheringTest {
|
|||||||
// Ignore stale callbacks registered by previous test cases.
|
// Ignore stale callbacks registered by previous test cases.
|
||||||
if (mUnregistered) return;
|
if (mUnregistered) return;
|
||||||
|
|
||||||
final boolean wasTethered = mTetheringStartedLatch.getCount() == 0;
|
|
||||||
if (!mInterfaceWasTethered && (mIface == null || interfaces.contains(mIface))) {
|
if (!mInterfaceWasTethered && (mIface == null || interfaces.contains(mIface))) {
|
||||||
// This interface is being tethered for the first time.
|
// This interface is being tethered for the first time.
|
||||||
Log.d(TAG, "Tethering started: " + interfaces);
|
Log.d(TAG, "Tethering started: " + interfaces);
|
||||||
@@ -291,20 +381,48 @@ public class EthernetTetheringTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLocalOnlyInterfacesChanged(List<String> interfaces) {
|
||||||
|
// Ignore stale callbacks registered by previous test cases.
|
||||||
|
if (mUnregistered) return;
|
||||||
|
|
||||||
|
if (!mInterfaceWasLocalOnly && (mIface == null || interfaces.contains(mIface))) {
|
||||||
|
// This interface is being put into local-only mode for the first time.
|
||||||
|
Log.d(TAG, "Local-only started: " + interfaces);
|
||||||
|
mInterfaceWasLocalOnly = true;
|
||||||
|
mLocalOnlyStartedLatch.countDown();
|
||||||
|
} else if (mInterfaceWasLocalOnly && !interfaces.contains(mIface)) {
|
||||||
|
Log.d(TAG, "Local-only stopped: " + interfaces);
|
||||||
|
mLocalOnlyStoppedLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void awaitInterfaceTethered() throws Exception {
|
public void awaitInterfaceTethered() throws Exception {
|
||||||
assertTrue("Ethernet not tethered after " + TIMEOUT_MS + "ms",
|
assertTrue("Ethernet not tethered after " + TIMEOUT_MS + "ms",
|
||||||
mTetheringStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
mTetheringStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void awaitInterfaceLocalOnly() throws Exception {
|
||||||
|
assertTrue("Ethernet not local-only after " + TIMEOUT_MS + "ms",
|
||||||
|
mLocalOnlyStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
|
}
|
||||||
|
|
||||||
public void awaitInterfaceUntethered() throws Exception {
|
public void awaitInterfaceUntethered() throws Exception {
|
||||||
// Don't block teardown if the interface was never tethered.
|
// Don't block teardown if the interface was never tethered.
|
||||||
// This is racy because the interface might become tethered right after this check, but
|
// This is racy because the interface might become tethered right after this check, but
|
||||||
// that can only happen in tearDown if startTethering timed out, which likely means
|
// that can only happen in tearDown if startTethering timed out, which likely means
|
||||||
// the test has already failed.
|
// the test has already failed.
|
||||||
if (!mInterfaceWasTethered) return;
|
if (!mInterfaceWasTethered && !mInterfaceWasLocalOnly) return;
|
||||||
|
|
||||||
|
if (mInterfaceWasTethered) {
|
||||||
assertTrue(mIface + " not untethered after " + TIMEOUT_MS + "ms",
|
assertTrue(mIface + " not untethered after " + TIMEOUT_MS + "ms",
|
||||||
mTetheringStoppedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
mTetheringStoppedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
|
} else if (mInterfaceWasLocalOnly) {
|
||||||
|
assertTrue(mIface + " not untethered after " + TIMEOUT_MS + "ms",
|
||||||
|
mLocalOnlyStoppedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
|
||||||
|
} else {
|
||||||
|
fail(mIface + " cannot be both tethered and local-only. Update this test class.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -347,7 +465,19 @@ public class EthernetTetheringTest {
|
|||||||
};
|
};
|
||||||
Log.d(TAG, "Starting Ethernet tethering");
|
Log.d(TAG, "Starting Ethernet tethering");
|
||||||
mTm.startTethering(request, mHandler::post /* executor */, startTetheringCallback);
|
mTm.startTethering(request, mHandler::post /* executor */, startTetheringCallback);
|
||||||
|
|
||||||
|
final int connectivityType = request.getConnectivityScope();
|
||||||
|
switch (connectivityType) {
|
||||||
|
case CONNECTIVITY_SCOPE_GLOBAL:
|
||||||
callback.awaitInterfaceTethered();
|
callback.awaitInterfaceTethered();
|
||||||
|
break;
|
||||||
|
case CONNECTIVITY_SCOPE_LOCAL:
|
||||||
|
callback.awaitInterfaceLocalOnly();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fail("Unexpected connectivity type requested: " + connectivityType);
|
||||||
|
}
|
||||||
|
|
||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,7 +574,6 @@ public class EthernetTetheringTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static final class TetheredInterfaceRequester implements TetheredInterfaceCallback {
|
private static final class TetheredInterfaceRequester implements TetheredInterfaceCallback {
|
||||||
private final CountDownLatch mInterfaceAvailableLatch = new CountDownLatch(1);
|
|
||||||
private final Handler mHandler;
|
private final Handler mHandler;
|
||||||
private final EthernetManager mEm;
|
private final EthernetManager mEm;
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package android.net.util;
|
package android.net.util;
|
||||||
|
|
||||||
|
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
|
||||||
import static android.net.TetheringManager.TETHERING_USB;
|
import static android.net.TetheringManager.TETHERING_USB;
|
||||||
import static android.net.TetheringManager.TETHERING_WIFI;
|
import static android.net.TetheringManager.TETHERING_WIFI;
|
||||||
import static android.system.OsConstants.AF_UNIX;
|
import static android.system.OsConstants.AF_UNIX;
|
||||||
@@ -78,7 +79,7 @@ public class TetheringUtilsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsTetheringRequestEquals() throws Exception {
|
public void testIsTetheringRequestEquals() {
|
||||||
TetheringRequestParcel request = makeTetheringRequestParcel();
|
TetheringRequestParcel request = makeTetheringRequestParcel();
|
||||||
|
|
||||||
assertTrue(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, mTetheringRequest));
|
assertTrue(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, mTetheringRequest));
|
||||||
@@ -104,7 +105,11 @@ public class TetheringUtilsTest {
|
|||||||
request.showProvisioningUi = false;
|
request.showProvisioningUi = false;
|
||||||
assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request));
|
assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request));
|
||||||
|
|
||||||
MiscAsserts.assertFieldCountEquals(5, TetheringRequestParcel.class);
|
request = makeTetheringRequestParcel();
|
||||||
|
request.connectivityScope = CONNECTIVITY_SCOPE_LOCAL;
|
||||||
|
assertFalse(TetheringUtils.isTetheringRequestEquals(mTetheringRequest, request));
|
||||||
|
|
||||||
|
MiscAsserts.assertFieldCountEquals(6, TetheringRequestParcel.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes the specified packet to a filedescriptor, skipping the Ethernet header.
|
// Writes the specified packet to a filedescriptor, skipping the Ethernet header.
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import android.net.IIntResultListener;
|
|||||||
import android.net.ITetheringConnector;
|
import android.net.ITetheringConnector;
|
||||||
import android.net.ITetheringEventCallback;
|
import android.net.ITetheringEventCallback;
|
||||||
import android.net.TetheringRequestParcel;
|
import android.net.TetheringRequestParcel;
|
||||||
|
import android.net.ip.IpServer;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.ResultReceiver;
|
import android.os.ResultReceiver;
|
||||||
@@ -158,7 +159,7 @@ public final class TetheringServiceTest {
|
|||||||
private void runTether(final TestTetheringResult result) throws Exception {
|
private void runTether(final TestTetheringResult result) throws Exception {
|
||||||
mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
|
mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
|
||||||
verify(mTethering).isTetheringSupported();
|
verify(mTethering).isTetheringSupported();
|
||||||
verify(mTethering).tether(eq(TEST_IFACE_NAME), eq(result));
|
verify(mTethering).tether(TEST_IFACE_NAME, IpServer.STATE_TETHERED, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
|
|||||||
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||||
import static android.net.RouteInfo.RTN_UNICAST;
|
import static android.net.RouteInfo.RTN_UNICAST;
|
||||||
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
|
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
|
||||||
|
import static android.net.TetheringManager.CONNECTIVITY_SCOPE_GLOBAL;
|
||||||
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
|
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
|
||||||
import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
|
import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
|
||||||
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
|
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
|
||||||
@@ -702,17 +703,19 @@ public class TetheringTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TetheringRequestParcel createTetheringRequestParcel(final int type) {
|
private TetheringRequestParcel createTetheringRequestParcel(final int type) {
|
||||||
return createTetheringRequestParcel(type, null, null, false);
|
return createTetheringRequestParcel(type, null, null, false, CONNECTIVITY_SCOPE_GLOBAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TetheringRequestParcel createTetheringRequestParcel(final int type,
|
private TetheringRequestParcel createTetheringRequestParcel(final int type,
|
||||||
final LinkAddress serverAddr, final LinkAddress clientAddr, final boolean exempt) {
|
final LinkAddress serverAddr, final LinkAddress clientAddr, final boolean exempt,
|
||||||
|
final int scope) {
|
||||||
final TetheringRequestParcel request = new TetheringRequestParcel();
|
final TetheringRequestParcel request = new TetheringRequestParcel();
|
||||||
request.tetheringType = type;
|
request.tetheringType = type;
|
||||||
request.localIPv4Address = serverAddr;
|
request.localIPv4Address = serverAddr;
|
||||||
request.staticClientAddress = clientAddr;
|
request.staticClientAddress = clientAddr;
|
||||||
request.exemptFromEntitlementCheck = exempt;
|
request.exemptFromEntitlementCheck = exempt;
|
||||||
request.showProvisioningUi = false;
|
request.showProvisioningUi = false;
|
||||||
|
request.connectivityScope = scope;
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
@@ -1973,16 +1976,14 @@ public class TetheringTest {
|
|||||||
final ResultListener thirdResult = new ResultListener(TETHER_ERROR_NO_ERROR);
|
final ResultListener thirdResult = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||||
|
|
||||||
// Enable USB tethering and check that Tethering starts USB.
|
// Enable USB tethering and check that Tethering starts USB.
|
||||||
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
|
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), firstResult);
|
||||||
null, null, false), firstResult);
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
firstResult.assertHasResult();
|
firstResult.assertHasResult();
|
||||||
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
|
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
|
||||||
verifyNoMoreInteractions(mUsbManager);
|
verifyNoMoreInteractions(mUsbManager);
|
||||||
|
|
||||||
// Enable USB tethering again with the same request and expect no change to USB.
|
// Enable USB tethering again with the same request and expect no change to USB.
|
||||||
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
|
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), secondResult);
|
||||||
null, null, false), secondResult);
|
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
secondResult.assertHasResult();
|
secondResult.assertHasResult();
|
||||||
verify(mUsbManager, never()).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
verify(mUsbManager, never()).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
||||||
@@ -1991,7 +1992,7 @@ public class TetheringTest {
|
|||||||
// Enable USB tethering with a different request and expect that USB is stopped and
|
// Enable USB tethering with a different request and expect that USB is stopped and
|
||||||
// started.
|
// started.
|
||||||
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
|
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
|
||||||
serverLinkAddr, clientLinkAddr, false), thirdResult);
|
serverLinkAddr, clientLinkAddr, false, CONNECTIVITY_SCOPE_GLOBAL), thirdResult);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
thirdResult.assertHasResult();
|
thirdResult.assertHasResult();
|
||||||
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE);
|
||||||
@@ -2014,7 +2015,7 @@ public class TetheringTest {
|
|||||||
final ArgumentCaptor<DhcpServingParamsParcel> dhcpParamsCaptor =
|
final ArgumentCaptor<DhcpServingParamsParcel> dhcpParamsCaptor =
|
||||||
ArgumentCaptor.forClass(DhcpServingParamsParcel.class);
|
ArgumentCaptor.forClass(DhcpServingParamsParcel.class);
|
||||||
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
|
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB,
|
||||||
serverLinkAddr, clientLinkAddr, false), null);
|
serverLinkAddr, clientLinkAddr, false, CONNECTIVITY_SCOPE_GLOBAL), null);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
|
verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_RNDIS);
|
||||||
mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
|
mTethering.interfaceStatusChanged(TEST_USB_IFNAME, true);
|
||||||
@@ -2080,7 +2081,8 @@ public class TetheringTest {
|
|||||||
public void testExemptFromEntitlementCheck() throws Exception {
|
public void testExemptFromEntitlementCheck() throws Exception {
|
||||||
setupForRequiredProvisioning();
|
setupForRequiredProvisioning();
|
||||||
final TetheringRequestParcel wifiNotExemptRequest =
|
final TetheringRequestParcel wifiNotExemptRequest =
|
||||||
createTetheringRequestParcel(TETHERING_WIFI, null, null, false);
|
createTetheringRequestParcel(TETHERING_WIFI, null, null, false,
|
||||||
|
CONNECTIVITY_SCOPE_GLOBAL);
|
||||||
mTethering.startTethering(wifiNotExemptRequest, null);
|
mTethering.startTethering(wifiNotExemptRequest, null);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mEntitleMgr).startProvisioningIfNeeded(TETHERING_WIFI, false);
|
verify(mEntitleMgr).startProvisioningIfNeeded(TETHERING_WIFI, false);
|
||||||
@@ -2093,7 +2095,8 @@ public class TetheringTest {
|
|||||||
|
|
||||||
setupForRequiredProvisioning();
|
setupForRequiredProvisioning();
|
||||||
final TetheringRequestParcel wifiExemptRequest =
|
final TetheringRequestParcel wifiExemptRequest =
|
||||||
createTetheringRequestParcel(TETHERING_WIFI, null, null, true);
|
createTetheringRequestParcel(TETHERING_WIFI, null, null, true,
|
||||||
|
CONNECTIVITY_SCOPE_GLOBAL);
|
||||||
mTethering.startTethering(wifiExemptRequest, null);
|
mTethering.startTethering(wifiExemptRequest, null);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
verify(mEntitleMgr, never()).startProvisioningIfNeeded(TETHERING_WIFI, false);
|
verify(mEntitleMgr, never()).startProvisioningIfNeeded(TETHERING_WIFI, false);
|
||||||
@@ -2386,7 +2389,7 @@ public class TetheringTest {
|
|||||||
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, false);
|
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, false);
|
||||||
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, true);
|
mTethering.interfaceStatusChanged(TEST_BT_IFNAME, true);
|
||||||
final ResultListener tetherResult = new ResultListener(TETHER_ERROR_NO_ERROR);
|
final ResultListener tetherResult = new ResultListener(TETHER_ERROR_NO_ERROR);
|
||||||
mTethering.tether(TEST_BT_IFNAME, tetherResult);
|
mTethering.tether(TEST_BT_IFNAME, IpServer.STATE_TETHERED, tetherResult);
|
||||||
mLooper.dispatchAll();
|
mLooper.dispatchAll();
|
||||||
tetherResult.assertHasResult();
|
tetherResult.assertHasResult();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user