WifiInfo: Embed location sensitive TransportInfo

Migrate existing WifiInfo masking to use this new mechanism
(instead of existing masking in WifiService).

Bug: 162602799
Test: atest android.net.wifi
Test: atest android.net.wifi.cts.WifiLocationTest
Change-Id: Ibcf0c67114f09cbc25bf56b8ea5b63113defecc4
Merged-In: Ibcf0c67114f09cbc25bf56b8ea5b63113defecc4
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 28224cf..9e2bf94 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -284,6 +284,7 @@
     method public android.net.wifi.SupplicantState getSupplicantState();
     method @IntRange(from=0xffffffff) public int getTxLinkSpeedMbps();
     method public int getWifiStandard();
+    method @NonNull public android.net.wifi.WifiInfo makeCopy(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final String FREQUENCY_UNITS = "MHz";
     field public static final String LINK_SPEED_UNITS = "Mbps";
@@ -661,6 +662,7 @@
     method @Nullable public java.net.Inet6Address getPeerIpv6Addr();
     method public int getPort();
     method public int getTransportProtocol();
+    method @NonNull public android.net.wifi.aware.WifiAwareNetworkInfo makeCopy(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.WifiAwareNetworkInfo> CREATOR;
   }
diff --git a/framework/java/android/net/wifi/WifiInfo.java b/framework/java/android/net/wifi/WifiInfo.java
index 7437082..f0a9d60 100644
--- a/framework/java/android/net/wifi/WifiInfo.java
+++ b/framework/java/android/net/wifi/WifiInfo.java
@@ -16,11 +16,14 @@
 
 package android.net.wifi;
 
+import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
+
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.net.NetworkCapabilities;
 import android.net.NetworkInfo.DetailedState;
 import android.net.TransportInfo;
 import android.os.Build;
@@ -85,6 +88,12 @@
         stateMap.put(SupplicantState.INVALID, DetailedState.FAILED);
     }
 
+    /**
+     * Indicates whether parceling should preserve fields that are set based on permissions of
+     * the process receiving the {@link NetworkCapabilities}.
+     */
+    private final boolean mParcelLocationSenstiveFields;
+
     private SupplicantState mSupplicantState;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private String mBSSID;
@@ -309,6 +318,7 @@
     /** @hide */
     @UnsupportedAppUsage
     public WifiInfo() {
+        mParcelLocationSenstiveFields = false;
         mWifiSsid = null;
         mBSSID = null;
         mNetworkId = -1;
@@ -320,6 +330,12 @@
 
     /** @hide */
     public void reset() {
+        if (mParcelLocationSenstiveFields) {
+            // To ensure that we don't accidentally set this bit on the master copy of WifiInfo
+            // (reset is only invoked in the master copy)
+            throw new UnsupportedOperationException(
+                    "Cannot clear WifiInfo when parcelSensitiveLocationFields is set");
+        }
         setInetAddress(null);
         setBSSID(null);
         setSSID(null);
@@ -354,6 +370,15 @@
      * @hide
      */
     public WifiInfo(WifiInfo source) {
+        this(source, true);
+    }
+
+    /**
+     * Copy constructor
+     * @hide
+     */
+    private WifiInfo(WifiInfo source, boolean parcelSensitiveFields) {
+        mParcelLocationSenstiveFields = parcelSensitiveFields;
         if (source != null) {
             mSupplicantState = source.mSupplicantState;
             mBSSID = source.mBSSID;
@@ -918,7 +943,7 @@
         StringBuffer sb = new StringBuffer();
         String none = "<none>";
 
-        sb.append("SSID: ").append(mWifiSsid == null ? WifiManager.UNKNOWN_SSID : mWifiSsid)
+        sb.append("SSID: ").append(getSSID())
                 .append(", BSSID: ").append(mBSSID == null ? none : mBSSID)
                 .append(", MAC: ").append(mMacAddress == null ? none : mMacAddress)
                 .append(", Supplicant state: ")
@@ -946,7 +971,7 @@
 
     /** Implement the Parcelable interface {@hide} */
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mNetworkId);
+        dest.writeInt(mParcelLocationSenstiveFields ? mNetworkId : INVALID_NETWORK_ID);
         dest.writeInt(mRssi);
         dest.writeInt(mLinkSpeed);
         dest.writeInt(mTxLinkSpeed);
@@ -960,11 +985,17 @@
         }
         if (mWifiSsid != null) {
             dest.writeInt(1);
-            mWifiSsid.writeToParcel(dest, flags);
+            final WifiSsid ssid;
+            if (mParcelLocationSenstiveFields) {
+                ssid = mWifiSsid;
+            } else {
+                ssid = WifiSsid.createFromHex(null);
+            }
+            ssid.writeToParcel(dest, flags);
         } else {
             dest.writeInt(0);
         }
-        dest.writeString(mBSSID);
+        dest.writeString(mParcelLocationSenstiveFields ? mBSSID : DEFAULT_MAC_ADDRESS);
         dest.writeString(mMacAddress);
         dest.writeInt(mMeteredHint ? 1 : 0);
         dest.writeInt(mEphemeral ? 1 : 0);
@@ -981,12 +1012,12 @@
         mSupplicantState.writeToParcel(dest, flags);
         dest.writeInt(mOsuAp ? 1 : 0);
         dest.writeString(mRequestingPackageName);
-        dest.writeString(mFqdn);
-        dest.writeString(mProviderFriendlyName);
+        dest.writeString(mParcelLocationSenstiveFields ? mFqdn : null);
+        dest.writeString(mParcelLocationSenstiveFields ? mProviderFriendlyName : null);
         dest.writeInt(mWifiStandard);
         dest.writeInt(mMaxSupportedTxLinkSpeed);
         dest.writeInt(mMaxSupportedRxLinkSpeed);
-        dest.writeString(mPasspointUniqueId);
+        dest.writeString(mParcelLocationSenstiveFields ? mPasspointUniqueId : null);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -1143,4 +1174,30 @@
                 mMaxSupportedRxLinkSpeed,
                 mPasspointUniqueId);
     }
+
+    /**
+     * Make a copy of WifiInfo instance.
+     *
+     * @param parcelSensitiveFields Whether to parcel location sensitive fields or not.
+     * @return instance of {@link WifiInfo}.
+     */
+    @Override
+    @NonNull
+    public WifiInfo makeCopy(boolean parcelSensitiveFields) {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return new WifiInfo(this, parcelSensitiveFields);
+    }
+
+    /**
+     * Whether it has location sensitive data or not.
+     */
+    @Override
+    public boolean hasLocationSensitiveFields() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return true;
+    }
 }
diff --git a/framework/java/android/net/wifi/aware/WifiAwareNetworkInfo.java b/framework/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
index 60fe604..095c0de 100644
--- a/framework/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
+++ b/framework/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
@@ -16,12 +16,15 @@
 
 package android.net.wifi.aware;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.net.NetworkCapabilities;
 import android.net.TransportInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.modules.utils.build.SdkLevel;
+
 import java.net.Inet6Address;
 import java.net.NetworkInterface;
 import java.net.SocketException;
@@ -46,13 +49,22 @@
  * Note: these are the peer's IPv6 and port information - not the local device's!
  */
 public final class WifiAwareNetworkInfo implements TransportInfo, Parcelable {
-    private Inet6Address mIpv6Addr;
-    private int mPort = 0; // a value of 0 is considered invalid
-    private int mTransportProtocol = -1; // a value of -1 is considered invalid
+    private final Inet6Address mIpv6Addr;
+    private final int mPort;
+    private final int mTransportProtocol;
+
+    /** @hide */
+    public WifiAwareNetworkInfo() {
+        mIpv6Addr = null;
+        mPort = 0; // a value of 0 is considered invalid
+        mTransportProtocol = -1;  // a value of -1 is considered invalid
+    }
 
     /** @hide */
     public WifiAwareNetworkInfo(Inet6Address ipv6Addr) {
         mIpv6Addr = ipv6Addr;
+        mPort = 0; // a value of 0 is considered invalid
+        mTransportProtocol = -1;  // a value of -1 is considered invalid
     }
 
     /** @hide */
@@ -62,6 +74,12 @@
         mTransportProtocol = transportProtocol;
     }
 
+    private WifiAwareNetworkInfo(@Nullable WifiAwareNetworkInfo source) {
+        mIpv6Addr = source != null ? source.mIpv6Addr : null;
+        mPort = source != null ? source.mPort : 0;
+        mTransportProtocol = source != null ? source.mTransportProtocol : -1;
+    }
+
     /**
      * Get the scoped link-local IPv6 address of the Wi-Fi Aware peer (not of the local device!).
      *
@@ -137,7 +155,7 @@
                         ipv6Addr = Inet6Address.getByAddress(null, addr, ni);
                     } catch (UnknownHostException e) {
                         e.printStackTrace();
-                        return new WifiAwareNetworkInfo(null);
+                        return new WifiAwareNetworkInfo();
                     }
                     return new WifiAwareNetworkInfo(ipv6Addr, port, transportProtocol);
                 }
@@ -179,4 +197,31 @@
     public int hashCode() {
         return Objects.hash(mIpv6Addr, mPort, mTransportProtocol);
     }
+
+    /**
+     * Make a copy of WifiAwareNetworkInfo instance.
+     *
+     * @param parcelSensitiveFields Whether to parcel location sensitive fields or not.
+     * @return instance of {@link WifiAwareNetworkInfo}.
+     */
+    @Override
+    @NonNull
+    public WifiAwareNetworkInfo makeCopy(boolean parcelSensitiveFields) {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        // No location sensitive data, ignore parcelSensitiveFields.
+        return new WifiAwareNetworkInfo(this);
+    }
+
+    /**
+     * Whether it has location sensitive data or not.
+     */
+    @Override
+    public boolean hasLocationSensitiveFields() {
+        if (!SdkLevel.isAtLeastS()) {
+            throw new UnsupportedOperationException();
+        }
+        return false;
+    }
 }
diff --git a/framework/tests/src/android/net/wifi/WifiInfoTest.java b/framework/tests/src/android/net/wifi/WifiInfoTest.java
index cf1f83a..5cb16a5 100644
--- a/framework/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/framework/tests/src/android/net/wifi/WifiInfoTest.java
@@ -17,10 +17,13 @@
 package android.net.wifi;
 
 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.assertNotSame;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
 
 import android.os.Parcel;
 
@@ -57,7 +60,112 @@
      *  Verify parcel write/read with WifiInfo.
      */
     @Test
-    public void testWifiInfoParcelWriteRead() throws Exception {
+    public void testWifiInfoParcelWriteReadWithLocationSensitiveInfo() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        WifiInfo writeWifiInfo = new WifiInfo();
+        writeWifiInfo.txSuccess = TEST_TX_SUCCESS;
+        writeWifiInfo.txRetries = TEST_TX_RETRIES;
+        writeWifiInfo.txBad = TEST_TX_BAD;
+        writeWifiInfo.rxSuccess = TEST_RX_SUCCESS;
+        writeWifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID));
+        writeWifiInfo.setBSSID(TEST_BSSID);
+        writeWifiInfo.setNetworkId(TEST_NETWORK_ID);
+        writeWifiInfo.setTrusted(true);
+        writeWifiInfo.setOsuAp(true);
+        writeWifiInfo.setFQDN(TEST_FQDN);
+        writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME);
+        writeWifiInfo.setRequestingPackageName(TEST_PACKAGE_NAME);
+        writeWifiInfo.setWifiStandard(TEST_WIFI_STANDARD);
+        writeWifiInfo.setMaxSupportedTxLinkSpeedMbps(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS);
+        writeWifiInfo.setMaxSupportedRxLinkSpeedMbps(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS);
+
+        // Make a copy which allows parcelling of location sensitive data.
+        WifiInfo writeWifiInfoWithLocationSensitiveInfo = writeWifiInfo.makeCopy(true);
+
+        Parcel parcel = Parcel.obtain();
+        writeWifiInfoWithLocationSensitiveInfo.writeToParcel(parcel, 0);
+        // Rewind the pointer to the head of the parcel.
+        parcel.setDataPosition(0);
+        WifiInfo readWifiInfo = WifiInfo.CREATOR.createFromParcel(parcel);
+
+        assertNotNull(readWifiInfo);
+        assertEquals(TEST_TX_SUCCESS, readWifiInfo.txSuccess);
+        assertEquals(TEST_TX_RETRIES, readWifiInfo.txRetries);
+        assertEquals(TEST_TX_BAD, readWifiInfo.txBad);
+        assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess);
+        assertEquals("\"" + TEST_SSID + "\"", readWifiInfo.getSSID());
+        assertEquals(TEST_BSSID, readWifiInfo.getBSSID());
+        assertEquals(TEST_NETWORK_ID, readWifiInfo.getNetworkId());
+        assertTrue(readWifiInfo.isTrusted());
+        assertTrue(readWifiInfo.isOsuAp());
+        assertTrue(readWifiInfo.isPasspointAp());
+        assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getRequestingPackageName());
+        assertEquals(TEST_FQDN, readWifiInfo.getPasspointFqdn());
+        assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getPasspointProviderFriendlyName());
+        assertEquals(TEST_WIFI_STANDARD, readWifiInfo.getWifiStandard());
+        assertEquals(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS,
+                readWifiInfo.getMaxSupportedTxLinkSpeedMbps());
+        assertEquals(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS,
+                readWifiInfo.getMaxSupportedRxLinkSpeedMbps());
+    }
+
+    /**
+     *  Verify parcel write/read with WifiInfo.
+     */
+    @Test
+    public void testWifiInfoParcelWriteReadWithoutLocationSensitiveInfo() throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+
+        WifiInfo writeWifiInfo = new WifiInfo();
+        writeWifiInfo.txSuccess = TEST_TX_SUCCESS;
+        writeWifiInfo.txRetries = TEST_TX_RETRIES;
+        writeWifiInfo.txBad = TEST_TX_BAD;
+        writeWifiInfo.rxSuccess = TEST_RX_SUCCESS;
+        writeWifiInfo.setSSID(WifiSsid.createFromAsciiEncoded(TEST_SSID));
+        writeWifiInfo.setBSSID(TEST_BSSID);
+        writeWifiInfo.setNetworkId(TEST_NETWORK_ID);
+        writeWifiInfo.setTrusted(true);
+        writeWifiInfo.setOsuAp(true);
+        writeWifiInfo.setFQDN(TEST_FQDN);
+        writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME);
+        writeWifiInfo.setRequestingPackageName(TEST_PACKAGE_NAME);
+        writeWifiInfo.setWifiStandard(TEST_WIFI_STANDARD);
+        writeWifiInfo.setMaxSupportedTxLinkSpeedMbps(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS);
+        writeWifiInfo.setMaxSupportedRxLinkSpeedMbps(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS);
+
+        // Make a copy which allows parcelling of location sensitive data.
+        WifiInfo writeWifiInfoWithoutLocationSensitiveInfo = writeWifiInfo.makeCopy(false);
+
+        Parcel parcel = Parcel.obtain();
+        writeWifiInfoWithoutLocationSensitiveInfo.writeToParcel(parcel, 0);
+        // Rewind the pointer to the head of the parcel.
+        parcel.setDataPosition(0);
+        WifiInfo readWifiInfo = WifiInfo.CREATOR.createFromParcel(parcel);
+
+        assertNotNull(readWifiInfo);
+        assertEquals(TEST_TX_SUCCESS, readWifiInfo.txSuccess);
+        assertEquals(TEST_TX_RETRIES, readWifiInfo.txRetries);
+        assertEquals(TEST_TX_BAD, readWifiInfo.txBad);
+        assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess);
+        assertEquals(WifiManager.UNKNOWN_SSID, readWifiInfo.getSSID());
+        assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS, readWifiInfo.getBSSID());
+        assertEquals(WifiConfiguration.INVALID_NETWORK_ID, readWifiInfo.getNetworkId());
+        assertTrue(readWifiInfo.isTrusted());
+        assertTrue(readWifiInfo.isOsuAp());
+        assertFalse(readWifiInfo.isPasspointAp()); // fqdn & friendly name is masked.
+        assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getRequestingPackageName());
+        assertNull(readWifiInfo.getPasspointFqdn());
+        assertNull(readWifiInfo.getPasspointProviderFriendlyName());
+        assertEquals(TEST_WIFI_STANDARD, readWifiInfo.getWifiStandard());
+        assertEquals(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS,
+                readWifiInfo.getMaxSupportedTxLinkSpeedMbps());
+        assertEquals(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS,
+                readWifiInfo.getMaxSupportedRxLinkSpeedMbps());
+    }
+
+    @Test
+    public void testWifiInfoCopyConstructor() throws Exception {
         WifiInfo writeWifiInfo = new WifiInfo();
         writeWifiInfo.txSuccess = TEST_TX_SUCCESS;
         writeWifiInfo.txRetries = TEST_TX_RETRIES;
@@ -72,13 +180,8 @@
         writeWifiInfo.setMaxSupportedTxLinkSpeedMbps(TEST_MAX_SUPPORTED_TX_LINK_SPEED_MBPS);
         writeWifiInfo.setMaxSupportedRxLinkSpeedMbps(TEST_MAX_SUPPORTED_RX_LINK_SPEED_MBPS);
 
-        Parcel parcel = Parcel.obtain();
-        writeWifiInfo.writeToParcel(parcel, 0);
-        // Rewind the pointer to the head of the parcel.
-        parcel.setDataPosition(0);
-        WifiInfo readWifiInfo = WifiInfo.CREATOR.createFromParcel(parcel);
+        WifiInfo readWifiInfo = new WifiInfo(writeWifiInfo);
 
-        assertNotNull(readWifiInfo);
         assertEquals(TEST_TX_SUCCESS, readWifiInfo.txSuccess);
         assertEquals(TEST_TX_RETRIES, readWifiInfo.txRetries);
         assertEquals(TEST_TX_BAD, readWifiInfo.txBad);