Add compat flag for ActiveNetworkInfo blocked state
Before aosp/3001087, getNetworkActiveInfo did not return network info with blocked state for apps without PERMISSION_INTERNET even if the network is actually blocked. aosp/3001087 updated getNetworkActiveInfo to return correct blocked state on V+. However, this broke some apps that use getNetworkActiveInfo in wrong way and depends on the previous behavior. So this CL introduces the compat flag to keep previous behavior for apps targeting U or older releases. Test: TH Bug: 333340911 Change-Id: I0e0950f2148de0ffdb45495903a5a87e0d4c1c0b
This commit is contained in:
parent
a08692f7c7
commit
0b4be79e52
6 changed files with 161 additions and 2 deletions
|
|
@ -99,6 +99,25 @@ public final class ConnectivityCompatChanges {
|
|||
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||
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.
|
||||
* <p>
|
||||
* 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}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@ChangeId
|
||||
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||
public static final long NETWORKINFO_WITHOUT_INTERNET_BLOCKED = 333340911L;
|
||||
|
||||
private ConnectivityCompatChanges() {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -805,6 +805,25 @@ public class BpfNetMaps {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get granted permissions for specified uid. If uid is not in the map, this method returns
|
||||
* {@link android.net.INetd.PERMISSION_INTERNET} since this is a default permission.
|
||||
* See {@link #setNetPermForUids}
|
||||
*
|
||||
* @param uid target uid
|
||||
* @return granted permissions.
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||
public int getNetPermForUid(final int uid) {
|
||||
try {
|
||||
final U8 permissions = sUidPermissionMap.getValue(new S32(uid));
|
||||
return permissions != null ? permissions.val : PERMISSION_INTERNET;
|
||||
} catch (ErrnoException e) {
|
||||
Log.wtf(TAG, "Failed to get permission for uid: " + uid);
|
||||
return PERMISSION_INTERNET;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Data Saver enabled or disabled
|
||||
*
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
|
|||
import static android.net.ConnectivityManager.getNetworkTypeName;
|
||||
import static android.net.ConnectivityManager.isNetworkTypeValid;
|
||||
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
|
||||
import static android.net.INetd.PERMISSION_INTERNET;
|
||||
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
|
||||
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
|
||||
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_SKIPPED;
|
||||
|
|
@ -101,6 +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.os.Process.INVALID_UID;
|
||||
import static android.os.Process.VPN_UID;
|
||||
import static android.system.OsConstants.ETH_P_ALL;
|
||||
|
|
@ -2241,7 +2243,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||
try {
|
||||
final boolean metered = nc == null ? true : nc.isMetered();
|
||||
if (mDeps.isAtLeastV()) {
|
||||
return mBpfNetMaps.isUidNetworkingBlocked(uid, metered);
|
||||
return mBpfNetMaps.isUidNetworkingBlocked(uid, metered)
|
||||
|| (mBpfNetMaps.getNetPermForUid(uid) & PERMISSION_INTERNET) == 0;
|
||||
} else {
|
||||
return mPolicyManager.isUidNetworkingBlocked(uid, metered);
|
||||
}
|
||||
|
|
@ -2322,7 +2325,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||
final int uid = mDeps.getCallingUid();
|
||||
final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid);
|
||||
if (nai == null) return null;
|
||||
final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false);
|
||||
// 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);
|
||||
maybeLogBlockedNetworkInfo(networkInfo, uid);
|
||||
return networkInfo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -847,6 +847,21 @@ public final class BpfNetMapsTest {
|
|||
assertNull(mUidPermissionMap.getValue(new S32(uid1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
|
||||
public void testGetNetPermFoUid() throws Exception {
|
||||
mUidPermissionMap.deleteEntry(new S32(TEST_UID));
|
||||
assertEquals(PERMISSION_INTERNET, mBpfNetMaps.getNetPermForUid(TEST_UID));
|
||||
|
||||
mUidPermissionMap.updateEntry(new S32(TEST_UID), new U8((short) PERMISSION_NONE));
|
||||
assertEquals(PERMISSION_NONE, mBpfNetMaps.getNetPermForUid(TEST_UID));
|
||||
|
||||
mUidPermissionMap.updateEntry(new S32(TEST_UID),
|
||||
new U8((short) (PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS)));
|
||||
assertEquals(PERMISSION_INTERNET | PERMISSION_UPDATE_DEVICE_STATS,
|
||||
mBpfNetMaps.getNetPermForUid(TEST_UID));
|
||||
}
|
||||
|
||||
@Test
|
||||
@IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
public void testSwapActiveStatsMap() throws Exception {
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
|
|||
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OFF;
|
||||
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
|
||||
import static android.net.ConnectivitySettingsManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
|
||||
import static android.net.INetd.PERMISSION_INTERNET;
|
||||
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_DNS;
|
||||
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_FALLBACK;
|
||||
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_HTTP;
|
||||
|
|
@ -151,6 +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.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;
|
||||
|
|
@ -1945,6 +1947,9 @@ public class ConnectivityServiceTest {
|
|||
setCaptivePortalMode(ConnectivitySettingsManager.CAPTIVE_PORTAL_MODE_PROMPT);
|
||||
setAlwaysOnNetworks(false);
|
||||
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
|
||||
|
||||
mDeps.setChangeIdEnabled(true, NETWORKINFO_WITHOUT_INTERNET_BLOCKED, 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
|
||||
// tools in ConnectivityServiceTest.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server
|
||||
|
||||
import android.net.INetd.PERMISSION_INTERNET
|
||||
import android.net.INetd.PERMISSION_NONE
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
|
||||
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.os.Build
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||
import com.android.testutils.DevSdkIgnoreRunner
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers.anyBoolean
|
||||
import org.mockito.ArgumentMatchers.anyInt
|
||||
import org.mockito.Mockito.doReturn
|
||||
|
||||
private fun nc() = NetworkCapabilities.Builder()
|
||||
.addTransportType(TRANSPORT_WIFI)
|
||||
.addCapability(NET_CAPABILITY_INTERNET)
|
||||
.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
|
||||
.build()
|
||||
|
||||
@RunWith(DevSdkIgnoreRunner::class)
|
||||
@SmallTest
|
||||
@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||
class CSActiveNetworkInfoTest : CSTest() {
|
||||
|
||||
fun doTestGetActiveNetworkInfo(
|
||||
changeEnabled: Boolean,
|
||||
permissions: Int,
|
||||
expectBlocked: Boolean
|
||||
) {
|
||||
deps.setChangeIdEnabled(changeEnabled, NETWORKINFO_WITHOUT_INTERNET_BLOCKED)
|
||||
doReturn(permissions).`when`(bpfNetMaps).getNetPermForUid(anyInt())
|
||||
|
||||
val agent = Agent(nc = nc())
|
||||
agent.connect()
|
||||
|
||||
val networkInfo = cm.activeNetworkInfo
|
||||
assertNotNull(networkInfo)
|
||||
if (expectBlocked) {
|
||||
assertEquals(BLOCKED, networkInfo.detailedState)
|
||||
} else {
|
||||
assertEquals(CONNECTED, networkInfo.detailedState)
|
||||
}
|
||||
agent.disconnect()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testGetActiveNetworkInfo() {
|
||||
doReturn(true).`when`(bpfNetMaps).isUidNetworkingBlocked(anyInt(), anyBoolean())
|
||||
doTestGetActiveNetworkInfo(
|
||||
changeEnabled = true,
|
||||
permissions = PERMISSION_NONE,
|
||||
expectBlocked = true
|
||||
)
|
||||
doTestGetActiveNetworkInfo(
|
||||
changeEnabled = false,
|
||||
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
|
||||
doTestGetActiveNetworkInfo(
|
||||
changeEnabled = false,
|
||||
permissions = PERMISSION_NONE,
|
||||
expectBlocked = false
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue