From b15be228d26e819569296ff0bf7905499fcc78ef Mon Sep 17 00:00:00 2001 From: Motomu Utsumi Date: Wed, 15 May 2024 18:50:08 +0900 Subject: [PATCH] Update APIs that depends on isUidNetworkingBlocked to follow compat flag NETWORKINFO_WITHOUT_INTERNET_BLOCKED compat flag only changed the behavior of getActiveNetworkInfo that depends on bpfNetMaps#isUidNetworkingBlocked. But isUidNetworkingBlocked is used from other APIs(e.g. getActiveNetwork) This CL update all APIs that depends on isUidNetworkingBlocked to follow the compat flag to make behavior consistent between APIs. aosp/3079290 will update onBlockedStatusChanged callback to follow this compat flag. Bug: 340773991 Bug: 339780435 Test: TH Change-Id: If64ec800f21c2adc613884838202e2dece4a8d95 --- .../ConnectivityCompatChanges.java | 23 +++++++++++-------- .../android/server/ConnectivityService.java | 23 +++++++++++-------- .../server/ConnectivityServiceTest.java | 5 ++-- .../CSActiveNetworkInfoTest.kt | 9 ++++---- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/framework/src/android/net/connectivity/ConnectivityCompatChanges.java b/framework/src/android/net/connectivity/ConnectivityCompatChanges.java index 8701851d38..02ef8b7724 100644 --- a/framework/src/android/net/connectivity/ConnectivityCompatChanges.java +++ b/framework/src/android/net/connectivity/ConnectivityCompatChanges.java @@ -100,23 +100,26 @@ public final class ConnectivityCompatChanges { public static final long ENABLE_MATCH_LOCAL_NETWORK = 319212206L; /** - * On Android {@link android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM} or higher releases, when - * apps targeting Android {@link android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM} or higher - * that do not have the {@link android.Manifest.permission#INTERNET} permission call - * {@link android.net.ConnectivityManager#getActiveNetworkInfo()}, the state of the returned - * {@link android.net.NetworkInfo} object will always be - * {@link android.net.NetworkInfo.DetailedState#BLOCKED}. This is because apps without the - * permission cannot access any network. + * On Android {@link android.os.Build.VERSION_CODES.VANILLA_ICE_CREAM} or higher releases, + * network access from apps targeting Android 36 or higher that do not have the + * {@link android.Manifest.permission#INTERNET} permission is considered blocked. + * This results in API behaviors change for apps without + * {@link android.Manifest.permission#INTERNET} permission. + * {@link android.net.NetworkInfo} returned from {@link android.net.ConnectivityManager} APIs + * always has {@link android.net.NetworkInfo.DetailedState#BLOCKED}. + * {@link android.net.ConnectivityManager#getActiveNetwork()} always returns null. + * {@link android.net.ConnectivityManager.NetworkCallback#onBlockedStatusChanged()} is always + * called with blocked=true. *

* For backwards compatibility, apps running on older releases, or targeting older SDK levels, - * will instead receive objects with the network's current state, - * such as {@link android.net.NetworkInfo.DetailedState#CONNECTED}. + * network access from apps without {@link android.Manifest.permission#INTERNET} permission is + * considered not blocked even though apps cannot access any networks. * * @hide */ @ChangeId @EnabledAfter(targetSdkVersion = 35) // TODO: change to VANILLA_ICE_CREAM. - public static final long NETWORKINFO_WITHOUT_INTERNET_BLOCKED = 333340911L; + public static final long NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION = 333340911L; private ConnectivityCompatChanges() { } diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 46bd9bc6b4..39ea286a0a 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -102,7 +102,7 @@ import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST; import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY; import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_MATCH_LOCAL_NETWORK; import static android.net.connectivity.ConnectivityCompatChanges.ENABLE_SELF_CERTIFIED_CAPABILITIES_DECLARATION; -import static android.net.connectivity.ConnectivityCompatChanges.NETWORKINFO_WITHOUT_INTERNET_BLOCKED; +import static android.net.connectivity.ConnectivityCompatChanges.NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION; import static android.os.Process.INVALID_UID; import static android.os.Process.VPN_UID; import static android.system.OsConstants.ETH_P_ALL; @@ -2229,6 +2229,11 @@ public class ConnectivityService extends IConnectivityManager.Stub return nai; } + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + private boolean hasInternetPermission(final int uid) { + return (mBpfNetMaps.getNetPermForUid(uid) & PERMISSION_INTERNET) != 0; + } + /** * Check if UID should be blocked from using the specified network. */ @@ -2243,8 +2248,13 @@ public class ConnectivityService extends IConnectivityManager.Stub try { final boolean metered = nc == null ? true : nc.isMetered(); if (mDeps.isAtLeastV()) { - return mBpfNetMaps.isUidNetworkingBlocked(uid, metered) - || (mBpfNetMaps.getNetPermForUid(uid) & PERMISSION_INTERNET) == 0; + final boolean hasInternetPermission = hasInternetPermission(uid); + final boolean blockedByUidRules = mBpfNetMaps.isUidNetworkingBlocked(uid, metered); + if (mDeps.isChangeEnabled(NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION, uid)) { + return blockedByUidRules || !hasInternetPermission; + } else { + return hasInternetPermission && blockedByUidRules; + } } else { return mPolicyManager.isUidNetworkingBlocked(uid, metered); } @@ -2325,12 +2335,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final int uid = mDeps.getCallingUid(); final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid); if (nai == null) return null; - // Ignore blocked state to keep the backward compatibility if the compat flag is - // disabled and app does not have PERMISSION_INTERNET. - final boolean ignoreBlocked = mDeps.isAtLeastV() - && !mDeps.isChangeEnabled(NETWORKINFO_WITHOUT_INTERNET_BLOCKED, uid) - && (mBpfNetMaps.getNetPermForUid(uid) & PERMISSION_INTERNET) == 0; - final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, ignoreBlocked); + final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false /* ignoreBlocked */); maybeLogBlockedNetworkInfo(networkInfo, uid); return networkInfo; } diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index 717c5a1ab6..b6cb09bcb2 100755 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -152,7 +152,7 @@ import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_TEST_ONLY import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED; import static android.net.Proxy.PROXY_CHANGE_ACTION; import static android.net.RouteInfo.RTN_UNREACHABLE; -import static android.net.connectivity.ConnectivityCompatChanges.NETWORKINFO_WITHOUT_INTERNET_BLOCKED; +import static android.net.connectivity.ConnectivityCompatChanges.NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION; import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED; import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_REMOVED; import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE; @@ -1948,7 +1948,8 @@ public class ConnectivityServiceTest { setAlwaysOnNetworks(false); setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com"); - mDeps.setChangeIdEnabled(true, NETWORKINFO_WITHOUT_INTERNET_BLOCKED, Process.myUid()); + mDeps.setChangeIdEnabled( + true, NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION, Process.myUid()); doReturn(PERMISSION_INTERNET).when(mBpfNetMaps).getNetPermForUid(anyInt()); // Note : Please do not add any new instrumentation here. If you need new instrumentation, // please add it in CSTest and use subclasses of CSTest instead of adding more diff --git a/tests/unit/java/com/android/server/connectivityservice/CSActiveNetworkInfoTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSActiveNetworkInfoTest.kt index 1891a78230..360a298949 100644 --- a/tests/unit/java/com/android/server/connectivityservice/CSActiveNetworkInfoTest.kt +++ b/tests/unit/java/com/android/server/connectivityservice/CSActiveNetworkInfoTest.kt @@ -24,7 +24,7 @@ import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED import android.net.NetworkCapabilities.TRANSPORT_WIFI import android.net.NetworkInfo.DetailedState.BLOCKED import android.net.NetworkInfo.DetailedState.CONNECTED -import android.net.connectivity.ConnectivityCompatChanges.NETWORKINFO_WITHOUT_INTERNET_BLOCKED +import android.net.connectivity.ConnectivityCompatChanges.NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION import android.os.Build import androidx.test.filters.SmallTest import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo @@ -53,7 +53,7 @@ class CSActiveNetworkInfoTest : CSTest() { permissions: Int, expectBlocked: Boolean ) { - deps.setChangeIdEnabled(changeEnabled, NETWORKINFO_WITHOUT_INTERNET_BLOCKED) + deps.setChangeIdEnabled(changeEnabled, NETWORK_BLOCKED_WITHOUT_INTERNET_PERMISSION) doReturn(permissions).`when`(bpfNetMaps).getNetPermForUid(anyInt()) val agent = Agent(nc = nc()) @@ -66,6 +66,7 @@ class CSActiveNetworkInfoTest : CSTest() { } else { assertEquals(CONNECTED, networkInfo.detailedState) } + assertEquals(expectBlocked, cm.activeNetwork == null) agent.disconnect() } @@ -82,8 +83,8 @@ class CSActiveNetworkInfoTest : CSTest() { permissions = PERMISSION_INTERNET, expectBlocked = true ) - // getActiveNetworkInfo does not return NetworkInfo with blocked state if the compat change - // is disabled and the app does not have PERMISSION_INTERNET + // Network access is considered not blocked if the compat change is disabled and an app + // does not have PERMISSION_INTERNET doTestGetActiveNetworkInfo( changeEnabled = false, permissions = PERMISSION_NONE,