Loading src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java +52 −0 Original line number Diff line number Diff line Loading @@ -410,6 +410,7 @@ public class IpMemoryStoreDatabase { 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) { Loading @@ -431,6 +432,57 @@ public class IpMemoryStoreDatabase { return result; } /** * 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. Loading src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java +4 −0 Original line number Diff line number Diff line Loading @@ -410,8 +410,12 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub { }); } /** * Wipe the data in IpMemoryStore database upon network factory reset. */ @Override public void factoryReset() { mExecutor.execute(() -> IpMemoryStoreDatabase.wipeDataUponNetworkReset(mDb)); } /** Get db size threshold. */ Loading tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java +100 −28 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ import java.net.Inet6Address; 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; Loading @@ -77,7 +78,11 @@ public class IpMemoryStoreServiceTest { 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) { Loading Loading @@ -124,6 +129,29 @@ public class IpMemoryStoreServiceTest { 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() { Loading Loading @@ -265,7 +293,7 @@ public class IpMemoryStoreServiceTest { } } // 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); } Loading @@ -278,15 +306,28 @@ public class IpMemoryStoreServiceTest { }))); } // 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( Loading @@ -298,7 +339,8 @@ public class IpMemoryStoreServiceTest { 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); } Loading @@ -320,12 +362,10 @@ public class IpMemoryStoreServiceTest { @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); Loading Loading @@ -420,16 +460,9 @@ public class IpMemoryStoreServiceTest { @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( Loading Loading @@ -564,11 +597,10 @@ public class IpMemoryStoreServiceTest { @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 Loading Loading @@ -601,7 +633,6 @@ public class IpMemoryStoreServiceTest { }))); } @Test public void testFullMaintenance() { insertFakeDataAndOverThreshold(); Loading Loading @@ -660,4 +691,45 @@ public class IpMemoryStoreServiceTest { // 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(); }))); } } Loading
src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java +52 −0 Original line number Diff line number Diff line Loading @@ -410,6 +410,7 @@ public class IpMemoryStoreDatabase { 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) { Loading @@ -431,6 +432,57 @@ public class IpMemoryStoreDatabase { return result; } /** * 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. Loading
src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java +4 −0 Original line number Diff line number Diff line Loading @@ -410,8 +410,12 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub { }); } /** * Wipe the data in IpMemoryStore database upon network factory reset. */ @Override public void factoryReset() { mExecutor.execute(() -> IpMemoryStoreDatabase.wipeDataUponNetworkReset(mDb)); } /** Get db size threshold. */ Loading
tests/unit/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java +100 −28 Original line number Diff line number Diff line Loading @@ -62,6 +62,7 @@ import java.net.Inet6Address; 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; Loading @@ -77,7 +78,11 @@ public class IpMemoryStoreServiceTest { 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) { Loading Loading @@ -124,6 +129,29 @@ public class IpMemoryStoreServiceTest { 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() { Loading Loading @@ -265,7 +293,7 @@ public class IpMemoryStoreServiceTest { } } // 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); } Loading @@ -278,15 +306,28 @@ public class IpMemoryStoreServiceTest { }))); } // 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( Loading @@ -298,7 +339,8 @@ public class IpMemoryStoreServiceTest { 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); } Loading @@ -320,12 +362,10 @@ public class IpMemoryStoreServiceTest { @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); Loading Loading @@ -420,16 +460,9 @@ public class IpMemoryStoreServiceTest { @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( Loading Loading @@ -564,11 +597,10 @@ public class IpMemoryStoreServiceTest { @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 Loading Loading @@ -601,7 +633,6 @@ public class IpMemoryStoreServiceTest { }))); } @Test public void testFullMaintenance() { insertFakeDataAndOverThreshold(); Loading Loading @@ -660,4 +691,45 @@ public class IpMemoryStoreServiceTest { // 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(); }))); } }