Merge "Wipe the data in IpMemoryStore database upon network factory reset."
This commit is contained in:
@@ -410,6 +410,7 @@ public class IpMemoryStoreDatabase {
|
|||||||
private static final String[] DATA_COLUMN = new String[] {
|
private static final String[] DATA_COLUMN = new String[] {
|
||||||
PrivateDataContract.COLNAME_DATA
|
PrivateDataContract.COLNAME_DATA
|
||||||
};
|
};
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
static byte[] retrieveBlob(@NonNull final SQLiteDatabase db, @NonNull final String key,
|
static byte[] retrieveBlob(@NonNull final SQLiteDatabase db, @NonNull final String key,
|
||||||
@NonNull final String clientId, @NonNull final String name) {
|
@NonNull final String clientId, @NonNull final String name) {
|
||||||
@@ -431,6 +432,57 @@ public class IpMemoryStoreDatabase {
|
|||||||
return result;
|
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
|
* 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.
|
* have a way to query a binary blob. This, almost certainly, is an overlook.
|
||||||
|
|||||||
@@ -410,8 +410,12 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wipe the data in IpMemoryStore database upon network factory reset.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void factoryReset() {
|
public void factoryReset() {
|
||||||
|
mExecutor.execute(() -> IpMemoryStoreDatabase.wipeDataUponNetworkReset(mDb));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get db size threshold. */
|
/** Get db size threshold. */
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ import java.net.Inet6Address;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@@ -77,7 +78,11 @@ public class IpMemoryStoreServiceTest {
|
|||||||
private static final int DEFAULT_TIMEOUT_MS = 5000;
|
private static final int DEFAULT_TIMEOUT_MS = 5000;
|
||||||
private static final int LONG_TIMEOUT_MS = 30000;
|
private static final int LONG_TIMEOUT_MS = 30000;
|
||||||
private static final int FAKE_KEY_COUNT = 20;
|
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 String[] FAKE_KEYS;
|
||||||
|
private static final byte[] TEST_BLOB_DATA = new byte[] { -3, 6, 8, -9, 12,
|
||||||
|
-128, 0, 89, 112, 91, -34 };
|
||||||
static {
|
static {
|
||||||
FAKE_KEYS = new String[FAKE_KEY_COUNT];
|
FAKE_KEYS = new String[FAKE_KEY_COUNT];
|
||||||
for (int i = 0; i < FAKE_KEYS.length; ++i) {
|
for (int i = 0; i < FAKE_KEYS.length; ++i) {
|
||||||
@@ -124,6 +129,29 @@ public class IpMemoryStoreServiceTest {
|
|||||||
mDbFile.delete();
|
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 */
|
/** Helper method to make a vanilla IOnStatusListener */
|
||||||
private IOnStatusListener onStatus(Consumer<Status> functor) {
|
private IOnStatusListener onStatus(Consumer<Status> functor) {
|
||||||
return new IOnStatusListener() {
|
return new IOnStatusListener() {
|
||||||
@@ -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) {
|
private void storeAttributes(final String l2Key, final NetworkAttributes na) {
|
||||||
storeAttributes("Did not complete storing attributes", l2Key, na);
|
storeAttributes("Did not complete storing attributes", l2Key, na);
|
||||||
}
|
}
|
||||||
@@ -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. */
|
/** Insert large data that db size will be over threshold for maintenance test usage. */
|
||||||
private void insertFakeDataAndOverThreshold() {
|
private void insertFakeDataAndOverThreshold() {
|
||||||
try {
|
try {
|
||||||
final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
|
final NetworkAttributes.Builder na = buildTestNetworkAttributes(
|
||||||
na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
|
(Inet4Address) Inet4Address.getByName("1.2.3.4"), LEASE_EXPIRY_NULL,
|
||||||
na.setGroupHint("hint1");
|
"hint1", Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")),
|
||||||
na.setMtu(219);
|
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 long time = System.currentTimeMillis() - 1;
|
final long time = System.currentTimeMillis() - 1;
|
||||||
for (int i = 0; i < 1000; i++) {
|
for (int i = 0; i < 1000; i++) {
|
||||||
int errorCode = IpMemoryStoreDatabase.storeNetworkAttributes(
|
int errorCode = IpMemoryStoreDatabase.storeNetworkAttributes(
|
||||||
@@ -298,7 +339,8 @@ public class IpMemoryStoreServiceTest {
|
|||||||
assertEquals(errorCode, Status.SUCCESS);
|
assertEquals(errorCode, Status.SUCCESS);
|
||||||
|
|
||||||
errorCode = IpMemoryStoreDatabase.storeBlob(
|
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);
|
assertEquals(errorCode, Status.SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,12 +362,10 @@ public class IpMemoryStoreServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNetworkAttributes() throws UnknownHostException {
|
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 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();
|
NetworkAttributes attributes = na.build();
|
||||||
storeAttributes(l2Key, attributes);
|
storeAttributes(l2Key, attributes);
|
||||||
|
|
||||||
@@ -420,16 +460,9 @@ public class IpMemoryStoreServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPrivateData() {
|
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];
|
final String l2Key = FAKE_KEYS[0];
|
||||||
doLatched("Did not complete storing private data", latch ->
|
final Blob b = new Blob();
|
||||||
mService.storeBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, b,
|
storeBlobOrFail(l2Key, b, TEST_BLOB_DATA);
|
||||||
onStatus(status -> {
|
|
||||||
assertTrue("Store status not successful : " + status.resultCode,
|
|
||||||
status.isSuccess());
|
|
||||||
latch.countDown();
|
|
||||||
})));
|
|
||||||
|
|
||||||
doLatched("Did not complete retrieving private data", latch ->
|
doLatched("Did not complete retrieving private data", latch ->
|
||||||
mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, onBlobRetrieved(
|
mService.retrieveBlob(l2Key, TEST_CLIENT_ID, TEST_DATA_NAME, onBlobRetrieved(
|
||||||
@@ -564,11 +597,10 @@ public class IpMemoryStoreServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsSameNetwork() throws UnknownHostException {
|
public void testIsSameNetwork() throws UnknownHostException {
|
||||||
final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
|
final NetworkAttributes.Builder na = buildTestNetworkAttributes(
|
||||||
na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
|
(Inet4Address) Inet4Address.getByName("1.2.3.4"), LEASE_EXPIRY_NULL,
|
||||||
na.setGroupHint("hint1");
|
"hint1", Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")),
|
||||||
na.setMtu(219);
|
219);
|
||||||
na.setDnsAddresses(Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")));
|
|
||||||
|
|
||||||
storeAttributes(FAKE_KEYS[0], na.build());
|
storeAttributes(FAKE_KEYS[0], na.build());
|
||||||
// 0 and 1 have identical attributes
|
// 0 and 1 have identical attributes
|
||||||
@@ -601,7 +633,6 @@ public class IpMemoryStoreServiceTest {
|
|||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFullMaintenance() {
|
public void testFullMaintenance() {
|
||||||
insertFakeDataAndOverThreshold();
|
insertFakeDataAndOverThreshold();
|
||||||
@@ -660,4 +691,45 @@ public class IpMemoryStoreServiceTest {
|
|||||||
// still be over the threshold.
|
// still be over the threshold.
|
||||||
assertTrue(mService.isDbSizeOverThreshold());
|
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();
|
||||||
|
})));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ import android.net.INetworkStatsService;
|
|||||||
import android.net.ISocketKeepaliveCallback;
|
import android.net.ISocketKeepaliveCallback;
|
||||||
import android.net.ITetheringEventCallback;
|
import android.net.ITetheringEventCallback;
|
||||||
import android.net.InetAddresses;
|
import android.net.InetAddresses;
|
||||||
|
import android.net.IpMemoryStore;
|
||||||
import android.net.IpPrefix;
|
import android.net.IpPrefix;
|
||||||
import android.net.LinkProperties;
|
import android.net.LinkProperties;
|
||||||
import android.net.LinkProperties.CompareResult;
|
import android.net.LinkProperties.CompareResult;
|
||||||
@@ -6893,6 +6894,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
|
|
||||||
final int userId = UserHandle.getCallingUserId();
|
final int userId = UserHandle.getCallingUserId();
|
||||||
|
|
||||||
|
final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext);
|
||||||
|
ipMemoryStore.factoryReset();
|
||||||
|
|
||||||
// Turn airplane mode off
|
// Turn airplane mode off
|
||||||
setAirplaneMode(false);
|
setAirplaneMode(false);
|
||||||
|
|
||||||
|
|||||||
@@ -212,4 +212,16 @@ public abstract class IpMemoryStoreClient {
|
|||||||
null, null, null));
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -321,4 +321,11 @@ public class IpMemoryStoreTest {
|
|||||||
eq(TEST_OTHER_DATA_NAME), any());
|
eq(TEST_OTHER_DATA_NAME), any());
|
||||||
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
|
assertEquals(TEST_NETWORK_ATTRIBUTES, new NetworkAttributes(mNapCaptor.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFactoryReset() throws RemoteException {
|
||||||
|
startIpMemoryStore(true /* supplyService */);
|
||||||
|
mStore.factoryReset();
|
||||||
|
verify(mMockService, times(1)).factoryReset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user