TransportInfo: Add a generic redaction mechanism

This replaces the existing mechanism for redacting location sensitive
fields with a more extensible mechanism. Currently supported redactions
are for the following permissions:
i. ACCESS_FINE_LOCATION
ii. LOCAL_MAC_ADDRESS
iii. NETWORK_SETTINGS

Also, removed WifiInfo from ConnectivityServiceTest to reduce cross
dependencies on wifi code.

Bug: 156867433
Bug: 162602799
Test: atest android.net
Test: atest com.android.server
Change-Id: I2bb980c624667a55c1383f13ab71b9b97ed6eeab
This commit is contained in:
Roshan Pius
2021-02-23 08:47:39 -08:00
parent c2ea3ab97d
commit 98f59ecb99
8 changed files with 570 additions and 171 deletions

View File

@@ -27,7 +27,13 @@ package android.net {
}
public final class NetworkCapabilities implements android.os.Parcelable {
ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, long);
method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L
field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L
field public static final long REDACT_FOR_NETWORK_SETTINGS = 4L; // 0x4L
field public static final long REDACT_NONE = 0L; // 0x0L
field public static final int TRANSPORT_TEST = 7; // 0x7
}
@@ -79,6 +85,11 @@ package android.net {
field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkSpecifier> CREATOR;
}
public interface TransportInfo {
method public default long getApplicableRedactions();
method @NonNull public default android.net.TransportInfo makeCopy(long);
}
public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
ctor public VpnTransportInfo(int);
method public int describeContents();

View File

@@ -263,7 +263,6 @@ package android.net {
}
public final class NetworkCapabilities implements android.os.Parcelable {
ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, boolean);
method @NonNull public int[] getAdministratorUids();
method @Nullable public String getSsid();
method @NonNull public int[] getTransportTypes();
@@ -437,11 +436,6 @@ package android.net {
field public final int tcpWindowScale;
}
public interface TransportInfo {
method public default boolean hasLocationSensitiveFields();
method @NonNull public default android.net.TransportInfo makeCopy(boolean);
}
}
package android.net.apf {

View File

@@ -434,7 +434,7 @@ public abstract class NetworkAgent {
}
mInitialConfiguration = new InitialConfiguration(context,
new NetworkCapabilities(nc, /* parcelLocationSensitiveFields */ true),
new NetworkCapabilities(nc, NetworkCapabilities.REDACT_NONE),
new LinkProperties(lp), score, config, ni);
}
@@ -878,8 +878,7 @@ public abstract class NetworkAgent {
mBandwidthUpdatePending.set(false);
mLastBwRefreshTime = System.currentTimeMillis();
final NetworkCapabilities nc =
new NetworkCapabilities(networkCapabilities,
/* parcelLocationSensitiveFields */ true);
new NetworkCapabilities(networkCapabilities, NetworkCapabilities.REDACT_NONE);
queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc));
}

View File

@@ -19,6 +19,7 @@ package android.net;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import android.annotation.IntDef;
import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -65,6 +66,68 @@ import java.util.StringJoiner;
public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
/**
* Mechanism to support redaction of fields in NetworkCapabilities that are guarded by specific
* app permissions.
**/
/**
* Don't redact any fields since the receiving app holds all the necessary permissions.
*
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final long REDACT_NONE = 0;
/**
* Redact any fields that need {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
* permission since the receiving app does not hold this permission or the location toggle
* is off.
*
* @see android.Manifest.permission#ACCESS_FINE_LOCATION
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1 << 0;
/**
* Redact any fields that need {@link android.Manifest.permission#LOCAL_MAC_ADDRESS}
* permission since the receiving app does not hold this permission.
*
* @see android.Manifest.permission#LOCAL_MAC_ADDRESS
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 1 << 1;
/**
*
* Redact any fields that need {@link android.Manifest.permission#NETWORK_SETTINGS}
* permission since the receiving app does not hold this permission.
*
* @see android.Manifest.permission#NETWORK_SETTINGS
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final long REDACT_FOR_NETWORK_SETTINGS = 1 << 2;
/**
* Redact all fields in this object that require any relevant permission.
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final long REDACT_ALL = -1L;
/** @hide */
@LongDef(flag = true, prefix = { "REDACT_" }, value = {
REDACT_NONE,
REDACT_FOR_ACCESS_FINE_LOCATION,
REDACT_FOR_LOCAL_MAC_ADDRESS,
REDACT_FOR_NETWORK_SETTINGS,
REDACT_ALL
})
@Retention(RetentionPolicy.SOURCE)
public @interface RedactionType {}
// Set to true when private DNS is broken.
private boolean mPrivateDnsBroken;
@@ -79,32 +142,31 @@ public final class NetworkCapabilities implements Parcelable {
private String mRequestorPackageName;
/**
* Indicates whether parceling should preserve fields that are set based on permissions of
* the process receiving the {@link NetworkCapabilities}.
* Indicates what fields should be redacted from this instance.
*/
private final boolean mParcelLocationSensitiveFields;
private final @RedactionType long mRedactions;
public NetworkCapabilities() {
mParcelLocationSensitiveFields = false;
mRedactions = REDACT_ALL;
clearAll();
mNetworkCapabilities = DEFAULT_CAPABILITIES;
}
public NetworkCapabilities(NetworkCapabilities nc) {
this(nc, false /* parcelLocationSensitiveFields */);
this(nc, REDACT_ALL);
}
/**
* Make a copy of NetworkCapabilities.
*
* @param nc Original NetworkCapabilities
* @param parcelLocationSensitiveFields Whether to parcel location sensitive data or not.
* @param redactions bitmask of redactions that needs to be performed on this new instance of
* {@link NetworkCapabilities}.
* @hide
*/
@SystemApi
public NetworkCapabilities(
@Nullable NetworkCapabilities nc, boolean parcelLocationSensitiveFields) {
mParcelLocationSensitiveFields = parcelLocationSensitiveFields;
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public NetworkCapabilities(@Nullable NetworkCapabilities nc, @RedactionType long redactions) {
mRedactions = redactions;
if (nc != null) {
set(nc);
}
@@ -116,11 +178,13 @@ public final class NetworkCapabilities implements Parcelable {
* @hide
*/
public void clearAll() {
// Ensures that the internal copies maintained by the connectivity stack does not set
// this bit.
if (mParcelLocationSensitiveFields) {
// Ensures that the internal copies maintained by the connectivity stack does not set it to
// anything other than |REDACT_ALL|.
if (mRedactions != REDACT_ALL) {
// This is needed because the current redaction mechanism relies on redaction while
// parceling.
throw new UnsupportedOperationException(
"Cannot clear NetworkCapabilities when parcelLocationSensitiveFields is set");
"Cannot clear NetworkCapabilities when mRedactions is set");
}
mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0;
mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
@@ -150,7 +214,7 @@ public final class NetworkCapabilities implements Parcelable {
mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
mNetworkSpecifier = nc.mNetworkSpecifier;
if (nc.getTransportInfo() != null) {
setTransportInfo(nc.getTransportInfo().makeCopy(mParcelLocationSensitiveFields));
setTransportInfo(nc.getTransportInfo().makeCopy(mRedactions));
} else {
setTransportInfo(null);
}
@@ -2350,6 +2414,23 @@ public final class NetworkCapabilities implements Parcelable {
}
}
/**
* Returns a bitmask of all the applicable redactions (based on the permissions held by the
* receiving app) to be performed on this object.
*
* @return bitmask of redactions applicable on this instance.
* @hide
*/
public @RedactionType long getApplicableRedactions() {
// Currently, there are no fields redacted in NetworkCapabilities itself, so we just
// passthrough the redactions required by the embedded TransportInfo. If this changes
// in the future, modify this method.
if (mTransportInfo == null) {
return NetworkCapabilities.REDACT_NONE;
}
return mTransportInfo.getApplicableRedactions();
}
/**
* Builder class for NetworkCapabilities.
*

View File

@@ -29,35 +29,47 @@ import android.annotation.SystemApi;
public interface TransportInfo {
/**
* Create a copy of a {@link TransportInfo} that will preserve location sensitive fields that
* were set based on the permissions of the process that originally received it.
* Create a copy of a {@link TransportInfo} with some fields redacted based on the permissions
* held by the receiving app.
*
* <p>By default {@link TransportInfo} does not preserve such fields during parceling, as
* they should not be shared outside of the process that receives them without appropriate
* checks.
* <p>
* Usage by connectivity stack:
* <ul>
* <li> Connectivity stack will invoke {@link #getApplicableRedactions()} to find the list
* of redactions that are required by this {@link TransportInfo} instance.</li>
* <li> Connectivity stack then loops through each bit in the bitmask returned and checks if the
* receiving app holds the corresponding permission.
* <ul>
* <li> If the app holds the corresponding permission, the bit is cleared from the
* |redactions| bitmask. </li>
* <li> If the app does not hold the corresponding permission, the bit is retained in the
* |redactions| bitmask. </li>
* </ul>
* <li> Connectivity stack then invokes {@link #makeCopy(long)} with the necessary |redactions|
* to create a copy to send to the corresponding app. </li>
* </ul>
* </p>
*
* @param parcelLocationSensitiveFields Whether the location sensitive fields should be kept
* when parceling
* @return Copy of this instance.
* @param redactions bitmask of redactions that needs to be performed on this instance.
* @return Copy of this instance with the necessary redactions.
* @hide
*/
@SystemApi
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@NonNull
default TransportInfo makeCopy(boolean parcelLocationSensitiveFields) {
default TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
return this;
}
/**
* Returns whether this TransportInfo type has location sensitive fields or not (helps
* to determine whether to perform a location permission check or not before sending to
* apps).
* Returns a bitmask of all the applicable redactions (based on the permissions held by the
* receiving app) to be performed on this TransportInfo.
*
* @return {@code true} if this instance contains location sensitive info, {@code false}
* otherwise.
* @return bitmask of redactions applicable on this instance.
* @see #makeCopy(long)
* @hide
*/
@SystemApi
default boolean hasLocationSensitiveFields() {
return false;
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
default @NetworkCapabilities.RedactionType long getApplicableRedactions() {
return NetworkCapabilities.REDACT_NONE;
}
}

View File

@@ -69,6 +69,9 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
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.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
@@ -1779,7 +1782,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.network,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
nc, false /* includeLocationSensitiveInfo */,
mDeps.getCallingUid(), callingPackageName, callingAttributionTag));
getCallingPid(), mDeps.getCallingUid(), callingPackageName,
callingAttributionTag));
}
}
@@ -1794,7 +1798,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
nc,
false /* includeLocationSensitiveInfo */,
mDeps.getCallingUid(), callingPackageName,
getCallingPid(), mDeps.getCallingUid(), callingPackageName,
callingAttributionTag));
}
}
@@ -1877,7 +1881,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
return createWithLocationInfoSanitizedIfNecessaryWhenParceled(
getNetworkCapabilitiesInternal(network),
false /* includeLocationSensitiveInfo */,
mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
getCallingPid(), mDeps.getCallingUid(), callingPackageName, callingAttributionTag);
}
@VisibleForTesting
@@ -1896,40 +1900,137 @@ public class ConnectivityService extends IConnectivityManager.Stub
return newNc;
}
private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName,
@Nullable String callingAttributionTag) {
final long token = Binder.clearCallingIdentity();
try {
return mLocationPermissionChecker.checkLocationPermission(
callerPkgName, callingAttributionTag, callerUid, null /* message */);
} finally {
Binder.restoreCallingIdentity(token);
/**
* Wrapper used to cache the permission check results performed for the corresponding
* app. This avoid performing multiple permission checks for different fields in
* NetworkCapabilities.
* Note: This wrapper does not support any sort of invalidation and thus must not be
* persistent or long-lived. It may only be used for the time necessary to
* compute the redactions required by one particular NetworkCallback or
* synchronous call.
*/
private class RedactionPermissionChecker {
private final int mCallingPid;
private final int mCallingUid;
@NonNull private final String mCallingPackageName;
@Nullable private final String mCallingAttributionTag;
private Boolean mHasLocationPermission = null;
private Boolean mHasLocalMacAddressPermission = null;
private Boolean mHasSettingsPermission = null;
RedactionPermissionChecker(int callingPid, int callingUid,
@NonNull String callingPackageName, @Nullable String callingAttributionTag) {
mCallingPid = callingPid;
mCallingUid = callingUid;
mCallingPackageName = callingPackageName;
mCallingAttributionTag = callingAttributionTag;
}
private boolean hasLocationPermissionInternal() {
final long token = Binder.clearCallingIdentity();
try {
return mLocationPermissionChecker.checkLocationPermission(
mCallingPackageName, mCallingAttributionTag, mCallingUid,
null /* message */);
} finally {
Binder.restoreCallingIdentity(token);
}
}
/**
* Returns whether the app holds location permission or not (might return cached result
* if the permission was already checked before).
*/
public boolean hasLocationPermission() {
if (mHasLocationPermission == null) {
// If there is no cached result, perform the check now.
mHasLocationPermission = hasLocationPermissionInternal();
}
return mHasLocationPermission;
}
/**
* Returns whether the app holds local mac address permission or not (might return cached
* result if the permission was already checked before).
*/
public boolean hasLocalMacAddressPermission() {
if (mHasLocalMacAddressPermission == null) {
// If there is no cached result, perform the check now.
mHasLocalMacAddressPermission =
checkLocalMacAddressPermission(mCallingPid, mCallingUid);
}
return mHasLocalMacAddressPermission;
}
/**
* Returns whether the app holds settings permission or not (might return cached
* result if the permission was already checked before).
*/
public boolean hasSettingsPermission() {
if (mHasSettingsPermission == null) {
// If there is no cached result, perform the check now.
mHasSettingsPermission = checkSettingsPermission(mCallingPid, mCallingUid);
}
return mHasSettingsPermission;
}
}
private static boolean shouldRedact(@NetworkCapabilities.RedactionType long redactions,
@NetworkCapabilities.NetCapability long redaction) {
return (redactions & redaction) != 0;
}
/**
* Use the provided |applicableRedactions| to check the receiving app's
* permissions and clear/set the corresponding bit in the returned bitmask. The bitmask
* returned will be used to ensure the necessary redactions are performed by NetworkCapabilities
* before being sent to the corresponding app.
*/
private @NetworkCapabilities.RedactionType long retrieveRequiredRedactions(
@NetworkCapabilities.RedactionType long applicableRedactions,
@NonNull RedactionPermissionChecker redactionPermissionChecker,
boolean includeLocationSensitiveInfo) {
long redactions = applicableRedactions;
if (shouldRedact(redactions, REDACT_FOR_ACCESS_FINE_LOCATION)) {
if (includeLocationSensitiveInfo
&& redactionPermissionChecker.hasLocationPermission()) {
redactions &= ~REDACT_FOR_ACCESS_FINE_LOCATION;
}
}
if (shouldRedact(redactions, REDACT_FOR_LOCAL_MAC_ADDRESS)) {
if (redactionPermissionChecker.hasLocalMacAddressPermission()) {
redactions &= ~REDACT_FOR_LOCAL_MAC_ADDRESS;
}
}
if (shouldRedact(redactions, REDACT_FOR_NETWORK_SETTINGS)) {
if (redactionPermissionChecker.hasSettingsPermission()) {
redactions &= ~REDACT_FOR_NETWORK_SETTINGS;
}
}
return redactions;
}
@VisibleForTesting
@Nullable
NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled(
@Nullable NetworkCapabilities nc, boolean includeLocationSensitiveInfo,
int callerUid, @NonNull String callerPkgName, @Nullable String callingAttributionTag) {
int callingPid, int callingUid, @NonNull String callingPkgName,
@Nullable String callingAttributionTag) {
if (nc == null) {
return null;
}
Boolean hasLocationPermission = null;
final NetworkCapabilities newNc;
// Avoid doing location permission check if the transport info has no location sensitive
// data.
if (includeLocationSensitiveInfo
&& nc.getTransportInfo() != null
&& nc.getTransportInfo().hasLocationSensitiveFields()) {
hasLocationPermission =
hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
newNc = new NetworkCapabilities(nc, hasLocationPermission);
} else {
newNc = new NetworkCapabilities(nc, false /* parcelLocationSensitiveFields */);
}
final RedactionPermissionChecker redactionPermissionChecker =
new RedactionPermissionChecker(callingPid, callingUid, callingPkgName,
callingAttributionTag);
final long redactions = retrieveRequiredRedactions(
nc.getApplicableRedactions(), redactionPermissionChecker,
includeLocationSensitiveInfo);
final NetworkCapabilities newNc = new NetworkCapabilities(nc, redactions);
// Reset owner uid if not destined for the owner app.
if (callerUid != nc.getOwnerUid()) {
if (callingUid != nc.getOwnerUid()) {
newNc.setOwnerUid(INVALID_UID);
return newNc;
}
@@ -1938,23 +2039,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Owner UIDs already checked above. No need to re-check.
return newNc;
}
// If the caller does not want location sensitive data & target SDK >= S, then mask info.
// Else include the owner UID iff the caller has location permission to provide backwards
// If the calling does not want location sensitive data & target SDK >= S, then mask info.
// Else include the owner UID iff the calling has location permission to provide backwards
// compatibility for older apps.
if (!includeLocationSensitiveInfo
&& isTargetSdkAtleast(
Build.VERSION_CODES.S, callerUid, callerPkgName)) {
Build.VERSION_CODES.S, callingUid, callingPkgName)) {
newNc.setOwnerUid(INVALID_UID);
return newNc;
}
if (hasLocationPermission == null) {
// Location permission not checked yet, check now for masking owner UID.
hasLocationPermission =
hasLocationPermission(callerUid, callerPkgName, callingAttributionTag);
}
// Reset owner uid if the app has no location permission.
if (!hasLocationPermission) {
if (!redactionPermissionChecker.hasLocationPermission()) {
newNc.setOwnerUid(INVALID_UID);
}
return newNc;
@@ -2469,6 +2564,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
mContext.enforceCallingOrSelfPermission(KeepaliveTracker.PERMISSION, "ConnectivityService");
}
private boolean checkLocalMacAddressPermission(int pid, int uid) {
return PERMISSION_GRANTED == mContext.checkPermission(
Manifest.permission.LOCAL_MAC_ADDRESS, pid, uid);
}
private void sendConnectedBroadcast(NetworkInfo info) {
sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
}
@@ -7170,7 +7270,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
nc, includeLocationSensitiveInfo, nri.mUid,
nc, includeLocationSensitiveInfo, nri.mPid, nri.mUid,
nrForCallback.getRequestorPackageName(),
nri.mCallingAttributionTag));
putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions(
@@ -7191,7 +7291,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
putParcelable(
bundle,
createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, includeLocationSensitiveInfo, nri.mUid,
netCap, includeLocationSensitiveInfo, nri.mPid, nri.mUid,
nrForCallback.getRequestorPackageName(),
nri.mCallingAttributionTag));
break;

View File

@@ -35,6 +35,9 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
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.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -51,7 +54,6 @@ import static com.android.testutils.MiscAsserts.assertEmpty;
import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
import static com.android.testutils.ParcelUtils.parcelingRoundTrip;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -62,7 +64,6 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import android.net.wifi.WifiInfo;
import android.net.wifi.aware.DiscoverySession;
import android.net.wifi.aware.PeerHandle;
import android.net.wifi.aware.WifiAwareNetworkSpecifier;
@@ -352,55 +353,6 @@ public class NetworkCapabilitiesTest {
testParcelSane(netCap);
}
private NetworkCapabilities createNetworkCapabilitiesWithWifiInfo() {
// uses a real WifiInfo to test parceling of sensitive data.
final WifiInfo wifiInfo = new WifiInfo.Builder()
.setSsid("sssid1234".getBytes())
.setBssid("00:11:22:33:44:55")
.build();
return new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED)
.setSSID(TEST_SSID)
.setTransportInfo(wifiInfo)
.setRequestorPackageName("com.android.test")
.setRequestorUid(9304);
}
@Test
public void testParcelNetworkCapabilitiesWithLocationSensitiveFields() {
assumeTrue(isAtLeastS());
final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo();
final NetworkCapabilities netCapWithLocationSensitiveFields =
new NetworkCapabilities(netCap, true);
assertParcelingIsLossless(netCapWithLocationSensitiveFields);
testParcelSane(netCapWithLocationSensitiveFields);
assertEquals(netCapWithLocationSensitiveFields,
parcelingRoundTrip(netCapWithLocationSensitiveFields));
}
@Test
public void testParcelNetworkCapabilitiesWithoutLocationSensitiveFields() {
assumeTrue(isAtLeastS());
final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo();
final NetworkCapabilities netCapWithoutLocationSensitiveFields =
new NetworkCapabilities(netCap, false);
final NetworkCapabilities sanitizedNetCap =
new NetworkCapabilities(netCapWithoutLocationSensitiveFields);
final WifiInfo sanitizedWifiInfo = new WifiInfo.Builder()
.setSsid(new byte[0])
.setBssid(WifiInfo.DEFAULT_MAC_ADDRESS)
.build();
sanitizedNetCap.setTransportInfo(sanitizedWifiInfo);
assertEquals(sanitizedNetCap, parcelingRoundTrip(netCapWithoutLocationSensitiveFields));
}
private void testParcelSane(NetworkCapabilities cap) {
if (isAtLeastS()) {
assertParcelSane(cap, 17);
@@ -411,6 +363,45 @@ public class NetworkCapabilitiesTest {
}
}
private static NetworkCapabilities createNetworkCapabilitiesWithTransportInfo() {
return new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED)
.setSSID(TEST_SSID)
.setTransportInfo(new TestTransportInfo())
.setRequestorPackageName("com.android.test")
.setRequestorUid(9304);
}
@Test
public void testNetworkCapabilitiesCopyWithNoRedactions() {
assumeTrue(isAtLeastS());
final NetworkCapabilities netCap = createNetworkCapabilitiesWithTransportInfo();
final NetworkCapabilities netCapWithNoRedactions =
new NetworkCapabilities(netCap, NetworkCapabilities.REDACT_NONE);
TestTransportInfo testTransportInfo =
(TestTransportInfo) netCapWithNoRedactions.getTransportInfo();
assertFalse(testTransportInfo.locationRedacted);
assertFalse(testTransportInfo.localMacAddressRedacted);
assertFalse(testTransportInfo.settingsRedacted);
}
@Test
public void testNetworkCapabilitiesCopyWithoutLocationSensitiveFields() {
assumeTrue(isAtLeastS());
final NetworkCapabilities netCap = createNetworkCapabilitiesWithTransportInfo();
final NetworkCapabilities netCapWithNoRedactions =
new NetworkCapabilities(netCap, REDACT_FOR_ACCESS_FINE_LOCATION);
TestTransportInfo testTransportInfo =
(TestTransportInfo) netCapWithNoRedactions.getTransportInfo();
assertTrue(testTransportInfo.locationRedacted);
assertFalse(testTransportInfo.localMacAddressRedacted);
assertFalse(testTransportInfo.settingsRedacted);
}
@Test
public void testOemPaid() {
NetworkCapabilities nc = new NetworkCapabilities();
@@ -1062,18 +1053,42 @@ public class NetworkCapabilitiesTest {
} catch (IllegalArgumentException e) { }
}
private class TestTransportInfo implements TransportInfo {
/**
* Test TransportInfo to verify redaction mechanism.
*/
private static class TestTransportInfo implements TransportInfo {
public final boolean locationRedacted;
public final boolean localMacAddressRedacted;
public final boolean settingsRedacted;
TestTransportInfo() {
locationRedacted = false;
localMacAddressRedacted = false;
settingsRedacted = false;
}
TestTransportInfo(boolean locationRedacted,
boolean localMacAddressRedacted,
boolean settingsRedacted) {
this.locationRedacted = locationRedacted;
this.localMacAddressRedacted =
localMacAddressRedacted;
this.settingsRedacted = settingsRedacted;
}
@Override
public TransportInfo makeCopy(boolean parcelLocationSensitiveFields) {
return this;
public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
return new TestTransportInfo(
(redactions & NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
(redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
(redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
);
}
@Override
public boolean hasLocationSensitiveFields() {
return false;
public @NetworkCapabilities.RedactionType long getApplicableRedactions() {
return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS
| REDACT_FOR_NETWORK_SETTINGS;
}
}
@@ -1084,7 +1099,7 @@ public class NetworkCapabilitiesTest {
final int requestUid = 10100;
final int[] administratorUids = {ownerUid, 10001};
final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(1);
final TestTransportInfo transportInfo = new TestTransportInfo();
final TransportInfo transportInfo = new TransportInfo() {};
final String ssid = "TEST_SSID";
final String packageName = "com.google.test.networkcapabilities";
final NetworkCapabilities nc = new NetworkCapabilities.Builder()

View File

@@ -82,6 +82,10 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
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_NONE;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
@@ -235,7 +239,6 @@ import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
import android.net.wifi.WifiInfo;
import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Build;
@@ -8838,29 +8841,34 @@ public class ConnectivityServiceTest {
final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid);
return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, includeLocationSensitiveInfo, callerUid,
netCap, includeLocationSensitiveInfo, Process.myUid(), callerUid,
mContext.getPackageName(), getAttributionTag())
.getOwnerUid();
}
private void verifyWifiInfoCopyNetCapsPermission(
private void verifyTransportInfoCopyNetCapsPermission(
int callerUid, boolean includeLocationSensitiveInfo,
boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
final WifiInfo wifiInfo = mock(WifiInfo.class);
when(wifiInfo.hasLocationSensitiveFields()).thenReturn(true);
final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions()).thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION);
final NetworkCapabilities netCap =
new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, includeLocationSensitiveInfo, callerUid,
netCap, includeLocationSensitiveInfo, Process.myPid(), callerUid,
mContext.getPackageName(), getAttributionTag());
verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable));
if (shouldMakeCopyWithLocationSensitiveFieldsParcelable) {
verify(transportInfo).makeCopy(REDACT_NONE);
} else {
verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
}
}
private void verifyOwnerUidAndWifiInfoNetCapsPermission(
private void verifyOwnerUidAndTransportInfoNetCapsPermission(
boolean shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag,
boolean shouldInclLocationSensitiveOwnerUidWithIncludeFlag,
boolean shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag,
boolean shouldInclLocationSensitiveWifiInfoWithIncludeFlag) {
boolean shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag,
boolean shouldInclLocationSensitiveTransportInfoWithIncludeFlag) {
final int myUid = Process.myUid();
final int expectedOwnerUidWithoutIncludeFlag =
@@ -8874,13 +8882,13 @@ public class ConnectivityServiceTest {
assertEquals(expectedOwnerUidWithIncludeFlag, getOwnerUidNetCapsPermission(
myUid, myUid, true /* includeLocationSensitiveInfo */));
verifyWifiInfoCopyNetCapsPermission(myUid,
verifyTransportInfoCopyNetCapsPermission(myUid,
false, /* includeLocationSensitiveInfo */
shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag);
shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag);
verifyWifiInfoCopyNetCapsPermission(myUid,
verifyTransportInfoCopyNetCapsPermission(myUid,
true, /* includeLocationSensitiveInfo */
shouldInclLocationSensitiveWifiInfoWithIncludeFlag);
shouldInclLocationSensitiveTransportInfoWithIncludeFlag);
}
@@ -8890,15 +8898,15 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we include owner uid even if the request asks to remove it since the
// app has necessary permissions and targetSdk < S.
true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8908,15 +8916,15 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we include owner uid even if the request asks to remove it since the
// app has necessary permissions and targetSdk < S.
true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8927,15 +8935,15 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we owner UID if the request asks us to remove it even if the app
// has necessary permissions since targetSdk >= S.
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8945,15 +8953,15 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
// Ensure that we owner UID if the request asks us to remove it even if the app
// has necessary permissions since targetSdk >= S.
true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
// Ensure that we remove location info if the request asks to remove it even if the
// app has necessary permissions.
true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8963,11 +8971,11 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -8990,11 +8998,11 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -9004,14 +9012,193 @@ public class ConnectivityServiceTest {
// Test that not having fine location permission leads to sanitization.
setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
verifyOwnerUidAndWifiInfoNetCapsPermission(
verifyOwnerUidAndTransportInfoNetCapsPermission(
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@Test
public void testCreateForCallerWithLocalMacAddressSanitizedWithLocalMacAddressPermission()
throws Exception {
mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_GRANTED);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions())
.thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
final NetworkCapabilities netCap =
new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
Process.myPid(), Process.myUid(),
mContext.getPackageName(), getAttributionTag());
// don't redact MAC_ADDRESS fields, only location sensitive fields.
verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
}
@Test
public void testCreateForCallerWithLocalMacAddressSanitizedWithoutLocalMacAddressPermission()
throws Exception {
mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions())
.thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS);
final NetworkCapabilities netCap =
new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
Process.myPid(), Process.myUid(),
mContext.getPackageName(), getAttributionTag());
// redact both MAC_ADDRESS & location sensitive fields.
verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION
| REDACT_FOR_LOCAL_MAC_ADDRESS);
}
@Test
public void testCreateForCallerWithLocalMacAddressSanitizedWithSettingsPermission()
throws Exception {
mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions())
.thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
final NetworkCapabilities netCap =
new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
Process.myPid(), Process.myUid(),
mContext.getPackageName(), getAttributionTag());
// don't redact NETWORK_SETTINGS fields, only location sensitive fields.
verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION);
}
@Test
public void testCreateForCallerWithLocalMacAddressSanitizedWithoutSettingsPermission()
throws Exception {
mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions())
.thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
final NetworkCapabilities netCap =
new NetworkCapabilities().setTransportInfo(transportInfo);
mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled(
netCap, false /* includeLocationSensitiveInfoInTransportInfo */,
Process.myPid(), Process.myUid(),
mContext.getPackageName(), getAttributionTag());
// redact both NETWORK_SETTINGS & location sensitive fields.
verify(transportInfo).makeCopy(
REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS);
}
/**
* Test TransportInfo to verify redaction mechanism.
*/
private static class TestTransportInfo implements TransportInfo {
public final boolean locationRedacted;
public final boolean localMacAddressRedacted;
public final boolean settingsRedacted;
TestTransportInfo() {
locationRedacted = false;
localMacAddressRedacted = false;
settingsRedacted = false;
}
TestTransportInfo(boolean locationRedacted, boolean localMacAddressRedacted,
boolean settingsRedacted) {
this.locationRedacted = locationRedacted;
this.localMacAddressRedacted =
localMacAddressRedacted;
this.settingsRedacted = settingsRedacted;
}
@Override
public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) {
return new TestTransportInfo(
(redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0,
(redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0,
(redactions & REDACT_FOR_NETWORK_SETTINGS) != 0
);
}
@Override
public @NetworkCapabilities.RedactionType long getApplicableRedactions() {
return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS
| REDACT_FOR_NETWORK_SETTINGS;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof TestTransportInfo)) return false;
TestTransportInfo that = (TestTransportInfo) other;
return that.locationRedacted == this.locationRedacted
&& that.localMacAddressRedacted == this.localMacAddressRedacted
&& that.settingsRedacted == this.settingsRedacted;
}
@Override
public int hashCode() {
return Objects.hash(locationRedacted, localMacAddressRedacted, settingsRedacted);
}
}
private void verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
@NonNull TestNetworkCallback wifiNetworkCallback, int actualOwnerUid,
@NonNull TransportInfo actualTransportInfo, int expectedOwnerUid,
@NonNull TransportInfo expectedTransportInfo) throws Exception {
when(mPackageManager.getTargetSdkVersion(anyString())).thenReturn(Build.VERSION_CODES.S);
final NetworkCapabilities ncTemplate =
new NetworkCapabilities()
.addTransportType(TRANSPORT_WIFI)
.setOwnerUid(actualOwnerUid);
final NetworkRequest wifiRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_WIFI).build();
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
ncTemplate);
mWiFiNetworkAgent.connect(false);
wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// Send network capabilities update with TransportInfo to trigger capabilities changed
// callback.
mWiFiNetworkAgent.setNetworkCapabilities(
ncTemplate.setTransportInfo(actualTransportInfo), true);
wifiNetworkCallback.expectCapabilitiesThat(mWiFiNetworkAgent,
nc -> Objects.equals(expectedOwnerUid, nc.getOwnerUid())
&& Objects.equals(expectedTransportInfo, nc.getTransportInfo()));
}
@Test
public void testVerifyLocationDataIsNotIncludedWhenInclFlagNotSet() throws Exception {
final TestNetworkCallback wifiNetworkCallack = new TestNetworkCallback();
final int ownerUid = Process.myUid();
final TransportInfo transportInfo = new TestTransportInfo();
// Even though the test uid holds privileged permissions, mask location fields since
// the callback did not explicitly opt-in to get location data.
final TransportInfo sanitizedTransportInfo = new TestTransportInfo(
true, /* locationRedacted */
true, /* localMacAddressRedacted */
true /* settingsRedacted */
);
// Should not expect location data since the callback does not set the flag for including
// location data.
verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps(
wifiNetworkCallack, ownerUid, transportInfo, INVALID_UID, sanitizedTransportInfo);
}
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
throws Exception {
final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE);