Merge "Build framework-connectivity-tiramisu library"
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 0b54783..bb435d8 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -206,4 +206,5 @@
sdk {
name: "tethering-module-sdk",
bootclasspath_fragments: ["com.android.tethering-bootclasspath-fragment"],
+ systemserverclasspath_fragments: ["com.android.tethering-systemserverclasspath-fragment"],
}
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index c314815..9bbf3d5 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -44,12 +44,15 @@
bootclasspath_fragments: [
"com.android.tethering-bootclasspath-fragment",
],
- java_libs: [
- "service-connectivity",
+ systemserverclasspath_fragments: [
+ "com.android.tethering-systemserverclasspath-fragment",
],
multilib: {
first: {
- jni_libs: ["libservice-connectivity"],
+ jni_libs: [
+ "libservice-connectivity",
+ "libcom_android_connectivity_com_android_net_module_util_jni"
+ ],
},
both: {
jni_libs: ["libframework-connectivity-jni"],
@@ -116,6 +119,12 @@
},
}
+systemserverclasspath_fragment {
+ name: "com.android.tethering-systemserverclasspath-fragment",
+ standalone_contents: ["service-connectivity"],
+ apex_available: ["com.android.tethering"],
+}
+
override_apex {
name: "com.android.tethering.inprocess",
base: "com.android.tethering",
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 78f2afc..55c24d3 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -123,6 +123,7 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import androidx.annotation.NonNull;
@@ -267,6 +268,9 @@
private String mConfiguredEthernetIface;
private EthernetCallback mEthernetCallback;
private SettingsObserver mSettingsObserver;
+ private BluetoothPan mBluetoothPan;
+ private PanServiceListener mBluetoothPanListener;
+ private ArrayList<Pair<Boolean, IIntResultListener>> mPendingPanRequests;
public Tethering(TetheringDependencies deps) {
mLog.mark("Tethering.constructed");
@@ -276,6 +280,11 @@
mLooper = mDeps.getTetheringLooper();
mNotificationUpdater = mDeps.getNotificationUpdater(mContext, mLooper);
+ // This is intended to ensrure that if something calls startTethering(bluetooth) just after
+ // bluetooth is enabled. Before onServiceConnected is called, store the calls into this
+ // list and handle them as soon as onServiceConnected is called.
+ mPendingPanRequests = new ArrayList<>();
+
mTetherStates = new ArrayMap<>();
mConnectedClientsTracker = new ConnectedClientsTracker();
@@ -701,35 +710,82 @@
return;
}
- adapter.getProfileProxy(mContext, new ServiceListener() {
- @Override
- public void onServiceDisconnected(int profile) { }
+ if (mBluetoothPanListener != null && mBluetoothPanListener.isConnected()) {
+ // The PAN service is connected. Enable or disable bluetooth tethering.
+ // When bluetooth tethering is enabled, any time a PAN client pairs with this
+ // host, bluetooth will bring up a bt-pan interface and notify tethering to
+ // enable IP serving.
+ setBluetoothTetheringSettings(mBluetoothPan, enable, listener);
+ return;
+ }
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- // Clear identify is fine because caller already pass tethering permission at
- // ConnectivityService#startTethering()(or stopTethering) before the control comes
- // here. Bluetooth will check tethering permission again that there is
- // Context#getOpPackageName() under BluetoothPan#setBluetoothTethering() to get
- // caller's package name for permission check.
- // Calling BluetoothPan#setBluetoothTethering() here means the package name always
- // be system server. If calling identity is not cleared, that package's uid might
- // not match calling uid and end up in permission denied.
- final long identityToken = Binder.clearCallingIdentity();
- try {
- ((BluetoothPan) proxy).setBluetoothTethering(enable);
- } finally {
- Binder.restoreCallingIdentity(identityToken);
+ // The reference of IIntResultListener should only exist when application want to start
+ // tethering but tethering is not bound to pan service yet. Even if the calling process
+ // dies, the referenice of IIntResultListener would still keep in mPendingPanRequests. Once
+ // tethering bound to pan service (onServiceConnected) or bluetooth just crash
+ // (onServiceDisconnected), all the references from mPendingPanRequests would be cleared.
+ mPendingPanRequests.add(new Pair(enable, listener));
+
+ // Bluetooth tethering is not a popular feature. To avoid bind to bluetooth pan service all
+ // the time but user never use bluetooth tethering. mBluetoothPanListener is created first
+ // time someone calls a bluetooth tethering method (even if it's just to disable tethering
+ // when it's already disabled) and never unset after that.
+ if (mBluetoothPanListener == null) {
+ mBluetoothPanListener = new PanServiceListener();
+ adapter.getProfileProxy(mContext, mBluetoothPanListener, BluetoothProfile.PAN);
+ }
+ }
+
+ private class PanServiceListener implements ServiceListener {
+ private boolean mIsConnected = false;
+
+ @Override
+ public void onServiceConnected(int profile, BluetoothProfile proxy) {
+ // Posting this to handling onServiceConnected in tethering handler thread may have
+ // race condition that bluetooth service may disconnected when tethering thread
+ // actaully handle onServiceconnected. If this race happen, calling
+ // BluetoothPan#setBluetoothTethering would silently fail. It is fine because pan
+ // service is unreachable and both bluetooth and bluetooth tethering settings are off.
+ mHandler.post(() -> {
+ mBluetoothPan = (BluetoothPan) proxy;
+ mIsConnected = true;
+
+ for (Pair<Boolean, IIntResultListener> request : mPendingPanRequests) {
+ setBluetoothTetheringSettings(mBluetoothPan, request.first, request.second);
}
- // TODO: Enabling bluetooth tethering can fail asynchronously here.
- // We should figure out a way to bubble up that failure instead of sending success.
- final int result = (((BluetoothPan) proxy).isTetheringOn() == enable)
- ? TETHER_ERROR_NO_ERROR
- : TETHER_ERROR_INTERNAL_ERROR;
- sendTetherResult(listener, result, TETHERING_BLUETOOTH);
- adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
- }
- }, BluetoothProfile.PAN);
+ mPendingPanRequests.clear();
+ });
+ }
+
+ @Override
+ public void onServiceDisconnected(int profile) {
+ mHandler.post(() -> {
+ // onServiceDisconnected means Bluetooth is off (or crashed) and is not
+ // reachable before next onServiceConnected.
+ mIsConnected = false;
+
+ for (Pair<Boolean, IIntResultListener> request : mPendingPanRequests) {
+ sendTetherResult(request.second, TETHER_ERROR_SERVICE_UNAVAIL,
+ TETHERING_BLUETOOTH);
+ }
+ mPendingPanRequests.clear();
+ });
+ }
+
+ public boolean isConnected() {
+ return mIsConnected;
+ }
+ }
+
+ private void setBluetoothTetheringSettings(@NonNull final BluetoothPan bluetoothPan,
+ final boolean enable, final IIntResultListener listener) {
+ bluetoothPan.setBluetoothTethering(enable);
+
+ // Enabling bluetooth tethering settings can silently fail. Send internal error if the
+ // result is not expected.
+ final int result = bluetoothPan.isTetheringOn() == enable
+ ? TETHER_ERROR_NO_ERROR : TETHER_ERROR_INTERNAL_ERROR;
+ sendTetherResult(listener, result, TETHERING_BLUETOOTH);
}
private int setEthernetTethering(final boolean enable) {
diff --git a/Tethering/tests/integration/src/android/net/TetheringTester.java b/Tethering/tests/integration/src/android/net/TetheringTester.java
index 38d74ad..d61bbb3 100644
--- a/Tethering/tests/integration/src/android/net/TetheringTester.java
+++ b/Tethering/tests/integration/src/android/net/TetheringTester.java
@@ -30,7 +30,7 @@
import java.nio.ByteBuffer;
import java.util.Random;
import java.util.concurrent.TimeoutException;
-import java.util.function.Function;
+import java.util.function.Predicate;
/**
* A class simulate tethered client. When caller create TetheringTester, it would connect to
@@ -129,27 +129,43 @@
mDownstreamReader.sendResponse(packet);
}
- private DhcpPacket getNextDhcpPacket() {
- return getNextMatchedPacket((p) -> {
+ private DhcpPacket getNextDhcpPacket() throws Exception {
+ final byte[] packet = getNextMatchedPacket((p) -> {
+ // Test whether this is DHCP packet.
try {
- return DhcpPacket.decodeFullPacket(p, p.length, DhcpPacket.ENCAP_L2);
+ DhcpPacket.decodeFullPacket(p, p.length, DhcpPacket.ENCAP_L2);
} catch (DhcpPacket.ParseException e) {
- // Not a DHCP packet. Continue.
+ // Not a DHCP packet.
+ return false;
}
- return null;
+ return true;
});
+
+ return packet == null ? null :
+ DhcpPacket.decodeFullPacket(packet, packet.length, DhcpPacket.ENCAP_L2);
}
- private <R> R getNextMatchedPacket(Function<byte[], R> match) {
- byte[] packet;
- R result;
- while ((packet = mDownstreamReader.popPacket(PACKET_READ_TIMEOUT_MS)) != null) {
- result = match.apply(packet);
+ public void sendPacket(ByteBuffer packet) throws Exception {
+ mDownstreamReader.sendResponse(packet);
+ }
- if (result != null) return result;
+ public byte[] getNextMatchedPacket(Predicate<byte[]> filter) {
+ return mDownstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter);
+ }
+
+ public static class RemoteResponder {
+ final TapPacketReader mUpstreamReader;
+ public RemoteResponder(TapPacketReader reader) {
+ mUpstreamReader = reader;
}
- return null;
+ public void sendPacket(ByteBuffer packet) throws Exception {
+ mUpstreamReader.sendResponse(packet);
+ }
+
+ public byte[] getNextMatchedPacket(Predicate<byte[]> filter) throws Exception {
+ return mUpstreamReader.poll(PACKET_READ_TIMEOUT_MS, filter);
+ }
}
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index f45768f..40d133a 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -2558,10 +2558,10 @@
@Test
public void testBluetoothTethering() throws Exception {
final ResultListener result = new ResultListener(TETHER_ERROR_NO_ERROR);
- when(mBluetoothAdapter.isEnabled()).thenReturn(true);
+ mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */);
mTethering.startTethering(createTetheringRequestParcel(TETHERING_BLUETOOTH), result);
mLooper.dispatchAll();
- verifySetBluetoothTethering(true);
+ verifySetBluetoothTethering(true /* enable */, true /* bindToPanService */);
result.assertHasResult();
mTethering.interfaceAdded(TEST_BT_IFNAME);
@@ -2574,6 +2574,64 @@
mLooper.dispatchAll();
tetherResult.assertHasResult();
+ verifyNetdCommandForBtSetup();
+
+ // Turning tethering on a second time does not bind to the PAN service again, since it's
+ // already bound.
+ mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */);
+ final ResultListener secondResult = new ResultListener(TETHER_ERROR_NO_ERROR);
+ mTethering.startTethering(createTetheringRequestParcel(TETHERING_BLUETOOTH), secondResult);
+ mLooper.dispatchAll();
+ verifySetBluetoothTethering(true /* enable */, false /* bindToPanService */);
+ secondResult.assertHasResult();
+
+ mockBluetoothSettings(true /* bluetoothOn */, false /* tetheringOn */);
+ mTethering.stopTethering(TETHERING_BLUETOOTH);
+ mLooper.dispatchAll();
+ final ResultListener untetherResult = new ResultListener(TETHER_ERROR_NO_ERROR);
+ mTethering.untether(TEST_BT_IFNAME, untetherResult);
+ mLooper.dispatchAll();
+ untetherResult.assertHasResult();
+ verifySetBluetoothTethering(false /* enable */, false /* bindToPanService */);
+
+ verifyNetdCommandForBtTearDown();
+ }
+
+ @Test
+ public void testBluetoothServiceDisconnects() throws Exception {
+ final ResultListener result = new ResultListener(TETHER_ERROR_NO_ERROR);
+ mockBluetoothSettings(true /* bluetoothOn */, true /* tetheringOn */);
+ mTethering.startTethering(createTetheringRequestParcel(TETHERING_BLUETOOTH), result);
+ mLooper.dispatchAll();
+ ServiceListener panListener = verifySetBluetoothTethering(true /* enable */,
+ true /* bindToPanService */);
+ result.assertHasResult();
+
+ mTethering.interfaceAdded(TEST_BT_IFNAME);
+ mLooper.dispatchAll();
+
+ mTethering.interfaceStatusChanged(TEST_BT_IFNAME, false);
+ mTethering.interfaceStatusChanged(TEST_BT_IFNAME, true);
+ final ResultListener tetherResult = new ResultListener(TETHER_ERROR_NO_ERROR);
+ mTethering.tether(TEST_BT_IFNAME, IpServer.STATE_TETHERED, tetherResult);
+ mLooper.dispatchAll();
+ tetherResult.assertHasResult();
+
+ verifyNetdCommandForBtSetup();
+
+ panListener.onServiceDisconnected(BluetoothProfile.PAN);
+ mTethering.interfaceStatusChanged(TEST_BT_IFNAME, false);
+ mLooper.dispatchAll();
+
+ verifyNetdCommandForBtTearDown();
+ }
+
+ private void mockBluetoothSettings(boolean bluetoothOn, boolean tetheringOn) {
+ when(mBluetoothAdapter.isEnabled()).thenReturn(bluetoothOn);
+ when(mBluetoothPan.isTetheringOn()).thenReturn(tetheringOn);
+ }
+
+ private void verifyNetdCommandForBtSetup() throws Exception {
verify(mNetd).tetherInterfaceAdd(TEST_BT_IFNAME);
verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, TEST_BT_IFNAME);
verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(TEST_BT_IFNAME),
@@ -2584,39 +2642,41 @@
anyString(), anyString());
verifyNoMoreInteractions(mNetd);
reset(mNetd);
+ }
- when(mBluetoothAdapter.isEnabled()).thenReturn(true);
- mTethering.stopTethering(TETHERING_BLUETOOTH);
- mLooper.dispatchAll();
- final ResultListener untetherResult = new ResultListener(TETHER_ERROR_NO_ERROR);
- mTethering.untether(TEST_BT_IFNAME, untetherResult);
- mLooper.dispatchAll();
- untetherResult.assertHasResult();
- verifySetBluetoothTethering(false);
-
+ private void verifyNetdCommandForBtTearDown() throws Exception {
verify(mNetd).tetherApplyDnsInterfaces();
verify(mNetd).tetherInterfaceRemove(TEST_BT_IFNAME);
verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, TEST_BT_IFNAME);
verify(mNetd).interfaceSetCfg(any(InterfaceConfigurationParcel.class));
verify(mNetd).tetherStop();
verify(mNetd).ipfwdDisableForwarding(TETHERING_NAME);
- verifyNoMoreInteractions(mNetd);
}
- private void verifySetBluetoothTethering(final boolean enable) {
- final ArgumentCaptor<ServiceListener> listenerCaptor =
- ArgumentCaptor.forClass(ServiceListener.class);
+ // If bindToPanService is true, this function would return ServiceListener which could notify
+ // PanService is connected or disconnected.
+ private ServiceListener verifySetBluetoothTethering(final boolean enable,
+ final boolean bindToPanService) {
+ ServiceListener listener = null;
verify(mBluetoothAdapter).isEnabled();
- verify(mBluetoothAdapter).getProfileProxy(eq(mServiceContext), listenerCaptor.capture(),
- eq(BluetoothProfile.PAN));
- final ServiceListener listener = listenerCaptor.getValue();
- when(mBluetoothPan.isTetheringOn()).thenReturn(enable);
- listener.onServiceConnected(BluetoothProfile.PAN, mBluetoothPan);
+ if (bindToPanService) {
+ final ArgumentCaptor<ServiceListener> listenerCaptor =
+ ArgumentCaptor.forClass(ServiceListener.class);
+ verify(mBluetoothAdapter).getProfileProxy(eq(mServiceContext), listenerCaptor.capture(),
+ eq(BluetoothProfile.PAN));
+ listener = listenerCaptor.getValue();
+ listener.onServiceConnected(BluetoothProfile.PAN, mBluetoothPan);
+ mLooper.dispatchAll();
+ } else {
+ verify(mBluetoothAdapter, never()).getProfileProxy(eq(mServiceContext), any(),
+ anyInt());
+ }
verify(mBluetoothPan).setBluetoothTethering(enable);
verify(mBluetoothPan).isTetheringOn();
- verify(mBluetoothAdapter).closeProfileProxy(eq(BluetoothProfile.PAN), eq(mBluetoothPan));
verifyNoMoreInteractions(mBluetoothAdapter, mBluetoothPan);
reset(mBluetoothAdapter, mBluetoothPan);
+
+ return listener;
}
private void runDualStackUsbTethering(final String expectedIface) throws Exception {
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 9a77a3c..827da6d 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -206,6 +206,7 @@
}
public final class IpPrefix implements android.os.Parcelable {
+ ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
method public boolean contains(@NonNull java.net.InetAddress);
method public int describeContents();
method @NonNull public java.net.InetAddress getAddress();
@@ -293,6 +294,7 @@
ctor public NetworkCapabilities(android.net.NetworkCapabilities);
method public int describeContents();
method @NonNull public int[] getCapabilities();
+ method @NonNull public int[] getEnterpriseCapabilitySubLevels();
method public int getLinkDownstreamBandwidthKbps();
method public int getLinkUpstreamBandwidthKbps();
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
@@ -316,6 +318,7 @@
field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
field public static final int NET_CAPABILITY_MCX = 23; // 0x17
field public static final int NET_CAPABILITY_MMS = 0; // 0x0
+ field public static final int NET_CAPABILITY_MMTEL = 33; // 0x21
field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
@@ -439,11 +442,15 @@
method @NonNull public android.net.IpPrefix getDestination();
method @Nullable public java.net.InetAddress getGateway();
method @Nullable public String getInterface();
+ method public int getType();
method public boolean hasGateway();
method public boolean isDefaultRoute();
method public boolean matches(java.net.InetAddress);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR;
+ field public static final int RTN_THROW = 9; // 0x9
+ field public static final int RTN_UNICAST = 1; // 0x1
+ field public static final int RTN_UNREACHABLE = 7; // 0x7
}
public abstract class SocketKeepalive implements java.lang.AutoCloseable {
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 50dd2ad..81a1e5d 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -121,6 +121,11 @@
public final class NetworkCapabilities implements android.os.Parcelable {
method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
method public boolean hasForbiddenCapability(int);
+ field public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1 = 1; // 0x1
+ field public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2 = 2; // 0x2
+ field public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3 = 3; // 0x3
+ field public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4 = 4; // 0x4
+ field public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5 = 5; // 0x5
field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L
field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index cfab872..8d084e6 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -131,7 +131,6 @@
}
public final class IpPrefix implements android.os.Parcelable {
- ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
ctor public IpPrefix(@NonNull String);
}
@@ -295,9 +294,11 @@
ctor public NetworkCapabilities.Builder();
ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder addEnterpriseCapabilitySubLevel(int);
method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
method @NonNull public android.net.NetworkCapabilities build();
method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder removeEnterpriseCapabilitySubLevel(int);
method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int);
@@ -432,10 +433,6 @@
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
method public int getMtu();
- method public int getType();
- field public static final int RTN_THROW = 9; // 0x9
- field public static final int RTN_UNICAST = 1; // 0x1
- field public static final int RTN_UNREACHABLE = 7; // 0x7
}
public abstract class SocketKeepalive implements java.lang.AutoCloseable {
diff --git a/framework/src/android/net/IpPrefix.java b/framework/src/android/net/IpPrefix.java
index bf4481a..c26a0b5 100644
--- a/framework/src/android/net/IpPrefix.java
+++ b/framework/src/android/net/IpPrefix.java
@@ -87,9 +87,7 @@
*
* @param address the IP address. Must be non-null.
* @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
- * @hide
*/
- @SystemApi
public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) {
// We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
// which is unnecessary because getAddress() already returns a clone.
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index ca5dc34..84f7cbb 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import android.annotation.IntDef;
@@ -146,6 +148,70 @@
*/
private String mRequestorPackageName;
+ /**
+ * enterprise capability sub level 1
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1 = 1;
+
+ /**
+ * enterprise capability sub level 2
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2 = 2;
+
+ /**
+ * enterprise capability sub level 3
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3 = 3;
+
+ /**
+ * enterprise capability sub level 4
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4 = 4;
+
+ /**
+ * enterprise capability sub level 5
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5 = 5;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "NET_CAPABILITY_ENTERPRISE_SUB_LEVEL" }, value = {
+ NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1,
+ NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2,
+ NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3,
+ NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4,
+ NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5,
+ })
+
+ public @interface EnterpriseCapabilitySubLevel {
+ }
+
+ /**
+ * Bitfield representing the network's enterprise capability sublevel. If any are specified
+ * they will be satisfied by any Network that matches all of them.
+ * {@see addEnterpriseCapabilitySubLevel} for details on how masks are added
+ */
+ private int mEnterpriseCapabilitySubLevel;
+
+ /**
+ * @return all the enteprise capabilities sub level set on this {@code NetworkCapability}
+ * instance.
+ *
+ */
+ public @NonNull @EnterpriseCapabilitySubLevel int[] getEnterpriseCapabilitySubLevels() {
+ return NetworkCapabilitiesUtils.unpackBits(mEnterpriseCapabilitySubLevel);
+ }
+
public NetworkCapabilities() {
clearAll();
mNetworkCapabilities = DEFAULT_CAPABILITIES;
@@ -192,6 +258,7 @@
mRequestorPackageName = null;
mSubIds = new ArraySet<>();
mUnderlyingNetworks = null;
+ mEnterpriseCapabilitySubLevel = 0;
}
/**
@@ -224,6 +291,7 @@
// mUnderlyingNetworks is an unmodifiable list if non-null, so a defensive copy is not
// necessary.
mUnderlyingNetworks = nc.mUnderlyingNetworks;
+ mEnterpriseCapabilitySubLevel = nc.mEnterpriseCapabilitySubLevel;
}
/**
@@ -274,6 +342,7 @@
NET_CAPABILITY_VSIM,
NET_CAPABILITY_BIP,
NET_CAPABILITY_HEAD_UNIT,
+ NET_CAPABILITY_MMTEL,
})
public @interface NetCapability { }
@@ -512,8 +581,13 @@
*/
public static final int NET_CAPABILITY_HEAD_UNIT = 32;
+ /**
+ * Indicates that this network has ability to support MMTEL (Multimedia Telephony service).
+ */
+ public static final int NET_CAPABILITY_MMTEL = 33;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_HEAD_UNIT;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_MMTEL;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -710,6 +784,38 @@
}
/**
+ * Adds the given enterprise capability sub level to this {@code NetworkCapability} instance.
+ * Note that when searching for a network to satisfy a request, all capabilities sub level
+ * requested must be satisfied.
+ *
+ * @param enterpriseCapabilitySubLevel the enterprise capability sub level to be added.
+ * @return This NetworkCapabilities instance, to facilitate chaining.
+ * @hide
+ */
+ private @NonNull NetworkCapabilities addEnterpriseCapabilitySubLevel(
+ @EnterpriseCapabilitySubLevel int enterpriseCapabilitySubLevel) {
+ checkValidEnterpriseCapabilitySublevel(enterpriseCapabilitySubLevel);
+ mEnterpriseCapabilitySubLevel |= 1 << enterpriseCapabilitySubLevel;
+ return this;
+ }
+
+ /**
+ * Removes (if found) the given enterprise capability sublevel from this
+ * {@code NetworkCapability} instance that were added via addEnterpriseCapabilitySubLevel(int)
+ *
+ * @param enterpriseCapabilitySubLevel the enterprise capability sublevel to be removed.
+ * @return This NetworkCapabilities instance, to facilitate chaining.
+ * @hide
+ */
+ private @NonNull NetworkCapabilities removeEnterpriseCapabilitySubLevel(
+ @EnterpriseCapabilitySubLevel int enterpriseCapabilitySubLevel) {
+ checkValidEnterpriseCapabilitySublevel(enterpriseCapabilitySubLevel);
+ final int mask = ~(1 << enterpriseCapabilitySubLevel);
+ mEnterpriseCapabilitySubLevel &= mask;
+ return this;
+ }
+
+ /**
* Set the underlying networks of this network.
*
* @param networks The underlying networks of this network.
@@ -809,6 +915,22 @@
return null;
}
+ private boolean equalsEnterpriseCapabilitiesSubLevel(@NonNull NetworkCapabilities nc) {
+ return nc.mEnterpriseCapabilitySubLevel == this.mEnterpriseCapabilitySubLevel;
+ }
+
+ private boolean satisfiedByEnterpriseCapabilitiesSubLevel(@NonNull NetworkCapabilities nc) {
+ final int requestedEnterpriseCapabilitiesSubLevel = mEnterpriseCapabilitySubLevel;
+ final int providedEnterpriseCapabailitiesSubLevel = nc.mEnterpriseCapabilitySubLevel;
+
+ if ((providedEnterpriseCapabailitiesSubLevel & requestedEnterpriseCapabilitiesSubLevel)
+ == requestedEnterpriseCapabilitiesSubLevel) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
private boolean satisfiedByNetCapabilities(@NonNull NetworkCapabilities nc,
boolean onlyImmutable) {
long requestedCapabilities = mNetworkCapabilities;
@@ -1592,28 +1714,6 @@
}
/**
- * Compare if the given NetworkCapabilities have the same UIDs.
- *
- * @hide
- */
- public static boolean hasSameUids(@Nullable NetworkCapabilities nc1,
- @Nullable NetworkCapabilities nc2) {
- final Set<UidRange> uids1 = (nc1 == null) ? null : nc1.mUids;
- final Set<UidRange> uids2 = (nc2 == null) ? null : nc2.mUids;
- if (null == uids1) return null == uids2;
- if (null == uids2) return false;
- // Make a copy so it can be mutated to check that all ranges in uids2 also are in uids.
- final Set<UidRange> uids = new ArraySet<>(uids2);
- for (UidRange range : uids1) {
- if (!uids.contains(range)) {
- return false;
- }
- uids.remove(range);
- }
- return uids.isEmpty();
- }
-
- /**
* Tests if the set of UIDs that this network applies to is the same as the passed network.
* <p>
* This test only checks whether equal range objects are in both sets. It will
@@ -1623,13 +1723,13 @@
* Note that this method is not very optimized, which is fine as long as it's not used very
* often.
* <p>
- * nc is assumed nonnull.
+ * nc is assumed nonnull, else NPE.
*
* @hide
*/
@VisibleForTesting
public boolean equalsUids(@NonNull NetworkCapabilities nc) {
- return hasSameUids(nc, this);
+ return UidRange.hasSameUids(nc.mUids, mUids);
}
/**
@@ -1736,6 +1836,7 @@
&& satisfiedByTransportTypes(nc)
&& (onlyImmutable || satisfiedByLinkBandwidths(nc))
&& satisfiedBySpecifier(nc)
+ && satisfiedByEnterpriseCapabilitiesSubLevel(nc)
&& (onlyImmutable || satisfiedBySignalStrength(nc))
&& (onlyImmutable || satisfiedByUids(nc))
&& (onlyImmutable || satisfiedBySSID(nc))
@@ -1838,7 +1939,8 @@
&& equalsRequestor(that)
&& equalsAdministratorUids(that)
&& equalsSubscriptionIds(that)
- && equalsUnderlyingNetworks(that);
+ && equalsUnderlyingNetworks(that)
+ && equalsEnterpriseCapabilitiesSubLevel(that);
}
@Override
@@ -1862,7 +1964,8 @@
+ Objects.hashCode(mRequestorPackageName) * 59
+ Arrays.hashCode(mAdministratorUids) * 61
+ Objects.hashCode(mSubIds) * 67
- + Objects.hashCode(mUnderlyingNetworks) * 71;
+ + Objects.hashCode(mUnderlyingNetworks) * 71
+ + mEnterpriseCapabilitySubLevel * 73;
}
@Override
@@ -1898,6 +2001,7 @@
dest.writeString(mRequestorPackageName);
dest.writeIntArray(CollectionUtils.toIntArray(mSubIds));
dest.writeTypedList(mUnderlyingNetworks);
+ dest.writeInt(mEnterpriseCapabilitySubLevel);
}
public static final @android.annotation.NonNull Creator<NetworkCapabilities> CREATOR =
@@ -1927,6 +2031,7 @@
netCap.mSubIds.add(subIdInts[i]);
}
netCap.setUnderlyingNetworks(in.createTypedArrayList(Network.CREATOR));
+ netCap.mEnterpriseCapabilitySubLevel = in.readInt();
return netCap;
}
@Override
@@ -2018,6 +2123,12 @@
sb.append(" SubscriptionIds: ").append(mSubIds);
}
+ if (0 != mEnterpriseCapabilitySubLevel) {
+ sb.append(" EnterpriseCapabilitySublevel: ");
+ appendStringRepresentationOfBitMaskToStringBuilder(sb, mEnterpriseCapabilitySubLevel,
+ NetworkCapabilities::enterpriseCapabilitySublevelNameOf, "&");
+ }
+
sb.append(" UnderlyingNetworks: ");
if (mUnderlyingNetworks != null) {
sb.append("[");
@@ -2112,10 +2223,16 @@
case NET_CAPABILITY_VSIM: return "VSIM";
case NET_CAPABILITY_BIP: return "BIP";
case NET_CAPABILITY_HEAD_UNIT: return "HEAD_UNIT";
+ case NET_CAPABILITY_MMTEL: return "MMTEL";
default: return Integer.toString(capability);
}
}
+ private static @NonNull String enterpriseCapabilitySublevelNameOf(
+ @NetCapability int capability) {
+ return Integer.toString(capability);
+ }
+
/**
* @hide
*/
@@ -2156,6 +2273,20 @@
}
}
+ private static boolean isValidEnterpriseCapabilitySubLevel(
+ @NetworkCapabilities.EnterpriseCapabilitySubLevel int enterpriseCapabilitySubLevel) {
+ return enterpriseCapabilitySubLevel >= NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1
+ && enterpriseCapabilitySubLevel <= NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5;
+ }
+
+ private static void checkValidEnterpriseCapabilitySublevel(
+ @NetworkCapabilities.EnterpriseCapabilitySubLevel int enterpriseCapabilitySubLevel) {
+ if (!isValidEnterpriseCapabilitySubLevel(enterpriseCapabilitySubLevel)) {
+ throw new IllegalArgumentException("enterprise capability sublevel "
+ + enterpriseCapabilitySubLevel + " is out of range");
+ }
+ }
+
/**
* Check if this {@code NetworkCapability} instance is metered.
*
@@ -2482,6 +2613,37 @@
}
/**
+ * Adds the given enterprise capability sub level.
+ * Note that when searching for a network to satisfy a request, all capabilities sub level
+ * requested must be satisfied. Enterprise capability sub-level is applicable only
+ * for NET_CAPABILITY_ENTERPRISE capability
+ *
+ * @param enterpriseCapabilitySubLevel enterprise capability sub-level.
+ *
+ * @return this builder
+ */
+ @NonNull
+ public Builder addEnterpriseCapabilitySubLevel(
+ @EnterpriseCapabilitySubLevel int enterpriseCapabilitySubLevel) {
+ mCaps.addEnterpriseCapabilitySubLevel(enterpriseCapabilitySubLevel);
+ return this;
+ }
+
+ /**
+ * Removes the given enterprise capability sub level. Enterprise capability sub-level is
+ * applicable only for NET_CAPABILITY_ENTERPRISE capability
+ *
+ * @param enterpriseCapabilitySubLevel the enterprise capability subLevel
+ * @return this builder
+ */
+ @NonNull
+ public Builder removeEnterpriseCapabilitySubLevel(
+ @EnterpriseCapabilitySubLevel int enterpriseCapabilitySubLevel) {
+ mCaps.removeEnterpriseCapabilitySubLevel(enterpriseCapabilitySubLevel);
+ return this;
+ }
+
+ /**
* Sets the owner UID.
*
* The default value is {@link Process#INVALID_UID}. Pass this value to reset.
@@ -2739,6 +2901,12 @@
+ " administrator UIDs.");
}
}
+
+ if ((mCaps.getEnterpriseCapabilitySubLevels().length != 0)
+ && !mCaps.hasCapability(NET_CAPABILITY_ENTERPRISE)) {
+ throw new IllegalStateException("Enterprise capability sublevel is applicable only"
+ + " with ENTERPRISE capability.");
+ }
return new NetworkCapabilities(mCaps);
}
}
diff --git a/framework/src/android/net/RouteInfo.java b/framework/src/android/net/RouteInfo.java
index fad3144..df5f151 100644
--- a/framework/src/android/net/RouteInfo.java
+++ b/framework/src/android/net/RouteInfo.java
@@ -86,16 +86,26 @@
private final String mInterface;
- /** Unicast route. @hide */
- @SystemApi
+ /**
+ * Unicast route.
+ *
+ * Indicates that destination is reachable directly or via gateway.
+ **/
public static final int RTN_UNICAST = 1;
- /** Unreachable route. @hide */
- @SystemApi
+ /**
+ * Unreachable route.
+ *
+ * Indicates that destination is unreachable.
+ **/
public static final int RTN_UNREACHABLE = 7;
- /** Throw route. @hide */
- @SystemApi
+ /**
+ * Throw route.
+ *
+ * Indicates that routing information about this destination is not in this table.
+ * Routing lookup should continue in another table.
+ **/
public static final int RTN_THROW = 9;
/**
@@ -391,10 +401,7 @@
* Retrieves the type of this route.
*
* @return The type of this route; one of the {@code RTN_xxx} constants defined in this class.
- *
- * @hide
*/
- @SystemApi
@RouteType
public int getType() {
return mType;
diff --git a/framework/src/android/net/UidRange.java b/framework/src/android/net/UidRange.java
index bd33292..a1f64f2 100644
--- a/framework/src/android/net/UidRange.java
+++ b/framework/src/android/net/UidRange.java
@@ -180,4 +180,24 @@
}
return uids;
}
+
+ /**
+ * Compare if the given UID range sets have the same UIDs.
+ *
+ * @hide
+ */
+ public static boolean hasSameUids(@Nullable Set<UidRange> uids1,
+ @Nullable Set<UidRange> uids2) {
+ if (null == uids1) return null == uids2;
+ if (null == uids2) return false;
+ // Make a copy so it can be mutated to check that all ranges in uids2 also are in uids.
+ final Set<UidRange> remainingUids = new ArraySet<>(uids2);
+ for (UidRange range : uids1) {
+ if (!remainingUids.contains(range)) {
+ return false;
+ }
+ remainingUids.remove(range);
+ }
+ return remainingUids.isEmpty();
+ }
}
diff --git a/service/Android.bp b/service/Android.bp
index 1f87848..76f9153 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -19,6 +19,33 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
+// The library name match the service-connectivity jarjar rules that put the JNI utils in the
+// com.android.connectivity.com.android.net.module.util package.
+cc_library_shared {
+ name: "libcom_android_connectivity_com_android_net_module_util_jni",
+ min_sdk_version: "30",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wthread-safety",
+ ],
+ srcs: [
+ "jni/com_android_net_module_util/onload.cpp",
+ ],
+ stl: "libc++_static",
+ static_libs: [
+ "libnet_utils_device_common_bpfjni",
+ ],
+ shared_libs: [
+ "liblog",
+ "libnativehelper",
+ ],
+ apex_available: [
+ "com.android.tethering",
+ ],
+}
+
cc_library_shared {
name: "libservice-connectivity",
min_sdk_version: "30",
@@ -69,6 +96,7 @@
"modules-utils-build",
"modules-utils-shell-command-handler",
"net-utils-device-common",
+ "net-utils-device-common-bpf",
"net-utils-device-common-netlink",
"net-utils-framework-common",
"netd-client",
diff --git a/service/jni/com_android_net_module_util/onload.cpp b/service/jni/com_android_net_module_util/onload.cpp
new file mode 100644
index 0000000..1d17622
--- /dev/null
+++ b/service/jni/com_android_net_module_util/onload.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <nativehelper/JNIHelp.h>
+#include <log/log.h>
+
+namespace android {
+
+int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name);
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
+ JNIEnv *env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ ALOGE("GetEnv failed");
+ return JNI_ERR;
+ }
+
+ if (register_com_android_net_module_util_BpfMap(env,
+ "com/android/connectivity/com/android/net/module/util/BpfMap") < 0) return JNI_ERR;
+
+ return JNI_VERSION_1_6;
+}
+
+};
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index d507b4b..6227bb2 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -7705,7 +7705,9 @@
// changed.
// TODO: Try to track the default network that apps use and only send a proxy broadcast when
// that happens to prevent false alarms.
- if (nai.isVPN() && nai.everConnected && !NetworkCapabilities.hasSameUids(prevNc, newNc)
+ final Set<UidRange> prevUids = prevNc == null ? null : prevNc.getUidRanges();
+ final Set<UidRange> newUids = newNc == null ? null : newNc.getUidRanges();
+ if (nai.isVPN() && nai.everConnected && !UidRange.hasSameUids(prevUids, newUids)
&& (nai.linkProperties.getHttpProxy() != null || isProxySetOnAnyDefaultNetwork())) {
mProxyTracker.sendProxyBroadcast();
}
diff --git a/tests/common/java/android/net/IpPrefixTest.java b/tests/common/java/android/net/IpPrefixTest.java
index 50ecb42..f61c8c3 100644
--- a/tests/common/java/android/net/IpPrefixTest.java
+++ b/tests/common/java/android/net/IpPrefixTest.java
@@ -122,6 +122,9 @@
p = new IpPrefix("[2001:db8::123]/64");
assertEquals("2001:db8::/64", p.toString());
+
+ p = new IpPrefix(InetAddresses.parseNumericAddress("::128"), 64);
+ assertEquals("::/64", p.toString());
}
@Test
diff --git a/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java
index 32f00a3..2a4df7a 100644
--- a/tests/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -22,6 +22,12 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
@@ -347,7 +353,7 @@
if (isAtLeastS()) {
// When this test is run on S+, NetworkCapabilities is as recent as the test,
// so this should be the most recent known number of fields.
- assertParcelSane(cap, 17);
+ assertParcelSane(cap, 18);
} else if (isAtLeastR()) {
assertParcelSane(cap, 15);
} else {
@@ -797,6 +803,87 @@
} catch (IllegalStateException expected) { }
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.S)
+ public void testEnterpriseCapabilitySubLevel() {
+ final NetworkCapabilities nc1 = new NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_ENTERPRISE)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+ .build();
+ assertEquals(1, nc1.getEnterpriseCapabilitySubLevels().length);
+ assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1,
+ nc1.getEnterpriseCapabilitySubLevels()[0]);
+ final NetworkCapabilities nc2 = new NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_ENTERPRISE)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+ .build();
+ assertEquals(2, nc2.getEnterpriseCapabilitySubLevels().length);
+ assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1,
+ nc2.getEnterpriseCapabilitySubLevels()[0]);
+ assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2,
+ nc2.getEnterpriseCapabilitySubLevels()[1]);
+ final NetworkCapabilities nc3 = new NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_ENTERPRISE)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5)
+ .build();
+ assertEquals(5, nc3.getEnterpriseCapabilitySubLevels().length);
+ assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1,
+ nc3.getEnterpriseCapabilitySubLevels()[0]);
+ assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2,
+ nc3.getEnterpriseCapabilitySubLevels()[1]);
+ assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_3,
+ nc3.getEnterpriseCapabilitySubLevels()[2]);
+ assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_4,
+ nc3.getEnterpriseCapabilitySubLevels()[3]);
+ assertEquals(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_5,
+ nc3.getEnterpriseCapabilitySubLevels()[4]);
+
+ final Class<IllegalArgumentException> illegalArgumentExceptionClass =
+ IllegalArgumentException.class;
+ assertThrows(illegalArgumentExceptionClass, () -> new NetworkCapabilities.Builder()
+ .addEnterpriseCapabilitySubLevel(6)
+ .build());
+ assertThrows(illegalArgumentExceptionClass, () -> new NetworkCapabilities.Builder()
+ .removeEnterpriseCapabilitySubLevel(6)
+ .build());
+
+ final Class<IllegalStateException> illegalStateException =
+ IllegalStateException.class;
+ assertThrows(illegalStateException, () -> new NetworkCapabilities.Builder()
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+ .build());
+
+ final NetworkCapabilities nc4 = new NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_ENTERPRISE)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+ .removeEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+ .removeEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+ .build();
+ assertEquals(0, nc4.getEnterpriseCapabilitySubLevels().length);
+
+ final NetworkCapabilities nc5 = new NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_CBS)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+ .addEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+ .removeEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_1)
+ .removeEnterpriseCapabilitySubLevel(NET_CAPABILITY_ENTERPRISE_SUB_LEVEL_2)
+ .build();
+
+ assertTrue(nc4.satisfiedByNetworkCapabilities(nc1));
+ assertFalse(nc1.satisfiedByNetworkCapabilities(nc4));
+
+ assertFalse(nc3.satisfiedByNetworkCapabilities(nc2));
+ assertTrue(nc2.satisfiedByNetworkCapabilities(nc3));
+
+ assertFalse(nc1.satisfiedByNetworkCapabilities(nc5));
+ assertFalse(nc5.satisfiedByNetworkCapabilities(nc1));
+ }
+
@Test
public void testWifiAwareNetworkSpecifier() {
final NetworkCapabilities nc = new NetworkCapabilities()
diff --git a/tests/common/java/android/net/RouteInfoTest.java b/tests/common/java/android/net/RouteInfoTest.java
index 71689f9..b69b045 100644
--- a/tests/common/java/android/net/RouteInfoTest.java
+++ b/tests/common/java/android/net/RouteInfoTest.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.net.RouteInfo.RTN_THROW;
+import static android.net.RouteInfo.RTN_UNICAST;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static com.android.testutils.MiscAsserts.assertEqualBothWays;
@@ -329,6 +331,16 @@
}
@Test
+ public void testRouteTypes() {
+ RouteInfo r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE);
+ assertEquals(RTN_UNREACHABLE, r.getType());
+ r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNICAST);
+ assertEquals(RTN_UNICAST, r.getType());
+ r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_THROW);
+ assertEquals(RTN_THROW, r.getType());
+ }
+
+ @Test
public void testTruncation() {
LinkAddress l;
RouteInfo r;
diff --git a/tests/common/java/android/net/UidRangeTest.java b/tests/common/java/android/net/UidRangeTest.java
index 1b1c954..a435119 100644
--- a/tests/common/java/android/net/UidRangeTest.java
+++ b/tests/common/java/android/net/UidRangeTest.java
@@ -22,11 +22,15 @@
import static android.os.UserHandle.getUid;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.os.Build;
import android.os.UserHandle;
+import android.util.ArraySet;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -38,6 +42,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Set;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class UidRangeTest {
@@ -110,4 +116,61 @@
assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getStartUser());
assertEquals(USER_SYSTEM + 1, uidRangeOfSecondaryUser.getEndUser());
}
+
+ private static void assertSameUids(@NonNull final String msg, @Nullable final Set<UidRange> s1,
+ @Nullable final Set<UidRange> s2) {
+ assertTrue(msg + " : " + s1 + " unexpectedly different from " + s2,
+ UidRange.hasSameUids(s1, s2));
+ }
+
+ private static void assertDifferentUids(@NonNull final String msg,
+ @Nullable final Set<UidRange> s1, @Nullable final Set<UidRange> s2) {
+ assertFalse(msg + " : " + s1 + " unexpectedly equal to " + s2,
+ UidRange.hasSameUids(s1, s2));
+ }
+
+ // R doesn't have UidRange.hasSameUids, but since S has the module, it does have hasSameUids.
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testHasSameUids() {
+ final UidRange uids1 = new UidRange(1, 100);
+ final UidRange uids2 = new UidRange(3, 300);
+ final UidRange uids3 = new UidRange(1, 1000);
+ final UidRange uids4 = new UidRange(800, 1000);
+
+ assertSameUids("null <=> null", null, null);
+ final Set<UidRange> set1 = new ArraySet<>();
+ assertDifferentUids("empty <=> null", set1, null);
+ final Set<UidRange> set2 = new ArraySet<>();
+ set1.add(uids1);
+ assertDifferentUids("uids1 <=> null", set1, null);
+ assertDifferentUids("null <=> uids1", null, set1);
+ assertDifferentUids("uids1 <=> empty", set1, set2);
+ set2.add(uids1);
+ assertSameUids("uids1 <=> uids1", set1, set2);
+ set1.add(uids2);
+ assertDifferentUids("uids1,2 <=> uids1", set1, set2);
+ set1.add(uids3);
+ assertDifferentUids("uids1,2,3 <=> uids1", set1, set2);
+ set2.add(uids3);
+ assertDifferentUids("uids1,2,3 <=> uids1,3", set1, set2);
+ set2.add(uids2);
+ assertSameUids("uids1,2,3 <=> uids1,2,3", set1, set2);
+ set1.remove(uids2);
+ assertDifferentUids("uids1,3 <=> uids1,2,3", set1, set2);
+ set1.add(uids4);
+ assertDifferentUids("uids1,3,4 <=> uids1,2,3", set1, set2);
+ set2.add(uids4);
+ assertDifferentUids("uids1,3,4 <=> uids1,2,3,4", set1, set2);
+ assertDifferentUids("uids1,3,4 <=> null", set1, null);
+ set2.remove(uids2);
+ assertSameUids("uids1,3,4 <=> uids1,3,4", set1, set2);
+ set2.remove(uids1);
+ assertDifferentUids("uids1,3,4 <=> uids3,4", set1, set2);
+ set2.remove(uids3);
+ assertDifferentUids("uids1,3,4 <=> uids4", set1, set2);
+ set2.remove(uids4);
+ assertDifferentUids("uids1,3,4 <=> empty", set1, set2);
+ assertDifferentUids("null <=> empty", null, set2);
+ assertSameUids("empty <=> empty", set2, new ArraySet<>());
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
index 721ad82..c9fed44 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
@@ -40,6 +40,7 @@
import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+import static com.android.testutils.Cleanup.testAndCleanup;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -224,16 +225,16 @@
final TestNetworkCallback testNetworkCallback = new TestNetworkCallback();
- try {
+ testAndCleanup(() -> {
doBroadcastCarrierConfigsAndVerifyOnConnectivityReportAvailable(
subId, carrierConfigReceiver, testNetworkCallback);
- } finally {
+ }, () -> {
runWithShellPermissionIdentity(
() -> mCarrierConfigManager.overrideConfig(subId, null),
android.Manifest.permission.MODIFY_PHONE_STATE);
mConnectivityManager.unregisterNetworkCallback(testNetworkCallback);
mContext.unregisterReceiver(carrierConfigReceiver);
- }
+ });
}
private String getCertHashForThisPackage() throws Exception {
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 1025fe3..48751f4 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -25,7 +25,7 @@
"ld-android",
"libbase",
"libbinder",
- "libbpf",
+ "libbpf_bcc",
"libbpf_android",
"libc++",
"libcgrouprc",
diff --git a/tests/unit/java/android/net/NetworkStatsAccessTest.java b/tests/unit/java/android/net/NetworkStatsAccessTest.java
index 0f9ed41..bcbbcc92 100644
--- a/tests/unit/java/android/net/NetworkStatsAccessTest.java
+++ b/tests/unit/java/android/net/NetworkStatsAccessTest.java
@@ -22,7 +22,7 @@
import android.Manifest;
import android.Manifest.permission;
import android.app.AppOpsManager;
-import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
@@ -30,7 +30,6 @@
import androidx.test.filters.SmallTest;
-import com.android.server.LocalServices;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
@@ -49,29 +48,26 @@
private static final int TEST_UID = 12345;
@Mock private Context mContext;
- @Mock private DevicePolicyManagerInternal mDpmi;
+ @Mock private DevicePolicyManager mDpm;
@Mock private TelephonyManager mTm;
@Mock private AppOpsManager mAppOps;
// Hold the real service so we can restore it when tearing down the test.
- private DevicePolicyManagerInternal mSystemDpmi;
+ private DevicePolicyManager mSystemDpm;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mSystemDpmi = LocalServices.getService(DevicePolicyManagerInternal.class);
- LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
- LocalServices.addService(DevicePolicyManagerInternal.class, mDpmi);
-
when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTm);
when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOps);
+ when(mContext.getSystemServiceName(DevicePolicyManager.class))
+ .thenReturn(Context.DEVICE_POLICY_SERVICE);
+ when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(mDpm);
}
@After
public void tearDown() throws Exception {
- LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
- LocalServices.addService(DevicePolicyManagerInternal.class, mSystemDpmi);
}
@Test
@@ -169,11 +165,11 @@
}
private void setIsDeviceOwner(boolean isOwner) {
- when(mDpmi.isActiveDeviceOwner(TEST_UID)).thenReturn(isOwner);
+ when(mDpm.isDeviceOwnerApp(TEST_PKG)).thenReturn(isOwner);
}
private void setIsProfileOwner(boolean isOwner) {
- when(mDpmi.isActiveProfileOwner(TEST_UID)).thenReturn(isOwner);
+ when(mDpm.isProfileOwnerApp(TEST_PKG)).thenReturn(isOwner);
}
private void setHasAppOpsPermission(int appOpsMode, boolean hasPermission) {
diff --git a/tests/unit/java/android/net/NetworkStatsCollectionTest.java b/tests/unit/java/android/net/NetworkStatsCollectionTest.java
index 0c4ffac..1c557d6 100644
--- a/tests/unit/java/android/net/NetworkStatsCollectionTest.java
+++ b/tests/unit/java/android/net/NetworkStatsCollectionTest.java
@@ -28,7 +28,7 @@
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
-import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
+import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational;
import static com.android.testutils.MiscAsserts.assertThrows;
import static org.junit.Assert.assertArrayEquals;
diff --git a/tests/unit/java/android/net/NetworkTemplateTest.kt b/tests/unit/java/android/net/NetworkTemplateTest.kt
index 572c1ef..5d6e6dd 100644
--- a/tests/unit/java/android/net/NetworkTemplateTest.kt
+++ b/tests/unit/java/android/net/NetworkTemplateTest.kt
@@ -29,8 +29,12 @@
import android.net.NetworkStats.METERED_NO
import android.net.NetworkStats.METERED_YES
import android.net.NetworkStats.ROAMING_ALL
+import android.net.NetworkTemplate.MATCH_BLUETOOTH
+import android.net.NetworkTemplate.MATCH_CARRIER
+import android.net.NetworkTemplate.MATCH_ETHERNET
import android.net.NetworkTemplate.MATCH_MOBILE
import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
+import android.net.NetworkTemplate.MATCH_PROXY
import android.net.NetworkTemplate.MATCH_WIFI
import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD
import android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA
@@ -38,8 +42,7 @@
import android.net.NetworkTemplate.OEM_MANAGED_ALL
import android.net.NetworkTemplate.OEM_MANAGED_NO
import android.net.NetworkTemplate.OEM_MANAGED_YES
-import android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT
-import android.net.NetworkTemplate.WIFI_NETWORKID_ALL
+import android.net.NetworkTemplate.WIFI_NETWORK_KEY_ALL
import android.net.NetworkTemplate.buildTemplateCarrierMetered
import android.net.NetworkTemplate.buildTemplateMobileAll
import android.net.NetworkTemplate.buildTemplateMobileWildcard
@@ -49,6 +52,8 @@
import android.net.NetworkTemplate.normalize
import android.os.Build
import android.telephony.TelephonyManager
+import com.android.net.module.util.NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL
+import com.android.net.module.util.NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.assertParcelSane
@@ -58,6 +63,7 @@
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
import kotlin.test.assertEquals
+import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
@@ -131,7 +137,7 @@
val templateWifiSsid1 = buildTemplateWifi(TEST_SSID1)
val templateWifiSsid1ImsiNull = buildTemplateWifi(TEST_SSID1, null)
val templateWifiSsid1Imsi1 = buildTemplateWifi(TEST_SSID1, TEST_IMSI1)
- val templateWifiSsidAllImsi1 = buildTemplateWifi(WIFI_NETWORKID_ALL, TEST_IMSI1)
+ val templateWifiSsidAllImsi1 = buildTemplateWifi(WIFI_NETWORK_KEY_ALL, TEST_IMSI1)
val identMobile1 = buildNetworkIdentity(mockContext, buildMobileNetworkState(TEST_IMSI1),
false, TelephonyManager.NETWORK_TYPE_UMTS)
@@ -536,4 +542,105 @@
it.assertMatches(identMobileImsi3)
}
}
+
+ @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S)
+ @Test
+ fun testBuilderMatchRules() {
+ // Verify unknown match rules cannot construct templates.
+ listOf(Integer.MIN_VALUE, -1, Integer.MAX_VALUE).forEach {
+ assertFailsWith<IllegalArgumentException> {
+ NetworkTemplate.Builder(it).build()
+ }
+ }
+
+ // Verify hidden match rules cannot construct templates.
+ listOf(MATCH_WIFI_WILDCARD, MATCH_MOBILE_WILDCARD, MATCH_PROXY).forEach {
+ assertFailsWith<IllegalArgumentException> {
+ NetworkTemplate.Builder(it).build()
+ }
+ }
+
+ // Verify template which matches metered cellular and carrier networks with
+ // the given IMSI. See buildTemplateMobileAll and buildTemplateCarrierMetered.
+ listOf(MATCH_MOBILE, MATCH_CARRIER).forEach { matchRule ->
+ NetworkTemplate.Builder(matchRule).setSubscriberIds(setOf(TEST_IMSI1))
+ .setMeteredness(METERED_YES).build().let {
+ val expectedTemplate = NetworkTemplate(matchRule, TEST_IMSI1,
+ arrayOf(TEST_IMSI1), null, METERED_YES,
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT)
+ assertEquals(expectedTemplate, it)
+ }
+ }
+
+ // Verify carrier template cannot be created without IMSI.
+ assertFailsWith<IllegalArgumentException> {
+ NetworkTemplate.Builder(MATCH_CARRIER).build()
+ }
+
+ // Verify template which matches metered cellular networks,
+ // regardless of IMSI. See buildTemplateMobileWildcard.
+ NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES).build().let {
+ val expectedTemplate = NetworkTemplate(MATCH_MOBILE_WILDCARD, null /*subscriberId*/,
+ null /*subscriberIds*/, null /*wifiNetworkKey*/,
+ METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_ALL)
+ assertEquals(expectedTemplate, it)
+ }
+
+ // Verify template which matches metered cellular networks and ratType.
+ // See NetworkTemplate#buildTemplateMobileWithRatType.
+ NetworkTemplate.Builder(MATCH_MOBILE).setSubscriberIds(setOf(TEST_IMSI1))
+ .setMeteredness(METERED_YES).setRatType(TelephonyManager.NETWORK_TYPE_UMTS)
+ .build().let {
+ val expectedTemplate = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1,
+ arrayOf(TEST_IMSI1), null, METERED_YES,
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_UMTS,
+ OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT)
+ assertEquals(expectedTemplate, it)
+ }
+
+ // Verify template which matches all wifi networks,
+ // regardless of Wifi Network Key. See buildTemplateWifiWildcard and buildTemplateWifi.
+ NetworkTemplate.Builder(MATCH_WIFI).build().let {
+ val expectedTemplate = NetworkTemplate(MATCH_WIFI_WILDCARD, null /*subscriberId*/,
+ null /*subscriberIds*/, null /*wifiNetworkKey*/,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_ALL)
+ assertEquals(expectedTemplate, it)
+ }
+
+ // Verify template which matches wifi networks with the given Wifi Network Key.
+ // See buildTemplateWifi(wifiNetworkKey).
+ NetworkTemplate.Builder(MATCH_WIFI).setWifiNetworkKey(TEST_SSID1).build().let {
+ val expectedTemplate = NetworkTemplate(MATCH_WIFI, null /*subscriberId*/,
+ null /*subscriberIds*/, TEST_SSID1,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_ALL)
+ assertEquals(expectedTemplate, it)
+ }
+
+ // Verify template which matches all wifi networks with the
+ // given Wifi Network Key, and IMSI. See buildTemplateWifi(wifiNetworkKey, subscriberId).
+ NetworkTemplate.Builder(MATCH_WIFI).setSubscriberIds(setOf(TEST_IMSI1))
+ .setWifiNetworkKey(TEST_SSID1).build().let {
+ val expectedTemplate = NetworkTemplate(MATCH_WIFI, TEST_IMSI1,
+ arrayOf(TEST_IMSI1), TEST_SSID1,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT)
+ assertEquals(expectedTemplate, it)
+ }
+
+ // Verify template which matches ethernet and bluetooth networks.
+ // See buildTemplateEthernet and buildTemplateBluetooth.
+ listOf(MATCH_ETHERNET, MATCH_BLUETOOTH).forEach { matchRule ->
+ NetworkTemplate.Builder(matchRule).build().let {
+ val expectedTemplate = NetworkTemplate(matchRule, null /*subscriberId*/,
+ null /*subscriberIds*/, null /*wifiNetworkKey*/,
+ METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_ALL)
+ assertEquals(expectedTemplate, it)
+ }
+ }
+ }
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 044ff02..c47604c 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -81,6 +81,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMTEL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
@@ -3586,7 +3587,7 @@
|| capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS
|| capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP
|| capability == NET_CAPABILITY_VSIM || capability == NET_CAPABILITY_BIP
- || capability == NET_CAPABILITY_ENTERPRISE) {
+ || capability == NET_CAPABILITY_ENTERPRISE || capability == NET_CAPABILITY_MMTEL) {
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
} else {
assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
@@ -3714,6 +3715,7 @@
tryNetworkFactoryRequests(NET_CAPABILITY_WIFI_P2P);
tryNetworkFactoryRequests(NET_CAPABILITY_IA);
tryNetworkFactoryRequests(NET_CAPABILITY_RCS);
+ tryNetworkFactoryRequests(NET_CAPABILITY_MMTEL);
tryNetworkFactoryRequests(NET_CAPABILITY_XCAP);
tryNetworkFactoryRequests(NET_CAPABILITY_ENTERPRISE);
tryNetworkFactoryRequests(NET_CAPABILITY_EIMS);
diff --git a/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java
index 5bbbe40..45f3d3c 100644
--- a/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/unit/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -60,6 +60,7 @@
import android.os.Binder;
import android.os.Build;
import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.system.Os;
import android.test.mock.MockContext;
import android.util.ArraySet;
@@ -188,9 +189,15 @@
}
}
+ private IpSecService.Dependencies makeDependencies() throws RemoteException {
+ final IpSecService.Dependencies deps = mock(IpSecService.Dependencies.class);
+ when(deps.getNetdInstance(mTestContext)).thenReturn(mMockNetd);
+ return deps;
+ }
+
INetd mMockNetd;
PackageManager mMockPkgMgr;
- IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
+ IpSecService.Dependencies mDeps;
IpSecService mIpSecService;
Network fakeNetwork = new Network(0xAB);
int mUid = Os.getuid();
@@ -219,11 +226,8 @@
public void setUp() throws Exception {
mMockNetd = mock(INetd.class);
mMockPkgMgr = mock(PackageManager.class);
- mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(mTestContext, mMockIpSecSrvConfig);
-
- // Injecting mock netd
- when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
+ mDeps = makeDependencies();
+ mIpSecService = new IpSecService(mTestContext, mDeps);
// PackageManager should always return true (feature flag tests in IpSecServiceTest)
when(mMockPkgMgr.hasSystemFeature(anyString())).thenReturn(true);
diff --git a/tests/unit/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/unit/java/com/android/server/IpSecServiceRefcountedResourceTest.java
index 6957d51..5c7ca6f 100644
--- a/tests/unit/java/com/android/server/IpSecServiceRefcountedResourceTest.java
+++ b/tests/unit/java/com/android/server/IpSecServiceRefcountedResourceTest.java
@@ -57,14 +57,14 @@
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
public class IpSecServiceRefcountedResourceTest {
Context mMockContext;
- IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
+ IpSecService.Dependencies mMockDeps;
IpSecService mIpSecService;
@Before
public void setUp() throws Exception {
mMockContext = mock(Context.class);
- mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
+ mMockDeps = mock(IpSecService.Dependencies.class);
+ mIpSecService = new IpSecService(mMockContext, mMockDeps);
}
private void assertResourceState(
diff --git a/tests/unit/java/com/android/server/IpSecServiceTest.java b/tests/unit/java/com/android/server/IpSecServiceTest.java
index fabd6f1..7e6b157 100644
--- a/tests/unit/java/com/android/server/IpSecServiceTest.java
+++ b/tests/unit/java/com/android/server/IpSecServiceTest.java
@@ -46,6 +46,7 @@
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteException;
import android.system.ErrnoException;
import android.system.Os;
import android.system.StructStat;
@@ -122,24 +123,22 @@
Context mMockContext;
INetd mMockNetd;
- IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
+ IpSecService.Dependencies mDeps;
IpSecService mIpSecService;
@Before
public void setUp() throws Exception {
mMockContext = mock(Context.class);
mMockNetd = mock(INetd.class);
- mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
- mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
-
- // Injecting mock netd
- when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
+ mDeps = makeDependencies();
+ mIpSecService = new IpSecService(mMockContext, mDeps);
+ assertNotNull(mIpSecService);
}
- @Test
- public void testIpSecServiceCreate() throws InterruptedException {
- IpSecService ipSecSrv = IpSecService.create(mMockContext);
- assertNotNull(ipSecSrv);
+ private IpSecService.Dependencies makeDependencies() throws RemoteException {
+ final IpSecService.Dependencies deps = mock(IpSecService.Dependencies.class);
+ when(deps.getNetdInstance(mMockContext)).thenReturn(mMockNetd);
+ return deps;
}
@Test
@@ -611,7 +610,7 @@
public void testOpenUdpEncapSocketTagsSocket() throws Exception {
IpSecService.UidFdTagger mockTagger = mock(IpSecService.UidFdTagger.class);
IpSecService testIpSecService = new IpSecService(
- mMockContext, mMockIpSecSrvConfig, mockTagger);
+ mMockContext, mDeps, mockTagger);
IpSecUdpEncapResponse udpEncapResp =
testIpSecService.openUdpEncapsulationSocket(0, new Binder());
diff --git a/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
index e2ad00d..a3da05d 100644
--- a/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -94,6 +94,7 @@
public class MultipathPolicyTrackerTest {
private static final Network TEST_NETWORK = new Network(123);
private static final int POLICY_SNOOZED = -100;
+ private static final String TEST_IMSI1 = "TEST_IMSI1";
@Mock private Context mContext;
@Mock private Context mUserAllContext;
@@ -148,6 +149,7 @@
when(mDeps.getClock()).thenReturn(mClock);
when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+ when(mTelephonyManager.getSubscriberId()).thenReturn(TEST_IMSI1);
mContentResolver = Mockito.spy(new MockContentResolver(mContext));
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index fd9aefa..33c0868 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -17,6 +17,9 @@
package com.android.server.connectivity;
import static android.Manifest.permission.BIND_VPN_SERVICE;
+import static android.Manifest.permission.CONTROL_VPN;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.UserInfo.FLAG_ADMIN;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.content.pm.UserInfo.FLAG_PRIMARY;
@@ -26,6 +29,9 @@
import static android.net.INetd.IF_STATE_UP;
import static android.os.UserHandle.PER_USER_RANGE;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
+import static com.android.testutils.MiscAsserts.assertThrows;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -259,6 +265,10 @@
IpSecManager.Status.OK, TEST_TUNNEL_RESOURCE_ID, TEST_IFACE_NAME);
when(mIpSecService.createTunnelInterface(any(), any(), any(), any(), any()))
.thenReturn(tunnelResp);
+ // The unit test should know what kind of permission it needs and set the permission by
+ // itself, so set the default value of Context#checkCallingOrSelfPermission to
+ // PERMISSION_DENIED.
+ doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(any());
}
private <T> void mockService(Class<T> clazz, String name, T service) {
@@ -511,6 +521,7 @@
@Test
public void testLockdownRuleReversibility() throws Exception {
+ doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN);
final Vpn vpn = createVpn(primaryUser.id);
final UidRangeParcel[] entireUser = {
new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())
@@ -538,6 +549,27 @@
}
@Test
+ public void testPrepare_throwSecurityExceptionWhenGivenPackageDoesNotBelongToTheCaller()
+ throws Exception {
+ assumeTrue(isAtLeastT());
+ final Vpn vpn = createVpnAndSetupUidChecks();
+ assertThrows(SecurityException.class,
+ () -> vpn.prepare("com.not.vpn.owner", null, VpnManager.TYPE_VPN_SERVICE));
+ assertThrows(SecurityException.class,
+ () -> vpn.prepare(null, "com.not.vpn.owner", VpnManager.TYPE_VPN_SERVICE));
+ assertThrows(SecurityException.class,
+ () -> vpn.prepare("com.not.vpn.owner1", "com.not.vpn.owner2",
+ VpnManager.TYPE_VPN_SERVICE));
+ }
+
+ @Test
+ public void testPrepare_bothOldPackageAndNewPackageAreNull() throws Exception {
+ final Vpn vpn = createVpnAndSetupUidChecks();
+ assertTrue(vpn.prepare(null, null, VpnManager.TYPE_VPN_SERVICE));
+
+ }
+
+ @Test
public void testIsAlwaysOnPackageSupported() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index 4948e66..dd92f3a 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -50,7 +50,6 @@
import static android.net.NetworkTemplate.NETWORK_TYPE_ALL;
import static android.net.NetworkTemplate.OEM_MANAGED_NO;
import static android.net.NetworkTemplate.OEM_MANAGED_YES;
-import static android.net.NetworkTemplate.SUBSCRIBER_ID_MATCH_RULE_EXACT;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateMobileWithRatType;
import static android.net.NetworkTemplate.buildTemplateWifi;
@@ -63,6 +62,7 @@
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
+import static com.android.net.module.util.NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
import static org.junit.Assert.assertEquals;