summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/moduleutils/src/android/net/shared/ProvisioningConfiguration.java182
-rw-r--r--common/networkstackclient/Android.bp3
-rw-r--r--common/networkstackclient/src/android/net/InformationElementParcelable.aidl22
-rw-r--r--common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl2
-rw-r--r--common/networkstackclient/src/android/net/ScanResultInfoParcelable.aidl24
-rw-r--r--tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java27
6 files changed, 257 insertions, 3 deletions
diff --git a/common/moduleutils/src/android/net/shared/ProvisioningConfiguration.java b/common/moduleutils/src/android/net/shared/ProvisioningConfiguration.java
index 00b4e19..7de376a 100644
--- a/common/moduleutils/src/android/net/shared/ProvisioningConfiguration.java
+++ b/common/moduleutils/src/android/net/shared/ProvisioningConfiguration.java
@@ -16,14 +16,25 @@
package android.net.shared;
+import static android.net.shared.ParcelableUtil.fromParcelableArray;
+import static android.net.shared.ParcelableUtil.toParcelableArray;
+
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.INetd;
+import android.net.InformationElementParcelable;
import android.net.Network;
import android.net.ProvisioningConfigurationParcelable;
+import android.net.ScanResultInfoParcelable;
import android.net.StaticIpConfiguration;
import android.net.apf.ApfCapabilities;
import android.net.ip.IIpClient;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;
@@ -193,6 +204,17 @@ public class ProvisioningConfiguration {
}
/**
+ * Specify the information elements included in wifi scan result that was obtained
+ * prior to connecting to the access point, if this is a WiFi network.
+ *
+ * <p>The scan result can be used to infer whether the network is metered.
+ */
+ public Builder withScanResultInfo(ScanResultInfo scanResultInfo) {
+ mConfig.mScanResultInfo = scanResultInfo;
+ return this;
+ }
+
+ /**
* Build the configuration using previously specified parameters.
*/
public ProvisioningConfiguration build() {
@@ -200,6 +222,158 @@ public class ProvisioningConfiguration {
}
}
+ /**
+ * Class wrapper of {@link android.net.wifi.ScanResult} to encapsulate the SSID and
+ * InformationElements fields of ScanResult.
+ */
+ public static class ScanResultInfo {
+ private final String mSsid;
+ private final List<InformationElement> mInformationElements;
+
+ /**
+ * Class wrapper of {@link android.net.wifi.ScanResult.InformationElement} to encapsulate
+ * the specific IE id and payload fields.
+ */
+ public static class InformationElement {
+ private final int mId;
+ private final byte[] mPayload;
+
+ public InformationElement(int id, @NonNull ByteBuffer payload) {
+ mId = id;
+ mPayload = convertToByteArray(payload.asReadOnlyBuffer());
+ }
+
+ /**
+ * Get the element ID of the information element.
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * Get the specific content of the information element.
+ */
+ public ByteBuffer getPayload() {
+ return ByteBuffer.wrap(mPayload).asReadOnlyBuffer();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof InformationElement)) return false;
+ InformationElement other = (InformationElement) o;
+ return mId == other.mId && Arrays.equals(mPayload, other.mPayload);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId, mPayload);
+ }
+
+ @Override
+ public String toString() {
+ return "ID: " + mId + ", " + Arrays.toString(mPayload);
+ }
+
+ /**
+ * Convert this InformationElement to a {@link InformationElementParcelable}.
+ */
+ public InformationElementParcelable toStableParcelable() {
+ final InformationElementParcelable p = new InformationElementParcelable();
+ p.id = mId;
+ p.payload = mPayload.clone();
+ return p;
+ }
+
+ /**
+ * Create an instance of {@link InformationElement} based on the contents of the
+ * specified {@link InformationElementParcelable}.
+ */
+ public static InformationElement fromStableParcelable(InformationElementParcelable p) {
+ if (p == null) return null;
+ return new InformationElement(p.id,
+ ByteBuffer.wrap(p.payload.clone()).asReadOnlyBuffer());
+ }
+ }
+
+ public ScanResultInfo(String ssid, @NonNull List<InformationElement> informationElements) {
+ mSsid = ssid;
+ mInformationElements =
+ Collections.unmodifiableList(new ArrayList<>(informationElements));
+ }
+
+ /**
+ * Get the scanned network name.
+ */
+ public String getSsid() {
+ return mSsid;
+ }
+
+ /**
+ * Get all information elements found in the beacon.
+ */
+ public List<InformationElement> getInformationElements() {
+ return mInformationElements;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer str = new StringBuffer();
+ str.append("SSID: ").append(mSsid);
+ str.append(", Information Elements: {");
+ for (InformationElement ie : mInformationElements) {
+ str.append("[").append(ie.toString()).append("]");
+ }
+ str.append("}");
+ return str.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof ScanResultInfo)) return false;
+ ScanResultInfo other = (ScanResultInfo) o;
+ return Objects.equals(mSsid, other.mSsid)
+ && mInformationElements.equals(other.mInformationElements);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mSsid, mInformationElements);
+ }
+
+ /**
+ * Convert this ScanResultInfo to a {@link ScanResultInfoParcelable}.
+ */
+ public ScanResultInfoParcelable toStableParcelable() {
+ final ScanResultInfoParcelable p = new ScanResultInfoParcelable();
+ p.ssid = mSsid;
+ p.informationElements = toParcelableArray(mInformationElements,
+ InformationElement::toStableParcelable, InformationElementParcelable.class);
+ return p;
+ }
+
+ /**
+ * Create an instance of {@link ScanResultInfo} based on the contents of the specified
+ * {@link ScanResultInfoParcelable}.
+ */
+ public static ScanResultInfo fromStableParcelable(ScanResultInfoParcelable p) {
+ if (p == null) return null;
+ final List<InformationElement> ies = new ArrayList<InformationElement>();
+ ies.addAll(fromParcelableArray(p.informationElements,
+ InformationElement::fromStableParcelable));
+ return new ScanResultInfo(p.ssid, ies);
+ }
+
+ private static byte[] convertToByteArray(final ByteBuffer buffer) {
+ if (buffer == null) return null;
+ byte[] bytes = new byte[buffer.limit()];
+ final ByteBuffer copy = buffer.asReadOnlyBuffer();
+ copy.get(bytes);
+ return bytes;
+ }
+ }
+
public boolean mEnableIPv4 = true;
public boolean mEnableIPv6 = true;
public boolean mEnablePreconnection = false;
@@ -213,6 +387,7 @@ public class ProvisioningConfiguration {
public int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
public Network mNetwork = null;
public String mDisplayName = null;
+ public ScanResultInfo mScanResultInfo;
public ProvisioningConfiguration() {} // used by Builder
@@ -232,6 +407,7 @@ public class ProvisioningConfiguration {
mIPv6AddrGenMode = other.mIPv6AddrGenMode;
mNetwork = other.mNetwork;
mDisplayName = other.mDisplayName;
+ mScanResultInfo = other.mScanResultInfo;
}
/**
@@ -254,6 +430,7 @@ public class ProvisioningConfiguration {
p.ipv6AddrGenMode = mIPv6AddrGenMode;
p.network = mNetwork;
p.displayName = mDisplayName;
+ p.scanResultInfo = mScanResultInfo == null ? null : mScanResultInfo.toStableParcelable();
return p;
}
@@ -279,6 +456,7 @@ public class ProvisioningConfiguration {
config.mIPv6AddrGenMode = p.ipv6AddrGenMode;
config.mNetwork = p.network;
config.mDisplayName = p.displayName;
+ config.mScanResultInfo = ScanResultInfo.fromStableParcelable(p.scanResultInfo);
return config;
}
@@ -298,6 +476,7 @@ public class ProvisioningConfiguration {
.add("mIPv6AddrGenMode: " + mIPv6AddrGenMode)
.add("mNetwork: " + mNetwork)
.add("mDisplayName: " + mDisplayName)
+ .add("mScanResultInfo: " + mScanResultInfo)
.toString();
}
@@ -317,7 +496,8 @@ public class ProvisioningConfiguration {
&& mProvisioningTimeoutMs == other.mProvisioningTimeoutMs
&& mIPv6AddrGenMode == other.mIPv6AddrGenMode
&& Objects.equals(mNetwork, other.mNetwork)
- && Objects.equals(mDisplayName, other.mDisplayName);
+ && Objects.equals(mDisplayName, other.mDisplayName)
+ && Objects.equals(mScanResultInfo, other.mScanResultInfo);
}
public boolean isValid() {
diff --git a/common/networkstackclient/Android.bp b/common/networkstackclient/Android.bp
index 31f3384..dbe8ff0 100644
--- a/common/networkstackclient/Android.bp
+++ b/common/networkstackclient/Android.bp
@@ -45,6 +45,7 @@ aidl_interface {
include_dirs: [
"frameworks/base/core/java", // For framework parcelables.
"frameworks/native/aidl/binder/android/os", // For PersistableBundle.aidl
+ "frameworks/base/wifi/aidl-export", // For wifi parcelables.
],
srcs: [
"src/android/net/DhcpResultsParcelable.aidl",
@@ -53,10 +54,12 @@ aidl_interface {
"src/android/net/INetworkStackConnector.aidl",
"src/android/net/INetworkStackStatusCallback.aidl",
"src/android/net/InitialConfigurationParcelable.aidl",
+ "src/android/net/InformationElementParcelable.aidl",
"src/android/net/Layer2PacketParcelable.aidl",
"src/android/net/NattKeepalivePacketDataParcelable.aidl",
"src/android/net/PrivateDnsConfigParcel.aidl",
"src/android/net/ProvisioningConfigurationParcelable.aidl",
+ "src/android/net/ScanResultInfoParcelable.aidl",
"src/android/net/TcpKeepalivePacketDataParcelable.aidl",
"src/android/net/dhcp/DhcpServingParamsParcel.aidl",
"src/android/net/dhcp/IDhcpServer.aidl",
diff --git a/common/networkstackclient/src/android/net/InformationElementParcelable.aidl b/common/networkstackclient/src/android/net/InformationElementParcelable.aidl
new file mode 100644
index 0000000..c70bf6f
--- /dev/null
+++ b/common/networkstackclient/src/android/net/InformationElementParcelable.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 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 android.net;
+
+parcelable InformationElementParcelable {
+ int id;
+ byte[] payload;
+}
diff --git a/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl b/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl
index 0b6d7d5..9fcb036 100644
--- a/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl
+++ b/common/networkstackclient/src/android/net/ProvisioningConfigurationParcelable.aidl
@@ -19,6 +19,7 @@ package android.net;
import android.net.InitialConfigurationParcelable;
import android.net.Network;
+import android.net.ScanResultInfoParcelable;
import android.net.StaticIpConfiguration;
import android.net.apf.ApfCapabilities;
@@ -36,4 +37,5 @@ parcelable ProvisioningConfigurationParcelable {
Network network;
String displayName;
boolean enablePreconnection;
+ ScanResultInfoParcelable scanResultInfo;
}
diff --git a/common/networkstackclient/src/android/net/ScanResultInfoParcelable.aidl b/common/networkstackclient/src/android/net/ScanResultInfoParcelable.aidl
new file mode 100644
index 0000000..f5f101d
--- /dev/null
+++ b/common/networkstackclient/src/android/net/ScanResultInfoParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 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 android.net;
+
+import android.net.InformationElementParcelable;
+
+parcelable ScanResultInfoParcelable {
+ String ssid;
+ InformationElementParcelable[] informationElements;
+}
diff --git a/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java b/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java
index e645a2c..e9384c8 100644
--- a/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java
+++ b/tests/unit/src/android/net/shared/ProvisioningConfigurationTest.java
@@ -28,6 +28,7 @@ import android.net.LinkAddress;
import android.net.Network;
import android.net.StaticIpConfiguration;
import android.net.apf.ApfCapabilities;
+import android.net.shared.ProvisioningConfiguration.ScanResultInfo;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -36,6 +37,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.nio.ByteBuffer;
+import java.util.Collections;
import java.util.function.Consumer;
/**
@@ -46,6 +49,17 @@ import java.util.function.Consumer;
public class ProvisioningConfigurationTest {
private ProvisioningConfiguration mConfig;
+ private ScanResultInfo makeScanResultInfo(final String ssid) {
+ final byte[] payload = new byte[] {
+ (byte) 0x00, (byte) 0x17, (byte) 0xF2, (byte) 0x06, (byte) 0x01,
+ (byte) 0x01, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x00,
+ };
+ final ScanResultInfo.InformationElement ie =
+ new ScanResultInfo.InformationElement(0xdd /* vendor specific IE id */,
+ ByteBuffer.wrap(payload));
+ return new ScanResultInfo(ssid, Collections.singletonList(ie));
+ }
+
@Before
public void setUp() {
mConfig = new ProvisioningConfiguration();
@@ -67,8 +81,9 @@ public class ProvisioningConfigurationTest {
mConfig.mNetwork = new Network(321);
mConfig.mDisplayName = "test_config";
mConfig.mEnablePreconnection = false;
+ mConfig.mScanResultInfo = makeScanResultInfo("ssid");
// Any added field must be included in equals() to be tested properly
- assertFieldCountEquals(13, ProvisioningConfiguration.class);
+ assertFieldCountEquals(14, ProvisioningConfiguration.class);
}
@Test
@@ -101,6 +116,12 @@ public class ProvisioningConfigurationTest {
}
@Test
+ public void testParcelUnparcel_NullScanResultInfo() {
+ mConfig.mScanResultInfo = null;
+ doParcelUnparcelTest();
+ }
+
+ @Test
public void testParcelUnparcel_WithPreDhcpConnection() {
mConfig.mEnablePreconnection = true;
doParcelUnparcelTest();
@@ -136,7 +157,9 @@ public class ProvisioningConfigurationTest {
assertNotEqualsAfterChange(c -> c.mDisplayName = "other_test");
assertNotEqualsAfterChange(c -> c.mDisplayName = null);
assertNotEqualsAfterChange(c -> c.mEnablePreconnection = true);
- assertFieldCountEquals(13, ProvisioningConfiguration.class);
+ assertNotEqualsAfterChange(c -> c.mScanResultInfo = null);
+ assertNotEqualsAfterChange(c -> c.mScanResultInfo = makeScanResultInfo("another ssid"));
+ assertFieldCountEquals(14, ProvisioningConfiguration.class);
}
private void assertNotEqualsAfterChange(Consumer<ProvisioningConfiguration> mutator) {