Merge "Add bt dep for tethering tests"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 302c0b3..1b2c0ed 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -32,6 +32,9 @@
},
{
"name": "libnetworkstats_test"
+ },
+ {
+ "name": "FrameworksNetIntegrationTests"
}
],
"postsubmit": [
@@ -55,6 +58,9 @@
},
{
"name": "libnetworkstats_test"
+ },
+ {
+ "name": "FrameworksNetDeflakeTest"
}
],
"mainline-presubmit": [
@@ -88,6 +94,35 @@
"name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]",
"keywords": ["sim"]
},
+ // TODO: move to mainline-presubmit when known green.
+ // Test with APK modules only, in cases where APEX is not supported, or the other modules were simply not updated
+ {
+ "name": "CtsNetTestCasesLatestSdk[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk]",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ },
+ {
+ "exclude-annotation": "com.android.testutils.ConnectivityModuleTest"
+ }
+ ]
+ },
+ // TODO: move to mainline-presubmit when known green.
+ // Test with connectivity/tethering module only, to catch integration issues with older versions of other modules
+ {
+ "name": "CtsNetTestCasesLatestSdk[com.google.android.tethering.apex]",
+ "options": [
+ {
+ "exclude-annotation": "com.android.testutils.SkipPresubmit"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.RequiresDevice"
+ }
+ ]
+ },
{
"name": "TetheringCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
},
@@ -96,6 +131,23 @@
"name": "bpf_existence_test[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
}
],
+ "auto-postsubmit": [
+ // Test tag for automotive targets. These are only running in postsubmit so as to harden the
+ // automotive targets to avoid introducing additional test flake and build time. The plan for
+ // presubmit testing for auto is to augment the existing tests to cover auto use cases as well.
+ // Additionally, this tag is used in targeted test suites to limit resource usage on the test
+ // infra during the hardening phase.
+ // TODO: this tag to be removed once the above is no longer an issue.
+ {
+ "name": "FrameworksNetTests"
+ },
+ {
+ "name": "FrameworksNetIntegrationTests"
+ },
+ {
+ "name": "FrameworksNetDeflakeTest"
+ }
+ ],
"imports": [
{
"path": "frameworks/base/core/java/android/net"
@@ -110,9 +162,6 @@
"path": "packages/modules/CaptivePortalLogin"
},
{
- "path": "packages/modules/Connectivity"
- },
- {
"path": "packages/modules/Connectivity/Tethering"
}
]
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index a26ffa9..451abf7 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -180,7 +180,7 @@
// The permission configuration *must* be included to ensure security of the device
required: [
"NetworkPermissionConfig",
- "privapp_whitelist_com.android.networkstack.tethering",
+ "privapp_allowlist_com.android.tethering",
],
apex_available: ["com.android.tethering"],
lint: { strict_updatability_linting: true },
@@ -200,7 +200,7 @@
// The permission configuration *must* be included to ensure security of the device
required: [
"NetworkPermissionConfig",
- "privapp_whitelist_com.android.networkstack.tethering",
+ "privapp_allowlist_com.android.tethering",
],
apex_available: ["com.android.tethering"],
lint: { strict_updatability_linting: true },
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 2734d48..358a5dd 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -78,7 +78,10 @@
"ServiceConnectivityResources",
"HalfSheetUX",
],
- prebuilts: ["current_sdkinfo"],
+ prebuilts: [
+ "current_sdkinfo",
+ "privapp_allowlist_com.android.tethering",
+ ],
manifest: "manifest.json",
key: "com.android.tethering.key",
// Indicates that pre-installed version of this apex can be compressed.
diff --git a/Tethering/apex/permissions/Android.bp b/Tethering/apex/permissions/Android.bp
new file mode 100644
index 0000000..ac9ec65
--- /dev/null
+++ b/Tethering/apex/permissions/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+ default_visibility: ["//packages/modules/Connectivity/Tethering:__subpackages__"],
+}
+
+prebuilt_etc {
+ name: "privapp_allowlist_com.android.tethering",
+ sub_dir: "permissions",
+ filename: "permissions.xml",
+ src: "permissions.xml",
+ installable: false,
+}
\ No newline at end of file
diff --git a/Tethering/apex/permissions/OWNERS b/Tethering/apex/permissions/OWNERS
new file mode 100644
index 0000000..8b7e2e5
--- /dev/null
+++ b/Tethering/apex/permissions/OWNERS
@@ -0,0 +1,2 @@
+per-file *.xml,OWNERS = set noparent
+per-file *.xml,OWNERS = file:platform/frameworks/base:/data/etc/OWNERS
diff --git a/Tethering/apex/permissions/permissions.xml b/Tethering/apex/permissions/permissions.xml
new file mode 100644
index 0000000..f26a961
--- /dev/null
+++ b/Tethering/apex/permissions/permissions.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+-->
+
+<permissions>
+ <privapp-permissions package="com.android.networkstack.tethering">
+ <permission name="android.permission.BLUETOOTH_PRIVILEGED" />
+ <permission name="android.permission.MANAGE_USB"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/>
+ <permission name="android.permission.TETHER_PRIVILEGED"/>
+ <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
+ <permission name="android.permission.UPDATE_DEVICE_STATS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
index 26040a2..22d2c5d 100644
--- a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
@@ -27,14 +27,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.TetherStatsValue;
-import java.util.function.BiConsumer;
-
/**
* Bpf coordinator class for API shims.
*/
@@ -164,7 +163,7 @@
@Override
public void tetherOffloadRuleForEach(boolean downstream,
- @NonNull BiConsumer<Tether4Key, Tether4Value> action) {
+ @NonNull ThrowingBiConsumer<Tether4Key, Tether4Value> action) {
/* no op */
}
diff --git a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
index e3b1539..5afb862 100644
--- a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
@@ -30,6 +30,7 @@
import androidx.annotation.Nullable;
import com.android.net.module.util.BpfMap;
+import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
@@ -47,7 +48,6 @@
import java.io.FileDescriptor;
import java.io.IOException;
-import java.util.function.BiConsumer;
/**
* Bpf coordinator class for API shims.
@@ -410,7 +410,7 @@
@Override
public void tetherOffloadRuleForEach(boolean downstream,
- @NonNull BiConsumer<Tether4Key, Tether4Value> action) {
+ @NonNull ThrowingBiConsumer<Tether4Key, Tether4Value> action) {
if (!isInitialized()) return;
try {
diff --git a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
index d663968..915e210 100644
--- a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
+++ b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
@@ -22,14 +22,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.TetherStatsValue;
-import java.util.function.BiConsumer;
-
/**
* Bpf coordinator class for API shims.
*/
@@ -163,7 +162,7 @@
*/
@Nullable
public abstract void tetherOffloadRuleForEach(boolean downstream,
- @NonNull BiConsumer<Tether4Key, Tether4Value> action);
+ @NonNull ThrowingBiConsumer<Tether4Key, Tether4Value> action);
/**
* Whether there is currently any IPv4 rule on the specified upstream.
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index 40956f7..6550de2 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -52,6 +52,7 @@
import android.system.OsConstants;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Base64;
import android.util.Log;
import android.util.SparseArray;
@@ -118,6 +119,9 @@
private static final String TETHER_ERROR_MAP_PATH = makeMapPath("error");
private static final String TETHER_DEV_MAP_PATH = makeMapPath("dev");
+ // Using "," as a separator is safe because base64 characters are [0-9a-zA-Z/=+].
+ private static final String DUMP_BASE64_DELIMITER = ",";
+
/** The names of all the BPF counters defined in bpf_tethering.h. */
public static final String[] sBpfCounterNames = getBpfCounterNames();
@@ -1068,6 +1072,42 @@
}
}
+ private String ipv4RuleToBase64String(Tether4Key key, Tether4Value value) {
+ final byte[] keyBytes = key.writeToBytes();
+ final String keyBase64Str = Base64.encodeToString(keyBytes, Base64.DEFAULT)
+ .replace("\n", "");
+ final byte[] valueBytes = value.writeToBytes();
+ final String valueBase64Str = Base64.encodeToString(valueBytes, Base64.DEFAULT)
+ .replace("\n", "");
+
+ return keyBase64Str + DUMP_BASE64_DELIMITER + valueBase64Str;
+ }
+
+ private void dumpRawIpv4ForwardingRuleMap(
+ BpfMap<Tether4Key, Tether4Value> map, IndentingPrintWriter pw) throws ErrnoException {
+ if (map == null) {
+ pw.println("No IPv4 support");
+ return;
+ }
+ if (map.isEmpty()) {
+ pw.println("No rules");
+ return;
+ }
+ map.forEach((k, v) -> pw.println(ipv4RuleToBase64String(k, v)));
+ }
+
+ /**
+ * Dump raw BPF map in base64 encoded strings. For test only.
+ */
+ public void dumpRawMap(@NonNull IndentingPrintWriter pw) {
+ try (BpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map()) {
+ // TODO: dump downstream map.
+ dumpRawIpv4ForwardingRuleMap(upstreamMap, pw);
+ } catch (ErrnoException e) {
+ pw.println("Error dumping IPv4 map: " + e);
+ }
+ }
+
private String l4protoToString(int proto) {
if (proto == OsConstants.IPPROTO_TCP) {
return "tcp";
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index db9a64f..301a682 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -2479,6 +2479,13 @@
@SuppressWarnings("resource") final IndentingPrintWriter pw = new IndentingPrintWriter(
writer, " ");
+ // Used for testing instead of human debug.
+ // TODO: add options to choose which map to dump.
+ if (argsContain(args, "bpfRawMap")) {
+ mBpfCoordinator.dumpRawMap(pw);
+ return;
+ }
+
if (argsContain(args, "bpf")) {
dumpBpf(pw);
return;
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index fda1045..5579db6 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -10,6 +10,8 @@
method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshots();
method @Nullable public android.net.ProxyInfo getGlobalProxy();
method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
+ method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.LinkProperties redactLinkPropertiesForPackage(@NonNull android.net.LinkProperties, int, @NonNull String);
+ method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.NetworkCapabilities redactNetworkCapabilitiesForPackage(@NonNull android.net.NetworkCapabilities, int, @NonNull String);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void replaceFirewallChain(int, @NonNull int[]);
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 5246623..e8e1efa 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -1625,16 +1625,45 @@
}
/**
- * Get the {@link NetworkCapabilities} for the given {@link Network}. This
- * will return {@code null} if the network is unknown or if the |network| argument is null.
+ * Redact {@link LinkProperties} for a given package
*
- * This will remove any location sensitive data in {@link TransportInfo} embedded in
- * {@link NetworkCapabilities#getTransportInfo()}. Some transport info instances like
- * {@link android.net.wifi.WifiInfo} contain location sensitive information. Retrieving
- * this location sensitive information (subject to app's location permissions) will be
- * noted by system. To include any location sensitive data in {@link TransportInfo},
- * use a {@link NetworkCallback} with
- * {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} flag.
+ * Returns an instance of the given {@link LinkProperties} appropriately redacted to send to the
+ * given package, considering its permissions.
+ *
+ * @param lp A {@link LinkProperties} which will be redacted.
+ * @param uid The target uid.
+ * @param packageName The name of the package, for appops logging.
+ * @return A redacted {@link LinkProperties} which is appropriate to send to the given uid,
+ * or null if the uid lacks the ACCESS_NETWORK_STATE permission.
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ @SystemApi(client = MODULE_LIBRARIES)
+ @Nullable
+ public LinkProperties redactLinkPropertiesForPackage(@NonNull LinkProperties lp, int uid,
+ @NonNull String packageName) {
+ try {
+ return mService.redactLinkPropertiesForPackage(
+ lp, uid, packageName, getAttributionTag());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Get the {@link NetworkCapabilities} for the given {@link Network}, or null.
+ *
+ * This will remove any location sensitive data in the returned {@link NetworkCapabilities}.
+ * Some {@link TransportInfo} instances like {@link android.net.wifi.WifiInfo} contain location
+ * sensitive information. To retrieve this location sensitive information (subject to
+ * the caller's location permissions), use a {@link NetworkCallback} with the
+ * {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} flag instead.
+ *
+ * This method returns {@code null} if the network is unknown or if the |network| argument
+ * is null.
*
* @param network The {@link Network} object identifying the network in question.
* @return The {@link NetworkCapabilities} for the network, or {@code null}.
@@ -1651,6 +1680,38 @@
}
/**
+ * Redact {@link NetworkCapabilities} for a given package.
+ *
+ * Returns an instance of {@link NetworkCapabilities} that is appropriately redacted to send
+ * to the given package, considering its permissions. Calling this method will blame the UID for
+ * retrieving the device location if the passed capabilities contain location-sensitive
+ * information.
+ *
+ * @param nc A {@link NetworkCapabilities} instance which will be redacted.
+ * @param uid The target uid.
+ * @param packageName The name of the package, for appops logging.
+ * @return A redacted {@link NetworkCapabilities} which is appropriate to send to the given uid,
+ * or null if the uid lacks the ACCESS_NETWORK_STATE permission.
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ @SystemApi(client = MODULE_LIBRARIES)
+ @Nullable
+ public NetworkCapabilities redactNetworkCapabilitiesForPackage(
+ @NonNull NetworkCapabilities nc,
+ int uid, @NonNull String packageName) {
+ try {
+ return mService.redactNetworkCapabilitiesForPackage(nc, uid, packageName,
+ getAttributionTag());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Gets a URL that can be used for resolving whether a captive portal is present.
* 1. This URL should respond with a 204 response to a GET request to indicate no captive
* portal is present.
@@ -3547,7 +3608,20 @@
* @hide
*/
public static final int FLAG_NONE = 0;
+
/**
+ * Inclusion of this flag means location-sensitive redaction requests keeping location info.
+ *
+ * Some objects like {@link NetworkCapabilities} may contain location-sensitive information.
+ * Prior to Android 12, this information is always returned to apps holding the appropriate
+ * permission, possibly noting that the app has used location.
+ * <p>In Android 12 and above, by default the sent objects do not contain any location
+ * information, even if the app holds the necessary permissions, and the system does not
+ * take note of location usage by the app. Apps can request that location information is
+ * included, in which case the system will check location permission and the location
+ * toggle state, and take note of location usage by the app if any such information is
+ * returned.
+ *
* Use this flag to include any location sensitive data in {@link NetworkCapabilities} sent
* via {@link #onCapabilitiesChanged(Network, NetworkCapabilities)}.
* <p>
@@ -3564,8 +3638,7 @@
* <li> Retrieving this location sensitive information (subject to app's location
* permissions) will be noted by system. </li>
* <li> Without this flag any {@link NetworkCapabilities} provided via the callback does
- * not include location sensitive info.
- * </p>
+ * not include location sensitive information.
*/
// Note: Some existing fields which are location sensitive may still be included without
// this flag if the app targets SDK < S (to maintain backwards compatibility).
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index df4663f..23a3850 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -76,10 +76,15 @@
LinkProperties getActiveLinkProperties();
LinkProperties getLinkPropertiesForType(int networkType);
LinkProperties getLinkProperties(in Network network);
+ LinkProperties redactLinkPropertiesForPackage(in LinkProperties lp, int uid, String packageName,
+ String callingAttributionTag);
NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName,
String callingAttributionTag);
+ NetworkCapabilities redactNetworkCapabilitiesForPackage(in NetworkCapabilities nc, int uid,
+ String callingPackageName, String callingAttributionTag);
+
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
NetworkState[] getAllNetworkState();
diff --git a/framework/src/android/net/KeepalivePacketData.java b/framework/src/android/net/KeepalivePacketData.java
index 5877f1f..f47cc5c 100644
--- a/framework/src/android/net/KeepalivePacketData.java
+++ b/framework/src/android/net/KeepalivePacketData.java
@@ -116,4 +116,13 @@
return mPacket.clone();
}
+ @Override
+ public String toString() {
+ return "KeepalivePacketData[srcAddress=" + mSrcAddress
+ + ", dstAddress=" + mDstAddress
+ + ", srcPort=" + mSrcPort
+ + ", dstPort=" + mDstPort
+ + ", packet.length=" + mPacket.length
+ + ']';
+ }
}
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index b6cd760..41be732 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -1536,9 +1536,12 @@
*/
public @NonNull NetworkCapabilities setNetworkSpecifier(
@NonNull NetworkSpecifier networkSpecifier) {
- if (networkSpecifier != null && Long.bitCount(mTransportTypes) != 1) {
- throw new IllegalStateException("Must have a single transport specified to use " +
- "setNetworkSpecifier");
+ if (networkSpecifier != null
+ // Transport can be test, or test + a single other transport
+ && mTransportTypes != (1L << TRANSPORT_TEST)
+ && Long.bitCount(mTransportTypes & ~(1L << TRANSPORT_TEST)) != 1) {
+ throw new IllegalStateException("Must have a single non-test transport specified to "
+ + "use setNetworkSpecifier");
}
mNetworkSpecifier = networkSpecifier;
diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt
index 65ed8a3..ee05df5 100644
--- a/service/jarjar-rules.txt
+++ b/service/jarjar-rules.txt
@@ -106,5 +106,8 @@
# From the API shims
rule com.android.networkstack.apishim.** com.android.connectivity.@0
+# From fast-pair-lite-protos
+rule service.proto.** com.android.server.nearby.@0
+
# Remaining are connectivity sources in com.android.server and com.android.server.connectivity:
# TODO: move to a subpackage of com.android.connectivity (such as com.android.connectivity.server)
diff --git a/service/jni/com_android_server_BpfNetMaps.cpp b/service/jni/com_android_server_BpfNetMaps.cpp
index c29eb2b..85cfc09 100644
--- a/service/jni/com_android_server_BpfNetMaps.cpp
+++ b/service/jni/com_android_server_BpfNetMaps.cpp
@@ -116,27 +116,11 @@
return (jint)res;
}
-static FirewallType getFirewallType(ChildChain chain) {
- switch (chain) {
- case DOZABLE:
- return ALLOWLIST;
- case STANDBY:
- return DENYLIST;
- case POWERSAVE:
- return ALLOWLIST;
- case RESTRICTED:
- return ALLOWLIST;
- case NONE:
- default:
- return DENYLIST;
- }
-}
-
static jint native_setUidRule(JNIEnv* env, jobject clazz, jint childChain, jint uid,
jint firewallRule) {
auto chain = static_cast<ChildChain>(childChain);
auto rule = static_cast<FirewallRule>(firewallRule);
- FirewallType fType = getFirewallType(chain);
+ FirewallType fType = mTc.getFirewallType(chain);
int res = mTc.changeUidOwnerRule(chain, uid, rule, fType);
if (res) {
diff --git a/service/proguard.flags b/service/proguard.flags
index 4651088..2b20ddd 100644
--- a/service/proguard.flags
+++ b/service/proguard.flags
@@ -6,10 +6,11 @@
-keep class com.android.net.** { *; }
-keep class com.android.server.** { *; }
-# Prevent proguard from stripping out any nearby-service.
+# Prevent proguard from stripping out any nearby-service and fast-pair-lite-protos fields.
# TODO: This could be optimized in the future to only keep the critical
# entry points and then let proguard strip out any unused code within
-# the service.
+# the service. "com.android.server.nearby.service.proto" must be kept to prevent proguard
+# from stripping out any fast-pair-lite-protos fields.
-keep class com.android.server.nearby.** { *; }
# The lite proto runtime uses reflection to access fields based on the names in
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 7bb4529..6024a2a 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -2164,6 +2164,19 @@
}
}
+ @Override
+ @Nullable
+ public LinkProperties redactLinkPropertiesForPackage(@NonNull LinkProperties lp, int uid,
+ @NonNull String packageName, @Nullable String callingAttributionTag) {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(lp);
+ enforceNetworkStackOrSettingsPermission();
+ if (!checkAccessPermission(-1 /* pid */, uid)) {
+ return null;
+ }
+ return linkPropertiesRestrictedForCallerPermissions(lp, -1 /* callerPid */, uid);
+ }
+
private NetworkCapabilities getNetworkCapabilitiesInternal(Network network) {
return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
}
@@ -2187,13 +2200,34 @@
getCallingPid(), mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
}
+ @Override
+ public NetworkCapabilities redactNetworkCapabilitiesForPackage(@NonNull NetworkCapabilities nc,
+ int uid, @NonNull String packageName, @Nullable String callingAttributionTag) {
+ Objects.requireNonNull(nc);
+ Objects.requireNonNull(packageName);
+ enforceNetworkStackOrSettingsPermission();
+ if (!checkAccessPermission(-1 /* pid */, uid)) {
+ return null;
+ }
+ return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
+ networkCapabilitiesRestrictedForCallerPermissions(nc, -1 /* callerPid */, uid),
+ true /* includeLocationSensitiveInfo */, -1 /* callingPid */, uid, packageName,
+ callingAttributionTag);
+ }
+
@VisibleForTesting
NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
NetworkCapabilities nc, int callerPid, int callerUid) {
+ // Note : here it would be nice to check ACCESS_NETWORK_STATE and return null, but
+ // this would be expensive (one more permission check every time any NC callback is
+ // sent) and possibly dangerous : apps normally can't lose ACCESS_NETWORK_STATE, if
+ // it happens for some reason (e.g. the package is uninstalled while CS is trying to
+ // send the callback) it would crash the system server with NPE.
final NetworkCapabilities newNc = new NetworkCapabilities(nc);
if (!checkSettingsPermission(callerPid, callerUid)) {
newNc.setUids(null);
newNc.setSSID(null);
+ // TODO: Processes holding NETWORK_FACTORY should be able to see the underlying networks
newNc.setUnderlyingNetworks(null);
}
if (newNc.getNetworkSpecifier() != null) {
@@ -2211,7 +2245,7 @@
/**
* Wrapper used to cache the permission check results performed for the corresponding
- * app. This avoid performing multiple permission checks for different fields in
+ * app. This avoids performing multiple permission checks for different fields in
* NetworkCapabilities.
* Note: This wrapper does not support any sort of invalidation and thus must not be
* persistent or long-lived. It may only be used for the time necessary to
@@ -2339,6 +2373,8 @@
includeLocationSensitiveInfo);
final NetworkCapabilities newNc = new NetworkCapabilities(nc, redactions);
// Reset owner uid if not destined for the owner app.
+ // TODO : calling UID is redacted because apps should generally not know what UID is
+ // bringing up the VPN, but this should not apply to some very privileged apps like settings
if (callingUid != nc.getOwnerUid()) {
newNc.setOwnerUid(INVALID_UID);
return newNc;
@@ -2364,9 +2400,15 @@
return newNc;
}
+ @NonNull
private LinkProperties linkPropertiesRestrictedForCallerPermissions(
LinkProperties lp, int callerPid, int callerUid) {
if (lp == null) return new LinkProperties();
+ // Note : here it would be nice to check ACCESS_NETWORK_STATE and return null, but
+ // this would be expensive (one more permission check every time any LP callback is
+ // sent) and possibly dangerous : apps normally can't lose ACCESS_NETWORK_STATE, if
+ // it happens for some reason (e.g. the package is uninstalled while CS is trying to
+ // send the callback) it would crash the system server with NPE.
// Only do a permission check if sanitization is needed, to avoid unnecessary binder calls.
final boolean needsSanitization =
@@ -2737,6 +2779,11 @@
"ConnectivityService");
}
+ private boolean checkAccessPermission(int pid, int uid) {
+ return mContext.checkPermission(android.Manifest.permission.ACCESS_NETWORK_STATE, pid, uid)
+ == PERMISSION_GRANTED;
+ }
+
/**
* Performs a strict and comprehensive check of whether a calling package is allowed to
* change the state of network, as the condition differs for pre-M, M+, and
diff --git a/tests/TEST_MAPPING b/tests/TEST_MAPPING
deleted file mode 100644
index 502f885..0000000
--- a/tests/TEST_MAPPING
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "presubmit": [
- {
- "name": "FrameworksNetIntegrationTests"
- }
- ],
- "postsubmit": [
- {
- "name": "FrameworksNetDeflakeTest"
- }
- ],
- "auto-postsubmit": [
- // Test tag for automotive targets. These are only running in postsubmit so as to harden the
- // automotive targets to avoid introducing additional test flake and build time. The plan for
- // presubmit testing for auto is to augment the existing tests to cover auto use cases as well.
- // Additionally, this tag is used in targeted test suites to limit resource usage on the test
- // infra during the hardening phase.
- // TODO: this tag to be removed once the above is no longer an issue.
- {
- "name": "FrameworksNetTests"
- },
- {
- "name": "FrameworksNetIntegrationTests"
- },
- {
- "name": "FrameworksNetDeflakeTest"
- }
- ],
- "imports": [
- {
- "path": "packages/modules/Connectivity"
- }
- ]
-}
\ No newline at end of file
diff --git a/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt b/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt
index 8d8958d..d14d127 100644
--- a/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt
+++ b/tests/common/java/android/net/ConnectivitySettingsManagerTest.kt
@@ -67,6 +67,7 @@
import androidx.test.InstrumentationRegistry
import androidx.test.filters.SmallTest
import com.android.net.module.util.ConnectivitySettingsUtils.getPrivateDnsModeAsString
+import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import junit.framework.Assert.assertEquals
@@ -295,6 +296,7 @@
testIntValues = intArrayOf(0))
}
+ @ConnectivityModuleTest // get/setIngressRateLimitInBytesPerSecond was added via module update
@Test
fun testInternetNetworkRateLimitInBytesPerSecond() {
val defaultRate = getIngressRateLimitInBytesPerSecond(context)
diff --git a/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java
index 742044b..b6926a8 100644
--- a/tests/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -49,6 +49,7 @@
import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_USB;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
@@ -727,25 +728,38 @@
@Test
public void testSetNetworkSpecifierOnMultiTransportNc() {
// Sequence 1: Transport + Transport + NetworkSpecifier
- NetworkCapabilities nc1 = new NetworkCapabilities();
+ NetworkCapabilities.Builder nc1 = new NetworkCapabilities.Builder();
nc1.addTransportType(TRANSPORT_CELLULAR).addTransportType(TRANSPORT_WIFI);
- try {
- nc1.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier("eth0"));
- fail("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!");
- } catch (IllegalStateException expected) {
- // empty
- }
+ final NetworkSpecifier specifier = CompatUtil.makeEthernetNetworkSpecifier("eth0");
+ assertThrows("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!",
+ IllegalStateException.class,
+ () -> nc1.build().setNetworkSpecifier(specifier));
+ assertThrows("Cannot set NetworkSpecifier on a NetworkCapability with multiple transports!",
+ IllegalStateException.class,
+ () -> nc1.setNetworkSpecifier(specifier));
// Sequence 2: Transport + NetworkSpecifier + Transport
- NetworkCapabilities nc2 = new NetworkCapabilities();
- nc2.addTransportType(TRANSPORT_CELLULAR).setNetworkSpecifier(
- CompatUtil.makeEthernetNetworkSpecifier("testtap3"));
- try {
- nc2.addTransportType(TRANSPORT_WIFI);
- fail("Cannot set a second TransportType of a network which has a NetworkSpecifier!");
- } catch (IllegalStateException expected) {
- // empty
- }
+ NetworkCapabilities.Builder nc2 = new NetworkCapabilities.Builder();
+ nc2.addTransportType(TRANSPORT_CELLULAR).setNetworkSpecifier(specifier);
+
+ assertThrows("Cannot set a second TransportType of a network which has a NetworkSpecifier!",
+ IllegalStateException.class,
+ () -> nc2.build().addTransportType(TRANSPORT_WIFI));
+ assertThrows("Cannot set a second TransportType of a network which has a NetworkSpecifier!",
+ IllegalStateException.class,
+ () -> nc2.addTransportType(TRANSPORT_WIFI));
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R) // New behavior in updatable NetworkCapabilities (S+)
+ public void testSetNetworkSpecifierOnTestMultiTransportNc() {
+ final NetworkSpecifier specifier = CompatUtil.makeEthernetNetworkSpecifier("eth0");
+ NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_TEST)
+ .addTransportType(TRANSPORT_ETHERNET)
+ .setNetworkSpecifier(specifier)
+ .build();
+ // Adding a specifier did not crash with 2 transports if one is TEST
+ assertEquals(specifier, nc.getNetworkSpecifier());
}
@Test
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
index 54eb927..eb7dca7 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyActivity.java
@@ -47,7 +47,8 @@
MyActivity.this.finish();
}
};
- registerReceiver(finishCommandReceiver, new IntentFilter(ACTION_FINISH_ACTIVITY));
+ registerReceiver(finishCommandReceiver, new IntentFilter(ACTION_FINISH_ACTIVITY),
+ Context.RECEIVER_EXPORTED);
final RemoteCallback callback = getIntent().getParcelableExtra(
Intent.EXTRA_REMOTE_CALLBACK);
if (callback != null) {
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyJobService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyJobService.java
index 51c3157..8c112b6 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyJobService.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyJobService.java
@@ -56,7 +56,8 @@
}
}
};
- registerReceiver(mFinishCommandReceiver, new IntentFilter(ACTION_FINISH_JOB));
+ registerReceiver(mFinishCommandReceiver, new IntentFilter(ACTION_FINISH_JOB),
+ Context.RECEIVER_EXPORTED);
return true;
}
diff --git a/tests/cts/net/AndroidTestTemplate.xml b/tests/cts/net/AndroidTestTemplate.xml
index d761c27..d605799 100644
--- a/tests/cts/net/AndroidTestTemplate.xml
+++ b/tests/cts/net/AndroidTestTemplate.xml
@@ -21,6 +21,8 @@
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="config-descriptor:metadata" key="mainline-param" value="CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk" />
+ <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.tethering.apex" />
<option name="not-shardable" value="true" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 53e4ab7..ea64252 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -16,9 +16,15 @@
package android.net.cts;
+import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
+import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.Manifest.permission.ACCESS_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_FACTORY;
import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.Manifest.permission.NETWORK_SETUP_WIZARD;
+import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.READ_DEVICE_CONFIG;
import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
import static android.content.pm.PackageManager.FEATURE_ETHERNET;
@@ -54,7 +60,9 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.net.cts.util.CtsNetUtils.ConnectivityActionReceiver;
import static android.net.cts.util.CtsNetUtils.HTTP_PORT;
import static android.net.cts.util.CtsNetUtils.NETWORK_CALLBACK_ACTION;
@@ -64,6 +72,7 @@
import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL;
import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
+import static android.os.Process.INVALID_UID;
import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
@@ -76,6 +85,7 @@
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_LOCKDOWN_VPN;
import static com.android.networkstack.apishim.ConstantsShim.BLOCKED_REASON_NONE;
import static com.android.testutils.Cleanup.testAndCleanup;
+import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.TestNetworkTrackerKt.initTestNetwork;
import static com.android.testutils.TestPermissionUtil.runAsShell;
@@ -103,6 +113,7 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.net.CaptivePortalData;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivitySettingsManager;
@@ -132,6 +143,7 @@
import android.net.cts.util.CtsNetUtils;
import android.net.cts.util.CtsTetheringUtils;
import android.net.util.KeepaliveUtils;
+import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
import android.os.Build;
@@ -160,6 +172,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.modules.utils.build.SdkLevel;
+import com.android.net.module.util.CollectionUtils;
import com.android.networkstack.apishim.ConnectivityManagerShimImpl;
import com.android.networkstack.apishim.ConstantsShim;
import com.android.networkstack.apishim.NetworkInformationShimImpl;
@@ -554,6 +567,223 @@
}
}
+ private boolean checkPermission(String perm, int uid) {
+ return mContext.checkPermission(perm, -1 /* pid */, uid) == PERMISSION_GRANTED;
+ }
+
+ private String findPackageByPermissions(@NonNull List<String> requiredPermissions,
+ @NonNull List<String> forbiddenPermissions) throws Exception {
+ final List<PackageInfo> packageInfos =
+ mPackageManager.getInstalledPackages(GET_PERMISSIONS);
+ for (PackageInfo packageInfo : packageInfos) {
+ final int uid = mPackageManager.getPackageUid(packageInfo.packageName, 0 /* flags */);
+ if (!CollectionUtils.all(requiredPermissions, perm -> checkPermission(perm, uid))) {
+ continue;
+ }
+ if (CollectionUtils.any(forbiddenPermissions, perm -> checkPermission(perm, uid))) {
+ continue;
+ }
+
+ return packageInfo.packageName;
+ }
+ return null;
+ }
+
+ @DevSdkIgnoreRule.IgnoreUpTo(SC_V2)
+ @Test
+ public void testRedactLinkPropertiesForPackage() throws Exception {
+ final String groundedPkg = findPackageByPermissions(
+ List.of(), /* requiredPermissions */
+ List.of(ACCESS_NETWORK_STATE) /* forbiddenPermissions */);
+ assertNotNull("Couldn't find any package without ACCESS_NETWORK_STATE", groundedPkg);
+ final int groundedUid = mPackageManager.getPackageUid(groundedPkg, 0 /* flags */);
+
+ final String normalPkg = findPackageByPermissions(
+ List.of(ACCESS_NETWORK_STATE) /* requiredPermissions */,
+ List.of(NETWORK_SETTINGS, NETWORK_STACK,
+ PERMISSION_MAINLINE_NETWORK_STACK) /* forbiddenPermissions */);
+ assertNotNull("Couldn't find any package with ACCESS_NETWORK_STATE but"
+ + " without NETWORK_SETTINGS", normalPkg);
+ final int normalUid = mPackageManager.getPackageUid(normalPkg, 0 /* flags */);
+
+ // There are some privileged packages on the system, like the phone process, the network
+ // stack and the system server.
+ final String privilegedPkg = findPackageByPermissions(
+ List.of(ACCESS_NETWORK_STATE, NETWORK_SETTINGS), /* requiredPermissions */
+ List.of() /* forbiddenPermissions */);
+ assertNotNull("Couldn't find a package with sufficient permissions", privilegedPkg);
+ final int privilegedUid = mPackageManager.getPackageUid(privilegedPkg, 0);
+
+ // Set parcelSensitiveFields to true to preserve CaptivePortalApiUrl & CaptivePortalData
+ // when parceling.
+ final LinkProperties lp = new LinkProperties(new LinkProperties(),
+ true /* parcelSensitiveFields */);
+ final Uri capportUrl = Uri.parse("https://capport.example.com/api");
+ final CaptivePortalData capportData = new CaptivePortalData.Builder().build();
+ final int mtu = 12345;
+ lp.setMtu(mtu);
+ lp.setCaptivePortalApiUrl(capportUrl);
+ lp.setCaptivePortalData(capportData);
+
+ // No matter what the given uid is, a SecurityException will be thrown if the caller
+ // doesn't hold the NETWORK_SETTINGS permission.
+ assertThrows(SecurityException.class,
+ () -> mCm.redactLinkPropertiesForPackage(lp, groundedUid, groundedPkg));
+ assertThrows(SecurityException.class,
+ () -> mCm.redactLinkPropertiesForPackage(lp, normalUid, normalPkg));
+ assertThrows(SecurityException.class,
+ () -> mCm.redactLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg));
+
+ runAsShell(NETWORK_SETTINGS, () -> {
+ // No matter what the given uid is, if the given LinkProperties is null, then
+ // NullPointerException will be thrown.
+ assertThrows(NullPointerException.class,
+ () -> mCm.redactLinkPropertiesForPackage(null, groundedUid, groundedPkg));
+ assertThrows(NullPointerException.class,
+ () -> mCm.redactLinkPropertiesForPackage(null, normalUid, normalPkg));
+ assertThrows(NullPointerException.class,
+ () -> mCm.redactLinkPropertiesForPackage(null, privilegedUid, privilegedPkg));
+
+ // Make sure null is returned for a UID without ACCESS_NETWORK_STATE.
+ assertNull(mCm.redactLinkPropertiesForPackage(lp, groundedUid, groundedPkg));
+
+ // CaptivePortalApiUrl & CaptivePortalData will be set to null if given uid doesn't hold
+ // the NETWORK_SETTINGS permission.
+ assertNull(mCm.redactLinkPropertiesForPackage(lp, normalUid, normalPkg)
+ .getCaptivePortalApiUrl());
+ assertNull(mCm.redactLinkPropertiesForPackage(lp, normalUid, normalPkg)
+ .getCaptivePortalData());
+ // MTU is not sensitive and is not redacted.
+ assertEquals(mtu, mCm.redactLinkPropertiesForPackage(lp, normalUid, normalPkg)
+ .getMtu());
+
+ // CaptivePortalApiUrl & CaptivePortalData will be preserved if the given uid holds the
+ // NETWORK_SETTINGS permission.
+ assertEquals(capportUrl,
+ mCm.redactLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg)
+ .getCaptivePortalApiUrl());
+ assertEquals(capportData,
+ mCm.redactLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg)
+ .getCaptivePortalData());
+ });
+ }
+
+ private NetworkCapabilities redactNc(@NonNull final NetworkCapabilities nc, int uid,
+ @NonNull String packageName) {
+ return mCm.redactNetworkCapabilitiesForPackage(nc, uid, packageName);
+ }
+
+ @DevSdkIgnoreRule.IgnoreUpTo(SC_V2)
+ @Test
+ public void testRedactNetworkCapabilitiesForPackage() throws Exception {
+ final String groundedPkg = findPackageByPermissions(
+ List.of(), /* requiredPermissions */
+ List.of(ACCESS_NETWORK_STATE) /* forbiddenPermissions */);
+ assertNotNull("Couldn't find any package without ACCESS_NETWORK_STATE", groundedPkg);
+ final int groundedUid = mPackageManager.getPackageUid(groundedPkg, 0 /* flags */);
+
+ // A package which doesn't have any of the permissions below, but has NETWORK_STATE.
+ // There should be a number of packages like this on the device; AOSP has many,
+ // including contacts, webview, the keyboard, pacprocessor, messaging.
+ final String normalPkg = findPackageByPermissions(
+ List.of(ACCESS_NETWORK_STATE) /* requiredPermissions */,
+ List.of(NETWORK_SETTINGS, NETWORK_FACTORY, NETWORK_SETUP_WIZARD,
+ NETWORK_STACK, PERMISSION_MAINLINE_NETWORK_STACK,
+ ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION) /* forbiddenPermissions */);
+ assertNotNull("Can't find a package with ACCESS_NETWORK_STATE but without any of"
+ + " the forbidden permissions", normalPkg);
+ final int normalUid = mPackageManager.getPackageUid(normalPkg, 0 /* flags */);
+
+ // There are some privileged packages on the system, like the phone process, the network
+ // stack and the system server.
+ final String privilegedPkg = findPackageByPermissions(
+ List.of(ACCESS_NETWORK_STATE, NETWORK_SETTINGS, NETWORK_FACTORY,
+ ACCESS_FINE_LOCATION), /* requiredPermissions */
+ List.of() /* forbiddenPermissions */);
+ assertNotNull("Couldn't find a package with sufficient permissions", privilegedPkg);
+ final int privilegedUid = mPackageManager.getPackageUid(privilegedPkg, 0);
+
+ final Set<Range<Integer>> uids = new ArraySet<>();
+ uids.add(new Range<>(10000, 10100));
+ uids.add(new Range<>(10200, 10300));
+ final String ssid = "My-WiFi";
+ // This test will set underlying networks in the capabilities to redact to see if they
+ // are appropriately redacted, so fetch the default network to put in there as an example.
+ final Network defaultNetwork = mCm.getActiveNetwork();
+ assertNotNull("CTS requires a working Internet connection", defaultNetwork);
+ final int subId1 = 1;
+ final int subId2 = 2;
+ final int[] administratorUids = {normalUid};
+ final String bssid = "location sensitive";
+ final int rssi = 43; // not location sensitive
+ final WifiInfo wifiInfo = new WifiInfo.Builder()
+ .setBssid(bssid)
+ .setRssi(rssi)
+ .build();
+ final NetworkCapabilities nc = new NetworkCapabilities.Builder()
+ .setUids(uids)
+ .setSsid(ssid)
+ .setUnderlyingNetworks(List.of(defaultNetwork))
+ .setSubscriptionIds(Set.of(subId1, subId2))
+ .setAdministratorUids(administratorUids)
+ .setOwnerUid(normalUid)
+ .setTransportInfo(wifiInfo)
+ .build();
+
+ // No matter what the given uid is, a SecurityException will be thrown if the caller
+ // doesn't hold the NETWORK_SETTINGS permission.
+ assertThrows(SecurityException.class, () -> redactNc(nc, groundedUid, groundedPkg));
+ assertThrows(SecurityException.class, () -> redactNc(nc, normalUid, normalPkg));
+ assertThrows(SecurityException.class, () -> redactNc(nc, privilegedUid, privilegedPkg));
+
+ runAsShell(NETWORK_SETTINGS, () -> {
+ // Make sure that the NC is null if the package doesn't hold ACCESS_NETWORK_STATE.
+ assertNull(redactNc(nc, groundedUid, groundedPkg));
+
+ // Uids, ssid, underlying networks & subscriptionIds will be redacted if the given uid
+ // doesn't hold the associated permissions. The wifi transport info is also suitably
+ // redacted.
+ final NetworkCapabilities redactedNormal = redactNc(nc, normalUid, normalPkg);
+ assertNull(redactedNormal.getUids());
+ assertNull(redactedNormal.getSsid());
+ assertNull(redactedNormal.getUnderlyingNetworks());
+ assertEquals(0, redactedNormal.getSubscriptionIds().size());
+ assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS,
+ ((WifiInfo) redactedNormal.getTransportInfo()).getBSSID());
+ assertEquals(rssi, ((WifiInfo) redactedNormal.getTransportInfo()).getRssi());
+
+ // Uids, ssid, underlying networks & subscriptionIds will be preserved if the given uid
+ // holds the associated permissions.
+ final NetworkCapabilities redactedPrivileged =
+ redactNc(nc, privilegedUid, privilegedPkg);
+ assertEquals(uids, redactedPrivileged.getUids());
+ assertEquals(ssid, redactedPrivileged.getSsid());
+ assertEquals(List.of(defaultNetwork), redactedPrivileged.getUnderlyingNetworks());
+ assertEquals(Set.of(subId1, subId2), redactedPrivileged.getSubscriptionIds());
+ assertEquals(bssid, ((WifiInfo) redactedPrivileged.getTransportInfo()).getBSSID());
+ assertEquals(rssi, ((WifiInfo) redactedPrivileged.getTransportInfo()).getRssi());
+
+ // The owner uid is only preserved when the network is a VPN and the uid is the
+ // same as the owner uid.
+ nc.addTransportType(TRANSPORT_VPN);
+ assertEquals(normalUid, redactNc(nc, normalUid, normalPkg).getOwnerUid());
+ assertEquals(INVALID_UID, redactNc(nc, privilegedUid, privilegedPkg).getOwnerUid());
+ nc.removeTransportType(TRANSPORT_VPN);
+
+ // If the given uid doesn't hold location permissions, the owner uid will be set to
+ // INVALID_UID even when sent to that UID (this avoids a wifi suggestor knowing where
+ // the device is by virtue of the device connecting to its own network).
+ assertEquals(INVALID_UID, redactNc(nc, normalUid, normalPkg).getOwnerUid());
+
+ // If the given uid holds location permissions, the owner uid is preserved. This works
+ // because the shell holds ACCESS_FINE_LOCATION.
+ final int[] administratorUids2 = { privilegedUid };
+ nc.setAdministratorUids(administratorUids2);
+ nc.setOwnerUid(privilegedUid);
+ assertEquals(privilegedUid, redactNc(nc, privilegedUid, privilegedPkg).getOwnerUid());
+ });
+ }
+
/**
* Tests that connections can be opened on WiFi and cellphone networks,
* and that they are made from different IP addresses.
diff --git a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java
index d221694..23744eb 100644
--- a/tests/cts/net/src/android/net/cts/IpConfigurationTest.java
+++ b/tests/cts/net/src/android/net/cts/IpConfigurationTest.java
@@ -29,6 +29,7 @@
import androidx.test.runner.AndroidJUnit4;
+import com.android.testutils.ConnectivityModuleTest;
import com.android.testutils.DevSdkIgnoreRule;
import libcore.net.InetAddressUtils;
@@ -106,7 +107,7 @@
assertIpConfigurationEqual(ipConfig, new IpConfiguration(ipConfig));
}
- @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+ @ConnectivityModuleTest @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
@Test
public void testBuilder() {
final IpConfiguration c = new IpConfiguration.Builder()
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 344482b..bf97339 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -77,6 +77,7 @@
import com.android.modules.utils.build.SdkLevel
import com.android.net.module.util.ArrayTrackRecord
import com.android.testutils.CompatUtil
+import com.android.testutils.ConnectivityModuleTest
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.RecorderCallback.CallbackEntry.Available
@@ -465,6 +466,7 @@
.addTransportType(TRANSPORT_TEST)
.setAccessUids(uids.toSet()).build()
+ @ConnectivityModuleTest // Functionality was added post-S via connectivity module update
@Test
fun testRejectedUpdates() {
val callback = TestableNetworkCallback()
diff --git a/tests/cts/net/src/android/net/cts/StaticIpConfigurationTest.java b/tests/cts/net/src/android/net/cts/StaticIpConfigurationTest.java
index 9b2756c..e2d3346 100644
--- a/tests/cts/net/src/android/net/cts/StaticIpConfigurationTest.java
+++ b/tests/cts/net/src/android/net/cts/StaticIpConfigurationTest.java
@@ -35,6 +35,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.testutils.ConnectivityModuleTest;
import com.android.testutils.DevSdkIgnoreRule;
import org.junit.Rule;
@@ -256,7 +257,7 @@
assertEquals(DNS1, s.getDnsServers().get(0));
}
- @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+ @ConnectivityModuleTest @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
@Test
public void testIllegalBuilders() {
assertThrows("Can't set IP Address to IPv6!", IllegalArgumentException.class, () -> {
diff --git a/tests/mts/Android.bp b/tests/mts/Android.bp
index 2c44010..74fee3d 100644
--- a/tests/mts/Android.bp
+++ b/tests/mts/Android.bp
@@ -27,6 +27,9 @@
"connectivity-mainline-presubmit-cc-defaults",
],
require_root: true,
+ header_libs: [
+ "bpf_headers",
+ ],
static_libs: [
"libbase",
"libmodules-utils-build",
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp
index 142e013..2bba282 100644
--- a/tests/mts/bpf_existence_test.cpp
+++ b/tests/mts/bpf_existence_test.cpp
@@ -23,6 +23,7 @@
#include <android/api-level.h>
#include <android-base/properties.h>
#include <android-modules-utils/sdk_level.h>
+#include <bpf/BpfUtils.h>
#include <gtest/gtest.h>
@@ -151,6 +152,8 @@
}
TEST_F(BpfExistenceTest, TestPrograms) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
// Pre-flight check to ensure test has been updated.
uint64_t buildVersionSdk = android_get_device_api_level();
ASSERT_NE(0, buildVersionSdk) << "Unable to determine device SDK version";