Merge "Wipe the data in IpMemoryStore database upon network factory reset."
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
index 764e2d0..a538a5b 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
@@ -410,6 +410,7 @@
private static final String[] DATA_COLUMN = new String[] {
PrivateDataContract.COLNAME_DATA
};
+
@Nullable
static byte[] retrieveBlob(@NonNull final SQLiteDatabase db, @NonNull final String key,
@NonNull final String clientId, @NonNull final String name) {
@@ -432,6 +433,57 @@
}
/**
+ * Wipe all data in tables when network factory reset occurs.
+ */
+ static void wipeDataUponNetworkReset(@NonNull final SQLiteDatabase db) {
+ for (int remainingRetries = 3; remainingRetries > 0; --remainingRetries) {
+ db.beginTransaction();
+ try {
+ db.delete(NetworkAttributesContract.TABLENAME, null, null);
+ db.delete(PrivateDataContract.TABLENAME, null, null);
+ final Cursor cursorNetworkAttributes = db.query(
+ // table name
+ NetworkAttributesContract.TABLENAME,
+ // column name
+ new String[] { NetworkAttributesContract.COLNAME_L2KEY },
+ null, // selection
+ null, // selectionArgs
+ null, // groupBy
+ null, // having
+ null, // orderBy
+ "1"); // limit
+ if (0 != cursorNetworkAttributes.getCount()) {
+ cursorNetworkAttributes.close();
+ continue;
+ }
+ cursorNetworkAttributes.close();
+ final Cursor cursorPrivateData = db.query(
+ // table name
+ PrivateDataContract.TABLENAME,
+ // column name
+ new String[] { PrivateDataContract.COLNAME_L2KEY },
+ null, // selection
+ null, // selectionArgs
+ null, // groupBy
+ null, // having
+ null, // orderBy
+ "1"); // limit
+ if (0 != cursorPrivateData.getCount()) {
+ cursorPrivateData.close();
+ continue;
+ }
+ cursorPrivateData.close();
+ db.setTransactionSuccessful();
+ return;
+ } catch (SQLiteException e) {
+ Log.e(TAG, "Could not wipe the data in database", e);
+ } finally {
+ db.endTransaction();
+ }
+ }
+ }
+
+ /**
* The following is a horrible hack that is necessary because the Android SQLite API does not
* have a way to query a binary blob. This, almost certainly, is an overlook.
*
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
index 8312dfe..ad2bae89 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
@@ -410,8 +410,12 @@
});
}
+ /**
+ * Wipe the data in IpMemoryStore database upon network factory reset.
+ */
@Override
public void factoryReset() {
+ mExecutor.execute(() -> IpMemoryStoreDatabase.wipeDataUponNetworkReset(mDb));
}
/** Get db size threshold. */
diff --git a/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
index 87346e5..c1d6a05 100644
--- a/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/packages/NetworkStack/tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -62,6 +62,7 @@
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
@@ -77,7 +78,11 @@
private static final int DEFAULT_TIMEOUT_MS = 5000;
private static final int LONG_TIMEOUT_MS = 30000;
private static final int FAKE_KEY_COUNT = 20;
+ private static final long LEASE_EXPIRY_NULL = -1L;
+ private static final int MTU_NULL = -1;
private static final String[] FAKE_KEYS;
+ private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12,
+ -128, 0, 89, 112, 91, -34 };
static {
FAKE_KEYS = new String[FAKE_KEY_COUNT];
for (int i = 0; i < FAKE_KEYS.length; ++i) {
@@ -124,6 +129,29 @@
mDbFile.delete();
}
+ /** Helper method to build test network attributes */
+ private static NetworkAttributes.Builder buildTestNetworkAttributes(
+ final Inet4Address ipAddress, final long expiry, final String hint,
+ final List<InetAddress> dnsServers, final int mtu) {
+ final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
+ if (null != ipAddress) {
+ na.setAssignedV4Address(ipAddress);
+ }
+ if (LEASE_EXPIRY_NULL != expiry) {
+ na.setAssignedV4AddressExpiry(expiry);
+ }
+ if (null != hint) {
+ na.setGroupHint(hint);
+ }
+ if (null != dnsServers) {
+ na.setDnsAddresses(dnsServers);
+ }
+ if (MTU_NULL != mtu) {
+ na.setMtu(mtu);
+ }
+ return na;
+ }
+
/** Helper method to make a vanilla IOnStatusListener */
private IOnStatusListener onStatus(Consumer<Status> functor) {
return new IOnStatusListener() {
@@ -265,7 +293,7 @@
}
}
- // Helper methods to factorize more boilerplate
+ // Helper method to store network attributes to database
private void storeAttributes(final String l2Key, final NetworkAttributes na) {
storeAttributes("Did not complete storing attributes", l2Key, na);
}
@@ -278,15 +306,28 @@
})));
}
+ // Helper method to store blob data to database
+ private void storeBlobOrFail(final String l2Key, final Blob b, final byte[] data) {
+ storeBlobOrFail("Did not complete storing private data", l2Key, b, data);
+ }
+ private void storeBlobOrFail(final String timeoutMessage, final String l2Key, final Blob b,
+ final byte[] data) {
+ b.data = data;
+ doLatched(timeoutMessage, latch -> mService.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME,
+ b, onStatus(status -> {
+ assertTrue("Store status not successful : " + status.resultCode,
+ status.isSuccess());
+ latch.countDown();
+ })));
+ }
+
/** Insert large data that db size will be over threshold for maintenance test usage. */
private void insertFakeDataAndOverThreshold() {
try {
- final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
- na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
- na.setGroupHint("hint1");
- na.setMtu(219);
- na.setDnsAddresses(Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")));
- final byte[] data = new byte[]{-3, 6, 8, -9, 12, -128, 0, 89, 112, 91, -34};
+ final NetworkAttributes.Builder na = buildTestNetworkAttributes(
+ (Inet4Address) Inet4Address.getByName("1.2.3.4"), LEASE_EXPIRY_NULL,
+ "hint1", Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")),
+ 219);
final long time = System.currentTimeMillis() - 1;
for (int i = 0; i < 1000; i++) {
int errorCode = IpMemoryStoreDatabase.storeNetworkAttributes(
@@ -298,7 +339,8 @@
assertEquals(errorCode, Status.SUCCESS);
errorCode = IpMemoryStoreDatabase.storeBlob(
- mService.mDb, "fakeKey" + i, TEST_CLIENT_ID, TEST_DATA_NAME, data);
+ mService.mDb, "fakeKey" + i, TEST_CLIENT_ID, TEST_DATA_NAME,
+ TEST_BLOB_DATA);
assertEquals(errorCode, Status.SUCCESS);
}
@@ -320,12 +362,10 @@
@Test
public void testNetworkAttributes() throws UnknownHostException {
- final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
- na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
- na.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
- na.setGroupHint("hint1");
- na.setMtu(219);
final String l2Key = FAKE_KEYS[0];
+ final NetworkAttributes.Builder na = buildTestNetworkAttributes(
+ (Inet4Address) Inet4Address.getByName("1.2.3.4"),
+ System.currentTimeMillis() + 7_200_000, "hint1", null, 219);
NetworkAttributes attributes = na.build();
storeAttributes(l2Key, attributes);
@@ -420,16 +460,9 @@
@Test
public void testPrivateData() {
- final Blob b = new Blob();
- b.data = new byte[] { -3, 6, 8, -9, 12, -128, 0, 89, 112, 91, -34 };
final String l2Key = FAKE_KEYS[0];
- doLatched("Did not complete storing private data", latch ->
- mService.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
- onStatus(status -> {
- assertTrue("Store status not successful : " + status.resultCode,
- status.isSuccess());
- latch.countDown();
- })));
+ final Blob b = new Blob();
+ storeBlobOrFail(l2Key, b, TEST_BLOB_DATA);
doLatched("Did not complete retrieving private data", latch ->
mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, onBlobRetrieved(
@@ -564,11 +597,10 @@
@Test
public void testIsSameNetwork() throws UnknownHostException {
- final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
- na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
- na.setGroupHint("hint1");
- na.setMtu(219);
- na.setDnsAddresses(Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")));
+ final NetworkAttributes.Builder na = buildTestNetworkAttributes(
+ (Inet4Address) Inet4Address.getByName("1.2.3.4"), LEASE_EXPIRY_NULL,
+ "hint1", Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")),
+ 219);
storeAttributes(FAKE_KEYS[0], na.build());
// 0 and 1 have identical attributes
@@ -601,7 +633,6 @@
})));
}
-
@Test
public void testFullMaintenance() {
insertFakeDataAndOverThreshold();
@@ -660,4 +691,45 @@
// still be over the threshold.
assertTrue(mService.isDbSizeOverThreshold());
}
+
+ @Test
+ public void testFactoryReset() throws UnknownHostException {
+ final String l2Key = FAKE_KEYS[0];
+
+ // store network attributes
+ final NetworkAttributes.Builder na = buildTestNetworkAttributes(
+ (Inet4Address) Inet4Address.getByName("1.2.3.4"),
+ System.currentTimeMillis() + 7_200_000, "hint1", null, 219);
+ storeAttributes(l2Key, na.build());
+
+ // store private data blob
+ final Blob b = new Blob();
+ storeBlobOrFail(l2Key, b, TEST_BLOB_DATA);
+
+ // wipe all data in Database
+ mService.factoryReset();
+
+ // retrieved network attributes should be null
+ doLatched("Did not complete retrieving attributes", latch ->
+ mService.retrieveNetworkAttributes(l2Key, onNetworkAttributesRetrieved(
+ (status, key, attr) -> {
+ assertTrue("Retrieve network attributes not successful : "
+ + status.resultCode, status.isSuccess());
+ assertEquals(l2Key, key);
+ assertNull(attr);
+ latch.countDown();
+ })));
+
+ // retrieved private data blob should be null
+ doLatched("Did not complete retrieving private data", latch ->
+ mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, onBlobRetrieved(
+ (status, key, name, data) -> {
+ assertTrue("Retrieve blob status not successful : " + status.resultCode,
+ status.isSuccess());
+ assertEquals(l2Key, key);
+ assertEquals(name, TEST_DATA_NAME);
+ assertNull(data);
+ latch.countDown();
+ })));
+ }
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7fa9c6e..4b2d481 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -77,6 +77,7 @@
import android.net.ISocketKeepaliveCallback;
import android.net.ITetheringEventCallback;
import android.net.InetAddresses;
+import android.net.IpMemoryStore;
import android.net.IpPrefix;
import android.net.LinkProperties;
import android.net.LinkProperties.CompareResult;
@@ -6893,6 +6894,9 @@
final int userId = UserHandle.getCallingUserId();
+ final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext);
+ ipMemoryStore.factoryReset();
+
// Turn airplane mode off
setAirplaneMode(false);
diff --git a/services/net/java/android/net/IpMemoryStoreClient.java b/services/net/java/android/net/IpMemoryStoreClient.java
index 3d56202..014b528 100644
--- a/services/net/java/android/net/IpMemoryStoreClient.java
+++ b/services/net/java/android/net/IpMemoryStoreClient.java
@@ -212,4 +212,16 @@
null, null, null));
}
}
+
+ /**
+ * Wipe the data in the database upon network factory reset.
+ */
+ public void factoryReset() {
+ try {
+ runWhenServiceReady(service -> ignoringRemoteException(
+ () -> service.factoryReset()));
+ } catch (ExecutionException m) {
+ Log.e(TAG, "Error executing factory reset", m);
+ }
+ }
}
diff --git a/tests/net/java/android/net/IpMemoryStoreTest.java b/tests/net/java/android/net/IpMemoryStoreTest.java
index 6e69b34..b81ca36 100644
--- a/tests/net/java/android/net/IpMemoryStoreTest.java
+++ b/tests/net/java/android/net/IpMemoryStoreTest.java
@@ -321,4 +321,11 @@
eq(TEST_OTHER_DATA_NAME), any());
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
}
+
+ @Test
+ public void testFactoryReset() throws RemoteException {
+ startIpMemoryStore(true /* supplyService */);
+ mStore.factoryReset();
+ verify(mMockService, times(1)).factoryReset();
+ }
}