summaryrefslogtreecommitdiffstats
path: root/service/java/com/android/server/wifi/WifiConfigStore.java
diff options
context:
space:
mode:
authorRoshan Pius <rpius@google.com>2018-10-19 08:20:30 -0700
committerRoshan Pius <rpius@google.com>2018-11-01 07:00:38 -0700
commit0b86079855b2bc120a6c7790c53c927d95485b62 (patch)
tree40eaea3a2451c01ebe0cc1e7a3b2346c84d27c9e /service/java/com/android/server/wifi/WifiConfigStore.java
parente77a84b320e776d0e783d87b492d5f80ac6f9648 (diff)
downloadandroid_frameworks_opt_net_wifi-0b86079855b2bc120a6c7790c53c927d95485b62.tar.gz
android_frameworks_opt_net_wifi-0b86079855b2bc120a6c7790c53c927d95485b62.tar.bz2
android_frameworks_opt_net_wifi-0b86079855b2bc120a6c7790c53c927d95485b62.zip
WifiConfigStore Refactor (1/2)
New WifiConfigStore Architecture: a) WifiConfigStore can now manage multiple user store files (StoreFile). It now manages a total of 3 files: 1 shared & 1 user (both existing) & 1 new one specifically for network suggestions. b) Clients(StoreData) should now register themselves to write/read from any one of the store files. c) |StoreFile|'s are only written if any one of the |StoreData|'s registered for that file indicates that it has new data to write. PS: Please refer to the bug for a summary of problems with the previous architecture. Bug: 117599800 Test: Unit tests Test: Verified upgrading device with some store data to the new architecture and ensured that we don't lose any data. Test: Will send for integration tests. Change-Id: Iebe54b6bef4d203540e7da490eae9851131d8827
Diffstat (limited to 'service/java/com/android/server/wifi/WifiConfigStore.java')
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStore.java399
1 files changed, 275 insertions, 124 deletions
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();
}
}