From 7cabd32bc5a761a0374e5220fae91e2653efaa09 Mon Sep 17 00:00:00 2001 From: Ying Xu <yinxu@google.com> Date: Mon, 15 Jan 2024 18:40:15 -0800 Subject: [PATCH] Support bringing up restricted wifi This CL allows the Carrier Config app to request restricted WiFi nework by setting the correspoding subscription ID in the network request. Bug: 315835605 Test: atest android.net.cts.NetworkRequestTest atest ConnectivityCoverageTests:android.net.connectivity.com.android.server.connectivity.CarrierPrivilegeAuthenticatorTest atest ConnectivityCoverageTests:android.net.connectivity.com.android.server.ConnectivityServiceTest Change-Id: I237e692d092ff5f969ce4b7962f6d58099a6f3a9 --- framework/api/current.txt | 3 + framework/api/system-current.txt | 2 - .../src/android/net/NetworkCapabilities.java | 5 +- framework/src/android/net/NetworkRequest.java | 23 ++- .../android/server/ConnectivityService.java | 112 ++++++++++++-- .../CarrierPrivilegeAuthenticator.java | 50 +++++- .../connectivity/ConnectivityFlags.java | 2 + .../server/connectivity/NetworkAgentInfo.java | 4 +- .../ConnectivityServiceIntegrationTest.kt | 8 +- .../server/ConnectivityServiceTest.java | 143 +++++++++++++++++- .../CarrierPrivilegeAuthenticatorTest.java | 54 ++++++- .../server/connectivityservice/base/CSTest.kt | 7 +- 12 files changed, 382 insertions(+), 31 deletions(-) diff --git a/framework/api/current.txt b/framework/api/current.txt index 554301b0c1..b23bd9138b 100644 --- a/framework/api/current.txt +++ b/framework/api/current.txt @@ -315,6 +315,7 @@ package android.net { method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier(); method public int getOwnerUid(); method public int getSignalStrength(); + method @FlaggedApi("com.android.net.flags.request_restricted_wifi") @NonNull public java.util.Set<java.lang.Integer> getSubscriptionIds(); method @Nullable public android.net.TransportInfo getTransportInfo(); method public boolean hasCapability(int); method public boolean hasEnterpriseId(int); @@ -419,6 +420,7 @@ package android.net { method public int describeContents(); method @NonNull public int[] getCapabilities(); method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier(); + method @FlaggedApi("com.android.net.flags.request_restricted_wifi") @NonNull public java.util.Set<java.lang.Integer> getSubscriptionIds(); method @NonNull public int[] getTransportTypes(); method public boolean hasCapability(int); method public boolean hasTransport(int); @@ -438,6 +440,7 @@ package android.net { method @NonNull public android.net.NetworkRequest.Builder setIncludeOtherUidNetworks(boolean); method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String); method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier); + method @FlaggedApi("com.android.net.flags.request_restricted_wifi") @NonNull public android.net.NetworkRequest.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>); } public class ParseException extends java.lang.RuntimeException { diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt index e812024a70..bef29a4283 100644 --- a/framework/api/system-current.txt +++ b/framework/api/system-current.txt @@ -307,7 +307,6 @@ package android.net { method @NonNull public int[] getAdministratorUids(); method @Nullable public static String getCapabilityCarrierName(int); method @Nullable public String getSsid(); - method @NonNull public java.util.Set<java.lang.Integer> getSubscriptionIds(); method @NonNull public int[] getTransportTypes(); method @Nullable public java.util.List<android.net.Network> getUnderlyingNetworks(); method public boolean isPrivateDnsBroken(); @@ -373,7 +372,6 @@ package android.net { public static class NetworkRequest.Builder { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int); - method @NonNull public android.net.NetworkRequest.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>); } public final class NetworkScore implements android.os.Parcelable { diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java index 8d9a844804..d7766bb0af 100644 --- a/framework/src/android/net/NetworkCapabilities.java +++ b/framework/src/android/net/NetworkCapabilities.java @@ -130,6 +130,8 @@ public final class NetworkCapabilities implements Parcelable { "com.android.net.flags.forbidden_capability"; static final String FLAG_NET_CAPABILITY_LOCAL_NETWORK = "com.android.net.flags.net_capability_local_network"; + static final String REQUEST_RESTRICTED_WIFI = + "com.android.net.flags.request_restricted_wifi"; } /** @@ -2790,10 +2792,9 @@ public final class NetworkCapabilities implements Parcelable { * receiver holds the NETWORK_FACTORY permission. In all other cases, it will be the empty set. * * @return - * @hide */ @NonNull - @SystemApi + @FlaggedApi(Flags.REQUEST_RESTRICTED_WIFI) public Set<Integer> getSubscriptionIds() { return new ArraySet<>(mSubIds); } diff --git a/framework/src/android/net/NetworkRequest.java b/framework/src/android/net/NetworkRequest.java index 653e41dc3b..4de02acefd 100644 --- a/framework/src/android/net/NetworkRequest.java +++ b/framework/src/android/net/NetworkRequest.java @@ -34,6 +34,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.TRANSPORT_TEST; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -145,6 +146,12 @@ import java.util.Set; * Look up the specific capability to learn whether its usage requires this self-certification. */ public class NetworkRequest implements Parcelable { + + /** @hide */ + public static class Flags { + static final String REQUEST_RESTRICTED_WIFI = + "com.android.net.flags.request_restricted_wifi"; + } /** * The first requestId value that will be allocated. * @hide only used by ConnectivityService. @@ -630,10 +637,9 @@ public class NetworkRequest implements Parcelable { * NETWORK_FACTORY permission. * * @param subIds A {@code Set} that represents subscription IDs. - * @hide */ @NonNull - @SystemApi + @FlaggedApi(Flags.REQUEST_RESTRICTED_WIFI) public Builder setSubscriptionIds(@NonNull Set<Integer> subIds) { mNetworkCapabilities.setSubscriptionIds(subIds); return this; @@ -890,4 +896,17 @@ public class NetworkRequest implements Parcelable { // a new array. return networkCapabilities.getTransportTypes(); } + + /** + * Gets all the subscription ids set on this {@code NetworkRequest} instance. + * + * @return Set of Integer values for this instance. + */ + @NonNull + @FlaggedApi(Flags.REQUEST_RESTRICTED_WIFI) + public Set<Integer> getSubscriptionIds() { + // No need to make a defensive copy here as NC#getSubscriptionIds() already returns + // a new set. + return networkCapabilities.getSubscriptionIds(); + } } diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 52f890d2b2..0974e4b5ca 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -113,6 +113,8 @@ import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPer import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr; import static com.android.net.module.util.PermissionUtils.hasAnyPermissionOf; import static com.android.server.ConnectivityStatsLog.CONNECTIVITY_STATE_SAMPLE; +import static com.android.server.connectivity.CarrierPrivilegeAuthenticator.CarrierPrivilegesLostListener; +import static com.android.server.connectivity.ConnectivityFlags.REQUEST_RESTRICTED_WIFI; import android.Manifest; import android.annotation.CheckResult; @@ -467,6 +469,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private volatile boolean mLockdownEnabled; + private final boolean mRequestRestrictedWifiEnabled; + /** * Stale copy of uid blocked reasons provided by NPMS. As long as they are accessed only in * internal handler thread, they don't need a lock. @@ -831,6 +835,11 @@ public class ConnectivityService extends IConnectivityManager.Stub */ private static final int EVENT_UID_FROZEN_STATE_CHANGED = 61; + /** + * Event to inform the ConnectivityService handler when a uid has lost carrier privileges. + */ + private static final int EVENT_UID_CARRIER_PRIVILEGES_LOST = 62; + /** * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification * should be shown. @@ -1270,6 +1279,18 @@ public class ConnectivityService extends IConnectivityManager.Stub } private final LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker(this); + private final CarrierPrivilegesLostListenerImpl mCarrierPrivilegesLostListenerImpl = + new CarrierPrivilegesLostListenerImpl(); + + private class CarrierPrivilegesLostListenerImpl implements CarrierPrivilegesLostListener { + @Override + public void onCarrierPrivilegesLost(int uid) { + if (mRequestRestrictedWifiEnabled) { + mHandler.sendMessage(mHandler.obtainMessage( + EVENT_UID_CARRIER_PRIVILEGES_LOST, uid, 0 /* arg2 */)); + } + } + } final LocalPriorityDump mPriorityDumper = new LocalPriorityDump(); /** * Helper class which parses out priority arguments and dumps sections according to their @@ -1328,6 +1349,11 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + @VisibleForTesting + CarrierPrivilegesLostListener getCarrierPrivilegesLostListener() { + return mCarrierPrivilegesLostListenerImpl; + } + /** * Dependencies of ConnectivityService, for injection in tests. */ @@ -1488,9 +1514,13 @@ public class ConnectivityService extends IConnectivityManager.Stub */ @Nullable public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator( - @NonNull final Context context, @NonNull final TelephonyManager tm) { + @NonNull final Context context, + @NonNull final TelephonyManager tm, + boolean requestRestrictedWifiEnabled, + @NonNull CarrierPrivilegesLostListener listener) { if (isAtLeastT()) { - return new CarrierPrivilegeAuthenticator(context, tm); + return new CarrierPrivilegeAuthenticator( + context, tm, requestRestrictedWifiEnabled, listener); } else { return null; } @@ -1759,8 +1789,11 @@ public class ConnectivityService extends IConnectivityManager.Stub mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext); - mCarrierPrivilegeAuthenticator = - mDeps.makeCarrierPrivilegeAuthenticator(mContext, mTelephonyManager); + mRequestRestrictedWifiEnabled = mDeps.isAtLeastU() + && mDeps.isFeatureEnabled(context, REQUEST_RESTRICTED_WIFI); + mCarrierPrivilegeAuthenticator = mDeps.makeCarrierPrivilegeAuthenticator( + mContext, mTelephonyManager, mRequestRestrictedWifiEnabled, + mCarrierPrivilegesLostListenerImpl); // To ensure uid state is synchronized with Network Policy, register for // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService @@ -6410,6 +6443,9 @@ public class ConnectivityService extends IConnectivityManager.Stub UidFrozenStateChangedArgs args = (UidFrozenStateChangedArgs) msg.obj; handleFrozenUids(args.mUids, args.mFrozenStates); break; + case EVENT_UID_CARRIER_PRIVILEGES_LOST: + handleUidCarrierPrivilegesLost(msg.arg1); + break; } } } @@ -7490,9 +7526,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } mAppOpsManager.checkPackage(callerUid, callerPackageName); - if (!nc.getSubscriptionIds().isEmpty()) { - enforceNetworkFactoryPermission(); + if (nc.getSubscriptionIds().isEmpty()) { + return; } + if (mRequestRestrictedWifiEnabled + && canRequestRestrictedNetworkDueToCarrierPrivileges(nc, callerUid)) { + return; + } + enforceNetworkFactoryPermission(); } private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) { @@ -7772,6 +7813,22 @@ public class ConnectivityService extends IConnectivityManager.Stub applicationNetworkCapabilities.enforceSelfCertifiedNetworkCapabilitiesDeclared( networkCapabilities); } + + private boolean canRequestRestrictedNetworkDueToCarrierPrivileges( + NetworkCapabilities networkCapabilities, int callingUid) { + if (mRequestRestrictedWifiEnabled) { + // For U+ devices, callers with carrier privilege could request restricted networks + // with CBS capabilities, or any restricted WiFi networks. + return ((networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS) + || networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) + && hasCarrierPrivilegeForNetworkCaps(callingUid, networkCapabilities)); + } else { + // For T+ devices, callers with carrier privilege could request with CBS + // capabilities. + return (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS) + && hasCarrierPrivilegeForNetworkCaps(callingUid, networkCapabilities)); + } + } private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities, String callingPackageName, String callingAttributionTag, final int callingUid) { if (shouldCheckCapabilitiesDeclaration(networkCapabilities, callingUid, @@ -7779,13 +7836,11 @@ public class ConnectivityService extends IConnectivityManager.Stub enforceRequestCapabilitiesDeclaration(callingPackageName, networkCapabilities, callingUid); } - if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) == false) { - // For T+ devices, callers with carrier privilege could request with CBS capabilities. - if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS) - && hasCarrierPrivilegeForNetworkCaps(callingUid, networkCapabilities)) { - return; + if (!networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) { + if (!canRequestRestrictedNetworkDueToCarrierPrivileges( + networkCapabilities, callingUid)) { + enforceConnectivityRestrictedNetworksPermission(true /* checkUidsAllowedList */); } - enforceConnectivityRestrictedNetworksPermission(true /* checkUidsAllowedList */); } else { enforceChangePermission(callingPackageName, callingAttributionTag); } @@ -9052,6 +9107,38 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void handleUidCarrierPrivilegesLost(int uid) { + ensureRunningOnConnectivityServiceThread(); + // A NetworkRequest needs to be revoked when all the conditions are met + // 1. It requests restricted network + // 2. The requestor uid matches the uid with the callback + // 3. The app doesn't have Carrier Privileges + // 4. The app doesn't have permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS + for (final NetworkRequest nr : mNetworkRequests.keySet()) { + if ((nr.isRequest() || nr.isListen()) + && !nr.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) + && nr.getRequestorUid() == uid + && !hasConnectivityRestrictedNetworksPermission(uid, true)) { + declareNetworkRequestUnfulfillable(nr); + } + } + + // A NetworkAgent's allowedUids may need to be updated if the app has lost + // carrier config + for (final NetworkAgentInfo nai : mNetworkAgentInfos) { + if (nai.networkCapabilities.getAllowedUidsNoCopy().contains(uid)) { + final NetworkCapabilities nc = new NetworkCapabilities(nai.networkCapabilities); + NetworkAgentInfo.restrictCapabilitiesFromNetworkAgent( + nc, + uid, + false /* hasAutomotiveFeature (irrelevant) */, + mDeps, + mCarrierPrivilegeAuthenticator); + updateCapabilities(nai.getScore(), nai, nc); + } + } + } + /** * Update the NetworkCapabilities for {@code nai} to {@code nc}. Specifically: * @@ -9499,7 +9586,6 @@ public class ConnectivityService extends IConnectivityManager.Stub final ArraySet<Integer> toAdd = new ArraySet<>(newUids); toRemove.removeAll(newUids); toAdd.removeAll(prevUids); - try { if (!toAdd.isEmpty()) { mNetd.networkAddUidRangesParcel(new NativeUidRangeConfig( diff --git a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java index 5705ebe6dc..533278e3ac 100644 --- a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java +++ b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java @@ -79,11 +79,16 @@ public class CarrierPrivilegeAuthenticator { @NonNull private final List<PrivilegeListener> mCarrierPrivilegesChangedListeners = new ArrayList<>(); private final boolean mUseCallbacksForServiceChanged; + private final boolean mRequestRestrictedWifiEnabled; + @NonNull + private final CarrierPrivilegesLostListener mListener; public CarrierPrivilegeAuthenticator(@NonNull final Context c, @NonNull final Dependencies deps, @NonNull final TelephonyManager t, - @NonNull final TelephonyManagerShim telephonyManagerShim) { + @NonNull final TelephonyManagerShim telephonyManagerShim, + final boolean requestRestrictedWifiEnabled, + @NonNull CarrierPrivilegesLostListener listener) { mContext = c; mTelephonyManager = t; mTelephonyManagerShim = telephonyManagerShim; @@ -92,6 +97,8 @@ public class CarrierPrivilegeAuthenticator { mHandler = new Handler(thread.getLooper()); mUseCallbacksForServiceChanged = deps.isFeatureEnabled( c, CARRIER_SERVICE_CHANGED_USE_CALLBACK); + mRequestRestrictedWifiEnabled = requestRestrictedWifiEnabled; + mListener = listener; final IntentFilter filter = new IntentFilter(); filter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED); synchronized (mLock) { @@ -113,8 +120,10 @@ public class CarrierPrivilegeAuthenticator { } public CarrierPrivilegeAuthenticator(@NonNull final Context c, - @NonNull final TelephonyManager t) { - this(c, new Dependencies(), t, TelephonyManagerShimImpl.newInstance(t)); + @NonNull final TelephonyManager t, final boolean requestRestrictedWifiEnabled, + @NonNull CarrierPrivilegesLostListener listener) { + this(c, new Dependencies(), t, TelephonyManagerShimImpl.newInstance(t), + requestRestrictedWifiEnabled, listener); } public static class Dependencies { @@ -133,6 +142,18 @@ public class CarrierPrivilegeAuthenticator { } } + /** + * Listener interface to get a notification when the carrier App lost its privileges. + */ + public interface CarrierPrivilegesLostListener { + /** + * Called when the carrier App lost its privileges. + * + * @param uid The uid of the carrier app which has lost its privileges. + */ + void onCarrierPrivilegesLost(int uid); + } + private void simConfigChanged() { synchronized (mLock) { unregisterCarrierPrivilegesListeners(); @@ -171,7 +192,11 @@ public class CarrierPrivilegeAuthenticator { return; } synchronized (mLock) { + int oldUid = mCarrierServiceUid.get(mLogicalSlot); mCarrierServiceUid.put(mLogicalSlot, carrierServiceUid); + if (oldUid != 0 && oldUid != carrierServiceUid) { + mListener.onCarrierPrivilegesLost(oldUid); + } } } } @@ -193,7 +218,11 @@ public class CarrierPrivilegeAuthenticator { private void unregisterCarrierPrivilegesListeners() { for (PrivilegeListener carrierPrivilegesListener : mCarrierPrivilegesChangedListeners) { removeCarrierPrivilegesListener(carrierPrivilegesListener); + int oldUid = mCarrierServiceUid.get(carrierPrivilegesListener.mLogicalSlot); mCarrierServiceUid.delete(carrierPrivilegesListener.mLogicalSlot); + if (oldUid != 0) { + mListener.onCarrierPrivilegesLost(oldUid); + } } mCarrierPrivilegesChangedListeners.clear(); } @@ -231,7 +260,7 @@ public class CarrierPrivilegeAuthenticator { public boolean isCarrierServiceUidForNetworkCapabilities(int callingUid, @NonNull NetworkCapabilities networkCapabilities) { if (callingUid == Process.INVALID_UID) return false; - final int subId; + int subId; if (networkCapabilities.hasSingleTransportBesidesTest(TRANSPORT_CELLULAR)) { subId = getSubIdFromTelephonySpecifier(networkCapabilities.getNetworkSpecifier()); } else if (networkCapabilities.hasSingleTransportBesidesTest(TRANSPORT_WIFI)) { @@ -239,6 +268,12 @@ public class CarrierPrivilegeAuthenticator { } else { subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; } + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID + && mRequestRestrictedWifiEnabled + && networkCapabilities.getSubscriptionIds().size() == 1) { + subId = networkCapabilities.getSubscriptionIds().toArray(new Integer[0])[0]; + } + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && !networkCapabilities.getSubscriptionIds().contains(subId)) { // Ideally, the code above should just use networkCapabilities.getSubscriptionIds() @@ -257,10 +292,16 @@ public class CarrierPrivilegeAuthenticator { @VisibleForTesting void updateCarrierServiceUid() { synchronized (mLock) { + SparseIntArray oldCarrierServiceUid = mCarrierServiceUid.clone(); mCarrierServiceUid.clear(); for (int i = 0; i < mModemCount; i++) { mCarrierServiceUid.put(i, getCarrierServicePackageUidForSlot(i)); } + for (int i = 0; i < oldCarrierServiceUid.size(); i++) { + if (mCarrierServiceUid.indexOfValue(oldCarrierServiceUid.valueAt(i)) < 0) { + mListener.onCarrierPrivilegesLost(oldCarrierServiceUid.valueAt(i)); + } + } } } @@ -340,6 +381,7 @@ public class CarrierPrivilegeAuthenticator { public void dump(IndentingPrintWriter pw) { pw.println("CarrierPrivilegeAuthenticator:"); + pw.println("mRequestRestrictedWifiEnabled = " + mRequestRestrictedWifiEnabled); synchronized (mLock) { final int size = mCarrierServiceUid.size(); for (int i = 0; i < size; ++i) { diff --git a/service/src/com/android/server/connectivity/ConnectivityFlags.java b/service/src/com/android/server/connectivity/ConnectivityFlags.java index f8f76ef443..bf09160289 100644 --- a/service/src/com/android/server/connectivity/ConnectivityFlags.java +++ b/service/src/com/android/server/connectivity/ConnectivityFlags.java @@ -36,6 +36,8 @@ public final class ConnectivityFlags { public static final String CARRIER_SERVICE_CHANGED_USE_CALLBACK = "carrier_service_changed_use_callback_version"; + public static final String REQUEST_RESTRICTED_WIFI = + "request_restricted_wifi"; private boolean mNoRematchAllRequestsOnRegister; /** diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java index 50cad45bbe..76993a6756 100644 --- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java +++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java @@ -1551,7 +1551,7 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable { * @param hasAutomotiveFeature true if this device has the automotive feature, false otherwise * @param authenticator the carrier privilege authenticator to check for telephony constraints */ - public void restrictCapabilitiesFromNetworkAgent(@NonNull final NetworkCapabilities nc, + public static void restrictCapabilitiesFromNetworkAgent(@NonNull final NetworkCapabilities nc, final int creatorUid, final boolean hasAutomotiveFeature, @NonNull final ConnectivityService.Dependencies deps, @Nullable final CarrierPrivilegeAuthenticator authenticator) { @@ -1564,7 +1564,7 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable { } } - private boolean areAllowedUidsAcceptableFromNetworkAgent( + private static boolean areAllowedUidsAcceptableFromNetworkAgent( @NonNull final NetworkCapabilities nc, final boolean hasAutomotiveFeature, @NonNull final ConnectivityService.Dependencies deps, @Nullable final CarrierPrivilegeAuthenticator carrierPrivilegeAuthenticator) { diff --git a/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index 9b1bf6e4ea..117e489eeb 100644 --- a/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt @@ -56,6 +56,7 @@ import com.android.server.ConnectivityService import com.android.server.NetworkAgentWrapper import com.android.server.TestNetIdManager import com.android.server.connectivity.CarrierPrivilegeAuthenticator +import com.android.server.connectivity.CarrierPrivilegeAuthenticator.CarrierPrivilegesLostListener import com.android.server.connectivity.ConnectivityResources import com.android.server.connectivity.MockableSystemProperties import com.android.server.connectivity.MultinetworkPolicyTracker @@ -240,14 +241,17 @@ class ConnectivityServiceIntegrationTest { override fun makeCarrierPrivilegeAuthenticator( context: Context, - tm: TelephonyManager + tm: TelephonyManager, + requestRestrictedWifiEnabled: Boolean, + listener: CarrierPrivilegesLostListener ): CarrierPrivilegeAuthenticator { return CarrierPrivilegeAuthenticator(context, object : CarrierPrivilegeAuthenticator.Dependencies() { override fun makeHandlerThread(): HandlerThread = super.makeHandlerThread().also { handlerThreads.add(it) } }, - tm, TelephonyManagerShimImpl.newInstance(tm)) + tm, TelephonyManagerShimImpl.newInstance(tm), + requestRestrictedWifiEnabled, listener) } } diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index 5562b6706b..9e34b7c754 100755 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -172,6 +172,7 @@ import static com.android.server.ConnectivityService.makeNflogPrefix; import static com.android.server.ConnectivityServiceTestUtils.transportToLegacyType; import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackRegister; import static com.android.server.NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister; +import static com.android.server.connectivity.CarrierPrivilegeAuthenticator.CarrierPrivilegesLostListener; import static com.android.testutils.Cleanup.testAndCleanup; import static com.android.testutils.ConcurrentUtils.await; import static com.android.testutils.ConcurrentUtils.durationOf; @@ -2053,7 +2054,9 @@ public class ConnectivityServiceTest { @Override public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator( @NonNull final Context context, - @NonNull final TelephonyManager tm) { + @NonNull final TelephonyManager tm, + final boolean requestRestrictedWifiEnabled, + CarrierPrivilegesLostListener listener) { return mDeps.isAtLeastT() ? mCarrierPrivilegeAuthenticator : null; } @@ -2147,6 +2150,8 @@ public class ConnectivityServiceTest { case ConnectivityFlags.NO_REMATCH_ALL_REQUESTS_ON_REGISTER: case ConnectivityFlags.CARRIER_SERVICE_CHANGED_USE_CALLBACK: return true; + case ConnectivityFlags.REQUEST_RESTRICTED_WIFI: + return true; case KEY_DESTROY_FROZEN_SOCKETS_VERSION: return true; case DELAY_DESTROY_FROZEN_SOCKETS_VERSION: @@ -17353,6 +17358,14 @@ public class ConnectivityServiceTest { .build(); } + private NetworkRequest getRestrictedRequestForWifiWithSubIds() { + return new NetworkRequest.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .setSubscriptionIds(Collections.singleton(Process.myUid())) + .build(); + } + @Test public void testNetworkRequestWithSubIdsWithNetworkFactoryPermission() throws Exception { mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED); @@ -17385,6 +17398,134 @@ public class ConnectivityServiceTest { () -> mCm.registerNetworkCallback(getRequestWithSubIds(), new NetworkCallback())); } + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testCarrierConfigAppSendNetworkRequestForRestrictedWifi() throws Exception { + mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_DENIED); + doReturn(true).when(mCarrierPrivilegeAuthenticator) + .isCarrierServiceUidForNetworkCapabilities(anyInt(), any()); + final PendingIntent pendingIntent = PendingIntent.getBroadcast( + mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE); + final NetworkCallback networkCallback1 = new NetworkCallback(); + final NetworkCallback networkCallback2 = new NetworkCallback(); + + mCm.requestNetwork(getRestrictedRequestForWifiWithSubIds(), networkCallback1); + mCm.requestNetwork(getRestrictedRequestForWifiWithSubIds(), pendingIntent); + mCm.registerNetworkCallback(getRestrictedRequestForWifiWithSubIds(), networkCallback2); + + mCm.unregisterNetworkCallback(networkCallback1); + mCm.releaseNetworkRequest(pendingIntent); + mCm.unregisterNetworkCallback(networkCallback2); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testRestrictedRequestRemovedDueToCarrierPrivilegesLost() throws Exception { + mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_DENIED); + NetworkCapabilities filter = getRestrictedRequestForWifiWithSubIds().networkCapabilities; + final HandlerThread handlerThread = new HandlerThread("testRestrictedFactoryRequests"); + handlerThread.start(); + final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), + mServiceContext, "testFactory", filter, mCsHandlerThread); + testFactory.register(); + + testFactory.assertRequestCountEquals(0); + doReturn(true).when(mCarrierPrivilegeAuthenticator) + .isCarrierServiceUidForNetworkCapabilities(eq(Process.myUid()), any()); + final TestNetworkCallback networkCallback1 = new TestNetworkCallback(); + final NetworkRequest networkrequest1 = getRestrictedRequestForWifiWithSubIds(); + mCm.requestNetwork(networkrequest1, networkCallback1); + testFactory.expectRequestAdd(); + testFactory.assertRequestCountEquals(1); + + NetworkCapabilities nc = new NetworkCapabilities.Builder(filter) + .setAllowedUids(Set.of(Process.myUid())) + .build(); + mWiFiAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), nc); + mWiFiAgent.connect(true); + networkCallback1.expectAvailableThenValidatedCallbacks(mWiFiAgent); + + final NetworkAgentInfo nai = mService.getNetworkAgentInfoForNetwork( + mWiFiAgent.getNetwork()); + + doReturn(false).when(mCarrierPrivilegeAuthenticator) + .isCarrierServiceUidForNetworkCapabilities(eq(Process.myUid()), any()); + final CarrierPrivilegesLostListener carrierPrivilegesLostListener = + mService.getCarrierPrivilegesLostListener(); + carrierPrivilegesLostListener.onCarrierPrivilegesLost(Process.myUid()); + waitForIdle(); + + testFactory.expectRequestRemove(); + testFactory.assertRequestCountEquals(0); + assertTrue(nai.networkCapabilities.getAllowedUidsNoCopy().isEmpty()); + networkCallback1.expect(NETWORK_CAPS_UPDATED); + networkCallback1.expect(UNAVAILABLE); + + handlerThread.quitSafely(); + handlerThread.join(); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testRequestNotRemoved_MismatchUid() throws Exception { + mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_DENIED); + NetworkCapabilities filter = getRestrictedRequestForWifiWithSubIds().networkCapabilities; + final HandlerThread handlerThread = new HandlerThread("testRestrictedFactoryRequests"); + handlerThread.start(); + + final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), + mServiceContext, "testFactory", filter, mCsHandlerThread); + testFactory.register(); + + doReturn(true).when(mCarrierPrivilegeAuthenticator) + .isCarrierServiceUidForNetworkCapabilities(anyInt(), any()); + final TestNetworkCallback networkCallback1 = new TestNetworkCallback(); + final NetworkRequest networkrequest1 = getRestrictedRequestForWifiWithSubIds(); + mCm.requestNetwork(networkrequest1, networkCallback1); + testFactory.expectRequestAdd(); + testFactory.assertRequestCountEquals(1); + + doReturn(false).when(mCarrierPrivilegeAuthenticator) + .isCarrierServiceUidForNetworkCapabilities(eq(Process.myUid()), any()); + final CarrierPrivilegesLostListener carrierPrivilegesLostListener = + mService.getCarrierPrivilegesLostListener(); + carrierPrivilegesLostListener.onCarrierPrivilegesLost(Process.myUid() + 1); + expectNoRequestChanged(testFactory); + + handlerThread.quitSafely(); + handlerThread.join(); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testRequestNotRemoved_HasRestrictedNetworkPermission() throws Exception { + mServiceContext.setPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, PERMISSION_GRANTED); + NetworkCapabilities filter = getRestrictedRequestForWifiWithSubIds().networkCapabilities; + final HandlerThread handlerThread = new HandlerThread("testRestrictedFactoryRequests"); + handlerThread.start(); + + final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), + mServiceContext, "testFactory", filter, mCsHandlerThread); + testFactory.register(); + + doReturn(true).when(mCarrierPrivilegeAuthenticator) + .isCarrierServiceUidForNetworkCapabilities(anyInt(), any()); + final TestNetworkCallback networkCallback1 = new TestNetworkCallback(); + final NetworkRequest networkrequest1 = getRestrictedRequestForWifiWithSubIds(); + mCm.requestNetwork(networkrequest1, networkCallback1); + testFactory.expectRequestAdd(); + testFactory.assertRequestCountEquals(1); + + doReturn(false).when(mCarrierPrivilegeAuthenticator) + .isCarrierServiceUidForNetworkCapabilities(eq(Process.myUid()), any()); + final CarrierPrivilegesLostListener carrierPrivilegesLostListener = + mService.getCarrierPrivilegesLostListener(); + carrierPrivilegesLostListener.onCarrierPrivilegesLost(Process.myUid()); + expectNoRequestChanged(testFactory); + + handlerThread.quitSafely(); + handlerThread.join(); + } @Test public void testAllowedUids() throws Exception { final int preferenceOrder = diff --git a/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java index f07593e99e..9f0ec3059f 100644 --- a/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java +++ b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java @@ -20,6 +20,7 @@ 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.server.connectivity.CarrierPrivilegeAuthenticator.CarrierPrivilegesLostListener; import static com.android.server.connectivity.ConnectivityFlags.CARRIER_SERVICE_CHANGED_USE_CALLBACK; import static org.junit.Assert.assertEquals; @@ -54,10 +55,12 @@ import com.android.networkstack.apishim.TelephonyManagerShimImpl; import com.android.networkstack.apishim.common.TelephonyManagerShim.CarrierPrivilegesListenerShim; import com.android.networkstack.apishim.common.UnsupportedApiLevelException; import com.android.server.connectivity.CarrierPrivilegeAuthenticator.Dependencies; +import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import com.android.testutils.DevSdkIgnoreRunner; import org.junit.After; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -67,6 +70,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.Set; /** * Tests for CarrierPrivilegeAuthenticatorTest. @@ -77,6 +81,9 @@ import java.util.Map; @RunWith(DevSdkIgnoreRunner.class) @IgnoreUpTo(Build.VERSION_CODES.S_V2) public class CarrierPrivilegeAuthenticatorTest { + @Rule + public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule(); + private static final int SUBSCRIPTION_COUNT = 2; private static final int TEST_SUBSCRIPTION_ID = 1; @@ -85,7 +92,9 @@ public class CarrierPrivilegeAuthenticatorTest { @NonNull private final TelephonyManagerShimImpl mTelephonyManagerShim; @NonNull private final PackageManager mPackageManager; @NonNull private TestCarrierPrivilegeAuthenticator mCarrierPrivilegeAuthenticator; + @NonNull private final CarrierPrivilegesLostListener mListener; private final int mCarrierConfigPkgUid = 12345; + private final boolean mUseCallbacks; private final String mTestPkg = "com.android.server.connectivity.test"; private final BroadcastReceiver mMultiSimBroadcastReceiver; @NonNull private final HandlerThread mHandlerThread; @@ -94,7 +103,8 @@ public class CarrierPrivilegeAuthenticatorTest { TestCarrierPrivilegeAuthenticator(@NonNull final Context c, @NonNull final Dependencies deps, @NonNull final TelephonyManager t) { - super(c, deps, t, mTelephonyManagerShim); + super(c, deps, t, mTelephonyManagerShim, true /* requestRestrictedWifiEnabled */, + mListener); } @Override protected int getSlotIndex(int subId) { @@ -119,7 +129,9 @@ public class CarrierPrivilegeAuthenticatorTest { mTelephonyManager = mock(TelephonyManager.class); mTelephonyManagerShim = mock(TelephonyManagerShimImpl.class); mPackageManager = mock(PackageManager.class); + mListener = mock(CarrierPrivilegesLostListener.class); mHandlerThread = new HandlerThread(CarrierPrivilegeAuthenticatorTest.class.getSimpleName()); + mUseCallbacks = useCallbacks; final Dependencies deps = mock(Dependencies.class); doReturn(useCallbacks).when(deps).isFeatureEnabled(any() /* context */, eq(CARRIER_SERVICE_CHANGED_USE_CALLBACK)); @@ -219,6 +231,18 @@ public class CarrierPrivilegeAuthenticatorTest { mCarrierConfigPkgUid + 1, nc)); } + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testCarrierPrivilegesLostDueToCarrierServiceUpdate() throws Exception { + final CarrierPrivilegesListenerShim l = getCarrierPrivilegesListeners().get(0); + + l.onCarrierServiceChanged(null, mCarrierConfigPkgUid); + l.onCarrierServiceChanged(null, mCarrierConfigPkgUid + 1); + if (mUseCallbacks) { + verify(mListener).onCarrierPrivilegesLost(eq(mCarrierConfigPkgUid)); + } + } + @Test public void testOnCarrierPrivilegesChanged() throws Exception { final CarrierPrivilegesListenerShim listener = getCarrierPrivilegesListeners().get(0); @@ -264,4 +288,32 @@ public class CarrierPrivilegeAuthenticatorTest { assertFalse(mCarrierPrivilegeAuthenticator.isCarrierServiceUidForNetworkCapabilities( mCarrierConfigPkgUid, ncBuilder.build())); } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testNetworkCapabilitiesContainOneSubId() throws Exception { + final CarrierPrivilegesListenerShim listener = getCarrierPrivilegesListeners().get(0); + listener.onCarrierServiceChanged(null, mCarrierConfigPkgUid); + + final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder(); + ncBuilder.addTransportType(TRANSPORT_WIFI); + ncBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + ncBuilder.setSubscriptionIds(Set.of(0)); + assertTrue(mCarrierPrivilegeAuthenticator.isCarrierServiceUidForNetworkCapabilities( + mCarrierConfigPkgUid, ncBuilder.build())); + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + public void testNetworkCapabilitiesContainTwoSubIds() throws Exception { + final CarrierPrivilegesListenerShim listener = getCarrierPrivilegesListeners().get(0); + listener.onCarrierServiceChanged(null, mCarrierConfigPkgUid); + + final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder(); + ncBuilder.addTransportType(TRANSPORT_WIFI); + ncBuilder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + ncBuilder.setSubscriptionIds(Set.of(0, 1)); + assertFalse(mCarrierPrivilegeAuthenticator.isCarrierServiceUidForNetworkCapabilities( + mCarrierConfigPkgUid, ncBuilder.build())); + } } diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt index 0708669b11..5c30c7906a 100644 --- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt +++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt @@ -59,6 +59,7 @@ import com.android.net.module.util.ArrayTrackRecord import com.android.networkstack.apishim.common.UnsupportedApiLevelException import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker import com.android.server.connectivity.CarrierPrivilegeAuthenticator +import com.android.server.connectivity.CarrierPrivilegeAuthenticator.CarrierPrivilegesLostListener import com.android.server.connectivity.ClatCoordinator import com.android.server.connectivity.ConnectivityFlags import com.android.server.connectivity.MulticastRoutingCoordinatorService @@ -66,7 +67,6 @@ import com.android.server.connectivity.MultinetworkPolicyTracker import com.android.server.connectivity.MultinetworkPolicyTrackerTestDependencies import com.android.server.connectivity.NetworkRequestStateStatsMetrics import com.android.server.connectivity.ProxyTracker -import com.android.server.connectivity.RoutingCoordinatorService import com.android.testutils.visibleOnHandlerThread import com.android.testutils.waitForIdle import java.util.concurrent.Executors @@ -133,6 +133,7 @@ open class CSTest { // permissions using static contexts. val enabledFeatures = HashMap<String, Boolean>().also { it[ConnectivityFlags.NO_REMATCH_ALL_REQUESTS_ON_REGISTER] = true + it[ConnectivityFlags.REQUEST_RESTRICTED_WIFI] = true it[ConnectivityService.KEY_DESTROY_FROZEN_SOCKETS_VERSION] = true it[ConnectivityService.DELAY_DESTROY_FROZEN_SOCKETS_VERSION] = true it[ConnectivityService.ALLOW_SYSUI_CONNECTIVITY_REPORTS] = true @@ -200,7 +201,9 @@ open class CSTest { override fun makeCarrierPrivilegeAuthenticator( context: Context, - tm: TelephonyManager + tm: TelephonyManager, + requestRestrictedWifiEnabled: Boolean, + listener: CarrierPrivilegesLostListener ) = if (SdkLevel.isAtLeastT()) mock<CarrierPrivilegeAuthenticator>() else null private inner class AOOKTDeps(c: Context) : AutomaticOnOffKeepaliveTracker.Dependencies(c) { -- GitLab