[connectivity] add NetworkCapabilities.RedactionHelper

Add a new hidden inner class NetworkCapabilities.RedactionHelper for
accessing conditionally available NetworkSpecifier methods via
reflection.

Reflection is necessary because NetworkSpecifier is platform code. So
it's possible for a mainline update to define a
getApplicableRedactions() or redact(long) method in a subclass of
NetworkSpecifier (e.g., EthernetNetworkSpecifier), and then to run
that mainline module on an Android release where the
NetworkSpecifier base class does not have those methods. On such a
device, ConnectivityService must still call those methods if they
exist, otherwise it would fail to redact information that needs to
be redacted. Another way to do this would be for ConnectivityService
to just call the method and catch NoSuchMethodError, but this code
runs fairly often and constructing exceptions is expensive.

This class is not used in this CL but will be used for NetworkSpecifier
redaction in ag/34242202 and ag/34242203

Bug 374037595
Flag: NONE new code nerver used

Change-Id: I8f88c6bb105ebf8d485e18cd214bebf2abe67e63
This commit is contained in:
Kangping Dong 2025-06-30 14:31:14 +08:00
commit 89c94195a0

View file

@ -51,6 +51,8 @@ import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_5;
import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.REDACT_FOR_THREAD_NETWORK_PRIVILEGED;
import static android.net.NetworkCapabilities.REDACT_NONE;
import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@ -63,9 +65,11 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
import static android.os.Process.INVALID_UID;
import static com.android.modules.utils.build.SdkLevel.isAtLeastB;
import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
import static com.android.modules.utils.build.SdkLevel.isAtLeastV;
import static com.android.net.thread.platform.flags.Flags.FLAG_THREAD_MOBILE_ENABLED;
import static com.android.testutils.MiscAsserts.assertEmpty;
import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
@ -74,11 +78,15 @@ import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import android.annotation.Nullable;
import android.net.NetworkCapabilities.RedactionHelper;
import android.net.wifi.aware.DiscoverySession;
import android.net.wifi.aware.PeerHandle;
import android.net.wifi.aware.WifiAwareNetworkSpecifier;
@ -99,6 +107,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -1235,6 +1244,44 @@ public class NetworkCapabilitiesTest {
}
}
/**
* Redactable NetworkSpecifier subclass for verifying redaction mechanism.
*/
private static final class RedactableNetworkSpecifier extends NetworkSpecifier {
final boolean locationRedacted;
final boolean threadNetworkRedacted;
RedactableNetworkSpecifier() {
locationRedacted = false;
threadNetworkRedacted = false;
}
RedactableNetworkSpecifier(boolean locationRedacted, boolean threadNetworkRedacted) {
this.locationRedacted = locationRedacted;
this.threadNetworkRedacted = threadNetworkRedacted;
}
@Override
public long getApplicableRedactions() {
return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_THREAD_NETWORK_PRIVILEGED;
}
@Override
@Nullable
public NetworkSpecifier redact(long redactions) {
return new RedactableNetworkSpecifier(
(redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
(redactions & REDACT_FOR_THREAD_NETWORK_PRIVILEGED) != 0);
}
}
/**
* Unredactable NetworkSpecifier subclass for verifying redaction mechanism.
*/
private static final class UnredactableNetworkSpecifier extends NetworkSpecifier {
// not overriding the getApplicableRedactions() and redact(long) methods
}
@Test
public void testBuilder() {
final int ownerUid = 1001;
@ -1621,4 +1668,35 @@ public class NetworkCapabilitiesTest {
assertFalse(wifiRequestNc.satisfiedByNetworkCapabilities(localWifiNc));
}
}
@Test
public void testRedactionHelper() throws Exception {
final UnredactableNetworkSpecifier unredactableSpecifier =
new UnredactableNetworkSpecifier();
final RedactableNetworkSpecifier redactableSpecifier = new RedactableNetworkSpecifier();
assertEquals(REDACT_NONE,
RedactionHelper.getSpecifierApplicableRedactions(unredactableSpecifier));
assertEquals(unredactableSpecifier,
RedactionHelper.getSpecifierRedactResult(
unredactableSpecifier, REDACT_FOR_ACCESS_FINE_LOCATION));
assertEquals(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_THREAD_NETWORK_PRIVILEGED,
RedactionHelper.getSpecifierApplicableRedactions(redactableSpecifier));
// Call getSpecifierApplicableRedactions() twice to make sure the cache works
assertEquals(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_THREAD_NETWORK_PRIVILEGED,
RedactionHelper.getSpecifierApplicableRedactions(redactableSpecifier));
final RedactableNetworkSpecifier redactedSpecifier =
(RedactableNetworkSpecifier) RedactionHelper.getSpecifierRedactResult(
redactableSpecifier,
REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_THREAD_NETWORK_PRIVILEGED);
assertTrue(redactedSpecifier.locationRedacted);
assertTrue(redactedSpecifier.threadNetworkRedacted);
// Call getSpecifierRedactResult twice to make sure the cache works
final RedactableNetworkSpecifier redactedSpecifier2 =
(RedactableNetworkSpecifier) RedactionHelper.getSpecifierRedactResult(
redactableSpecifier,
REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_THREAD_NETWORK_PRIVILEGED);
assertTrue(redactedSpecifier2.locationRedacted);
assertTrue(redactedSpecifier2.threadNetworkRedacted);
}
}