summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoshan Pius <rpius@google.com>2019-11-14 13:49:05 -0800
committerRoshan Pius <rpius@google.com>2019-11-18 11:38:02 -0800
commit017204e52af26d4dcf36889118c6eda91569fbdc (patch)
tree60cf8c2056a012bc81464ef1e29bb5ceb26a7bcd
parent24047e6933dcabd530fb2886ee343fded08b2604 (diff)
SoftApStoreData: Class for serializing/deserializing softap config
Bug: 144487256 Test: atest com.android.server.wifi Change-Id: Ic250919b2086774157df3dce589a222404f4013b
-rw-r--r--service/java/com/android/server/wifi/SoftApStoreData.java172
-rw-r--r--tests/wifitests/Android.bp1
-rw-r--r--tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java205
3 files changed, 378 insertions, 0 deletions
diff --git a/service/java/com/android/server/wifi/SoftApStoreData.java b/service/java/com/android/server/wifi/SoftApStoreData.java
new file mode 100644
index 000000000..2879c2aad
--- /dev/null
+++ b/service/java/com/android/server/wifi/SoftApStoreData.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2019 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.wifi;
+
+import android.annotation.Nullable;
+import android.net.wifi.WifiConfiguration;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil;
+import com.android.server.wifi.util.XmlUtil;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.BitSet;
+
+/**
+ * Store data for SoftAp
+ */
+public class SoftApStoreData implements WifiConfigStore.StoreData {
+ private static final String TAG = "SoftApStoreData";
+ private static final String XML_TAG_SECTION_HEADER_SOFTAP = "SoftAp";
+ private static final String XML_TAG_SSID = "SSID";
+ private static final String XML_TAG_BAND = "Band";
+ private static final String XML_TAG_CHANNEL = "Channel";
+ private static final String XML_TAG_HIDDEN_SSID = "HiddenSSID";
+ private static final String XML_TAG_ALLOWED_KEY_MGMT = "AllowedKeyMgmt";
+ private static final String XML_TAG_PRE_SHARED_KEY = "PreSharedKey";
+
+ private final DataSource mDataSource;
+
+ /**
+ * Interface define the data source for the notifier store data.
+ */
+ public interface DataSource {
+ /**
+ * Retrieve the SoftAp configuration from the data source to serialize them to disk.
+ *
+ * @return {@link WifiConfiguration} Instance of WifiConfiguration.
+ */
+ WifiConfiguration toSerialize();
+
+ /**
+ * Set the SoftAp configuration in the data source after serializing them from disk.
+ *
+ * @param config {@link WifiConfiguration} Instance of WifiConfiguration.
+ */
+ void fromDeserialized(WifiConfiguration config);
+
+ /**
+ * Clear internal data structure in preparation for user switch or initial store read.
+ */
+ void reset();
+
+ /**
+ * Indicates whether there is new data to serialize.
+ */
+ boolean hasNewDataToSerialize();
+ }
+
+ /**
+ * Creates the SSID Set store data.
+ *
+ * @param dataSource The DataSource that implements the update and retrieval of the SSID set.
+ */
+ SoftApStoreData(DataSource dataSource) {
+ mDataSource = dataSource;
+ }
+
+ @Override
+ public void serializeData(XmlSerializer out,
+ @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
+ throws XmlPullParserException, IOException {
+ WifiConfiguration softApConfig = mDataSource.toSerialize();
+ if (softApConfig != null) {
+ XmlUtil.writeNextValue(out, XML_TAG_SSID, softApConfig.SSID);
+ XmlUtil.writeNextValue(out, XML_TAG_BAND, softApConfig.apBand);
+ XmlUtil.writeNextValue(out, XML_TAG_CHANNEL, softApConfig.apChannel);
+ XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, softApConfig.hiddenSSID);
+ XmlUtil.writeNextValue(
+ out, XML_TAG_ALLOWED_KEY_MGMT,
+ softApConfig.allowedKeyManagement.toByteArray());
+ XmlUtil.writeNextValue(out, XML_TAG_PRE_SHARED_KEY, softApConfig.preSharedKey);
+ }
+ }
+
+ @Override
+ public void deserializeData(XmlPullParser in, int outerTagDepth,
+ @WifiConfigStore.Version int version,
+ @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
+ throws XmlPullParserException, IOException {
+ // Ignore empty reads.
+ if (in == null) {
+ return;
+ }
+ WifiConfiguration softApConfig = new WifiConfiguration();
+ while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
+ String[] valueName = new String[1];
+ Object value = XmlUtil.readCurrentValue(in, valueName);
+ if (TextUtils.isEmpty(valueName[0])) {
+ throw new XmlPullParserException("Missing value name");
+ }
+ switch (valueName[0]) {
+ case XML_TAG_SSID:
+ softApConfig.SSID = (String) value;
+ break;
+ case XML_TAG_BAND:
+ softApConfig.apBand = (int) value;
+ break;
+ case XML_TAG_CHANNEL:
+ softApConfig.apChannel = (int) value;
+ break;
+ case XML_TAG_HIDDEN_SSID:
+ softApConfig.hiddenSSID = (boolean) value;
+ break;
+ case XML_TAG_ALLOWED_KEY_MGMT:
+ byte[] allowedKeyMgmt = (byte[]) value;
+ softApConfig.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt);
+ break;
+ case XML_TAG_PRE_SHARED_KEY:
+ softApConfig.preSharedKey = (String) value;
+ break;
+ default:
+ Log.w(TAG, "Ignoring unknown value name " + valueName[0]);
+ break;
+ }
+ }
+ // We should at-least have SSID restored from store.
+ if (softApConfig.SSID == null) {
+ Log.e(TAG, "Failed to parse SSID");
+ return;
+ }
+ mDataSource.fromDeserialized(softApConfig);
+ }
+
+ @Override
+ public void resetData() {
+ mDataSource.reset();
+ }
+
+ @Override
+ public boolean hasNewDataToSerialize() {
+ return mDataSource.hasNewDataToSerialize();
+ }
+
+ @Override
+ public String getName() {
+ return XML_TAG_SECTION_HEADER_SOFTAP;
+ }
+
+ @Override
+ public @WifiConfigStore.StoreFileId int getStoreFileId() {
+ return WifiConfigStore.STORE_FILE_SHARED_SOFTAP; // Shared softap store.
+ }
+}
diff --git a/tests/wifitests/Android.bp b/tests/wifitests/Android.bp
index 3bbbc46c2..341ab0982 100644
--- a/tests/wifitests/Android.bp
+++ b/tests/wifitests/Android.bp
@@ -250,6 +250,7 @@ android_test {
"com.android.server.wifi.SoftApManager",
"com.android.server.wifi.SoftApManager.*",
"com.android.server.wifi.SoftApModeConfiguration",
+ "com.android.server.wifi.SoftApStoreData",
"com.android.server.wifi.SsidSetStoreData",
"com.android.server.wifi.SsidSetStoreData.*",
"com.android.server.wifi.StateChangeResult",
diff --git a/tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java
new file mode 100644
index 000000000..577767c16
--- /dev/null
+++ b/tests/wifitests/src/com/android/server/wifi/SoftApStoreDataTest.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2019 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.wifi;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.net.wifi.WifiConfiguration;
+import android.util.Xml;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Unit tests for {@link com.android.server.wifi.SoftApStoreData}.
+ */
+@SmallTest
+public class SoftApStoreDataTest extends WifiBaseTest {
+ private static final String TEST_SSID = "SSID";
+ private static final String TEST_PRESHARED_KEY = "Test";
+ private static final boolean TEST_HIDDEN = false;
+ private static final int TEST_BAND = WifiConfiguration.AP_BAND_ANY;
+ private static final int TEST_CHANNEL = 0;
+
+ private static final String TEST_SOFTAP_CONFIG_XML_STRING =
+ "<string name=\"SSID\">" + TEST_SSID + "</string>\n"
+ + "<int name=\"Band\" value=\"" + TEST_BAND + "\" />\n"
+ + "<int name=\"Channel\" value=\"" + TEST_CHANNEL + "\" />\n"
+ + "<boolean name=\"HiddenSSID\" value=\"" + TEST_HIDDEN + "\" />\n"
+ + "<byte-array name=\"AllowedKeyMgmt\" num=\"1\">02</byte-array>\n"
+ + "<string name=\"PreSharedKey\">" + TEST_PRESHARED_KEY + "</string>\n";
+
+ @Mock SoftApStoreData.DataSource mDataSource;
+ SoftApStoreData mSoftApStoreData;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mSoftApStoreData = new SoftApStoreData(mDataSource);
+ }
+
+ /**
+ * Helper function for serializing configuration data to a XML block.
+ *
+ * @return byte[] of the XML data
+ * @throws Exception
+ */
+ private byte[] serializeData() throws Exception {
+ final XmlSerializer out = new FastXmlSerializer();
+ final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+ mSoftApStoreData.serializeData(out, mock(WifiConfigStoreEncryptionUtil.class));
+ out.flush();
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * Helper function for parsing configuration data from a XML block.
+ *
+ * @param data XML data to parse from
+ * @throws Exception
+ */
+ private void deserializeData(byte[] data) throws Exception {
+ final XmlPullParser in = Xml.newPullParser();
+ final ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
+ in.setInput(inputStream, StandardCharsets.UTF_8.name());
+ mSoftApStoreData.deserializeData(in, in.getDepth(),
+ WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION,
+ mock(WifiConfigStoreEncryptionUtil.class));
+ }
+
+ /**
+ * Verify that parsing an empty data doesn't cause any crash and no configuration should
+ * be deserialized.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void deserializeEmptyStoreData() throws Exception {
+ deserializeData(new byte[0]);
+ verify(mDataSource, never()).fromDeserialized(any());
+ }
+
+ /**
+ * Verify that SoftApStoreData is written to
+ * {@link WifiConfigStore#STORE_FILE_SHARED_SOFTAP}.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void getUserStoreFileId() throws Exception {
+ assertEquals(WifiConfigStore.STORE_FILE_SHARED_SOFTAP,
+ mSoftApStoreData.getStoreFileId());
+ }
+
+ /**
+ * Verify that the store data is serialized correctly, matches the predefined test XML data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void serializeSoftAp() throws Exception {
+ WifiConfiguration softApConfig = new WifiConfiguration();
+ softApConfig.SSID = TEST_SSID;
+ softApConfig.preSharedKey = TEST_PRESHARED_KEY;
+ softApConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ softApConfig.apBand = TEST_BAND;
+ softApConfig.apChannel = TEST_CHANNEL;
+
+ when(mDataSource.toSerialize()).thenReturn(softApConfig);
+ byte[] actualData = serializeData();
+ assertEquals(TEST_SOFTAP_CONFIG_XML_STRING, new String(actualData));
+ }
+
+ /**
+ * Verify that the store data is deserialized correctly using the predefined test XML data.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void deserializeSoftAp() throws Exception {
+ deserializeData(TEST_SOFTAP_CONFIG_XML_STRING.getBytes());
+
+ ArgumentCaptor<WifiConfiguration> softapConfigCaptor =
+ ArgumentCaptor.forClass(WifiConfiguration.class);
+ verify(mDataSource).fromDeserialized(softapConfigCaptor.capture());
+ WifiConfiguration softApConfig = softapConfigCaptor.getValue();
+ assertNotNull(softApConfig);
+ assertEquals(softApConfig.SSID, TEST_SSID);
+ assertEquals(softApConfig.preSharedKey, TEST_PRESHARED_KEY);
+ assertTrue(softApConfig.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK));
+ assertEquals(softApConfig.hiddenSSID, TEST_HIDDEN);
+ assertEquals(softApConfig.apBand, TEST_BAND);
+ assertEquals(softApConfig.apChannel, TEST_CHANNEL);
+ }
+
+ /**
+ * Verify that the store data is serialized/deserialized correctly.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void serializeDeserializeSoftAp() throws Exception {
+ WifiConfiguration softApConfig = new WifiConfiguration();
+ softApConfig.SSID = TEST_SSID;
+ softApConfig.preSharedKey = TEST_PRESHARED_KEY;
+ softApConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
+ softApConfig.apBand = TEST_BAND;
+ softApConfig.apChannel = TEST_CHANNEL;
+
+ // Serialize first.
+ when(mDataSource.toSerialize()).thenReturn(softApConfig);
+ byte[] serializedData = serializeData();
+
+ // Now deserialize first.
+ deserializeData(serializedData);
+ ArgumentCaptor<WifiConfiguration> softapConfigCaptor =
+ ArgumentCaptor.forClass(WifiConfiguration.class);
+ verify(mDataSource).fromDeserialized(softapConfigCaptor.capture());
+ WifiConfiguration softApConfigDeserialized = softapConfigCaptor.getValue();
+ assertNotNull(softApConfigDeserialized);
+
+ assertEquals(softApConfig.SSID, softApConfigDeserialized.SSID);
+ assertEquals(softApConfig.preSharedKey, softApConfigDeserialized.preSharedKey);
+ assertEquals(softApConfig.allowedKeyManagement,
+ softApConfigDeserialized.allowedKeyManagement);
+ assertEquals(softApConfig.hiddenSSID, softApConfigDeserialized.hiddenSSID);
+ assertEquals(softApConfig.apBand, softApConfigDeserialized.apBand);
+ assertEquals(softApConfig.apChannel, softApConfigDeserialized.apChannel);
+ }
+}