diff options
author | Roshan Pius <rpius@google.com> | 2018-11-05 16:18:53 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-11-05 16:18:53 +0000 |
commit | 356236173d6dc1dc992376cd717cdd8c509f6872 (patch) | |
tree | 8a197a4cd90f3aa805f7baac83481591796e96dc | |
parent | 163e683668606f6b0a30535fb2e4219d0e0180a5 (diff) | |
parent | 697799b05b333bab62965d29f7b4fcb91b14fed9 (diff) |
Merge changes Ibc07a7ad,Iebe54b6b
* changes:
WifiConfigStore Refactor (2/2)
WifiConfigStore Refactor (1/2)
23 files changed, 1172 insertions, 741 deletions
diff --git a/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java b/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java index a129495b4..0fae643e1 100644 --- a/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java +++ b/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java @@ -40,27 +40,20 @@ public class DeletedEphemeralSsidsStoreData implements WifiConfigStore.StoreData DeletedEphemeralSsidsStoreData() {} @Override - public void serializeData(XmlSerializer out, boolean shared) + public void serializeData(XmlSerializer out) throws XmlPullParserException, IOException { - if (shared) { - throw new XmlPullParserException("Share data not supported"); - } if (mSsidList != null) { XmlUtil.writeNextValue(out, XML_TAG_SSID_LIST, mSsidList); } } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared) + public void deserializeData(XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { return; } - if (shared) { - throw new XmlPullParserException("Share data not supported"); - } - while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { String[] valueName = new String[1]; Object value = XmlUtil.readCurrentValue(in, valueName); @@ -80,10 +73,14 @@ public class DeletedEphemeralSsidsStoreData implements WifiConfigStore.StoreData } @Override - public void resetData(boolean shared) { - if (!shared) { - mSsidList = null; - } + public void resetData() { + mSsidList = null; + } + + @Override + public boolean hasNewDataToSerialize() { + // always persist. + return true; } @Override @@ -92,8 +89,9 @@ public class DeletedEphemeralSsidsStoreData implements WifiConfigStore.StoreData } @Override - public boolean supportShareData() { - return false; + public @WifiConfigStore.StoreFileId int getStoreFileId() { + // Shared general store. + return WifiConfigStore.STORE_FILE_USER_GENERAL; } /** diff --git a/service/java/com/android/server/wifi/NetworkListSharedStoreData.java b/service/java/com/android/server/wifi/NetworkListSharedStoreData.java new file mode 100644 index 000000000..1b0dc5366 --- /dev/null +++ b/service/java/com/android/server/wifi/NetworkListSharedStoreData.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 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.content.Context; + +/** + * Serialization & Deserialization of shared WiFi network configurations. + */ +public class NetworkListSharedStoreData extends NetworkListStoreData { + + public NetworkListSharedStoreData(Context context) { + super(context); + } + + @Override + public @WifiConfigStore.StoreFileId int getStoreFileId() { + // Shared general store. + return WifiConfigStore.STORE_FILE_SHARED_GENERAL; + } +} + diff --git a/service/java/com/android/server/wifi/NetworkListStoreData.java b/service/java/com/android/server/wifi/NetworkListStoreData.java index 9330a60ac..696647185 100644 --- a/service/java/com/android/server/wifi/NetworkListStoreData.java +++ b/service/java/com/android/server/wifi/NetworkListStoreData.java @@ -43,7 +43,7 @@ import java.util.List; * This class performs serialization and parsing of XML data block that contain the list of WiFi * network configurations (XML block data inside <NetworkList> tag). */ -public class NetworkListStoreData implements WifiConfigStore.StoreData { +public abstract class NetworkListStoreData implements WifiConfigStore.StoreData { private static final String TAG = "NetworkListStoreData"; private static final String XML_TAG_SECTION_HEADER_NETWORK_LIST = "NetworkList"; @@ -57,64 +57,48 @@ public class NetworkListStoreData implements WifiConfigStore.StoreData { private final Context mContext; /** - * List of saved shared networks visible to all the users to be stored in the shared store file. + * List of saved shared networks visible to all the users to be stored in the store file. */ - private List<WifiConfiguration> mSharedConfigurations; - /** - * List of saved private networks only visible to the current user to be stored in the user - * specific store file. - */ - private List<WifiConfiguration> mUserConfigurations; + private List<WifiConfiguration> mConfigurations; NetworkListStoreData(Context context) { mContext = context; } @Override - public void serializeData(XmlSerializer out, boolean shared) + public void serializeData(XmlSerializer out) throws XmlPullParserException, IOException { - if (shared) { - serializeNetworkList(out, mSharedConfigurations); - } else { - serializeNetworkList(out, mUserConfigurations); - } + serializeNetworkList(out, mConfigurations); } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared) + public void deserializeData(XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { return; } - if (shared) { - mSharedConfigurations = parseNetworkList(in, outerTagDepth); - } else { - mUserConfigurations = parseNetworkList(in, outerTagDepth); - } + mConfigurations = parseNetworkList(in, outerTagDepth); } @Override - public void resetData(boolean shared) { - if (shared) { - mSharedConfigurations = null; - } else { - mUserConfigurations = null; - } + public void resetData() { + mConfigurations = null; } @Override - public String getName() { - return XML_TAG_SECTION_HEADER_NETWORK_LIST; + public boolean hasNewDataToSerialize() { + // always persist. + return true; } @Override - public boolean supportShareData() { - return true; + public String getName() { + return XML_TAG_SECTION_HEADER_NETWORK_LIST; } - public void setSharedConfigurations(List<WifiConfiguration> configs) { - mSharedConfigurations = configs; + public void setConfigurations(List<WifiConfiguration> configs) { + mConfigurations = configs; } /** @@ -122,27 +106,11 @@ public class NetworkListStoreData implements WifiConfigStore.StoreData { * * @return List of {@link WifiConfiguration} */ - public List<WifiConfiguration> getSharedConfigurations() { - if (mSharedConfigurations == null) { - return new ArrayList<WifiConfiguration>(); - } - return mSharedConfigurations; - } - - public void setUserConfigurations(List<WifiConfiguration> configs) { - mUserConfigurations = configs; - } - - /** - * An empty list will be returned if no user configurations. - * - * @return List of {@link WifiConfiguration} - */ - public List<WifiConfiguration> getUserConfigurations() { - if (mUserConfigurations == null) { + public List<WifiConfiguration> getConfigurations() { + if (mConfigurations == null) { return new ArrayList<WifiConfiguration>(); } - return mUserConfigurations; + return mConfigurations; } /** diff --git a/service/java/com/android/server/wifi/NetworkListUserStoreData.java b/service/java/com/android/server/wifi/NetworkListUserStoreData.java new file mode 100644 index 000000000..c146c18f5 --- /dev/null +++ b/service/java/com/android/server/wifi/NetworkListUserStoreData.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 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.content.Context; + +/** + * Serialization & Deserialization of user specific WiFi network configurations. + */ +public class NetworkListUserStoreData extends NetworkListStoreData { + + public NetworkListUserStoreData(Context context) { + super(context); + } + + @Override + public @WifiConfigStore.StoreFileId int getStoreFileId() { + // Shared general store. + return WifiConfigStore.STORE_FILE_USER_GENERAL; + } +} + diff --git a/service/java/com/android/server/wifi/SsidSetStoreData.java b/service/java/com/android/server/wifi/SsidSetStoreData.java index 474740db5..7d1b99340 100644 --- a/service/java/com/android/server/wifi/SsidSetStoreData.java +++ b/service/java/com/android/server/wifi/SsidSetStoreData.java @@ -33,9 +33,6 @@ import java.util.Set; * * Below are the current configuration data for each respective store file: * - * Share Store (system wide configurations) - * - No data - * * User Store (user specific configurations) * - Set of blacklisted SSIDs */ @@ -77,11 +74,8 @@ public class SsidSetStoreData implements WifiConfigStore.StoreData { } @Override - public void serializeData(XmlSerializer out, boolean shared) + public void serializeData(XmlSerializer out) throws XmlPullParserException, IOException { - if (shared) { - throw new XmlPullParserException("Share data not supported"); - } Set<String> ssidSet = mDataSource.getSsids(); if (ssidSet != null && !ssidSet.isEmpty()) { XmlUtil.writeNextValue(out, XML_TAG_SSID_SET, mDataSource.getSsids()); @@ -89,16 +83,12 @@ public class SsidSetStoreData implements WifiConfigStore.StoreData { } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared) + public void deserializeData(XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { return; } - if (shared) { - throw new XmlPullParserException("Share data not supported"); - } - while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { String[] valueName = new String[1]; Object value = XmlUtil.readCurrentValue(in, valueName); @@ -117,10 +107,14 @@ public class SsidSetStoreData implements WifiConfigStore.StoreData { } @Override - public void resetData(boolean shared) { - if (!shared) { - mDataSource.setSsids(new HashSet<>()); - } + public void resetData() { + mDataSource.setSsids(new HashSet<>()); + } + + @Override + public boolean hasNewDataToSerialize() { + // always persist. + return true; } @Override @@ -129,7 +123,8 @@ public class SsidSetStoreData implements WifiConfigStore.StoreData { } @Override - public boolean supportShareData() { - return false; + public @WifiConfigStore.StoreFileId int getStoreFileId() { + // Shared general store. + return WifiConfigStore.STORE_FILE_USER_GENERAL; } } diff --git a/service/java/com/android/server/wifi/WakeupConfigStoreData.java b/service/java/com/android/server/wifi/WakeupConfigStoreData.java index d98567766..d191ee3d6 100644 --- a/service/java/com/android/server/wifi/WakeupConfigStoreData.java +++ b/service/java/com/android/server/wifi/WakeupConfigStoreData.java @@ -94,12 +94,8 @@ public class WakeupConfigStoreData implements StoreData { } @Override - public void serializeData(XmlSerializer out, boolean shared) + public void serializeData(XmlSerializer out) throws XmlPullParserException, IOException { - if (shared) { - throw new XmlPullParserException("Share data not supported"); - } - writeFeatureState(out); for (ScanResultMatchInfo scanResultMatchInfo : mNetworkDataSource.getData()) { @@ -145,22 +141,16 @@ public class WakeupConfigStoreData implements StoreData { } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared) + public void deserializeData(XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException { - if (!shared) { - if (!mHasBeenRead) { - Log.d(TAG, "WifiWake user data has been read"); - mHasBeenRead = true; - } + if (!mHasBeenRead) { + Log.d(TAG, "WifiWake user data has been read"); + mHasBeenRead = true; } - // Ignore empty reads. if (in == null) { return; } - if (shared) { - throw new XmlPullParserException("Shared data not supported"); - } Set<ScanResultMatchInfo> networks = new ArraySet<>(); @@ -254,13 +244,17 @@ public class WakeupConfigStoreData implements StoreData { } @Override - public void resetData(boolean shared) { - if (!shared) { - mNetworkDataSource.setData(Collections.emptySet()); - mIsActiveDataSource.setData(false); - mIsOnboardedDataSource.setData(false); - mNotificationsDataSource.setData(0); - } + public void resetData() { + mNetworkDataSource.setData(Collections.emptySet()); + mIsActiveDataSource.setData(false); + mIsOnboardedDataSource.setData(false); + mNotificationsDataSource.setData(0); + } + + @Override + public boolean hasNewDataToSerialize() { + // always persist. + return true; } @Override @@ -269,7 +263,8 @@ public class WakeupConfigStoreData implements StoreData { } @Override - public boolean supportShareData() { - return false; + public @WifiConfigStore.StoreFileId int getStoreFileId() { + // Shared general store. + return WifiConfigStore.STORE_FILE_USER_GENERAL; } } diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java index 5de7e99d2..4b622bf31 100644 --- a/service/java/com/android/server/wifi/WifiConfigManager.java +++ b/service/java/com/android/server/wifi/WifiConfigManager.java @@ -328,7 +328,8 @@ public class WifiConfigManager { // Store data for network list and deleted ephemeral SSID list. Used for serializing // parsing data to/from the config store. - private final NetworkListStoreData mNetworkListStoreData; + private final NetworkListSharedStoreData mNetworkListSharedStoreData; + private final NetworkListUserStoreData mNetworkListUserStoreData; private final DeletedEphemeralSsidsStoreData mDeletedEphemeralSsidsStoreData; // Store the saved network update listener. @@ -343,7 +344,8 @@ public class WifiConfigManager { WifiConfigStore wifiConfigStore, WifiConfigStoreLegacy wifiConfigStoreLegacy, WifiPermissionsUtil wifiPermissionsUtil, WifiPermissionsWrapper wifiPermissionsWrapper, - NetworkListStoreData networkListStoreData, + NetworkListSharedStoreData networkListSharedStoreData, + NetworkListUserStoreData networkListUserStoreData, DeletedEphemeralSsidsStoreData deletedEphemeralSsidsStoreData) { mContext = context; mClock = clock; @@ -361,9 +363,11 @@ public class WifiConfigManager { mDeletedEphemeralSSIDs = new HashSet<>(); // Register store data for network list and deleted ephemeral SSIDs. - mNetworkListStoreData = networkListStoreData; + mNetworkListSharedStoreData = networkListSharedStoreData; + mNetworkListUserStoreData = networkListUserStoreData; mDeletedEphemeralSsidsStoreData = deletedEphemeralSsidsStoreData; - mWifiConfigStore.registerStoreData(mNetworkListStoreData); + mWifiConfigStore.registerStoreData(mNetworkListSharedStoreData); + mWifiConfigStore.registerStoreData(mNetworkListUserStoreData); mWifiConfigStore.registerStoreData(mDeletedEphemeralSsidsStoreData); mOnlyLinkSameCredentialConfigurations = mContext.getResources().getBoolean( @@ -2754,7 +2758,7 @@ public class WifiConfigManager { // Setup user store for the current user in case it have not setup yet, so that data // owned by the current user will be backed to the user store. if (mDeferredUserUnlockRead) { - mWifiConfigStore.setUserStore(WifiConfigStore.createUserFile(mCurrentUserId)); + mWifiConfigStore.setUserStores(WifiConfigStore.createUserFiles(mCurrentUserId)); mDeferredUserUnlockRead = false; } @@ -2783,7 +2787,7 @@ public class WifiConfigManager { // configurations for the current user will also being loaded. if (mDeferredUserUnlockRead) { Log.i(TAG, "Handling user unlock before loading from store."); - mWifiConfigStore.setUserStore(WifiConfigStore.createUserFile(mCurrentUserId)); + mWifiConfigStore.setUserStores(WifiConfigStore.createUserFiles(mCurrentUserId)); mDeferredUserUnlockRead = false; } if (!mWifiConfigStore.areStoresPresent()) { @@ -2803,8 +2807,8 @@ public class WifiConfigManager { Log.wtf(TAG, "XML deserialization of store failed. All saved networks are lost!", e); return false; } - loadInternalData(mNetworkListStoreData.getSharedConfigurations(), - mNetworkListStoreData.getUserConfigurations(), + loadInternalData(mNetworkListSharedStoreData.getConfigurations(), + mNetworkListUserStoreData.getConfigurations(), mDeletedEphemeralSsidsStoreData.getSsidList()); return true; } @@ -2823,7 +2827,7 @@ public class WifiConfigManager { */ public boolean loadFromUserStoreAfterUnlockOrSwitch(int userId) { try { - mWifiConfigStore.switchUserStoreAndRead(WifiConfigStore.createUserFile(userId)); + mWifiConfigStore.switchUserStoresAndRead(WifiConfigStore.createUserFiles(userId)); } catch (IOException e) { Log.wtf(TAG, "Reading from new store failed. All saved private networks are lost!", e); return false; @@ -2832,7 +2836,7 @@ public class WifiConfigManager { "lost!", e); return false; } - loadInternalDataFromUserStore(mNetworkListStoreData.getUserConfigurations(), + loadInternalDataFromUserStore(mNetworkListUserStoreData.getConfigurations(), mDeletedEphemeralSsidsStoreData.getSsidList()); return true; } @@ -2892,8 +2896,8 @@ public class WifiConfigManager { } // Setup store data for write. - mNetworkListStoreData.setSharedConfigurations(sharedConfigurations); - mNetworkListStoreData.setUserConfigurations(userConfigurations); + mNetworkListSharedStoreData.setConfigurations(sharedConfigurations); + mNetworkListUserStoreData.setConfigurations(userConfigurations); mDeletedEphemeralSsidsStoreData.setSsidList(mDeletedEphemeralSSIDs); try { @@ -2932,6 +2936,7 @@ public class WifiConfigManager { pw.println("WifiConfigManager - Configured networks End ----"); pw.println("WifiConfigManager - Next network ID to be allocated " + mNextNetworkId); pw.println("WifiConfigManager - Last selected network ID " + mLastSelectedNetworkId); + mWifiConfigStore.dump(fd, pw, args); } /** diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index 17a6670ff..00f09f571 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -16,6 +16,8 @@ package com.android.server.wifi; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.content.Context; @@ -24,11 +26,13 @@ import android.os.FileUtils; import android.os.Handler; import android.os.Looper; import android.util.Log; +import android.util.SparseArray; import android.util.Xml; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.AtomicFile; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.Preconditions; import com.android.server.wifi.util.XmlUtil; import org.xmlpull.v1.XmlPullParser; @@ -38,22 +42,56 @@ import org.xmlpull.v1.XmlSerializer; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.HashSet; -import java.util.Map; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; /** - * This class provides the API's to save/load/modify network configurations from a persistent - * store. Uses keystore for certificate/key management operations. - * NOTE: This class should only be used from WifiConfigManager and is not thread-safe! + * This class provides a mechanism to save data to persistent store files {@link StoreFile}. + * Modules can register a {@link StoreData} instance indicating the {@StoreFile} into which they + * want to save their data to. + * + * NOTE: + * <li>Modules can register their {@StoreData} using + * {@link WifiConfigStore#registerStoreData(StoreData)} directly, but should + * use {@link WifiConfigManager#saveToStore(boolean)} for any writes.</li> + * <li>{@link WifiConfigManager} controls {@link WifiConfigStore} and initiates read at bootup and + * store file changes on user switch.</li> + * <li>Not thread safe!</li> */ public class WifiConfigStore { + /** + * Config store file for general shared store file. + */ + public static final int STORE_FILE_SHARED_GENERAL = 0; + /** + * Config store file for general user store file. + */ + public static final int STORE_FILE_USER_GENERAL = 1; + /** + * Config store file for network suggestions user store file. + */ + public static final int STORE_FILE_USER_NETWORK_SUGGESTIONS = 2; + + @IntDef(prefix = { "STORE_FILE_" }, value = { + STORE_FILE_SHARED_GENERAL, + STORE_FILE_USER_GENERAL, + STORE_FILE_USER_NETWORK_SUGGESTIONS + }) + @Retention(RetentionPolicy.SOURCE) + public @interface StoreFileId { } + private static final String XML_TAG_DOCUMENT_HEADER = "WifiConfigStoreData"; private static final String XML_TAG_VERSION = "Version"; /** @@ -76,10 +114,6 @@ public class WifiConfigStore { */ private static final String TAG = "WifiConfigStore"; /** - * Config store file name for both shared & user specific stores. - */ - private static final String STORE_FILE_NAME = "WifiConfigStore.xml"; - /** * Directory to store the config store files in. */ private static final String STORE_DIRECTORY_NAME = "wifi"; @@ -88,6 +122,29 @@ public class WifiConfigStore { */ private static final int BUFFERED_WRITE_ALARM_INTERVAL_MS = 10 * 1000; /** + * Config store file name for general shared store file. + */ + private static final String STORE_FILE_NAME_SHARED_GENERAL = "WifiConfigStore.xml"; + /** + * Config store file name for general user store file. + */ + private static final String STORE_FILE_NAME_USER_GENERAL = "WifiConfigStore.xml"; + /** + * Config store file name for network suggestions user store file. + */ + private static final String STORE_FILE_NAME_USER_NETWORK_SUGGESTIONS = + "WifiConfigStoreNetworkSuggestions.xml"; + /** + * Mapping of Store file Id to Store file names. + */ + private static final SparseArray<String> STORE_ID_TO_FILE_NAME = + new SparseArray<String>() {{ + put(STORE_FILE_SHARED_GENERAL, STORE_FILE_NAME_SHARED_GENERAL); + put(STORE_FILE_USER_GENERAL, STORE_FILE_NAME_USER_GENERAL); + put(STORE_FILE_USER_NETWORK_SUGGESTIONS, STORE_FILE_NAME_USER_NETWORK_SUGGESTIONS); + }}; + + /** * Handler instance to post alarm timeouts to */ private final Handler mEventHandler; @@ -100,13 +157,15 @@ public class WifiConfigStore { */ private final Clock mClock; /** - * Shared config store file instance. + * Shared config store file instance. There is 1 shared store file: + * {@link #STORE_FILE_NAME_SHARED_GENERAL}. */ private StoreFile mSharedStore; /** - * User specific store file instance. + * User specific store file instances. There are 2 user store files: + * {@link #STORE_FILE_NAME_USER_GENERAL} & {@link #STORE_FILE_NAME_USER_NETWORK_SUGGESTIONS}. */ - private StoreFile mUserStore; + private List<StoreFile> mUserStores; /** * Verbose logging flag. */ @@ -126,14 +185,13 @@ public class WifiConfigStore { } catch (IOException e) { Log.wtf(TAG, "Buffered write failed", e); } - } }; /** - * List of data container. + * List of data containers. */ - private final Map<String, StoreData> mStoreDataList; + private final List<StoreData> mStoreDataList; /** * Create a new instance of WifiConfigStore. @@ -151,33 +209,44 @@ public class WifiConfigStore { mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mEventHandler = new Handler(looper); mClock = clock; - mStoreDataList = new HashMap<>(); + mStoreDataList = new ArrayList<>(); // Initialize the store files. mSharedStore = sharedStore; // The user store is initialized to null, this will be set when the user unlocks and - // CE storage is accessible via |switchUserStoreAndRead|. - mUserStore = null; + // CE storage is accessible via |switchUserStoresAndRead|. + mUserStores = null; } - public void setUserStore(StoreFile userStore) { - mUserStore = userStore; + /** + * Set the user store files. + * (Useful for mocking in unit tests). + * @param userStores List of {@link StoreFile} created using {@link #createUserFiles(int)}. + */ + public void setUserStores(@NonNull List<StoreFile> userStores) { + Preconditions.checkNotNull(userStores); + mUserStores = userStores; } /** - * Register a {@link StoreData} to store. A {@link StoreData} is responsible - * for a block of data in the store file, and provides serialization/deserialization functions - * for those data. + * Register a {@link StoreData} to read/write data from/to a store. A {@link StoreData} is + * responsible for a block of data in the store file, and provides serialization/deserialization + * functions for those data. * * @param storeData The store data to be registered to the config store - * @return true if succeeded + * @return true if registered successfully, false if the store file name is not valid. */ - public boolean registerStoreData(StoreData storeData) { + public boolean registerStoreData(@NonNull StoreData storeData) { if (storeData == null) { Log.e(TAG, "Unable to register null store data"); return false; } - mStoreDataList.put(storeData.getName(), storeData); + int storeFileId = storeData.getStoreFileId(); + if (STORE_ID_TO_FILE_NAME.get(storeFileId) == null) { + Log.e(TAG, "Invalid shared store file specified" + storeFileId); + return false; + } + mStoreDataList.add(storeData); return true; } @@ -188,16 +257,18 @@ public class WifiConfigStore { * * @param storeBaseDir Base directory under which the store file is to be stored. The store file * will be at <storeBaseDir>/wifi/WifiConfigStore.xml. - * @return new instance of the store file. + * @param fileId Identifier for the file. See {@link StoreFileId}. + * @return new instance of the store file or null if the directory cannot be created. */ - private static StoreFile createFile(File storeBaseDir) { + private static StoreFile createFile(File storeBaseDir, @StoreFileId int fileId) { File storeDir = new File(storeBaseDir, STORE_DIRECTORY_NAME); if (!storeDir.exists()) { if (!storeDir.mkdir()) { Log.w(TAG, "Could not create store directory " + storeDir); + return null; } } - return new StoreFile(new File(storeDir, STORE_FILE_NAME)); + return new StoreFile(new File(storeDir, STORE_ID_TO_FILE_NAME.get(fileId)), fileId); } /** @@ -206,18 +277,23 @@ public class WifiConfigStore { * @return new instance of the store file or null if the directory cannot be created. */ public static StoreFile createSharedFile() { - return createFile(Environment.getDataMiscDirectory()); + return createFile(Environment.getDataMiscDirectory(), STORE_FILE_SHARED_GENERAL); } /** - * Create a new instance of the user specific store file. + * Create new instances of the user specific store files. * The user store file is inside the user's encrypted data directory. * * @param userId userId corresponding to the currently logged-in user. - * @return new instance of the store file or null if the directory cannot be created. - */ - public static StoreFile createUserFile(int userId) { - return createFile(Environment.getDataMiscCeDirectory(userId)); + * @return List of new instances of the store files created. + */ + public static List<StoreFile> createUserFiles(int userId) { + List<StoreFile> storeFiles = new ArrayList<>(); + storeFiles.add(createFile(Environment.getDataMiscCeDirectory(userId), + STORE_FILE_USER_GENERAL)); + storeFiles.add(createFile(Environment.getDataMiscCeDirectory(userId), + STORE_FILE_USER_NETWORK_SUGGESTIONS)); + return storeFiles; } /** @@ -234,7 +310,29 @@ public class WifiConfigStore { * @return true if any of the store file is present, false otherwise. */ public boolean areStoresPresent() { - return (mSharedStore.exists() || (mUserStore != null && mUserStore.exists())); + // Checking for the shared store file existence is sufficient since this is guaranteed + // to be present on migrated devices. + return mSharedStore.exists(); + } + + /** + * Retrieve the list of {@link StoreData} instances registered for the provided + * {@link StoreFile}. + */ + private List<StoreData> retrieveStoreDataListForStoreFile(@NonNull StoreFile storeFile) { + return mStoreDataList + .stream() + .filter(s -> s.getStoreFileId() == storeFile.mFileId) + .collect(Collectors.toList()); + } + + /** + * Check if any of the provided list of {@link StoreData} instances registered + * for the provided {@link StoreFile }have indicated that they have new data to serialize. + */ + private boolean hasNewDataToSerialize(@NonNull StoreFile storeFile) { + List<StoreData> storeDataList = retrieveStoreDataListForStoreFile(storeFile); + return storeDataList.stream().anyMatch(s -> s.hasNewDataToSerialize()); } /** @@ -247,50 +345,62 @@ public class WifiConfigStore { */ public void write(boolean forceSync) throws XmlPullParserException, IOException { + boolean hasAnyNewData = false; // Serialize the provided data and send it to the respective stores. The actual write will // be performed later depending on the |forceSync| flag . - byte[] sharedDataBytes = serializeData(true); - mSharedStore.storeRawDataToWrite(sharedDataBytes); - if (mUserStore != null) { - byte[] userDataBytes = serializeData(false); - mUserStore.storeRawDataToWrite(userDataBytes); + if (hasNewDataToSerialize(mSharedStore)) { + byte[] sharedDataBytes = serializeData(mSharedStore); + mSharedStore.storeRawDataToWrite(sharedDataBytes); + hasAnyNewData = true; + } + if (mUserStores != null) { + for (StoreFile userStoreFile : mUserStores) { + if (hasNewDataToSerialize(userStoreFile)) { + byte[] userDataBytes = serializeData(userStoreFile); + userStoreFile.storeRawDataToWrite(userDataBytes); + hasAnyNewData = true; + } + } } - // Every write provides a new snapshot to be persisted, so |forceSync| flag overrides any - // pending buffer writes. - if (forceSync) { + if (hasAnyNewData) { + // Every write provides a new snapshot to be persisted, so |forceSync| flag overrides + // any pending buffer writes. + if (forceSync) { + writeBufferedData(); + } else { + startBufferedWriteAlarm(); + } + } else if (forceSync && mBufferedWritePending) { + // no new data to write, but there is a pending buffered write. So, |forceSync| should + // flush that out. writeBufferedData(); - } else { - startBufferedWriteAlarm(); } } /** - * Serialize share data or user data from all store data. + * Serialize all the data from all the {@link StoreData} clients registered for the provided + * {@link StoreFile}. * - * @param shareData Flag indicating share data + * @param storeFile StoreFile that we want to write to. * @return byte[] of serialized bytes * @throws XmlPullParserException * @throws IOException */ - private byte[] serializeData(boolean shareData) throws XmlPullParserException, IOException { + private byte[] serializeData(@NonNull StoreFile storeFile) + throws XmlPullParserException, IOException { + List<StoreData> storeDataList = retrieveStoreDataListForStoreFile(storeFile); + final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); XmlUtil.writeDocumentStart(out, XML_TAG_DOCUMENT_HEADER); XmlUtil.writeNextValue(out, XML_TAG_VERSION, CURRENT_CONFIG_STORE_DATA_VERSION); - - for (Map.Entry<String, StoreData> entry : mStoreDataList.entrySet()) { - String tag = entry.getKey(); - StoreData storeData = entry.getValue(); - // Ignore this store data if this is for share file and the store data doesn't support - // share store. - if (shareData && !storeData.supportShareData()) { - continue; - } + for (StoreData storeData : storeDataList) { + String tag = storeData.getName(); XmlUtil.writeNextSectionStart(out, tag); - storeData.serializeData(out, shareData); + storeData.serializeData(out); XmlUtil.writeNextSectionEnd(out, tag); } XmlUtil.writeDocumentEnd(out, XML_TAG_DOCUMENT_HEADER); @@ -329,8 +439,10 @@ public class WifiConfigStore { long writeStartTime = mClock.getElapsedSinceBootMillis(); mSharedStore.writeBufferedRawData(); - if (mUserStore != null) { - mUserStore.writeBufferedRawData(); + if (mUserStores != null) { + for (StoreFile userStoreFile : mUserStores) { + userStoreFile.writeBufferedRawData(); + } } long writeTime = mClock.getElapsedSinceBootMillis() - writeStartTime; @@ -344,80 +456,87 @@ public class WifiConfigStore { */ public void read() throws XmlPullParserException, IOException { // Reset both share and user store data. - resetStoreData(true); - if (mUserStore != null) { - resetStoreData(false); + resetStoreData(mSharedStore); + if (mUserStores != null) { + for (StoreFile userStoreFile : mUserStores) { + resetStoreData(userStoreFile); + } } long readStartTime = mClock.getElapsedSinceBootMillis(); byte[] sharedDataBytes = mSharedStore.readRawData(); - byte[] userDataBytes = null; - if (mUserStore != null) { - userDataBytes = mUserStore.readRawData(); + deserializeData(sharedDataBytes, mSharedStore); + if (mUserStores != null) { + for (StoreFile userStoreFile : mUserStores) { + byte[] userDataBytes = userStoreFile.readRawData(); + deserializeData(userDataBytes, userStoreFile); + } } long readTime = mClock.getElapsedSinceBootMillis() - readStartTime; - Log.d(TAG, "Reading from stores completed in " + readTime + " ms."); - deserializeData(sharedDataBytes, true); - if (mUserStore != null) { - deserializeData(userDataBytes, false); - } + Log.d(TAG, "Reading from all stores completed in " + readTime + " ms."); } /** - * Handles a user switch. This method changes the user specific store file and reads from the - * new user's store file. + * Handles a user switch. This method changes the user specific store files and reads from the + * new user's store files. * - * @param userStore StoreFile instance pointing to the user specific store file. This should - * be retrieved using {@link #createUserFile(int)} method. + * @param userStores List of {@link StoreFile} created using {@link #createUserFiles(int)}. */ - public void switchUserStoreAndRead(StoreFile userStore) + public void switchUserStoresAndRead(@NonNull List<StoreFile> userStores) throws XmlPullParserException, IOException { // Reset user store data. - resetStoreData(false); + if (mUserStores != null) { + for (StoreFile userStoreFile : mUserStores) { + resetStoreData(userStoreFile); + } + } // Stop any pending buffered writes, if any. stopBufferedWriteAlarm(); - mUserStore = userStore; + mUserStores = userStores; // Now read from the user store file. long readStartTime = mClock.getElapsedSinceBootMillis(); - byte[] userDataBytes = mUserStore.readRawData(); + for (StoreFile userStoreFile : mUserStores) { + byte[] userDataBytes = userStoreFile.readRawData(); + deserializeData(userDataBytes, userStoreFile); + } long readTime = mClock.getElapsedSinceBootMillis() - readStartTime; - Log.d(TAG, "Reading from user store completed in " + readTime + " ms."); - deserializeData(userDataBytes, false); + Log.d(TAG, "Reading from user stores completed in " + readTime + " ms."); } /** - * Reset share data or user data in all store data. - * - * @param shareData Flag indicating share data + * Reset data for all {@link StoreData} instances registered for this {@link StoreFile}. */ - private void resetStoreData(boolean shareData) { - for (Map.Entry<String, StoreData> entry : mStoreDataList.entrySet()) { - entry.getValue().resetData(shareData); + private void resetStoreData(@NonNull StoreFile storeFile) { + for (StoreData storeData: retrieveStoreDataListForStoreFile(storeFile)) { + storeData.resetData(); } } // Inform all the provided store data clients that there is nothing in the store for them. - private void indicateNoDataForStoreDatas(Collection<StoreData> storeDataSet, boolean shareData) + private void indicateNoDataForStoreDatas(Collection<StoreData> storeDataSet) throws XmlPullParserException, IOException { for (StoreData storeData : storeDataSet) { - storeData.deserializeData(null, 0, shareData); + storeData.deserializeData(null, 0); } } /** - * Deserialize share data or user data into store data. + * Deserialize data from a {@link StoreFile} for all {@link StoreData} instances registered. * * @param dataBytes The data to parse - * @param shareData The flag indicating share data + * @param storeFile StoreFile that we read from. Will be used to retrieve the list of clients + * who have data to deserialize from this file. + * * @throws XmlPullParserException * @throws IOException */ - private void deserializeData(byte[] dataBytes, boolean shareData) + private void deserializeData(@NonNull byte[] dataBytes, @NonNull StoreFile storeFile) throws XmlPullParserException, IOException { + List<StoreData> storeDataList = retrieveStoreDataListForStoreFile(storeFile); if (dataBytes == null) { - indicateNoDataForStoreDatas(mStoreDataList.values(), shareData); + indicateNoDataForStoreDatas(storeDataList); return; } final XmlPullParser in = Xml.newPullParser(); @@ -431,18 +550,24 @@ public class WifiConfigStore { String[] headerName = new String[1]; Set<StoreData> storeDatasInvoked = new HashSet<>(); while (XmlUtil.gotoNextSectionOrEnd(in, headerName, rootTagDepth)) { - StoreData storeData = mStoreDataList.get(headerName[0]); + // There can only be 1 store data matching the tag (O indicates a fatal + // error). + StoreData storeData = storeDataList.stream() + .filter(s -> s.getName().equals(headerName[0])) + .findAny() + .orElse(null); if (storeData == null) { - throw new XmlPullParserException("Unknown store data: " + headerName[0]); + throw new XmlPullParserException("Unknown store data: " + headerName[0] + + ". List of store data: " + storeDataList); } - storeData.deserializeData(in, rootTagDepth + 1, shareData); + storeData.deserializeData(in, rootTagDepth + 1); storeDatasInvoked.add(storeData); } // Inform all the other registered store data clients that there is nothing in the store // for them. - Set<StoreData> storeDatasNotInvoked = new HashSet<>(mStoreDataList.values()); + Set<StoreData> storeDatasNotInvoked = new HashSet<>(storeDataList); storeDatasNotInvoked.removeAll(storeDatasInvoked); - indicateNoDataForStoreDatas(storeDatasNotInvoked, shareData); + indicateNoDataForStoreDatas(storeDatasNotInvoked); } /** @@ -464,6 +589,24 @@ public class WifiConfigStore { } /** + * Dump the local log buffer and other internal state of WifiConfigManager. + */ + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("Dump of WifiConfigStore"); + pw.println("WifiConfigStore - Store Data Begin ----"); + for (StoreData storeData : mStoreDataList) { + pw.print("StoreData =>"); + pw.print(" "); + pw.print("Name: " + storeData.getName()); + pw.print(", "); + pw.println("File Id: " + storeData.getStoreFileId()); + pw.print(", "); + pw.println("File Name: " + STORE_ID_TO_FILE_NAME.get(storeData.getStoreFileId())); + } + pw.println("WifiConfigStore - Store Data End ----"); + } + + /** * Class to encapsulate all file writes. This is a wrapper over {@link AtomicFile} to write/read * raw data from the persistent file. This class provides helper methods to read/write the * entire file into a byte array. @@ -486,10 +629,15 @@ public class WifiConfigStore { * Store the file name for setting the file permissions/logging purposes. */ private String mFileName; + /** + * {@link StoreFileId} Type of store file. + */ + private @StoreFileId int mFileId; - public StoreFile(File file) { + public StoreFile(File file, @StoreFileId int fileId) { mAtomicFile = new AtomicFile(file); mFileName = mAtomicFile.getBaseFile().getAbsolutePath(); + mFileId = fileId; } /** @@ -562,48 +710,44 @@ public class WifiConfigStore { * The module will be responsible for serializing/deserializing their own data. * Whenever {@link WifiConfigStore#read()} is invoked, all registered StoreData instances will * be notified that a read was performed via {@link StoreData#deserializeData( - * XmlPullParser, int, boolean)} regardless of whether there is any data for them or not in the + * XmlPullParser, int)} regardless of whether there is any data for them or not in the * store file. * * Note: StoreData clients that need a config store read to kick-off operations should wait - * for the {@link StoreData#deserializeData(XmlPullParser, int, boolean)} invocation. + * for the {@link StoreData#deserializeData(XmlPullParser, int)} invocation. */ public interface StoreData { /** - * Serialize a XML data block to the output stream. The |shared| flag indicates if the - * output stream is backed by a share store or an user store. + * Serialize a XML data block to the output stream. * * @param out The output stream to serialize the data to - * @param shared Flag indicating if the output stream is backed by a share store or an - * user store */ - void serializeData(XmlSerializer out, boolean shared) + void serializeData(XmlSerializer out) throws XmlPullParserException, IOException; /** - * Deserialize a XML data block from the input stream. The |shared| flag indicates if the - * input stream is backed by a share store or an user store. When |shared| is set to true, - * the shared configuration data will be overwritten by the parsed data. Otherwise, - * the user configuration will be overwritten by the parsed data. + * Deserialize a XML data block from the input stream. * * @param in The input stream to read the data from. This could be null if there is * nothing in the store. * @param outerTagDepth The depth of the outer tag in the XML document - * @Param shared Flag indicating if the input stream is backed by a share store or an - * user store - * Note: This will be invoked every time a store file is read. For example: clients - * will get 2 invocations on bootup, one for shared store file (shared=True) & - * one for user store file (shared=False). + * Note: This will be invoked every time a store file is read, even if there is nothing + * in the store for them. */ - void deserializeData(@Nullable XmlPullParser in, int outerTagDepth, boolean shared) + void deserializeData(@Nullable XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException; /** - * Reset configuration data. The |shared| flag indicates which configuration data to - * reset. When |shared| is set to true, the shared configuration data will be reset. - * Otherwise, the user configuration data will be reset. + * Reset configuration data. + */ + void resetData(); + + /** + * Check if there is any new data to persist from the last write. + * + * @return true if the module has new data to persist, false otherwise. */ - void resetData(boolean shared); + boolean hasNewDataToSerialize(); /** * Return the name of this store data. The data will be enclosed under this tag in @@ -614,10 +758,17 @@ public class WifiConfigStore { String getName(); /** - * Flag indicating if shared configuration data is supported. + * File Id where this data needs to be written to. + * This should be one of {@link #STORE_FILE_SHARED_GENERAL}, + * {@link #STORE_FILE_USER_GENERAL} or + * {@link #STORE_FILE_USER_NETWORK_SUGGESTIONS}. * - * @return true if shared configuration data is supported + * Note: For most uses, the shared or user general store is sufficient. Creating and + * managing store files are expensive. Only use specific store files if you have a large + * amount of data which may not need to be persisted frequently (or at least not as + * frequently as the general store). + * @return Id of the file where this data needs to be persisted. */ - boolean supportShareData(); + @StoreFileId int getStoreFileId(); } } diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index 9c2bf2c80..60e204a67 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -225,7 +225,8 @@ public class WifiInjector { mWifiConfigManager = new WifiConfigManager(mContext, mClock, UserManager.get(mContext), TelephonyManager.from(mContext), mWifiKeyStore, mWifiConfigStore, mWifiConfigStoreLegacy, mWifiPermissionsUtil, - mWifiPermissionsWrapper, new NetworkListStoreData(mContext), + mWifiPermissionsWrapper, new NetworkListSharedStoreData(mContext), + new NetworkListUserStoreData(mContext), new DeletedEphemeralSsidsStoreData()); mWifiMetrics.setWifiConfigManager(mWifiConfigManager); mWifiConnectivityHelper = new WifiConnectivityHelper(mWifiNative); diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java b/service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java new file mode 100644 index 000000000..419ea7993 --- /dev/null +++ b/service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2018 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.hotspot2; + +import com.android.server.wifi.WifiConfigStore; +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; + +/** + * Responsible for Passpoint specific configuration store data. There are two types of + * configuration data, system wide and user specific. The system wide configurations are stored + * in the share store and user specific configurations are store in the user store. + * + * Below are the current configuration data for each respective store file, the list will + * probably grow in the future. + * + * Share Store (system wide configurations) + * - Current provider index - use for assigning provider ID during provider creation, to make + * sure each provider will have an unique ID across all users. + * + * User Store (user specific configurations) + * - Provider list - list of Passpoint provider configurations + * + */ +public class PasspointConfigSharedStoreData implements WifiConfigStore.StoreData { + private static final String XML_TAG_SECTION_HEADER_PASSPOINT_CONFIG_DATA = + "PasspointConfigData"; + private static final String XML_TAG_PROVIDER_INDEX = "ProviderIndex"; + + private final DataSource mDataSource; + + /** + * Interface define the data source for the Passpoint configuration store data. + */ + public interface DataSource { + /** + * Retrieve the current provider index. + * + * @return long + */ + long getProviderIndex(); + + /** + * Set the current provider index. + * + * @param providerIndex The provider index used for provider creation + */ + void setProviderIndex(long providerIndex); + } + + PasspointConfigSharedStoreData(DataSource dataSource) { + mDataSource = dataSource; + } + + @Override + public void serializeData(XmlSerializer out) + throws XmlPullParserException, IOException { + serializeShareData(out); + } + + @Override + public void deserializeData(XmlPullParser in, int outerTagDepth) + throws XmlPullParserException, IOException { + // Ignore empty reads. + if (in == null) { + return; + } + deserializeShareData(in, outerTagDepth); + } + + /** + * Reset share data (system wide Passpoint configurations). + */ + @Override + public void resetData() { + mDataSource.setProviderIndex(0); + } + + @Override + public boolean hasNewDataToSerialize() { + // always persist. + return true; + } + + @Override + public String getName() { + return XML_TAG_SECTION_HEADER_PASSPOINT_CONFIG_DATA; + } + + @Override + public @WifiConfigStore.StoreFileId int getStoreFileId() { + // Shared general store. + return WifiConfigStore.STORE_FILE_SHARED_GENERAL; + } + + /** + * Serialize share data (system wide Passpoint configurations) to a XML block. + * + * @param out The output stream to serialize data to + * @throws XmlPullParserException + * @throws IOException + */ + private void serializeShareData(XmlSerializer out) throws XmlPullParserException, IOException { + XmlUtil.writeNextValue(out, XML_TAG_PROVIDER_INDEX, mDataSource.getProviderIndex()); + } + + /** + * Deserialize share data (system wide Passpoint configurations) from the input stream. + * + * @param in The input stream to read data from + * @param outerTagDepth The tag depth of the current XML section + * @throws XmlPullParserException + * @throws IOException + */ + private void deserializeShareData(XmlPullParser in, int outerTagDepth) + throws XmlPullParserException, IOException { + while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { + String[] valueName = new String[1]; + Object value = XmlUtil.readCurrentValue(in, valueName); + if (valueName[0] == null) { + throw new XmlPullParserException("Missing value name"); + } + switch (valueName[0]) { + case XML_TAG_PROVIDER_INDEX: + mDataSource.setProviderIndex((long) value); + break; + default: + throw new XmlPullParserException("Unknown value under share store data " + + valueName[0]); + } + } + } +} + + diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointConfigStoreData.java b/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java index 5c46d3515..6e4c5e6f9 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointConfigStoreData.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java @@ -49,7 +49,7 @@ import java.util.List; * - Provider list - list of Passpoint provider configurations * */ -public class PasspointConfigStoreData implements WifiConfigStore.StoreData { +public class PasspointConfigUserStoreData implements WifiConfigStore.StoreData { private static final String XML_TAG_SECTION_HEADER_PASSPOINT_CONFIG_DATA = "PasspointConfigData"; private static final String XML_TAG_SECTION_HEADER_PASSPOINT_PROVIDER_LIST = @@ -65,7 +65,6 @@ public class PasspointConfigStoreData implements WifiConfigStore.StoreData { private static final String XML_TAG_CLIENT_CERTIFICATE_ALIAS = "ClientCertificateAlias"; private static final String XML_TAG_CLIENT_PRIVATE_KEY_ALIAS = "ClientPrivateKeyAlias"; - private static final String XML_TAG_PROVIDER_INDEX = "ProviderIndex"; private static final String XML_TAG_HAS_EVER_CONNECTED = "HasEverConnected"; private final WifiKeyStore mKeyStore; @@ -89,23 +88,9 @@ public class PasspointConfigStoreData implements WifiConfigStore.StoreData { * @param providers The list of providers */ void setProviders(List<PasspointProvider> providers); - - /** - * Retrieve the current provider index. - * - * @return long - */ - long getProviderIndex(); - - /** - * Set the current provider index. - * - * @param providerIndex The provider index used for provider creation - */ - void setProviderIndex(long providerIndex); } - PasspointConfigStoreData(WifiKeyStore keyStore, SIMAccessor simAccessor, + PasspointConfigUserStoreData(WifiKeyStore keyStore, SIMAccessor simAccessor, DataSource dataSource) { mKeyStore = keyStore; mSimAccessor = simAccessor; @@ -113,57 +98,44 @@ public class PasspointConfigStoreData implements WifiConfigStore.StoreData { } @Override - public void serializeData(XmlSerializer out, boolean shared) + public void serializeData(XmlSerializer out) throws XmlPullParserException, IOException { - if (shared) { - serializeShareData(out); - } else { - serializeUserData(out); - } + serializeUserData(out); } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared) + public void deserializeData(XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { return; } - if (shared) { - deserializeShareData(in, outerTagDepth); - } else { - deserializeUserData(in, outerTagDepth); - } + deserializeUserData(in, outerTagDepth); } + /** + * Reset user data (user specific Passpoint configurations). + */ @Override - public void resetData(boolean shared) { - if (shared) { - resetShareData(); - } else { - resetUserData(); - } + public void resetData() { + mDataSource.setProviders(new ArrayList<PasspointProvider>()); } @Override - public String getName() { - return XML_TAG_SECTION_HEADER_PASSPOINT_CONFIG_DATA; + public boolean hasNewDataToSerialize() { + // always persist. + return true; } @Override - public boolean supportShareData() { - return true; + public String getName() { + return XML_TAG_SECTION_HEADER_PASSPOINT_CONFIG_DATA; } - /** - * Serialize share data (system wide Passpoint configurations) to a XML block. - * - * @param out The output stream to serialize data to - * @throws XmlPullParserException - * @throws IOException - */ - private void serializeShareData(XmlSerializer out) throws XmlPullParserException, IOException { - XmlUtil.writeNextValue(out, XML_TAG_PROVIDER_INDEX, mDataSource.getProviderIndex()); + @Override + public @WifiConfigStore.StoreFileId int getStoreFileId() { + // Shared general store. + return WifiConfigStore.STORE_FILE_USER_GENERAL; } /** @@ -226,33 +198,6 @@ public class PasspointConfigStoreData implements WifiConfigStore.StoreData { } /** - * Deserialize share data (system wide Passpoint configurations) from the input stream. - * - * @param in The input stream to read data from - * @param outerTagDepth The tag depth of the current XML section - * @throws XmlPullParserException - * @throws IOException - */ - private void deserializeShareData(XmlPullParser in, int outerTagDepth) - throws XmlPullParserException, IOException { - while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { - String[] valueName = new String[1]; - Object value = XmlUtil.readCurrentValue(in, valueName); - if (valueName[0] == null) { - throw new XmlPullParserException("Missing value name"); - } - switch (valueName[0]) { - case XML_TAG_PROVIDER_INDEX: - mDataSource.setProviderIndex((long) value); - break; - default: - throw new XmlPullParserException("Unknown value under share store data " - + valueName[0]); - } - } - } - - /** * Deserialize user data (user specific Passpoint configurations) from the input stream. * * @param in The input stream to read data from @@ -358,19 +303,5 @@ public class PasspointConfigStoreData implements WifiConfigStore.StoreData { caCertificateAlias, clientCertificateAlias, clientPrivateKeyAlias, hasEverConnected, shared); } - - /** - * Reset share data (system wide Passpoint configurations). - */ - private void resetShareData() { - mDataSource.setProviderIndex(0); - } - - /** - * Reset user data (user specific Passpoint configurations). - */ - private void resetUserData() { - mDataSource.setProviders(new ArrayList<PasspointProvider>()); - } } diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java index 2f6dc05dc..25a2d986b 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java @@ -167,9 +167,10 @@ public class PasspointManager { } /** - * Data provider for the Passpoint configuration store data {@link PasspointConfigStoreData}. + * Data provider for the Passpoint configuration store data + * {@link PasspointConfigUserStoreData}. */ - private class DataSourceHandler implements PasspointConfigStoreData.DataSource { + private class UserDataSourceHandler implements PasspointConfigUserStoreData.DataSource { @Override public List<PasspointProvider> getProviders() { List<PasspointProvider> providers = new ArrayList<>(); @@ -186,7 +187,13 @@ public class PasspointManager { mProviders.put(provider.getConfig().getHomeSp().getFqdn(), provider); } } + } + /** + * Data provider for the Passpoint configuration store data + * {@link PasspointConfigSharedStoreData}. + */ + private class SharedDataSourceHandler implements PasspointConfigSharedStoreData.DataSource { @Override public long getProviderIndex() { return mProviderIndex; @@ -214,8 +221,10 @@ public class PasspointManager { mWifiConfigManager = wifiConfigManager; mWifiMetrics = wifiMetrics; mProviderIndex = 0; - wifiConfigStore.registerStoreData(objectFactory.makePasspointConfigStoreData( - mKeyStore, mSimAccessor, new DataSourceHandler())); + wifiConfigStore.registerStoreData(objectFactory.makePasspointConfigUserStoreData( + mKeyStore, mSimAccessor, new UserDataSourceHandler())); + wifiConfigStore.registerStoreData(objectFactory.makePasspointConfigSharedStoreData( + new SharedDataSourceHandler())); mPasspointProvisioner = objectFactory.makePasspointProvisioner(context, wifiNative); sPasspointManager = this; } diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java b/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java index f743882e3..bced12bca 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointObjectFactory.java @@ -61,16 +61,26 @@ public class PasspointObjectFactory{ } /** - * Create a {@link PasspointConfigStoreData} instance. + * Create a {@link PasspointConfigUserStoreData} instance. * * @param keyStore Instance of {@link WifiKeyStore} * @param simAccessor Instance of {@link SIMAccessor} * @param dataSource Passpoint configuration data source - * @return {@link PasspointConfigStoreData} + * @return {@link PasspointConfigUserStoreData} */ - public PasspointConfigStoreData makePasspointConfigStoreData(WifiKeyStore keyStore, - SIMAccessor simAccessor, PasspointConfigStoreData.DataSource dataSource) { - return new PasspointConfigStoreData(keyStore, simAccessor, dataSource); + public PasspointConfigUserStoreData makePasspointConfigUserStoreData(WifiKeyStore keyStore, + SIMAccessor simAccessor, PasspointConfigUserStoreData.DataSource dataSource) { + return new PasspointConfigUserStoreData(keyStore, simAccessor, dataSource); + } + + /** + * Create a {@link PasspointConfigSharedStoreData} instance. + * @param dataSource Passpoint configuration data source + * @return {@link PasspointConfigSharedStoreData} + */ + public PasspointConfigSharedStoreData makePasspointConfigSharedStoreData( + PasspointConfigSharedStoreData.DataSource dataSource) { + return new PasspointConfigSharedStoreData(dataSource); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/DeletedEphemeralSsidsStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/DeletedEphemeralSsidsStoreDataTest.java index 289a3beab..2af8b557c 100644 --- a/tests/wifitests/src/com/android/server/wifi/DeletedEphemeralSsidsStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/DeletedEphemeralSsidsStoreDataTest.java @@ -27,7 +27,6 @@ import com.android.internal.util.FastXmlSerializer; import org.junit.Before; import org.junit.Test; import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.ByteArrayInputStream; @@ -61,15 +60,14 @@ public class DeletedEphemeralSsidsStoreDataTest { /** * Helper function for serializing configuration data to a XML block. * - * @param shared Flag indicating serializing shared or user configurations * @return byte[] of the XML data * @throws Exception */ - private byte[] serializeData(boolean shared) throws Exception { + private byte[] serializeData() throws Exception { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mDeletedEphemeralSsidsStoreData.serializeData(out, shared); + mDeletedEphemeralSsidsStoreData.serializeData(out); out.flush(); return outputStream.toByteArray(); } @@ -78,43 +76,18 @@ public class DeletedEphemeralSsidsStoreDataTest { * Helper function for parsing configuration data from a XML block. * * @param data XML data to parse from - * @param shared Flag indicating parsing of shared or user configurations * @return SSID list * @throws Exception */ - private Set<String> deserializeData(byte[] data, boolean shared) throws Exception { + private Set<String> deserializeData(byte[] data) throws Exception { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mDeletedEphemeralSsidsStoreData.deserializeData(in, in.getDepth(), shared); + mDeletedEphemeralSsidsStoreData.deserializeData(in, in.getDepth()); return mDeletedEphemeralSsidsStoreData.getSsidList(); } /** - * Verify that a XmlPullParserException will be thrown when attempting to serialize SSID list - * to the share store, since the deleted ephemeral SSID list should never be persist - * to the share store. - * - * @throws Exception - */ - @Test(expected = XmlPullParserException.class) - public void serializeShareData() throws Exception { - serializeData(true /* shared */); - } - - /** - * Verify that a XmlPullParserException will be thrown when attempting to parse SSID list - * from the share store, since the deleted ephemeral SSID list should never be persist - * to the share store. - * - * @throws Exception - */ - @Test(expected = XmlPullParserException.class) - public void deserializeShareData() throws Exception { - deserializeData(new byte[0], true /* shared */); - } - - /** * Verify that serializing the user store data without any configuration doesn't cause any * crash and no data should be serialized. * @@ -122,7 +95,7 @@ public class DeletedEphemeralSsidsStoreDataTest { */ @Test public void serializeEmptyConfigs() throws Exception { - assertEquals(0, serializeData(false /* shared */).length); + assertEquals(0, serializeData().length); } /** @@ -133,17 +106,19 @@ public class DeletedEphemeralSsidsStoreDataTest { */ @Test public void deserializeEmptyData() throws Exception { - assertTrue(deserializeData(new byte[0], false /* shared */).isEmpty()); + assertTrue(deserializeData(new byte[0]).isEmpty()); } /** - * Verify that DeletedEphemeralSsidsStoreData does not support share data. + * Verify that DeletedEphemeralSsidsStoreData is written to + * {@link WifiConfigStore#STORE_FILE_NAME_USER_GENERAL}. * * @throws Exception */ @Test - public void supportShareData() throws Exception { - assertFalse(mDeletedEphemeralSsidsStoreData.supportShareData()); + public void getUserStoreFileId() throws Exception { + assertEquals(WifiConfigStore.STORE_FILE_USER_GENERAL, + mDeletedEphemeralSsidsStoreData.getStoreFileId()); } /** @@ -158,7 +133,7 @@ public class DeletedEphemeralSsidsStoreDataTest { ssidList.add(TEST_SSID1); ssidList.add(TEST_SSID2); mDeletedEphemeralSsidsStoreData.setSsidList(ssidList); - byte[] actualData = serializeData(false /* shared */); + byte[] actualData = serializeData(); assertTrue(Arrays.equals(TEST_SSID_LIST_XML_BYTES, actualData)); } @@ -173,6 +148,6 @@ public class DeletedEphemeralSsidsStoreDataTest { Set<String> ssidList = new HashSet<>(); ssidList.add(TEST_SSID1); ssidList.add(TEST_SSID2); - assertEquals(ssidList, deserializeData(TEST_SSID_LIST_XML_BYTES, false /* shared */)); + assertEquals(ssidList, deserializeData(TEST_SSID_LIST_XML_BYTES)); } } diff --git a/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java index caed9445e..5fa15e81b 100644 --- a/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java @@ -48,7 +48,7 @@ import java.util.Arrays; import java.util.List; /** - * Unit tests for {@link com.android.server.wifi.NetworksListStoreData}. + * Unit tests for {@link com.android.server.wifi.NetworkListStoreData}. */ @SmallTest public class NetworkListStoreDataTest { @@ -182,7 +182,9 @@ public class NetworkListStoreDataTest { + "</WifiEnterpriseConfiguration>\n" + "</Network>\n"; - private NetworkListStoreData mNetworkListStoreData; + // We use {@link NetworkListSharedStoreData} instance because {@link NetworkListStoreData} is + // abstract. + private NetworkListSharedStoreData mNetworkListSharedStoreData; @Mock private Context mContext; @Mock private PackageManager mPackageManager; @@ -191,21 +193,20 @@ public class NetworkListStoreDataTest { MockitoAnnotations.initMocks(this); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getNameForUid(anyInt())).thenReturn(TEST_CREATOR_NAME); - mNetworkListStoreData = new NetworkListStoreData(mContext); + mNetworkListSharedStoreData = new NetworkListSharedStoreData(mContext); } /** * Helper function for serializing configuration data to a XML block. * - * @param shared Flag indicating serializing shared or user configurations * @return byte[] of the XML data * @throws Exception */ - private byte[] serializeData(boolean shared) throws Exception { + private byte[] serializeData() throws Exception { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mNetworkListStoreData.serializeData(out, shared); + mNetworkListSharedStoreData.serializeData(out); out.flush(); return outputStream.toByteArray(); } @@ -214,20 +215,15 @@ public class NetworkListStoreDataTest { * Helper function for parsing configuration data from a XML block. * * @param data XML data to parse from - * @param shared Flag indicating parsing of shared or user configurations * @return List of WifiConfiguration parsed * @throws Exception */ - private List<WifiConfiguration> deserializeData(byte[] data, boolean shared) throws Exception { + private List<WifiConfiguration> deserializeData(byte[] data) throws Exception { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mNetworkListStoreData.deserializeData(in, in.getDepth(), shared); - if (shared) { - return mNetworkListStoreData.getSharedConfigurations(); - } else { - return mNetworkListStoreData.getUserConfigurations(); - } + mNetworkListSharedStoreData.deserializeData(in, in.getDepth()); + return mNetworkListSharedStoreData.getConfigurations(); } /** @@ -288,8 +284,7 @@ public class NetworkListStoreDataTest { */ @Test public void serializeEmptyConfigs() throws Exception { - assertEquals(0, serializeData(true /* shared */).length); - assertEquals(0, serializeData(false /* shared */).length); + assertEquals(0, serializeData().length); } /** @@ -300,18 +295,23 @@ public class NetworkListStoreDataTest { */ @Test public void deserializeEmptyData() throws Exception { - assertTrue(deserializeData(new byte[0], true /* shared */).isEmpty()); - assertTrue(deserializeData(new byte[0], false /* shared */).isEmpty()); + assertTrue(deserializeData(new byte[0]).isEmpty()); } /** - * Verify that NetworkListStoreData does support share data. + * Verify that {@link NetworkListSharedStoreData} is written to + * {@link WifiConfigStore#STORE_FILE_NAME_SHARED_GENERAL}. + * Verify that {@link NetworkListUserStoreData} is written to + * {@link WifiConfigStore#STORE_FILE_NAME_USER_GENERAL}. * * @throws Exception */ @Test - public void supportShareData() throws Exception { - assertTrue(mNetworkListStoreData.supportShareData()); + public void getUserStoreFileId() throws Exception { + assertEquals(WifiConfigStore.STORE_FILE_SHARED_GENERAL, + mNetworkListSharedStoreData.getStoreFileId()); + assertEquals(WifiConfigStore.STORE_FILE_USER_GENERAL, + new NetworkListUserStoreData(mContext).getStoreFileId()); } /** @@ -323,9 +323,9 @@ public class NetworkListStoreDataTest { @Test public void serializeSharedConfigurations() throws Exception { List<WifiConfiguration> networkList = getTestNetworksConfig(true /* shared */); - mNetworkListStoreData.setSharedConfigurations(networkList); + mNetworkListSharedStoreData.setConfigurations(networkList); byte[] expectedData = getTestNetworksXmlBytes(networkList.get(0), networkList.get(1)); - assertTrue(Arrays.equals(expectedData, serializeData(true /* shared */))); + assertTrue(Arrays.equals(expectedData, serializeData())); } /** @@ -338,34 +338,7 @@ public class NetworkListStoreDataTest { List<WifiConfiguration> networkList = getTestNetworksConfig(true /* shared */); byte[] xmlData = getTestNetworksXmlBytes(networkList.get(0), networkList.get(1)); WifiConfigurationTestUtil.assertConfigurationsEqualForConfigStore( - networkList, deserializeData(xmlData, true /* shared */)); - } - - /** - * Verify that the user configurations (containing an open and an EAP network) are serialized - * correctly, matching the expected XML string. - * - * @throws Exception - */ - @Test - public void serializeUserConfigurations() throws Exception { - List<WifiConfiguration> networkList = getTestNetworksConfig(false /* shared */); - mNetworkListStoreData.setUserConfigurations(networkList); - byte[] expectedData = getTestNetworksXmlBytes(networkList.get(0), networkList.get(1)); - assertTrue(Arrays.equals(expectedData, serializeData(false /* shared */))); - } - - /** - * Verify that the user configurations are parsed correctly from a XML string containing - * test networks (an open and an EAP network). - * @throws Exception - */ - @Test - public void deserializeUserConfigurations() throws Exception { - List<WifiConfiguration> networkList = getTestNetworksConfig(false /* shared */); - byte[] xmlData = getTestNetworksXmlBytes(networkList.get(0), networkList.get(1)); - WifiConfigurationTestUtil.assertConfigurationsEqualForConfigStore( - networkList, deserializeData(xmlData, false /* shared */)); + networkList, deserializeData(xmlData)); } /** @@ -432,7 +405,7 @@ public class NetworkListStoreDataTest { openNetwork.SSID.replaceAll("\"", """), openNetwork.shared, openNetwork.creatorUid, openNetwork.getRandomizedMacAddress()) .getBytes(StandardCharsets.UTF_8); - deserializeData(xmlData, true); + deserializeData(xmlData); } /** @@ -450,7 +423,7 @@ public class NetworkListStoreDataTest { openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName, openNetwork.getRandomizedMacAddress()) .getBytes(StandardCharsets.UTF_8); - deserializeData(xmlData, true); + deserializeData(xmlData); } /** @@ -470,7 +443,7 @@ public class NetworkListStoreDataTest { String.format(XmlUtilTest.XML_STRING_EAP_METHOD_REPLACE_FORMAT, WifiEnterpriseConfig.Eap.NONE)); List<WifiConfiguration> retrievedNetworkList = - deserializeData(xmlString.getBytes(StandardCharsets.UTF_8), true /* shared */); + deserializeData(xmlString.getBytes(StandardCharsets.UTF_8)); // Retrieved network should not contain the eap network. assertEquals(1, retrievedNetworkList.size()); for (WifiConfiguration network : retrievedNetworkList) { @@ -495,7 +468,7 @@ public class NetworkListStoreDataTest { openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName, openNetwork.getRandomizedMacAddress()) .getBytes(StandardCharsets.UTF_8); - List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData, true); + List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData); assertEquals(1, deserializedNetworks.size()); assertEquals(openNetwork.configKey(), deserializedNetworks.get(0).configKey()); assertEquals(SYSTEM_UID, deserializedNetworks.get(0).creatorUid); @@ -523,7 +496,7 @@ public class NetworkListStoreDataTest { openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName, openNetwork.getRandomizedMacAddress()) .getBytes(StandardCharsets.UTF_8); - List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData, true); + List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData); assertEquals(1, deserializedNetworks.size()); assertEquals(openNetwork.configKey(), deserializedNetworks.get(0).configKey()); assertEquals(openNetwork.creatorUid, deserializedNetworks.get(0).creatorUid); @@ -550,7 +523,7 @@ public class NetworkListStoreDataTest { openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName, openNetwork.getRandomizedMacAddress()) .getBytes(StandardCharsets.UTF_8); - List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData, true); + List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData); assertEquals(1, deserializedNetworks.size()); assertEquals(openNetwork.configKey(), deserializedNetworks.get(0).configKey()); assertEquals(openNetwork.creatorUid, deserializedNetworks.get(0).creatorUid); @@ -571,7 +544,7 @@ public class NetworkListStoreDataTest { openNetwork.shared, openNetwork.creatorUid, openNetwork.creatorName, openNetwork.getRandomizedMacAddress()) .getBytes(StandardCharsets.UTF_8); - List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData, true); + List<WifiConfiguration> deserializedNetworks = deserializeData(xmlData); assertEquals(1, deserializedNetworks.size()); assertEquals(openNetwork.configKey(), deserializedNetworks.get(0).configKey()); assertEquals(openNetwork.creatorUid, deserializedNetworks.get(0).creatorUid); diff --git a/tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java index 8a9d9bc80..86ebb875f 100644 --- a/tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java @@ -17,7 +17,6 @@ package com.android.server.wifi; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; @@ -73,15 +72,14 @@ public class SsidSetStoreDataTest { /** * Helper function for serializing configuration data to a XML block. * - * @param shared Flag indicating serializing shared or user configurations * @return byte[] of the XML data * @throws Exception */ - private byte[] serializeData(boolean shared) throws Exception { + private byte[] serializeData() throws Exception { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mSsidSetStoreData.serializeData(out, shared); + mSsidSetStoreData.serializeData(out); out.flush(); return outputStream.toByteArray(); } @@ -90,36 +88,13 @@ public class SsidSetStoreDataTest { * Helper function for parsing configuration data from a XML block. * * @param data XML data to parse from - * @param shared Flag indicating parsing of shared or user configurations * @throws Exception */ - private void deserializeData(byte[] data, boolean shared) 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()); - mSsidSetStoreData.deserializeData(in, in.getDepth(), shared); - } - - /** - * Verify that a XmlPullParserException will be thrown when attempting to serialize data - * to the share store. - * - * @throws Exception - */ - @Test(expected = XmlPullParserException.class) - public void serializeShareData() throws Exception { - serializeData(true /* shared */); - } - - /** - * Verify that a XmlPullParserException will be thrown when attempting to deserialize - * data from the share store. - * - * @throws Exception - */ - @Test(expected = XmlPullParserException.class) - public void deserializeShareData() throws Exception { - deserializeData(new byte[0], true /* shared */); + mSsidSetStoreData.deserializeData(in, in.getDepth()); } /** @@ -131,7 +106,7 @@ public class SsidSetStoreDataTest { @Test public void serializeEmptyConfigs() throws Exception { when(mDataSource.getSsids()).thenReturn(new HashSet<String>()); - assertEquals(0, serializeData(false /* shared */).length); + assertEquals(0, serializeData().length); } /** @@ -142,18 +117,20 @@ public class SsidSetStoreDataTest { */ @Test public void deserializeEmptyStoreData() throws Exception { - deserializeData(new byte[0], false /* shared */); + deserializeData(new byte[0]); verify(mDataSource, never()).setSsids(any(Set.class)); } /** - * Verify that {@link SsidSetStoreData} does not support share data. + * Verify that SsidSetStoreData is written to + * {@link WifiConfigStore#STORE_FILE_NAME_USER_GENERAL}. * * @throws Exception */ @Test - public void supportShareData() throws Exception { - assertFalse(mSsidSetStoreData.supportShareData()); + public void getUserStoreFileId() throws Exception { + assertEquals(WifiConfigStore.STORE_FILE_USER_GENERAL, + mSsidSetStoreData.getStoreFileId()); } /** @@ -167,7 +144,7 @@ public class SsidSetStoreDataTest { ssidSet.add(TEST_SSID1); ssidSet.add(TEST_SSID2); when(mDataSource.getSsids()).thenReturn(ssidSet); - byte[] actualData = serializeData(false /* shared */); + byte[] actualData = serializeData(); assertTrue(Arrays.equals(TEST_SSID_SET_XML_BYTES, actualData)); } @@ -181,7 +158,7 @@ public class SsidSetStoreDataTest { Set<String> ssidSet = new HashSet<>(); ssidSet.add(TEST_SSID1); ssidSet.add(TEST_SSID2); - deserializeData(TEST_SSID_SET_XML_BYTES, false /* shared */); + deserializeData(TEST_SSID_SET_XML_BYTES); verify(mDataSource).setSsids(eq(ssidSet)); } @@ -199,6 +176,6 @@ public class SsidSetStoreDataTest { + "<string>" + TEST_SSID2 + "</string>\n" + "<Unknown>" + "badInput" + "</Unknown>" // Unknown tag. + "</set>\n"; - deserializeData(ssidSet.getBytes(StandardCharsets.UTF_8), false /* shared */); + deserializeData(ssidSet.getBytes(StandardCharsets.UTF_8)); } } diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java index 33f1b42fe..cfb0e1c80 100644 --- a/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java @@ -16,6 +16,7 @@ package com.android.server.wifi; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.eq; @@ -34,7 +35,6 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.ByteArrayInputStream; @@ -67,14 +67,13 @@ public class WakeupConfigStoreDataTest { /** * Helper function for serializing configuration data to a XML block. * - * @param shared Flag indicating serializing shared or user configurations * @return byte[] of the XML data */ - private byte[] serializeData(boolean shared) throws Exception { + private byte[] serializeData() throws Exception { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mWakeupConfigData.serializeData(out, shared); + mWakeupConfigData.serializeData(out); out.flush(); return outputStream.toByteArray(); } @@ -83,31 +82,12 @@ public class WakeupConfigStoreDataTest { * Helper function for parsing configuration data from a XML block. * * @param data XML data to parse from - * @param shared Flag indicating parsing of shared or user configurations */ - private void deserializeData(byte[] data, boolean shared) 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()); - mWakeupConfigData.deserializeData(in, in.getDepth(), shared); - } - - /** - * Verify that a XmlPullParserException will be thrown when attempting to serialize data - * to the share store. - */ - @Test(expected = XmlPullParserException.class) - public void serializeShareDataThrowsException() throws Exception { - serializeData(true /* shared */); - } - - /** - * Verify that a XmlPullParserException will be thrown when attempting to deserialize - * data from the share store. - */ - @Test(expected = XmlPullParserException.class) - public void deserializeShareDataThrowsException() throws Exception { - deserializeData(new byte[0], true /* shared */); + mWakeupConfigData.deserializeData(in, in.getDepth()); } /** @@ -125,8 +105,8 @@ public class WakeupConfigStoreDataTest { when(mNotificationsDataSource.getData()).thenReturn(notificationsShown); when(mNetworkDataSource.getData()).thenReturn(networks); - byte[] bytes = serializeData(false /* shared */); - deserializeData(bytes, false /* shared */); + byte[] bytes = serializeData(); + deserializeData(bytes); verify(mActiveDataSource).setData(eq(isActive)); verify(mIsOnboardedDataSource).setData(eq(isOnboarded)); @@ -161,8 +141,8 @@ public class WakeupConfigStoreDataTest { when(mNotificationsDataSource.getData()).thenReturn(notificationsShown); when(mNetworkDataSource.getData()).thenReturn(networks); - byte[] bytes = serializeData(false /* shared */); - deserializeData(bytes, false /* shared */); + byte[] bytes = serializeData(); + deserializeData(bytes); verify(mActiveDataSource).setData(eq(isActive)); verify(mIsOnboardedDataSource).setData(eq(isOnboarded)); @@ -175,7 +155,7 @@ public class WakeupConfigStoreDataTest { */ @Test public void resetDataWipesDataSources() { - mWakeupConfigData.resetData(false /* shared */); + mWakeupConfigData.resetData(); verify(mActiveDataSource).setData(false); verify(mIsOnboardedDataSource).setData(false); @@ -196,16 +176,19 @@ public class WakeupConfigStoreDataTest { */ @Test public void hasBeenReadIsTrueWhenUserStoreIsLoaded() throws Exception { - mWakeupConfigData.deserializeData(null /* in */, 0 /* outerTagDepth */, false /* shared */); + mWakeupConfigData.deserializeData(null /* in */, 0 /* outerTagDepth */); assertTrue(mWakeupConfigData.hasBeenRead()); } /** - * Verify that hasBeenRead returns false if only the shared store has been read. + * Verify that WakeUpConfigStoreData is written to + * {@link WifiConfigStore#STORE_FILE_NAME_USER_GENERAL}. + * + * @throws Exception */ @Test - public void hasBeenReadIsFalseWhenSharedStoreIsLoaded() throws Exception { - mWakeupConfigData.deserializeData(null /* in */, 0 /* outerTagDepth */, true /* shared */); - assertFalse(mWakeupConfigData.hasBeenRead()); + public void getUserStoreFileId() throws Exception { + assertEquals(WifiConfigStore.STORE_FILE_USER_GENERAL, + mWakeupConfigData.getStoreFileId()); } } diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java index 3734ba786..4d8f03481 100644 --- a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java @@ -142,7 +142,7 @@ public class WakeupControllerTest { private void readUserStore() { try { - mWakeupConfigStoreData.deserializeData(null, 0, false); + mWakeupConfigStoreData.deserializeData(null, 0); } catch (XmlPullParserException | IOException e) { // unreachable } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java index 6fd39a4a5..40f9f459d 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java @@ -109,7 +109,8 @@ public class WifiConfigManagerTest { @Mock private DevicePolicyManagerInternal mDevicePolicyManagerInternal; @Mock private WifiPermissionsUtil mWifiPermissionsUtil; @Mock private WifiPermissionsWrapper mWifiPermissionsWrapper; - @Mock private NetworkListStoreData mNetworkListStoreData; + @Mock private NetworkListSharedStoreData mNetworkListSharedStoreData; + @Mock private NetworkListUserStoreData mNetworkListUserStoreData; @Mock private DeletedEphemeralSsidsStoreData mDeletedEphemeralSsidsStoreData; @Mock private WifiConfigManager.OnSavedNetworkUpdateListener mWcmListener; @@ -129,7 +130,8 @@ public class WifiConfigManagerTest { // Set up the inorder for verifications. This is needed to verify that the broadcasts, // store writes for network updates followed by network additions are in the expected order. mContextConfigStoreMockOrder = inOrder(mContext, mWifiConfigStore); - mNetworkListStoreDataMockOrder = inOrder(mNetworkListStoreData); + mNetworkListStoreDataMockOrder = + inOrder(mNetworkListSharedStoreData, mNetworkListUserStoreData); // Set up the package name stuff & permission override. when(mContext.getPackageManager()).thenReturn(mPackageManager); @@ -2177,7 +2179,7 @@ public class WifiConfigManagerTest { // Now switch the user to user 2 and ensure that shared network's IDs have not changed. when(mUserManager.isUserUnlockingOrUnlocked(user2)).thenReturn(true); mWifiConfigManager.handleUserSwitch(user2); - verify(mWifiConfigStore).switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + verify(mWifiConfigStore).switchUserStoresAndRead(any(List.class)); // Again fetch the network ID's assigned to the shared networks and ensure they have not // changed. @@ -2254,7 +2256,7 @@ public class WifiConfigManagerTest { // Now switch the user to user 2 and ensure that user 1's private network has been removed. when(mUserManager.isUserUnlockingOrUnlocked(user2)).thenReturn(true); Set<Integer> removedNetworks = mWifiConfigManager.handleUserSwitch(user2); - verify(mWifiConfigStore).switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + verify(mWifiConfigStore).switchUserStoresAndRead(any(List.class)); assertTrue((removedNetworks.size() == 1) && (removedNetworks.contains(user1NetworkId))); // Set the expected networks to be |sharedNetwork| and |user2Network|. @@ -2316,7 +2318,7 @@ public class WifiConfigManagerTest { // Now switch the user to user 2 and ensure that no private network has been removed. when(mUserManager.isUserUnlockingOrUnlocked(user2)).thenReturn(true); Set<Integer> removedNetworks = mWifiConfigManager.handleUserSwitch(user2); - verify(mWifiConfigStore).switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + verify(mWifiConfigStore).switchUserStoresAndRead(any(List.class)); assertTrue(removedNetworks.isEmpty()); } @@ -2367,7 +2369,7 @@ public class WifiConfigManagerTest { }; setupStoreDataForUserRead(userNetworks, new HashSet<String>()); mWifiConfigManager.handleUserUnlock(user1); - verify(mWifiConfigStore).switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + verify(mWifiConfigStore).switchUserStoresAndRead(any(List.class)); // Capture the written data for the user 1 and ensure that it corresponds to what was // setup. Pair<List<WifiConfiguration>, List<WifiConfiguration>> writtenNetworkList = @@ -2446,7 +2448,7 @@ public class WifiConfigManagerTest { // the configured networks (migrated to PasspointManager). setupStoreDataForUserRead(new ArrayList<WifiConfiguration>(), new HashSet<String>()); mWifiConfigManager.handleUserUnlock(user1); - verify(mWifiConfigStore).switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + verify(mWifiConfigStore).switchUserStoresAndRead(any(List.class)); Pair<List<WifiConfiguration>, List<WifiConfiguration>> writtenNetworkList = captureWriteNetworksListStoreData(); assertTrue(writtenNetworkList.first.isEmpty()); @@ -2474,7 +2476,7 @@ public class WifiConfigManagerTest { mWifiConfigManager.handleUserSwitch(user2); // Ensure that the read was invoked. mContextConfigStoreMockOrder.verify(mWifiConfigStore) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); } /** @@ -2497,18 +2499,18 @@ public class WifiConfigManagerTest { // Ensure that the read was not invoked. mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); // Now try unlocking some other user (user1), this should be ignored. mWifiConfigManager.handleUserUnlock(user1); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); setupStoreDataForUserRead(new ArrayList<WifiConfiguration>(), new HashSet<String>()); // Unlock the user2 and ensure that we read the data now. mWifiConfigManager.handleUserUnlock(user2); mContextConfigStoreMockOrder.verify(mWifiConfigStore) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); } /** @@ -2528,12 +2530,12 @@ public class WifiConfigManagerTest { when(mUserManager.isUserUnlockingOrUnlocked(user2)).thenReturn(false); mWifiConfigManager.handleUserStop(user2); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); // Now try stopping the foreground user1, this should trigger a write to store. mWifiConfigManager.handleUserStop(user1); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); mContextConfigStoreMockOrder.verify(mWifiConfigStore).write(anyBoolean()); } @@ -2593,14 +2595,14 @@ public class WifiConfigManagerTest { mContextConfigStoreMockOrder.verify(mWifiConfigStore).read(); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()).write(anyBoolean()); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); setupStoreDataForUserRead(new ArrayList<WifiConfiguration>(), new HashSet<String>()); // Unlock the user1 (default user) for the first time and ensure that we read the data. mWifiConfigManager.handleUserUnlock(user1); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()).read(); mContextConfigStoreMockOrder.verify(mWifiConfigStore) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); mContextConfigStoreMockOrder.verify(mWifiConfigStore).write(anyBoolean()); } @@ -2619,13 +2621,13 @@ public class WifiConfigManagerTest { mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()).read(); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()).write(anyBoolean()); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); setupStoreDataForUserRead(new ArrayList<WifiConfiguration>(), new HashSet<String>()); // Read from store now. assertTrue(mWifiConfigManager.loadFromStore()); mContextConfigStoreMockOrder.verify(mWifiConfigStore) - .setUserStore(any(WifiConfigStore.StoreFile.class)); + .setUserStores(any(List.class)); mContextConfigStoreMockOrder.verify(mWifiConfigStore).read(); } @@ -2646,7 +2648,7 @@ public class WifiConfigManagerTest { mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()).read(); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()).write(anyBoolean()); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); // Now load from the store. assertTrue(mWifiConfigManager.loadFromStore()); @@ -2656,7 +2658,7 @@ public class WifiConfigManagerTest { setupStoreDataForUserRead(new ArrayList<>(), new HashSet<>()); mWifiConfigManager.handleUserUnlock(user2); mContextConfigStoreMockOrder.verify(mWifiConfigStore) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); } /** @@ -2678,12 +2680,12 @@ public class WifiConfigManagerTest { mWifiConfigManager.handleUserSwitch(user2); // Ensure that the read was invoked. mContextConfigStoreMockOrder.verify(mWifiConfigStore) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); // Unlock the user2 again and ensure that we don't read the data now. mWifiConfigManager.handleUserUnlock(user2); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); } /** @@ -2699,7 +2701,7 @@ public class WifiConfigManagerTest { when(mUserManager.isUserUnlockingOrUnlocked(user2)).thenReturn(false); mWifiConfigManager.handleUserSwitch(user2); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()).write(anyBoolean()); } @@ -2715,7 +2717,7 @@ public class WifiConfigManagerTest { // write the store files. mWifiConfigManager.handleUserUnlock(user1); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); mContextConfigStoreMockOrder.verify(mWifiConfigStore, never()).write(anyBoolean()); } @@ -2863,7 +2865,7 @@ public class WifiConfigManagerTest { mWifiConfigManager.handleUserSwitch(user2); // Ensure that the read was invoked. mContextConfigStoreMockOrder.verify(mWifiConfigStore) - .switchUserStoreAndRead(any(WifiConfigStore.StoreFile.class)); + .switchUserStoresAndRead(any(List.class)); } /** @@ -3753,8 +3755,8 @@ public class WifiConfigManagerTest { new WifiConfigManager( mContext, mClock, mUserManager, mTelephonyManager, mWifiKeyStore, mWifiConfigStore, mWifiConfigStoreLegacy, - mWifiPermissionsUtil, mWifiPermissionsWrapper, mNetworkListStoreData, - mDeletedEphemeralSsidsStoreData); + mWifiPermissionsUtil, mWifiPermissionsWrapper, mNetworkListSharedStoreData, + mNetworkListUserStoreData, mDeletedEphemeralSsidsStoreData); mWifiConfigManager.enableVerboseLogging(1); } @@ -3889,10 +3891,10 @@ public class WifiConfigManagerTest { ArgumentCaptor.forClass(ArrayList.class); ArgumentCaptor<ArrayList> userConfigsCaptor = ArgumentCaptor.forClass(ArrayList.class); - mNetworkListStoreDataMockOrder.verify(mNetworkListStoreData) - .setSharedConfigurations(sharedConfigsCaptor.capture()); - mNetworkListStoreDataMockOrder.verify(mNetworkListStoreData) - .setUserConfigurations(userConfigsCaptor.capture()); + mNetworkListStoreDataMockOrder.verify(mNetworkListSharedStoreData) + .setConfigurations(sharedConfigsCaptor.capture()); + mNetworkListStoreDataMockOrder.verify(mNetworkListUserStoreData) + .setConfigurations(userConfigsCaptor.capture()); mContextConfigStoreMockOrder.verify(mWifiConfigStore).write(anyBoolean()); return Pair.create(sharedConfigsCaptor.getValue(), userConfigsCaptor.getValue()); } catch (Exception e) { @@ -3937,19 +3939,19 @@ public class WifiConfigManagerTest { */ private void setupStoreDataForRead(List<WifiConfiguration> sharedConfigurations, List<WifiConfiguration> userConfigurations, Set<String> deletedEphemeralSsids) { - when(mNetworkListStoreData.getSharedConfigurations()) + when(mNetworkListSharedStoreData.getConfigurations()) .thenReturn(sharedConfigurations); - when(mNetworkListStoreData.getUserConfigurations()).thenReturn(userConfigurations); + when(mNetworkListUserStoreData.getConfigurations()).thenReturn(userConfigurations); when(mDeletedEphemeralSsidsStoreData.getSsidList()).thenReturn(deletedEphemeralSsids); } /** * Setup expectations for WifiNetworksListStoreData and DeletedEphemeralSsidsStoreData - * after WifiConfigStore#switchUserStoreAndRead. + * after WifiConfigStore#switchUserStoresAndRead. */ private void setupStoreDataForUserRead(List<WifiConfiguration> userConfigurations, Set<String> deletedEphemeralSsids) { - when(mNetworkListStoreData.getUserConfigurations()).thenReturn(userConfigurations); + when(mNetworkListUserStoreData.getConfigurations()).thenReturn(userConfigurations); when(mDeletedEphemeralSsidsStoreData.getSsidList()).thenReturn(deletedEphemeralSsids); } @@ -4076,7 +4078,8 @@ public class WifiConfigManagerTest { */ private NetworkUpdateResult addNetworkToWifiConfigManager(WifiConfiguration configuration, int uid) { - clearInvocations(mContext, mWifiConfigStore, mNetworkListStoreData); + clearInvocations(mContext, mWifiConfigStore, mNetworkListSharedStoreData, + mNetworkListUserStoreData); triggerStoreReadIfNeeded(); when(mClock.getWallClockMillis()).thenReturn(TEST_WALLCLOCK_CREATION_TIME_MILLIS); NetworkUpdateResult result = @@ -4148,7 +4151,8 @@ public class WifiConfigManagerTest { * to modify the configuration before we compare the added network with the retrieved network. */ private NetworkUpdateResult updateNetworkToWifiConfigManager(WifiConfiguration configuration) { - clearInvocations(mContext, mWifiConfigStore, mNetworkListStoreData); + clearInvocations(mContext, mWifiConfigStore, mNetworkListSharedStoreData, + mNetworkListUserStoreData); when(mClock.getWallClockMillis()).thenReturn(TEST_WALLCLOCK_UPDATE_TIME_MILLIS); NetworkUpdateResult result = mWifiConfigManager.addOrUpdateNetwork(configuration, TEST_UPDATE_UID); diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java index 1741acc4b..0240a67ab 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java @@ -27,6 +27,8 @@ import android.net.wifi.WifiConfiguration; import android.os.test.TestLooper; import android.support.test.filters.SmallTest; +import com.android.internal.util.ArrayUtils; +import com.android.server.wifi.WifiConfigStore.StoreData; import com.android.server.wifi.WifiConfigStore.StoreFile; import com.android.server.wifi.util.XmlUtil; @@ -53,13 +55,6 @@ import java.util.Set; */ @SmallTest public class WifiConfigStoreTest { - // Store file content without any data. - private static final String EMPTY_FILE_CONTENT = - "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" - + "<WifiConfigStoreData>\n" - + "<int name=\"Version\" value=\"1\" />\n" - + "</WifiConfigStoreData>\n"; - private static final String TEST_USER_DATA = "UserData"; private static final String TEST_SHARE_DATA = "ShareData"; private static final String TEST_CREATOR_NAME = "CreatorName"; @@ -150,7 +145,10 @@ public class WifiConfigStoreTest { @Mock private Clock mClock; private MockStoreFile mSharedStore; private MockStoreFile mUserStore; - private MockStoreData mStoreData; + private MockStoreFile mUserNetworkSuggestionsStore; + private List<StoreFile> mUserStores = new ArrayList<StoreFile>(); + private MockStoreData mSharedStoreData; + private MockStoreData mUserStoreData; /** * Test instance of WifiConfigStore. @@ -168,9 +166,15 @@ public class WifiConfigStoreTest { .thenReturn(mAlarmManager.getAlarmManager()); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getNameForUid(anyInt())).thenReturn(TEST_CREATOR_NAME); - mUserStore = new MockStoreFile(); - mSharedStore = new MockStoreFile(); - mStoreData = new MockStoreData(); + mSharedStore = new MockStoreFile(WifiConfigStore.STORE_FILE_SHARED_GENERAL); + mUserStore = new MockStoreFile(WifiConfigStore.STORE_FILE_USER_GENERAL); + mUserNetworkSuggestionsStore = + new MockStoreFile(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS); + mUserStores.add(mUserStore); + mUserStores.add(mUserNetworkSuggestionsStore); + + mSharedStoreData = new MockStoreData(WifiConfigStore.STORE_FILE_SHARED_GENERAL); + mUserStoreData = new MockStoreData(WifiConfigStore.STORE_FILE_USER_GENERAL); } /** @@ -194,24 +198,20 @@ public class WifiConfigStoreTest { } /** - * Verify the contents of the config file with empty data. The data content should be the - * same as {@link #EMPTY_FILE_CONTENT}. + * Verify that no write occurs if there is {@link StoreData} registered for any + * {@link StoreFile}. * * @throws Exception */ @Test - public void testWriteWithEmptyData() throws Exception { + public void testWriteWithNoStoreData() throws Exception { // Perform force write to both share and user store file. - mWifiConfigStore.switchUserStoreAndRead(mUserStore); + mWifiConfigStore.setUserStores(mUserStores); mWifiConfigStore.write(true); - assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); - assertTrue(mSharedStore.isStoreWritten()); - assertTrue(mUserStore.isStoreWritten()); - assertTrue(Arrays.equals(EMPTY_FILE_CONTENT.getBytes(StandardCharsets.UTF_8), - mSharedStore.getStoreBytes())); - assertTrue(Arrays.equals(EMPTY_FILE_CONTENT.getBytes(StandardCharsets.UTF_8), - mUserStore.getStoreBytes())); + assertFalse(mSharedStore.isStoreWritten()); + assertFalse(mUserStore.isStoreWritten()); + assertFalse(mUserNetworkSuggestionsStore.isStoreWritten()); } /** @@ -221,12 +221,17 @@ public class WifiConfigStoreTest { */ @Test public void testForceWrite() throws Exception { - mWifiConfigStore.switchUserStoreAndRead(mUserStore); + // Register data container. + mWifiConfigStore.registerStoreData(mSharedStoreData); + mWifiConfigStore.registerStoreData(mUserStoreData); + + mWifiConfigStore.switchUserStoresAndRead(mUserStores); mWifiConfigStore.write(true); assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); assertTrue(mSharedStore.isStoreWritten()); assertTrue(mUserStore.isStoreWritten()); + assertFalse(mUserNetworkSuggestionsStore.isStoreWritten()); } /** @@ -235,18 +240,24 @@ public class WifiConfigStoreTest { */ @Test public void testBufferedWrite() throws Exception { - mWifiConfigStore.switchUserStoreAndRead(mUserStore); + // Register data container. + mWifiConfigStore.registerStoreData(mSharedStoreData); + mWifiConfigStore.registerStoreData(mUserStoreData); + + mWifiConfigStore.switchUserStoresAndRead(mUserStores); mWifiConfigStore.write(false); assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); assertFalse(mSharedStore.isStoreWritten()); assertFalse(mUserStore.isStoreWritten()); + assertFalse(mUserNetworkSuggestionsStore.isStoreWritten()); // Now send the alarm and ensure that the writes happen. mAlarmManager.dispatch(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG); mLooper.dispatchAll(); assertTrue(mSharedStore.isStoreWritten()); assertTrue(mUserStore.isStoreWritten()); + assertFalse(mUserNetworkSuggestionsStore.isStoreWritten()); } /** @@ -257,12 +268,14 @@ public class WifiConfigStoreTest { @Test public void testForceWriteAfterBufferedWrite() throws Exception { // Register a test data container with bogus data. - mWifiConfigStore.registerStoreData(mStoreData); - mStoreData.setShareData("abcds"); - mStoreData.setUserData("asdfa"); + mWifiConfigStore.registerStoreData(mSharedStoreData); + mWifiConfigStore.registerStoreData(mUserStoreData); + + mSharedStoreData.setData("abcds"); + mUserStoreData.setData("asdfa"); // Perform buffered write for both user and share store file. - mWifiConfigStore.switchUserStoreAndRead(mUserStore); + mWifiConfigStore.switchUserStoresAndRead(mUserStores); mWifiConfigStore.write(false); assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); @@ -271,8 +284,8 @@ public class WifiConfigStoreTest { // Update the container with new set of data. The send a force write and ensure that the // writes have been performed and alarms have been stopped and updated data are written. - mStoreData.setUserData(TEST_USER_DATA); - mStoreData.setShareData(TEST_SHARE_DATA); + mUserStoreData.setData(TEST_USER_DATA); + mSharedStoreData.setData(TEST_SHARE_DATA); mWifiConfigStore.write(true); assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); @@ -281,35 +294,74 @@ public class WifiConfigStoreTest { // Verify correct data are loaded to the data container after a read. mWifiConfigStore.read(); - assertEquals(TEST_USER_DATA, mStoreData.getUserData()); - assertEquals(TEST_SHARE_DATA, mStoreData.getShareData()); + assertEquals(TEST_USER_DATA, mUserStoreData.getData()); + assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData()); } /** + * Tests the force write with no new data after a buffered write. + * Expected behaviour: The force write should flush the previous buffered write and stop the + * buffer write alarms. + */ + @Test + public void testForceWriteWithNoNewDataAfterBufferedWrite() throws Exception { + // Register a test data container with bogus data. + mWifiConfigStore.registerStoreData(mSharedStoreData); + mWifiConfigStore.registerStoreData(mUserStoreData); + + mSharedStoreData.setData("abcds"); + mUserStoreData.setData("asdfa"); + + // Perform buffered write for both user and share store file. + mWifiConfigStore.switchUserStoresAndRead(mUserStores); + mWifiConfigStore.write(false); + + assertTrue(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); + assertFalse(mSharedStore.isStoreWritten()); + assertFalse(mUserStore.isStoreWritten()); + + // Containers have no new data. + mUserStoreData.setHasAnyNewData(false); + mSharedStoreData.setHasAnyNewData(false); + mWifiConfigStore.write(true); + + assertFalse(mAlarmManager.isPending(WifiConfigStore.BUFFERED_WRITE_ALARM_TAG)); + assertTrue(mSharedStore.isStoreWritten()); + assertTrue(mUserStore.isStoreWritten()); + + // Verify correct data are loaded to the data container after a read. + mWifiConfigStore.read(); + assertEquals("abcds", mSharedStoreData.getData()); + assertEquals("asdfa", mUserStoreData.getData()); + } + + + /** * Tests the read API behaviour after a write to the store files. * Expected behaviour: The read should return the same data that was last written. */ @Test public void testReadAfterWrite() throws Exception { // Register data container. - mWifiConfigStore.registerStoreData(mStoreData); + mWifiConfigStore.registerStoreData(mSharedStoreData); + mWifiConfigStore.registerStoreData(mUserStoreData); // Read both share and user config store. - mWifiConfigStore.switchUserStoreAndRead(mUserStore); + mWifiConfigStore.switchUserStoresAndRead(mUserStores); // Verify no data is read. - assertNull(mStoreData.getUserData()); - assertNull(mStoreData.getShareData()); + assertNull(mUserStoreData.getData()); + assertNull(mSharedStoreData.getData()); // Write share and user data. - mStoreData.setUserData(TEST_USER_DATA); - mStoreData.setShareData(TEST_SHARE_DATA); + mUserStoreData.setData(TEST_USER_DATA); + mSharedStoreData.setData(TEST_SHARE_DATA); mWifiConfigStore.write(true); // Read and verify the data content in the data container. mWifiConfigStore.read(); - assertEquals(TEST_USER_DATA, mStoreData.getUserData()); - assertEquals(TEST_SHARE_DATA, mStoreData.getShareData()); + assertEquals(TEST_USER_DATA, mUserStoreData.getData()); + assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData()); } /** @@ -320,19 +372,25 @@ public class WifiConfigStoreTest { */ @Test public void testReadWithNoSharedStoreFileAndUserStoreNotVisible() throws Exception { - WifiConfigStore.StoreData storeData = mock(WifiConfigStore.StoreData.class); + StoreData sharedStoreData = mock(StoreData.class); + when(sharedStoreData.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); + StoreData userStoreData = mock(StoreData.class); + when(userStoreData.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); // Reading the mock store without a write should simulate the file not found case because // |readRawData| would return null. - mWifiConfigStore.registerStoreData(storeData); + mWifiConfigStore.registerStoreData(sharedStoreData); + mWifiConfigStore.registerStoreData(userStoreData); assertFalse(mWifiConfigStore.areStoresPresent()); mWifiConfigStore.read(); // Ensure that we got the call to deserialize empty shared data, but no user data. - verify(storeData).resetData(eq(true)); - verify(storeData).deserializeData(eq(null), anyInt(), eq(true)); - verify(storeData, never()).resetData(eq(false)); - verify(storeData, never()).deserializeData(eq(null), anyInt(), eq(false)); + verify(sharedStoreData).resetData(); + verify(sharedStoreData).deserializeData(eq(null), anyInt()); + verify(userStoreData, never()).resetData(); + verify(userStoreData, never()).deserializeData(any(), anyInt()); } /** @@ -342,21 +400,27 @@ public class WifiConfigStoreTest { */ @Test public void testReadWithNoStoreFiles() throws Exception { - WifiConfigStore.StoreData storeData = mock(WifiConfigStore.StoreData.class); + StoreData sharedStoreData = mock(StoreData.class); + when(sharedStoreData.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); + StoreData userStoreData = mock(StoreData.class); + when(userStoreData.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); // Reading the mock store without a write should simulate the file not found case because // |readRawData| would return null. - mWifiConfigStore.registerStoreData(storeData); + mWifiConfigStore.registerStoreData(sharedStoreData); + mWifiConfigStore.registerStoreData(userStoreData); // Read both share and user config store. - mWifiConfigStore.switchUserStoreAndRead(mUserStore); + mWifiConfigStore.setUserStores(mUserStores); assertFalse(mWifiConfigStore.areStoresPresent()); mWifiConfigStore.read(); // Ensure that we got the call to deserialize empty shared & user data. - verify(storeData).resetData(eq(true)); - verify(storeData).deserializeData(eq(null), anyInt(), eq(true)); - verify(storeData, times(2)).resetData(eq(false)); - verify(storeData, times(2)).deserializeData(eq(null), anyInt(), eq(false)); + verify(userStoreData).resetData(); + verify(userStoreData).deserializeData(eq(null), anyInt()); + verify(sharedStoreData).resetData(); + verify(sharedStoreData).deserializeData(eq(null), anyInt()); } /** @@ -367,14 +431,14 @@ public class WifiConfigStoreTest { @Test public void testReadAfterWriteWithNoUserStore() throws Exception { // Setup data container. - mWifiConfigStore.registerStoreData(mStoreData); - mStoreData.setShareData(TEST_SHARE_DATA); + mWifiConfigStore.registerStoreData(mSharedStoreData); + mSharedStoreData.setData(TEST_SHARE_DATA); // Perform write for the share store file. mWifiConfigStore.write(true); mWifiConfigStore.read(); // Verify data content for both user and share data. - assertEquals(TEST_SHARE_DATA, mStoreData.getShareData()); + assertEquals(TEST_SHARE_DATA, mSharedStoreData.getData()); } /** @@ -386,21 +450,22 @@ public class WifiConfigStoreTest { @Test public void testReadWillResetStoreData() throws Exception { // Register and setup store data. - mWifiConfigStore.registerStoreData(mStoreData); + mWifiConfigStore.registerStoreData(mSharedStoreData); + mWifiConfigStore.registerStoreData(mUserStoreData); // Perform force write with empty data content to both user and share store file. - mWifiConfigStore.switchUserStoreAndRead(mUserStore); + mWifiConfigStore.switchUserStoresAndRead(mUserStores); mWifiConfigStore.write(true); // Setup data container with some value. - mStoreData.setUserData(TEST_USER_DATA); - mStoreData.setShareData(TEST_SHARE_DATA); + mUserStoreData.setData(TEST_USER_DATA); + mSharedStoreData.setData(TEST_SHARE_DATA); // Perform read of both user and share store file and verify data in the data container // is in sync (empty) with what is in the file. mWifiConfigStore.read(); - assertNull(mStoreData.getShareData()); - assertNull(mStoreData.getUserData()); + assertNull(mSharedStoreData.getData()); + assertNull(mUserStoreData.getData()); } /** @@ -413,7 +478,7 @@ public class WifiConfigStoreTest { @Test public void testReadWifiConfigStoreData() throws Exception { // Setup network list. - NetworkListStoreData networkList = new NetworkListStoreData(mContext); + NetworkListStoreData networkList = new NetworkListUserStoreData(mContext); mWifiConfigStore.registerStoreData(networkList); WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(); openNetwork.creatorName = TEST_CREATOR_NAME; @@ -440,9 +505,9 @@ public class WifiConfigStoreTest { byte[] xmlBytes = xmlString.getBytes(StandardCharsets.UTF_8); mUserStore.storeRawDataToWrite(xmlBytes); - mWifiConfigStore.switchUserStoreAndRead(mUserStore); + mWifiConfigStore.switchUserStoresAndRead(mUserStores); WifiConfigurationTestUtil.assertConfigurationsEqualForConfigStore( - userConfigs, networkList.getUserConfigurations()); + userConfigs, networkList.getConfigurations()); assertEquals(ssidList, deletedEphemeralSsids.getSsidList()); } @@ -455,10 +520,10 @@ public class WifiConfigStoreTest { @Test public void testWriteWifiConfigStoreData() throws Exception { // Setup user store. - mWifiConfigStore.switchUserStoreAndRead(mUserStore); + mWifiConfigStore.switchUserStoresAndRead(mUserStores); // Setup network list store data. - NetworkListStoreData networkList = new NetworkListStoreData(mContext); + NetworkListStoreData networkList = new NetworkListUserStoreData(mContext); mWifiConfigStore.registerStoreData(networkList); WifiConfiguration openNetwork = WifiConfigurationTestUtil.createOpenNetwork(); openNetwork.creatorName = TEST_CREATOR_NAME; @@ -467,7 +532,7 @@ public class WifiConfigStoreTest { openNetwork.setRandomizedMacAddress(TEST_RANDOMIZED_MAC); List<WifiConfiguration> userConfigs = new ArrayList<>(); userConfigs.add(openNetwork); - networkList.setUserConfigurations(userConfigs); + networkList.setConfigurations(userConfigs); // Setup deleted ephemeral SSID list store data. DeletedEphemeralSsidsStoreData deletedEphemeralSsids = @@ -503,14 +568,12 @@ public class WifiConfigStoreTest { public void testReadWifiConfigStoreDataIndicateClientsThatThereIsNoDataForThem() throws Exception { // Set both the user store & shared store files. - mWifiConfigStore.switchUserStoreAndRead(mUserStore); + mWifiConfigStore.switchUserStoresAndRead(mUserStores); String storeData1Name = "test1"; String storeData2Name = "test2"; - WifiConfigStore.StoreData storeData1 = mock(WifiConfigStore.StoreData.class); - WifiConfigStore.StoreData storeData2 = mock(WifiConfigStore.StoreData.class); - when(storeData1.getName()).thenReturn(storeData1Name); - when(storeData2.getName()).thenReturn(storeData2Name); + StoreData storeData1 = mock(StoreData.class); + StoreData storeData2 = mock(StoreData.class); assertTrue(mWifiConfigStore.registerStoreData(storeData1)); assertTrue(mWifiConfigStore.registerStoreData(storeData2)); @@ -524,58 +587,122 @@ public class WifiConfigStoreTest { storeData1Name, storeData2Name); // Scenario 1: StoreData1 in shared store file. + when(storeData1.getName()).thenReturn(storeData1Name); + when(storeData2.getName()).thenReturn(storeData2Name); + when(storeData1.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); + when(storeData2.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); mSharedStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData1.getBytes()); mUserStore.storeRawDataToWrite(null); mWifiConfigStore.read(); - verify(storeData1).deserializeData(notNull(), anyInt(), eq(true)); - verify(storeData1, never()).deserializeData(eq(null), anyInt(), eq(true)); - verify(storeData1).deserializeData(eq(null), anyInt(), eq(false)); - verify(storeData2).deserializeData(eq(null), anyInt(), eq(true)); - verify(storeData2).deserializeData(eq(null), anyInt(), eq(false)); + verify(storeData1).deserializeData(notNull(), anyInt()); + verify(storeData1, never()).deserializeData(eq(null), anyInt()); + verify(storeData2).deserializeData(eq(null), anyInt()); reset(storeData1, storeData2); // Scenario 2: StoreData2 in user store file. + when(storeData1.getName()).thenReturn(storeData1Name); + when(storeData2.getName()).thenReturn(storeData2Name); + when(storeData1.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); + when(storeData2.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); mSharedStore.storeRawDataToWrite(null); mUserStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData2.getBytes()); mWifiConfigStore.read(); - verify(storeData1).deserializeData(eq(null), anyInt(), eq(true)); - verify(storeData1).deserializeData(eq(null), anyInt(), eq(false)); - verify(storeData2).deserializeData(eq(null), anyInt(), eq(true)); - verify(storeData2).deserializeData(notNull(), anyInt(), eq(false)); - verify(storeData2, never()).deserializeData(eq(null), anyInt(), eq(false)); + verify(storeData1).deserializeData(eq(null), anyInt()); + verify(storeData2).deserializeData(notNull(), anyInt()); + verify(storeData2, never()).deserializeData(eq(null), anyInt()); reset(storeData1, storeData2); // Scenario 3: StoreData1 in shared store file & StoreData2 in user store file. + when(storeData1.getName()).thenReturn(storeData1Name); + when(storeData2.getName()).thenReturn(storeData2Name); + when(storeData1.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); + when(storeData2.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); mSharedStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData1.getBytes()); mUserStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData2.getBytes()); mWifiConfigStore.read(); - verify(storeData1).deserializeData(notNull(), anyInt(), eq(true)); - verify(storeData1, never()).deserializeData(eq(null), anyInt(), eq(true)); - verify(storeData1).deserializeData(eq(null), anyInt(), eq(false)); - verify(storeData2).deserializeData(eq(null), anyInt(), eq(true)); - verify(storeData2).deserializeData(notNull(), anyInt(), eq(false)); - verify(storeData2, never()).deserializeData(eq(null), anyInt(), eq(false)); + verify(storeData1).deserializeData(notNull(), anyInt()); + verify(storeData1, never()).deserializeData(eq(null), anyInt()); + verify(storeData2).deserializeData(notNull(), anyInt()); + verify(storeData2, never()).deserializeData(eq(null), anyInt()); reset(storeData1, storeData2); // Scenario 4: StoreData1 & StoreData2 in shared store file. + when(storeData1.getName()).thenReturn(storeData1Name); + when(storeData2.getName()).thenReturn(storeData2Name); + when(storeData1.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); + when(storeData2.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); mSharedStore.storeRawDataToWrite( fileContentsXmlStringWithStoreData1AndStoreData2.getBytes()); mUserStore.storeRawDataToWrite(null); mWifiConfigStore.read(); - verify(storeData1).deserializeData(notNull(), anyInt(), eq(true)); - verify(storeData1, never()).deserializeData(eq(null), anyInt(), eq(true)); - verify(storeData1).deserializeData(eq(null), anyInt(), eq(false)); - verify(storeData2).deserializeData(notNull(), anyInt(), eq(true)); - verify(storeData2, never()).deserializeData(eq(null), anyInt(), eq(true)); - verify(storeData2).deserializeData(eq(null), anyInt(), eq(false)); + verify(storeData1).deserializeData(notNull(), anyInt()); + verify(storeData1, never()).deserializeData(eq(null), anyInt()); + verify(storeData2).deserializeData(notNull(), anyInt()); + verify(storeData2, never()).deserializeData(eq(null), anyInt()); reset(storeData1, storeData2); } /** + * Tests the write API behavior when all the store data's registered for a given store file + * has no new data to write. + * Expected behaviour: The write should not trigger a new file write for that specific store + * file. + */ + @Test + public void testWriteWithNoNewData() throws Exception { + StoreData sharedStoreData = mock(StoreData.class); + when(sharedStoreData.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); + when(sharedStoreData.hasNewDataToSerialize()).thenReturn(true); + when(sharedStoreData.getName()).thenReturn("sharedStoreData"); + + StoreData userStoreData = mock(StoreData.class); + when(userStoreData.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); + when(userStoreData.hasNewDataToSerialize()).thenReturn(true); + when(userStoreData.getName()).thenReturn("userStoreData"); + + StoreData userStoreNetworkSuggestionsData = + mock(StoreData.class); + when(userStoreNetworkSuggestionsData.getStoreFileId()) + .thenReturn(WifiConfigStore.STORE_FILE_USER_NETWORK_SUGGESTIONS); + when(userStoreNetworkSuggestionsData.hasNewDataToSerialize()).thenReturn(false); + when(userStoreNetworkSuggestionsData.getName()) + .thenReturn("userStoreNetworkSuggestionsData"); + + assertTrue(mWifiConfigStore.registerStoreData(sharedStoreData)); + assertTrue(mWifiConfigStore.registerStoreData(userStoreData)); + assertTrue(mWifiConfigStore.registerStoreData(userStoreNetworkSuggestionsData)); + + // Write both share and user config store. + mWifiConfigStore.setUserStores(mUserStores); + + // Now trigger a write. + mWifiConfigStore.write(true); + + verify(sharedStoreData).hasNewDataToSerialize(); + verify(userStoreData).hasNewDataToSerialize(); + verify(userStoreNetworkSuggestionsData).hasNewDataToSerialize(); + + // Verify that we serialized data from the first 2 data source, but not from the last one. + verify(sharedStoreData).serializeData(any()); + verify(userStoreData).serializeData(any()); + verify(userStoreNetworkSuggestionsData, never()).serializeData(any()); + } + + /** * Verify that a XmlPullParserException will be thrown when reading an user store file * containing unknown data. * @@ -591,7 +718,7 @@ public class WifiConfigStoreTest { + "</UnknownTag>\n" + "</WifiConfigStoreData>\n"; mUserStore.storeRawDataToWrite(storeFileData.getBytes(StandardCharsets.UTF_8)); - mWifiConfigStore.switchUserStoreAndRead(mUserStore); + mWifiConfigStore.switchUserStoresAndRead(mUserStores); } /** @@ -621,8 +748,8 @@ public class WifiConfigStoreTest { private byte[] mStoreBytes; private boolean mStoreWritten; - public MockStoreFile() { - super(new File("MockStoreFile")); + MockStoreFile(@WifiConfigStore.StoreFileId int fileId) { + super(new File("MockStoreFile"), fileId); } @Override @@ -643,7 +770,9 @@ public class WifiConfigStoreTest { @Override public void writeBufferedRawData() { - mStoreWritten = true; + if (!ArrayUtils.isEmpty(mStoreBytes)) { + mStoreWritten = true; + } } public byte[] getStoreBytes() { @@ -658,71 +787,63 @@ public class WifiConfigStoreTest { /** * Mock data container for providing test data for the store file. */ - private class MockStoreData implements WifiConfigStore.StoreData { + private class MockStoreData implements StoreData { private static final String XML_TAG_TEST_HEADER = "TestHeader"; private static final String XML_TAG_TEST_DATA = "TestData"; - private String mShareData; - private String mUserData; + private @WifiConfigStore.StoreFileId int mFileId; + private String mData; + private boolean mHasAnyNewData = true; - MockStoreData() {} + MockStoreData(@WifiConfigStore.StoreFileId int fileId) { + mFileId = fileId; + } @Override - public void serializeData(XmlSerializer out, boolean shared) + public void serializeData(XmlSerializer out) throws XmlPullParserException, IOException { - if (shared) { - XmlUtil.writeNextValue(out, XML_TAG_TEST_DATA, mShareData); - } else { - XmlUtil.writeNextValue(out, XML_TAG_TEST_DATA, mUserData); - } + XmlUtil.writeNextValue(out, XML_TAG_TEST_DATA, mData); } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared) + public void deserializeData(XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException { if (in == null) { return; } - if (shared) { - mShareData = (String) XmlUtil.readNextValueWithName(in, XML_TAG_TEST_DATA); - } else { - mUserData = (String) XmlUtil.readNextValueWithName(in, XML_TAG_TEST_DATA); - } + mData = (String) XmlUtil.readNextValueWithName(in, XML_TAG_TEST_DATA); } @Override - public void resetData(boolean shared) { - if (shared) { - mShareData = null; - } else { - mUserData = null; - } + public void resetData() { + mData = null; } @Override - public String getName() { - return XML_TAG_TEST_HEADER; + public boolean hasNewDataToSerialize() { + return mHasAnyNewData; } @Override - public boolean supportShareData() { - return true; + public String getName() { + return XML_TAG_TEST_HEADER; } - public String getShareData() { - return mShareData; + @Override + public @WifiConfigStore.StoreFileId int getStoreFileId() { + return mFileId; } - public void setShareData(String shareData) { - mShareData = shareData; + public String getData() { + return mData; } - public String getUserData() { - return mUserData; + public void setData(String data) { + mData = data; } - public void setUserData(String userData) { - mUserData = userData; + public void setHasAnyNewData(boolean hasAnyNewData) { + mHasAnyNewData = hasAnyNewData; } } } diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreDataTest.java new file mode 100644 index 000000000..6c2ab7bd5 --- /dev/null +++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreDataTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2018 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.hotspot2; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import android.support.test.filters.SmallTest; +import android.util.Xml; + +import com.android.internal.util.FastXmlSerializer; +import com.android.server.wifi.WifiConfigStore; + +import org.junit.Before; +import org.junit.Test; +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.hotspot2.PasspointConfigSharedStoreData}. + */ +@SmallTest +public class PasspointConfigSharedStoreDataTest { + @Mock PasspointConfigSharedStoreData.DataSource mDataSource; + PasspointConfigSharedStoreData mConfigStoreData; + + /** Sets up test. */ + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mConfigStoreData = new PasspointConfigSharedStoreData(mDataSource); + } + + /** + * Helper function for serializing store data to a XML block. + * + * @return byte[] + * @throws Exception + */ + private byte[] serializeData() throws Exception { + final XmlSerializer out = new FastXmlSerializer(); + final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + out.setOutput(outputStream, StandardCharsets.UTF_8.name()); + mConfigStoreData.serializeData(out); + out.flush(); + return outputStream.toByteArray(); + } + + /** + * Helper function for deserializing store data from a XML block. + * + * @param data The XML block data bytes + * @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()); + mConfigStoreData.deserializeData(in, in.getDepth()); + } + + /** + * Verify that the serialization and deserialization of share store data works as expected. + * The data used for serialization matches the result of the deserialization. + * + * @throws Exception + */ + @Test + public void serializeAndDeserializeShareStoreData() throws Exception { + // Setup expected data. + long providerIndex = 412; + + // Serialize data for share store. + when(mDataSource.getProviderIndex()).thenReturn(providerIndex); + byte[] data = serializeData(); + + // Deserialize data for share store and verify the content. + deserializeData(data); + verify(mDataSource).setProviderIndex(providerIndex); + } + + /** + * Verify that deserialization of an empty share store data doesn't cause any exception + * and the corresponding data source should not be updated. + * + * @throws Exception + */ + @Test + public void deserializeEmptyShareStoreData() throws Exception { + deserializeData(new byte[0]); + verify(mDataSource, never()).setProviderIndex(anyLong()); + } + + /** + * Verify that PasspointConfigUserStoreData is written to + * {@link WifiConfigStore#STORE_FILE_NAME_SHARED_GENERAL}. + * + * @throws Exception + */ + @Test + public void getUserStoreFileId() throws Exception { + assertEquals(WifiConfigStore.STORE_FILE_SHARED_GENERAL, + mConfigStoreData.getStoreFileId()); + } +} diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigUserStoreDataTest.java index 35f80a1f2..7ab29c972 100644 --- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigUserStoreDataTest.java @@ -29,6 +29,7 @@ import android.util.Xml; import com.android.internal.util.FastXmlSerializer; import com.android.server.wifi.SIMAccessor; +import com.android.server.wifi.WifiConfigStore; import com.android.server.wifi.WifiKeyStore; import org.junit.Before; @@ -51,10 +52,10 @@ import java.util.List; import java.util.Map; /** - * Unit tests for {@link com.android.server.wifi.hotspot2.PasspointConfigStoreData}. + * Unit tests for {@link com.android.server.wifi.hotspot2.PasspointConfigUserStoreData}. */ @SmallTest -public class PasspointConfigStoreDataTest { +public class PasspointConfigUserStoreDataTest { private static final String TEST_CA_CERTIFICATE_ALIAS = "CaCert"; private static final String TEST_CLIENT_CERTIFICATE_ALIAS = "ClientCert"; private static final String TEST_CLIENT_PRIVATE_KEY_ALIAS = "ClientPrivateKey"; @@ -65,14 +66,14 @@ public class PasspointConfigStoreDataTest { @Mock WifiKeyStore mKeyStore; @Mock SIMAccessor mSimAccessor; - @Mock PasspointConfigStoreData.DataSource mDataSource; - PasspointConfigStoreData mConfigStoreData; + @Mock PasspointConfigUserStoreData.DataSource mDataSource; + PasspointConfigUserStoreData mConfigStoreData; /** Sets up test. */ @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mConfigStoreData = new PasspointConfigStoreData(mKeyStore, mSimAccessor, mDataSource); + mConfigStoreData = new PasspointConfigUserStoreData(mKeyStore, mSimAccessor, mDataSource); } /** @@ -200,15 +201,14 @@ public class PasspointConfigStoreDataTest { /** * Helper function for serializing store data to a XML block. * - * @param share Flag indicating share or user data * @return byte[] * @throws Exception */ - private byte[] serializeData(boolean share) throws Exception { + private byte[] serializeData() throws Exception { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mConfigStoreData.serializeData(out, share); + mConfigStoreData.serializeData(out); out.flush(); return outputStream.toByteArray(); } @@ -217,14 +217,13 @@ public class PasspointConfigStoreDataTest { * Helper function for deserializing store data from a XML block. * * @param data The XML block data bytes - * @param share Flag indicating share or user data * @throws Exception */ - private void deserializeData(byte[] data, boolean share) 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()); - mConfigStoreData.deserializeData(in, in.getDepth(), share); + mConfigStoreData.deserializeData(in, in.getDepth()); } /** @@ -244,36 +243,16 @@ public class PasspointConfigStoreDataTest { // Serialize data for user store. when(mDataSource.getProviders()).thenReturn(providerList); - byte[] data = serializeData(false); + byte[] data = serializeData(); // Deserialize data for user store and verify the content. ArgumentCaptor<ArrayList> providersCaptor = ArgumentCaptor.forClass(ArrayList.class); - deserializeData(data, false); + deserializeData(data); verify(mDataSource).setProviders(providersCaptor.capture()); assertEquals(providerList, providersCaptor.getValue()); } /** - * Verify that the serialization and deserialization of share store data works as expected. - * The data used for serialization matches the result of the deserialization. - * - * @throws Exception - */ - @Test - public void serializeAndDeserializeShareStoreData() throws Exception { - // Setup expected data. - long providerIndex = 412; - - // Serialize data for share store. - when(mDataSource.getProviderIndex()).thenReturn(providerIndex); - byte[] data = serializeData(true); - - // Deserialize data for share store and verify the content. - deserializeData(data, true); - verify(mDataSource).setProviderIndex(providerIndex); - } - - /** * Verify that deserialization of an empty user store data doesn't cause any exception and * the corresponding data source should not be updated. * @@ -281,19 +260,19 @@ public class PasspointConfigStoreDataTest { */ @Test public void deserializeEmptyUserStoreData() throws Exception { - deserializeData(new byte[0], false); + deserializeData(new byte[0]); verify(mDataSource, never()).setProviders(any(ArrayList.class)); } /** - * Verify that deserialization of an empty share store data doesn't cause any exception - * and the corresponding data source should not be updated. + * Verify that PasspointConfigUserStoreData is written to + * {@link WifiConfigStore#STORE_FILE_NAME_USER_GENERAL}. * * @throws Exception */ @Test - public void deserializeEmptyShareStoreData() throws Exception { - deserializeData(new byte[0], true); - verify(mDataSource, never()).setProviderIndex(anyLong()); + public void getUserStoreFileId() throws Exception { + assertEquals(WifiConfigStore.STORE_FILE_USER_GENERAL, + mConfigStoreData.getStoreFileId()); } } diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java index 8d60bbbe9..415332964 100644 --- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java @@ -136,7 +136,8 @@ public class PasspointManagerTest { @Mock CertificateVerifier mCertVerifier; @Mock WifiConfigManager mWifiConfigManager; @Mock WifiConfigStore mWifiConfigStore; - @Mock PasspointConfigStoreData.DataSource mDataSource; + @Mock PasspointConfigSharedStoreData.DataSource mSharedDataSource; + @Mock PasspointConfigUserStoreData.DataSource mUserDataSource; @Mock WifiMetrics mWifiMetrics; @Mock OsuNetworkConnection mOsuNetworkConnection; @Mock OsuServerConnection mOsuServerConnection; @@ -170,12 +171,16 @@ public class PasspointManagerTest { ArgumentCaptor.forClass(PasspointEventHandler.Callbacks.class); verify(mObjectFactory).makePasspointEventHandler(any(WifiNative.class), callbacks.capture()); - ArgumentCaptor<PasspointConfigStoreData.DataSource> dataSource = - ArgumentCaptor.forClass(PasspointConfigStoreData.DataSource.class); - verify(mObjectFactory).makePasspointConfigStoreData( - any(WifiKeyStore.class), any(SIMAccessor.class), dataSource.capture()); + ArgumentCaptor<PasspointConfigSharedStoreData.DataSource> sharedDataSource = + ArgumentCaptor.forClass(PasspointConfigSharedStoreData.DataSource.class); + verify(mObjectFactory).makePasspointConfigSharedStoreData(sharedDataSource.capture()); + ArgumentCaptor<PasspointConfigUserStoreData.DataSource> userDataSource = + ArgumentCaptor.forClass(PasspointConfigUserStoreData.DataSource.class); + verify(mObjectFactory).makePasspointConfigUserStoreData( + any(WifiKeyStore.class), any(SIMAccessor.class), userDataSource.capture()); mCallbacks = callbacks.getValue(); - mDataSource = dataSource.getValue(); + mSharedDataSource = sharedDataSource.getValue(); + mUserDataSource = userDataSource.getValue(); mLooper = new TestLooper(); } @@ -491,11 +496,11 @@ public class PasspointManagerTest { reset(mWifiConfigManager); // Verify content in the data source. - List<PasspointProvider> providers = mDataSource.getProviders(); + List<PasspointProvider> providers = mUserDataSource.getProviders(); assertEquals(1, providers.size()); assertEquals(config, providers.get(0).getConfig()); // Provider index start with 0, should be 1 after adding a provider. - assertEquals(1, mDataSource.getProviderIndex()); + assertEquals(1, mSharedDataSource.getProviderIndex()); // Remove the provider. assertTrue(mManager.removeProvider(TEST_FQDN)); @@ -506,9 +511,9 @@ public class PasspointManagerTest { assertTrue(mManager.getProviderConfigs().isEmpty()); // Verify content in the data source. - assertTrue(mDataSource.getProviders().isEmpty()); + assertTrue(mUserDataSource.getProviders().isEmpty()); // Removing a provider should not change the provider index. - assertEquals(1, mDataSource.getProviderIndex()); + assertEquals(1, mSharedDataSource.getProviderIndex()); } /** @@ -531,11 +536,11 @@ public class PasspointManagerTest { reset(mWifiConfigManager); // Verify content in the data source. - List<PasspointProvider> providers = mDataSource.getProviders(); + List<PasspointProvider> providers = mUserDataSource.getProviders(); assertEquals(1, providers.size()); assertEquals(config, providers.get(0).getConfig()); // Provider index start with 0, should be 1 after adding a provider. - assertEquals(1, mDataSource.getProviderIndex()); + assertEquals(1, mSharedDataSource.getProviderIndex()); // Remove the provider. assertTrue(mManager.removeProvider(TEST_FQDN)); @@ -546,9 +551,9 @@ public class PasspointManagerTest { assertTrue(mManager.getProviderConfigs().isEmpty()); // Verify content in the data source. - assertTrue(mDataSource.getProviders().isEmpty()); + assertTrue(mUserDataSource.getProviders().isEmpty()); // Removing a provider should not change the provider index. - assertEquals(1, mDataSource.getProviderIndex()); + assertEquals(1, mSharedDataSource.getProviderIndex()); } /** @@ -574,10 +579,10 @@ public class PasspointManagerTest { reset(mWifiConfigManager); // Verify data source content. - List<PasspointProvider> origProviders = mDataSource.getProviders(); + List<PasspointProvider> origProviders = mUserDataSource.getProviders(); assertEquals(1, origProviders.size()); assertEquals(origConfig, origProviders.get(0).getConfig()); - assertEquals(1, mDataSource.getProviderIndex()); + assertEquals(1, mSharedDataSource.getProviderIndex()); // Add another provider with the same base domain as the existing provider. // This should replace the existing provider with the new configuration. @@ -592,10 +597,10 @@ public class PasspointManagerTest { verify(mWifiMetrics).incrementNumPasspointProviderInstallSuccess(); // Verify data source content. - List<PasspointProvider> newProviders = mDataSource.getProviders(); + List<PasspointProvider> newProviders = mUserDataSource.getProviders(); assertEquals(1, newProviders.size()); assertEquals(newConfig, newProviders.get(0).getConfig()); - assertEquals(2, mDataSource.getProviderIndex()); + assertEquals(2, mSharedDataSource.getProviderIndex()); } /** @@ -1084,7 +1089,7 @@ public class PasspointManagerTest { PasspointProvider provider = createMockProvider(config); List<PasspointProvider> providers = new ArrayList<>(); providers.add(provider); - mDataSource.setProviders(providers); + mUserDataSource.setProviders(providers); // Verify the providers maintained by PasspointManager. assertEquals(1, mManager.getProviderConfigs().size()); @@ -1100,8 +1105,8 @@ public class PasspointManagerTest { @Test public void verifyProviderIndexAfterDataSourceUpdate() throws Exception { long providerIndex = 9; - mDataSource.setProviderIndex(providerIndex); - assertEquals(providerIndex, mDataSource.getProviderIndex()); + mSharedDataSource.setProviderIndex(providerIndex); + assertEquals(providerIndex, mSharedDataSource.getProviderIndex()); // Add a provider. PasspointConfiguration config = createTestConfigWithUserCredential(TEST_FQDN); |