Merge "[MS55.2] Move NetworkStateSnapshot into module folder"
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 5cfab5d..5961e72 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -43,9 +43,11 @@
field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1
field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
+ field public static final int BLOCKED_REASON_LOW_POWER_STANDBY = 32; // 0x20
field public static final int BLOCKED_REASON_NONE = 0; // 0x0
field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
field public static final int FIREWALL_CHAIN_DOZABLE = 1; // 0x1
+ field public static final int FIREWALL_CHAIN_LOW_POWER_STANDBY = 5; // 0x5
field public static final int FIREWALL_CHAIN_POWERSAVE = 3; // 0x3
field public static final int FIREWALL_CHAIN_RESTRICTED = 4; // 0x4
field public static final int FIREWALL_CHAIN_STANDBY = 2; // 0x2
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 7593482..92ede91 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -877,6 +877,15 @@
public static final int BLOCKED_REASON_LOCKDOWN_VPN = 1 << 4;
/**
+ * Flag to indicate that an app is subject to Low Power Standby restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_LOW_POWER_STANDBY = 1 << 5;
+
+ /**
* Flag to indicate that an app is subject to Data saver restrictions that would
* result in its metered network access being blocked.
*
@@ -914,6 +923,7 @@
BLOCKED_REASON_APP_STANDBY,
BLOCKED_REASON_RESTRICTED_MODE,
BLOCKED_REASON_LOCKDOWN_VPN,
+ BLOCKED_REASON_LOW_POWER_STANDBY,
BLOCKED_METERED_REASON_DATA_SAVER,
BLOCKED_METERED_REASON_USER_RESTRICTED,
BLOCKED_METERED_REASON_ADMIN_DISABLED,
@@ -963,13 +973,22 @@
@SystemApi(client = MODULE_LIBRARIES)
public static final int FIREWALL_CHAIN_RESTRICTED = 4;
+ /**
+ * Firewall chain used for low power standby.
+ * Allowlist of apps that have access in low power standby.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final int FIREWALL_CHAIN_LOW_POWER_STANDBY = 5;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = false, prefix = "FIREWALL_CHAIN_", value = {
FIREWALL_CHAIN_DOZABLE,
FIREWALL_CHAIN_STANDBY,
FIREWALL_CHAIN_POWERSAVE,
- FIREWALL_CHAIN_RESTRICTED
+ FIREWALL_CHAIN_RESTRICTED,
+ FIREWALL_CHAIN_LOW_POWER_STANDBY
})
public @interface FirewallChain {}
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 4254a66..feb9fc1 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -621,22 +621,22 @@
* Network capabilities that are expected to be mutable, i.e., can change while a particular
* network is connected.
*/
- private static final long MUTABLE_CAPABILITIES =
+ private static final long MUTABLE_CAPABILITIES = NetworkCapabilitiesUtils.packBitList(
// TRUSTED can change when user explicitly connects to an untrusted network in Settings.
// http://b/18206275
- (1 << NET_CAPABILITY_TRUSTED)
- | (1 << NET_CAPABILITY_VALIDATED)
- | (1 << NET_CAPABILITY_CAPTIVE_PORTAL)
- | (1 << NET_CAPABILITY_NOT_ROAMING)
- | (1 << NET_CAPABILITY_FOREGROUND)
- | (1 << NET_CAPABILITY_NOT_CONGESTED)
- | (1 << NET_CAPABILITY_NOT_SUSPENDED)
- | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY)
- | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED)
- | (1 << NET_CAPABILITY_NOT_VCN_MANAGED)
+ NET_CAPABILITY_TRUSTED,
+ NET_CAPABILITY_VALIDATED,
+ NET_CAPABILITY_CAPTIVE_PORTAL,
+ NET_CAPABILITY_NOT_ROAMING,
+ NET_CAPABILITY_FOREGROUND,
+ NET_CAPABILITY_NOT_CONGESTED,
+ NET_CAPABILITY_NOT_SUSPENDED,
+ NET_CAPABILITY_PARTIAL_CONNECTIVITY,
+ NET_CAPABILITY_TEMPORARILY_NOT_METERED,
+ NET_CAPABILITY_NOT_VCN_MANAGED,
// The value of NET_CAPABILITY_HEAD_UNIT is 32, which cannot use int to do bit shift,
// otherwise there will be an overflow. Use long to do bit shift instead.
- | (1L << NET_CAPABILITY_HEAD_UNIT);
+ NET_CAPABILITY_HEAD_UNIT);
/**
* Network capabilities that are not allowed in NetworkRequests. This exists because the
@@ -650,25 +650,26 @@
// in an infinite loop about these.
private static final long NON_REQUESTABLE_CAPABILITIES =
MUTABLE_CAPABILITIES
- & ~(1 << NET_CAPABILITY_TRUSTED)
- & ~(1 << NET_CAPABILITY_NOT_VCN_MANAGED);
+ & ~(1L << NET_CAPABILITY_TRUSTED)
+ & ~(1L << NET_CAPABILITY_NOT_VCN_MANAGED);
/**
* Capabilities that are set by default when the object is constructed.
*/
- private static final long DEFAULT_CAPABILITIES =
- (1 << NET_CAPABILITY_NOT_RESTRICTED)
- | (1 << NET_CAPABILITY_TRUSTED)
- | (1 << NET_CAPABILITY_NOT_VPN);
+ private static final long DEFAULT_CAPABILITIES = NetworkCapabilitiesUtils.packBitList(
+ NET_CAPABILITY_NOT_RESTRICTED,
+ NET_CAPABILITY_TRUSTED,
+ NET_CAPABILITY_NOT_VPN);
/**
* Capabilities that are managed by ConnectivityService.
*/
private static final long CONNECTIVITY_MANAGED_CAPABILITIES =
- (1 << NET_CAPABILITY_VALIDATED)
- | (1 << NET_CAPABILITY_CAPTIVE_PORTAL)
- | (1 << NET_CAPABILITY_FOREGROUND)
- | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY);
+ NetworkCapabilitiesUtils.packBitList(
+ NET_CAPABILITY_VALIDATED,
+ NET_CAPABILITY_CAPTIVE_PORTAL,
+ NET_CAPABILITY_FOREGROUND,
+ NET_CAPABILITY_PARTIAL_CONNECTIVITY);
/**
* Capabilities that are allowed for test networks. This list must be set so that it is safe
@@ -677,14 +678,15 @@
* INTERNET, IMS, SUPL, etc.
*/
private static final long TEST_NETWORKS_ALLOWED_CAPABILITIES =
- (1 << NET_CAPABILITY_NOT_METERED)
- | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED)
- | (1 << NET_CAPABILITY_NOT_RESTRICTED)
- | (1 << NET_CAPABILITY_NOT_VPN)
- | (1 << NET_CAPABILITY_NOT_ROAMING)
- | (1 << NET_CAPABILITY_NOT_CONGESTED)
- | (1 << NET_CAPABILITY_NOT_SUSPENDED)
- | (1 << NET_CAPABILITY_NOT_VCN_MANAGED);
+ NetworkCapabilitiesUtils.packBitList(
+ NET_CAPABILITY_NOT_METERED,
+ NET_CAPABILITY_TEMPORARILY_NOT_METERED,
+ NET_CAPABILITY_NOT_RESTRICTED,
+ NET_CAPABILITY_NOT_VPN,
+ NET_CAPABILITY_NOT_ROAMING,
+ NET_CAPABILITY_NOT_CONGESTED,
+ NET_CAPABILITY_NOT_SUSPENDED,
+ NET_CAPABILITY_NOT_VCN_MANAGED);
/**
* Adds the given capability to this {@code NetworkCapability} instance.
@@ -1156,12 +1158,13 @@
/**
* Allowed transports on an unrestricted test network (in addition to TRANSPORT_TEST).
*/
- private static final int UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS =
- 1 << TRANSPORT_TEST
- // Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces
- | 1 << TRANSPORT_ETHERNET
- // Test VPN networks can be created but their UID ranges must be empty.
- | 1 << TRANSPORT_VPN;
+ private static final long UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS =
+ NetworkCapabilitiesUtils.packBitList(
+ TRANSPORT_TEST,
+ // Test eth networks are created with EthernetManager#setIncludeTestInterfaces
+ TRANSPORT_ETHERNET,
+ // Test VPN networks can be created but their UID ranges must be empty.
+ TRANSPORT_VPN);
/**
* Adds the given transport type to this {@code NetworkCapability} instance.
@@ -3076,4 +3079,4 @@
return new NetworkCapabilities(mCaps);
}
}
-}
+}
\ No newline at end of file
diff --git a/service/native/Android.bp b/service/native/Android.bp
index 0e805e2..a20c54f 100644
--- a/service/native/Android.bp
+++ b/service/native/Android.bp
@@ -70,6 +70,7 @@
"libnetdutils",
"libtraffic_controller",
"libutils",
+ "libnetd_updatable",
"netd_aidl_interface-lateststable-ndk",
],
}
diff --git a/service/native/TrafficControllerTest.cpp b/service/native/TrafficControllerTest.cpp
index f401636..39f3365 100644
--- a/service/native/TrafficControllerTest.cpp
+++ b/service/native/TrafficControllerTest.cpp
@@ -38,6 +38,7 @@
#include "TrafficController.h"
#include "bpf/BpfUtils.h"
+#include "NetdUpdatablePublic.h"
using namespace android::bpf; // NOLINT(google-build-using-namespace): grandfathered
@@ -746,5 +747,133 @@
expectPrivilegedUserSetEmpty();
}
+constexpr uint32_t SOCK_CLOSE_WAIT_US = 30 * 1000;
+constexpr uint32_t ENOBUFS_POLL_WAIT_US = 10 * 1000;
+
+using android::base::Error;
+using android::base::Result;
+using android::bpf::BpfMap;
+
+// This test set up a SkDestroyListener that is running parallel with the production
+// SkDestroyListener. The test will create thousands of sockets and tag them on the
+// production cookieUidTagMap and close them in a short time. When the number of
+// sockets get closed exceeds the buffer size, it will start to return ENOBUFF
+// error. The error will be ignored by the production SkDestroyListener and the
+// test will clean up the tags in tearDown if there is any remains.
+
+// TODO: Instead of test the ENOBUFF error, we can test the production
+// SkDestroyListener to see if it failed to delete a tagged socket when ENOBUFF
+// triggered.
+class NetlinkListenerTest : public testing::Test {
+ protected:
+ NetlinkListenerTest() {}
+ BpfMap<uint64_t, UidTagValue> mCookieTagMap;
+
+ void SetUp() {
+ mCookieTagMap.reset(android::bpf::mapRetrieveRW(COOKIE_TAG_MAP_PATH));
+ ASSERT_TRUE(mCookieTagMap.isValid());
+ }
+
+ void TearDown() {
+ const auto deleteTestCookieEntries = [](const uint64_t& key, const UidTagValue& value,
+ BpfMap<uint64_t, UidTagValue>& map) {
+ if ((value.uid == TEST_UID) && (value.tag == TEST_TAG)) {
+ Result<void> res = map.deleteValue(key);
+ if (res.ok() || (res.error().code() == ENOENT)) {
+ return Result<void>();
+ }
+ ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", key,
+ strerror(res.error().code()));
+ }
+ // Move forward to next cookie in the map.
+ return Result<void>();
+ };
+ EXPECT_RESULT_OK(mCookieTagMap.iterateWithValue(deleteTestCookieEntries));
+ }
+
+ Result<void> checkNoGarbageTagsExist() {
+ const auto checkGarbageTags = [](const uint64_t&, const UidTagValue& value,
+ const BpfMap<uint64_t, UidTagValue>&) -> Result<void> {
+ if ((TEST_UID == value.uid) && (TEST_TAG == value.tag)) {
+ return Error(EUCLEAN) << "Closed socket is not untagged";
+ }
+ return {};
+ };
+ return mCookieTagMap.iterateWithValue(checkGarbageTags);
+ }
+
+ bool checkMassiveSocketDestroy(int totalNumber, bool expectError) {
+ std::unique_ptr<android::netdutils::NetlinkListenerInterface> skDestroyListener;
+ auto result = android::net::TrafficController::makeSkDestroyListener();
+ if (!isOk(result)) {
+ ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
+ } else {
+ skDestroyListener = std::move(result.value());
+ }
+ int rxErrorCount = 0;
+ // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
+ const auto rxErrorHandler = [&rxErrorCount](const int, const int) { rxErrorCount++; };
+ skDestroyListener->registerSkErrorHandler(rxErrorHandler);
+ int fds[totalNumber];
+ for (int i = 0; i < totalNumber; i++) {
+ fds[i] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ // The likely reason for a failure is running out of available file descriptors.
+ EXPECT_LE(0, fds[i]) << i << " of " << totalNumber;
+ if (fds[i] < 0) {
+ // EXPECT_LE already failed above, so test case is a failure, but we don't
+ // want potentially tens of thousands of extra failures creating and then
+ // closing all these fds cluttering up the logs.
+ totalNumber = i;
+ break;
+ };
+ libnetd_updatable_tagSocket(fds[i], TEST_TAG, TEST_UID, 1000);
+ }
+
+ // TODO: Use a separate thread that has its own fd table so we can
+ // close sockets even faster simply by terminating that thread.
+ for (int i = 0; i < totalNumber; i++) {
+ EXPECT_EQ(0, close(fds[i]));
+ }
+ // wait a bit for netlink listener to handle all the messages.
+ usleep(SOCK_CLOSE_WAIT_US);
+ if (expectError) {
+ // If ENOBUFS triggered, check it only called into the handler once, ie.
+ // that the netlink handler is not spinning.
+ int currentErrorCount = rxErrorCount;
+ // 0 error count is acceptable because the system has chances to close all sockets
+ // normally.
+ EXPECT_LE(0, rxErrorCount);
+ if (!rxErrorCount) return true;
+
+ usleep(ENOBUFS_POLL_WAIT_US);
+ EXPECT_EQ(currentErrorCount, rxErrorCount);
+ } else {
+ EXPECT_RESULT_OK(checkNoGarbageTagsExist());
+ EXPECT_EQ(0, rxErrorCount);
+ }
+ return false;
+ }
+};
+
+TEST_F(NetlinkListenerTest, TestAllSocketUntagged) {
+ checkMassiveSocketDestroy(10, false);
+ checkMassiveSocketDestroy(100, false);
+}
+
+// Disabled because flaky on blueline-userdebug; this test relies on the main thread
+// winning a race against the NetlinkListener::run() thread. There's no way to ensure
+// things will be scheduled the same way across all architectures and test environments.
+TEST_F(NetlinkListenerTest, DISABLED_TestSkDestroyError) {
+ bool needRetry = false;
+ int retryCount = 0;
+ do {
+ needRetry = checkMassiveSocketDestroy(32500, true);
+ if (needRetry) retryCount++;
+ } while (needRetry && retryCount < 3);
+ // Should review test if it can always close all sockets correctly.
+ EXPECT_GT(3, retryCount);
+}
+
+
} // namespace net
} // namespace android
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index fb90053..a9a06e4 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -1339,6 +1339,18 @@
}
/**
+ * @see CarrierPrivilegeAuthenticator
+ */
+ public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator(
+ @NonNull final Context context, @NonNull final TelephonyManager tm) {
+ if (SdkLevel.isAtLeastT()) {
+ return new CarrierPrivilegeAuthenticator(context, tm);
+ } else {
+ return null;
+ }
+ }
+
+ /**
* @see DeviceConfigUtils#isFeatureEnabled
*/
public boolean isFeatureEnabled(Context context, String name, boolean defaultEnabled) {
@@ -1426,12 +1438,8 @@
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext);
- if (SdkLevel.isAtLeastT()) {
- mCarrierPrivilegeAuthenticator =
- new CarrierPrivilegeAuthenticator(mContext, mTelephonyManager);
- } else {
- mCarrierPrivilegeAuthenticator = null;
- }
+ mCarrierPrivilegeAuthenticator =
+ mDeps.makeCarrierPrivilegeAuthenticator(mContext, mTelephonyManager);
// To ensure uid state is synchronized with Network Policy, register for
// NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
@@ -4157,11 +4165,11 @@
}
}
- private boolean hasCarrierPrivilegeForNetworkRequest(int callingUid,
- NetworkRequest networkRequest) {
+ private boolean hasCarrierPrivilegeForNetworkCaps(final int callingUid,
+ @NonNull final NetworkCapabilities caps) {
if (SdkLevel.isAtLeastT() && mCarrierPrivilegeAuthenticator != null) {
- return mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(callingUid,
- networkRequest);
+ return mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
+ callingUid, caps);
}
return false;
}
@@ -4205,7 +4213,7 @@
}
}
if (req.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
- if (!hasCarrierPrivilegeForNetworkRequest(nri.mUid, req)
+ if (!hasCarrierPrivilegeForNetworkCaps(nri.mUid, req.networkCapabilities)
&& !checkConnectivityRestrictedNetworksPermission(
nri.mPid, nri.mUid)) {
requestToBeReleased = req;
@@ -6140,13 +6148,6 @@
}
}
- private void ensureRequestableCapabilities(NetworkCapabilities networkCapabilities) {
- final String badCapability = networkCapabilities.describeFirstNonRequestableCapability();
- if (badCapability != null) {
- throw new IllegalArgumentException("Cannot request network with " + badCapability);
- }
- }
-
// This checks that the passed capabilities either do not request a
// specific SSID/SignalStrength, or the calling app has permission to do so.
private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc,
@@ -6204,7 +6205,7 @@
nai.onSignalStrengthThresholdsUpdated(thresholdsArray);
}
- private void ensureValidNetworkSpecifier(NetworkCapabilities nc) {
+ private static void ensureValidNetworkSpecifier(NetworkCapabilities nc) {
if (nc == null) {
return;
}
@@ -6217,7 +6218,7 @@
}
}
- private void ensureValid(NetworkCapabilities nc) {
+ private static void ensureListenableCapabilities(@NonNull final NetworkCapabilities nc) {
ensureValidNetworkSpecifier(nc);
if (nc.isPrivateDnsBroken()) {
throw new IllegalArgumentException("Can't request broken private DNS");
@@ -6227,6 +6228,14 @@
}
}
+ private void ensureRequestableCapabilities(@NonNull final NetworkCapabilities nc) {
+ ensureListenableCapabilities(nc);
+ final String badCapability = nc.describeFirstNonRequestableCapability();
+ if (badCapability != null) {
+ throw new IllegalArgumentException("Cannot request network with " + badCapability);
+ }
+ }
+
// TODO: Set the mini sdk to 31 and remove @TargetApi annotation when b/205923322 is addressed.
@TargetApi(Build.VERSION_CODES.S)
private boolean isTargetSdkAtleast(int version, int callingUid,
@@ -6319,7 +6328,6 @@
if (timeoutMs < 0) {
throw new IllegalArgumentException("Bad timeout specified");
}
- ensureValid(networkCapabilities);
final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType);
@@ -6461,7 +6469,6 @@
Binder.getCallingPid(), callingUid, callingPackageName);
restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities,
callingUid, callingPackageName);
- ensureValid(networkCapabilities);
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
@@ -6528,7 +6535,7 @@
// There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
// can't request networks.
restrictBackgroundRequestForCaller(nc);
- ensureValid(nc);
+ ensureListenableCapabilities(nc);
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
@@ -6550,7 +6557,7 @@
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
}
- ensureValid(networkCapabilities);
+ ensureListenableCapabilities(networkCapabilities);
ensureSufficientPermissionsForRequest(networkCapabilities,
Binder.getCallingPid(), callingUid, callingPackageName);
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
@@ -7495,7 +7502,8 @@
nc.setOwnerUid(nai.networkCapabilities.getOwnerUid());
}
nai.declaredCapabilities = new NetworkCapabilities(nc);
- NetworkAgentInfo.restrictCapabilitiesFromNetworkAgent(nc, nai.creatorUid);
+ NetworkAgentInfo.restrictCapabilitiesFromNetworkAgent(nc, nai.creatorUid,
+ mCarrierPrivilegeAuthenticator);
}
/** Modifies |newNc| based on the capabilities of |underlyingNetworks| and |agentCaps|. */
diff --git a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
index c5107ad..ce955fd 100644
--- a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
+++ b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
@@ -25,7 +26,7 @@
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.net.NetworkRequest;
+import android.net.NetworkCapabilities;
import android.net.NetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
import android.os.Build;
@@ -235,24 +236,30 @@
}
/**
- * Check if network request is allowed based upon carrrier service package.
+ * Check if a UID is the carrier service app of the subscription ID in the provided capabilities
*
- * Network request for {@link NET_CAPABILITY_CBS} is allowed if the caller has
- * carrier privilege and provides the carrier config. This function checks if caller
- * has the same and returns true if it has else false.
+ * This returns whether the passed UID is the carrier service package for the subscription ID
+ * stored in the telephony network specifier in the passed network capabilities.
+ * If the capabilities don't code for a cellular network, or if they don't have the
+ * subscription ID in their specifier, this returns false.
*
- * @param callingUid user identifier that uniquely identifies the caller.
- * @param networkRequest the network request for which the carrier privilege is checked.
- * @return true if caller has carrier privilege and provides the carrier config else false.
+ * This method can be used to check that a network request for {@link NET_CAPABILITY_CBS} is
+ * allowed for the UID of a caller, which must hold carrier privilege and provide the carrier
+ * config.
+ * It can also be used to check that a factory is entitled to grant access to a given network
+ * to a given UID on grounds that it is the carrier service package.
+ *
+ * @param callingUid uid of the app claimed to be the carrier service package.
+ * @param networkCapabilities the network capabilities for which carrier privilege is checked.
+ * @return true if uid provides the relevant carrier config else false.
*/
- public boolean hasCarrierPrivilegeForNetworkRequest(int callingUid,
- NetworkRequest networkRequest) {
- if (callingUid != Process.INVALID_UID) {
- final int subId = getSubIdFromNetworkSpecifier(
- networkRequest.getNetworkSpecifier());
- return callingUid == getCarrierServiceUidForSubId(subId);
- }
- return false;
+ public boolean hasCarrierPrivilegeForNetworkCapabilities(int callingUid,
+ @NonNull NetworkCapabilities networkCapabilities) {
+ if (callingUid == Process.INVALID_UID) return false;
+ if (!networkCapabilities.hasSingleTransport(TRANSPORT_CELLULAR)) return false;
+ final int subId = getSubIdFromNetworkSpecifier(networkCapabilities.getNetworkSpecifier());
+ if (SubscriptionManager.INVALID_SUBSCRIPTION_ID == subId) return false;
+ return callingUid == getCarrierServiceUidForSubId(subId);
}
@VisibleForTesting
@@ -286,7 +293,7 @@
if (specifier instanceof TelephonyNetworkSpecifier) {
return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId();
}
- return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
}
@VisibleForTesting
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index b9e2a5f..e917b3f 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -60,6 +60,7 @@
import android.util.SparseArray;
import com.android.internal.util.WakeupMessage;
+import com.android.modules.utils.build.SdkLevel;
import com.android.server.ConnectivityService;
import java.io.PrintWriter;
@@ -1196,21 +1197,26 @@
*
* @param nc the capabilities to sanitize
* @param creatorUid the UID of the process creating this network agent
+ * @param authenticator the carrier privilege authenticator to check for telephony constraints
*/
public static void restrictCapabilitiesFromNetworkAgent(@NonNull final NetworkCapabilities nc,
- final int creatorUid) {
+ final int creatorUid, @NonNull final CarrierPrivilegeAuthenticator authenticator) {
if (nc.hasTransport(TRANSPORT_TEST)) {
nc.restrictCapabilitiesForTestNetwork(creatorUid);
}
- if (!areAccessUidsAcceptableFromNetworkAgent(nc)) {
+ if (!areAccessUidsAcceptableFromNetworkAgent(nc, authenticator)) {
nc.setAccessUids(new ArraySet<>());
}
}
private static boolean areAccessUidsAcceptableFromNetworkAgent(
- @NonNull final NetworkCapabilities nc) {
+ @NonNull final NetworkCapabilities nc,
+ @Nullable final CarrierPrivilegeAuthenticator carrierPrivilegeAuthenticator) {
// NCs without access UIDs are fine.
if (!nc.hasAccessUids()) return true;
+ // S and below must never accept access UIDs, even if an agent sends them, because netd
+ // didn't support the required feature in S.
+ if (!SdkLevel.isAtLeastT()) return false;
// On a non-restricted network, access UIDs make no sense
if (nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) return false;
@@ -1219,7 +1225,18 @@
// access UIDs
if (nc.hasTransport(TRANSPORT_TEST)) return true;
- // TODO : accept more supported cases
+ // Factories that make cell networks can allow the UID for the carrier service package.
+ // This can only work in T where there is support for CarrierPrivilegeAuthenticator
+ if (null != carrierPrivilegeAuthenticator
+ && nc.hasSingleTransport(TRANSPORT_CELLULAR)
+ && (1 == nc.getAccessUidsNoCopy().size())
+ && (carrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
+ nc.getAccessUidsNoCopy().valueAt(0), nc))) {
+ return true;
+ }
+
+ // TODO : accept Railway callers
+
return false;
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index e41a2ac..0132525 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -264,6 +264,7 @@
import android.net.RouteInfo;
import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
+import android.net.TelephonyNetworkSpecifier;
import android.net.TransportInfo;
import android.net.UidRange;
import android.net.UidRangeParcel;
@@ -334,6 +335,7 @@
import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
import com.android.server.ConnectivityService.NetworkRequestInfo;
import com.android.server.ConnectivityServiceTest.ConnectivityServiceDependencies.ReportedInterfaces;
+import com.android.server.connectivity.CarrierPrivilegeAuthenticator;
import com.android.server.connectivity.ConnectivityFlags;
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.Nat464Xlat;
@@ -529,6 +531,7 @@
@Mock Resources mResources;
@Mock PacProxyManager mPacProxyManager;
@Mock BpfNetMaps mBpfNetMaps;
+ @Mock CarrierPrivilegeAuthenticator mCarrierPrivilegeAuthenticator;
// BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
// underlying binder calls.
@@ -970,8 +973,6 @@
* @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET.
*/
public void connect(boolean validated, boolean hasInternet, boolean isStrictMode) {
- assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_INTERNET));
-
ConnectivityManager.NetworkCallback callback = null;
final ConditionVariable validatedCv = new ConditionVariable();
if (validated) {
@@ -1859,6 +1860,12 @@
}
@Override
+ public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator(
+ @NonNull final Context context, @NonNull final TelephonyManager tm) {
+ return SdkLevel.isAtLeastT() ? mCarrierPrivilegeAuthenticator : null;
+ }
+
+ @Override
public boolean intentFilterEquals(final PendingIntent a, final PendingIntent b) {
return runAsShell(GET_INTENT_SENDER_INTENT, () -> a.intentFilterEquals(b));
}
@@ -14643,43 +14650,157 @@
agent.getNetwork().getNetId(),
intToUidRangeStableParcels(uids),
preferenceOrder);
- inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids200Parcel);
+ if (SdkLevel.isAtLeastT()) {
+ inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids200Parcel);
+ }
uids.add(300);
uids.add(400);
nc.setAccessUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
- cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
+ if (SdkLevel.isAtLeastT()) {
+ cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
+ } else {
+ cb.assertNoCallback();
+ }
uids.remove(200);
final NativeUidRangeConfig uids300400Parcel = new NativeUidRangeConfig(
agent.getNetwork().getNetId(),
intToUidRangeStableParcels(uids),
preferenceOrder);
- inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids300400Parcel);
+ if (SdkLevel.isAtLeastT()) {
+ inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids300400Parcel);
+ }
nc.setAccessUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
- cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
- inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids200Parcel);
+ if (SdkLevel.isAtLeastT()) {
+ cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
+ inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids200Parcel);
+ } else {
+ cb.assertNoCallback();
+ }
uids.clear();
uids.add(600);
nc.setAccessUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
- cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
+ if (SdkLevel.isAtLeastT()) {
+ cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
+ } else {
+ cb.assertNoCallback();
+ }
final NativeUidRangeConfig uids600Parcel = new NativeUidRangeConfig(
agent.getNetwork().getNetId(),
intToUidRangeStableParcels(uids),
preferenceOrder);
- inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids600Parcel);
- inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids300400Parcel);
+ if (SdkLevel.isAtLeastT()) {
+ inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids600Parcel);
+ inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids300400Parcel);
+ }
uids.clear();
nc.setAccessUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
- cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().isEmpty());
- inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids600Parcel);
+ if (SdkLevel.isAtLeastT()) {
+ cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().isEmpty());
+ inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids600Parcel);
+ } else {
+ cb.assertNoCallback();
+ verify(mMockNetd, never()).networkAddUidRangesParcel(any());
+ verify(mMockNetd, never()).networkRemoveUidRangesParcel(any());
+ }
+
+ }
+
+ @Test
+ public void testCbsAccessUids() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+ mServiceContext.setPermission(MANAGE_TEST_NETWORKS, PERMISSION_GRANTED);
+
+ // In this test TEST_PACKAGE_UID will be the UID of the carrier service UID.
+ doReturn(true).when(mCarrierPrivilegeAuthenticator)
+ .hasCarrierPrivilegeForNetworkCapabilities(eq(TEST_PACKAGE_UID), any());
+
+ final ArraySet<Integer> serviceUidSet = new ArraySet<>();
+ serviceUidSet.add(TEST_PACKAGE_UID);
+ final ArraySet<Integer> nonServiceUidSet = new ArraySet<>();
+ nonServiceUidSet.add(TEST_PACKAGE_UID2);
+ final ArraySet<Integer> serviceUidSetPlus = new ArraySet<>();
+ serviceUidSetPlus.add(TEST_PACKAGE_UID);
+ serviceUidSetPlus.add(TEST_PACKAGE_UID2);
+
+ final TestNetworkCallback cb = new TestNetworkCallback();
+
+ // Simulate a restricted telephony network. The telephony factory is entitled to set
+ // the access UID to the service package on any of its restricted networks.
+ final NetworkCapabilities.Builder ncb = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .setNetworkSpecifier(new TelephonyNetworkSpecifier(1 /* subid */));
+
+ // Cell gets to set the service UID as access UID
+ mCm.requestNetwork(new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .build(), cb);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR,
+ new LinkProperties(), ncb.build());
+ mCellNetworkAgent.connect(true);
+ cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ ncb.setAccessUids(serviceUidSet);
+ mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
+ if (SdkLevel.isAtLeastT()) {
+ cb.expectCapabilitiesThat(mCellNetworkAgent,
+ caps -> caps.getAccessUids().equals(serviceUidSet));
+ } else {
+ // S must ignore access UIDs.
+ cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
+ }
+
+ // ...but not to some other UID. Rejection sets UIDs to the empty set
+ ncb.setAccessUids(nonServiceUidSet);
+ mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
+ if (SdkLevel.isAtLeastT()) {
+ cb.expectCapabilitiesThat(mCellNetworkAgent,
+ caps -> caps.getAccessUids().isEmpty());
+ } else {
+ // S must ignore access UIDs.
+ cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
+ }
+
+ // ...and also not to multiple UIDs even including the service UID
+ ncb.setAccessUids(serviceUidSetPlus);
+ mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
+ cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
+
+ mCellNetworkAgent.disconnect();
+ cb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ mCm.unregisterNetworkCallback(cb);
+
+ // Must be unset before touching the transports, because remove and add transport types
+ // check the specifier on the builder immediately, contradicting normal builder semantics
+ // TODO : fix the builder
+ ncb.setNetworkSpecifier(null);
+ ncb.removeTransportType(TRANSPORT_CELLULAR);
+ ncb.addTransportType(TRANSPORT_WIFI);
+ // Wifi does not get to set access UID, even to the correct UID
+ mCm.requestNetwork(new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .build(), cb);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI,
+ new LinkProperties(), ncb.build());
+ mWiFiNetworkAgent.connect(true);
+ cb.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+ ncb.setAccessUids(serviceUidSet);
+ mWiFiNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
+ cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
+ mCm.unregisterNetworkCallback(cb);
}
/**
diff --git a/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java
index d193aa9..157507b 100644
--- a/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
@@ -40,7 +41,9 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import com.android.networkstack.apishim.TelephonyManagerShimImpl;
@@ -66,27 +69,25 @@
@RunWith(DevSdkIgnoreRunner.class)
@IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available
public class CarrierPrivilegeAuthenticatorTest {
- private static final String PACKAGE_NAME =
- CarrierPrivilegeAuthenticatorTest.class.getPackage().getName();
- private static final int TEST_SIM_SLOT_INDEX = 0;
- private static final int TEST_SUBSCRIPTION_ID_1 = 2;
- private static final int TEST_SUBSCRIPTION_ID_2 = 3;
+ private static final int SUBSCRIPTION_COUNT = 2;
+ private static final int TEST_SUBSCRIPTION_ID = 1;
@NonNull private final Context mContext;
@NonNull private final TelephonyManager mTelephonyManager;
@NonNull private final TelephonyManagerShimImpl mTelephonyManagerShim;
@NonNull private final PackageManager mPackageManager;
- @NonNull private CarrierPrivilegeAuthenticatorChild mCarrierPrivilegeAuthenticator;
+ @NonNull private TestCarrierPrivilegeAuthenticator mCarrierPrivilegeAuthenticator;
private final int mCarrierConfigPkgUid = 12345;
private final String mTestPkg = "com.android.server.connectivity.test";
- public class CarrierPrivilegeAuthenticatorChild extends CarrierPrivilegeAuthenticator {
- CarrierPrivilegeAuthenticatorChild(@NonNull final Context c,
+ public class TestCarrierPrivilegeAuthenticator extends CarrierPrivilegeAuthenticator {
+ TestCarrierPrivilegeAuthenticator(@NonNull final Context c,
@NonNull final TelephonyManager t) {
super(c, t, mTelephonyManagerShim);
}
@Override
protected int getSlotIndex(int subId) {
+ if (SubscriptionManager.DEFAULT_SUBSCRIPTION_ID == subId) return TEST_SUBSCRIPTION_ID;
return subId;
}
}
@@ -100,7 +101,7 @@
@Before
public void setUp() throws Exception {
- doReturn(2).when(mTelephonyManager).getActiveModemCount();
+ doReturn(SUBSCRIPTION_COUNT).when(mTelephonyManager).getActiveModemCount();
doReturn(mTestPkg).when(mTelephonyManagerShim)
.getCarrierServicePackageNameForLogicalSlot(anyInt());
doReturn(mPackageManager).when(mContext).getPackageManager();
@@ -109,7 +110,7 @@
doReturn(applicationInfo).when(mPackageManager)
.getApplicationInfo(eq(mTestPkg), anyInt());
mCarrierPrivilegeAuthenticator =
- new CarrierPrivilegeAuthenticatorChild(mContext, mTelephonyManager);
+ new TestCarrierPrivilegeAuthenticator(mContext, mTelephonyManager);
}
private IntentFilter getIntentFilter() {
@@ -126,7 +127,6 @@
verify(mTelephonyManagerShim, atLeastOnce())
.addCarrierPrivilegesListener(anyInt(), any(), captor.capture());
} catch (UnsupportedApiLevelException e) {
-
}
return captor.getAllValues();
}
@@ -160,10 +160,10 @@
networkRequestBuilder.addTransportType(TRANSPORT_CELLULAR);
networkRequestBuilder.setNetworkSpecifier(telephonyNetworkSpecifier);
- assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
- mCarrierConfigPkgUid, networkRequestBuilder.build()));
- assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
- mCarrierConfigPkgUid + 1, networkRequestBuilder.build()));
+ assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
+ mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities));
+ assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
+ mCarrierConfigPkgUid + 1, networkRequestBuilder.build().networkCapabilities));
}
@Test
@@ -192,10 +192,10 @@
final NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
networkRequestBuilder.addTransportType(TRANSPORT_CELLULAR);
networkRequestBuilder.setNetworkSpecifier(telephonyNetworkSpecifier);
- assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
- mCarrierConfigPkgUid, networkRequestBuilder.build()));
- assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
- mCarrierConfigPkgUid + 1, networkRequestBuilder.build()));
+ assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
+ mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities));
+ assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
+ mCarrierConfigPkgUid + 1, networkRequestBuilder.build().networkCapabilities));
}
@Test
@@ -215,9 +215,30 @@
.getApplicationInfo(eq(mTestPkg), anyInt());
listener.onCarrierPrivilegesChanged(Collections.emptyList(), new int[] {});
- assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
- mCarrierConfigPkgUid, networkRequestBuilder.build()));
- assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(
- mCarrierConfigPkgUid + 1, networkRequestBuilder.build()));
+ assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
+ mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities));
+ assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
+ mCarrierConfigPkgUid + 1, networkRequestBuilder.build().networkCapabilities));
+ }
+
+ @Test
+ public void testDefaultSubscription() throws Exception {
+ final NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
+ networkRequestBuilder.addTransportType(TRANSPORT_CELLULAR);
+ assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
+ mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities));
+
+ networkRequestBuilder.setNetworkSpecifier(new TelephonyNetworkSpecifier(0));
+ assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
+ mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities));
+
+ // The builder for NetworkRequest doesn't allow removing the transport as long as a
+ // specifier is set, so unset it first. TODO : fix the builder
+ networkRequestBuilder.setNetworkSpecifier((NetworkSpecifier) null);
+ networkRequestBuilder.removeTransportType(TRANSPORT_CELLULAR);
+ networkRequestBuilder.addTransportType(TRANSPORT_WIFI);
+ networkRequestBuilder.setNetworkSpecifier(new TelephonyNetworkSpecifier(0));
+ assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
+ mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities));
}
}