Snap for 12730349 from e8080a3bb19cf47287bddd7b745104b48e4d3ab1 to 25Q1-release
Change-Id: Ie6a49d6c98ce7e7f38b708471284eab2bdfdd997
diff --git a/framework/Android.bp b/framework/Android.bp
index a5a7d61..a93a532 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -158,6 +158,7 @@
java_defaults {
name: "CronetJavaDefaults",
srcs: [":httpclient_api_sources"],
+ static_libs: ["com.android.net.http.flags-aconfig-java"],
libs: [
"androidx.annotation_annotation",
],
@@ -218,6 +219,7 @@
},
aconfig_declarations: [
"com.android.net.flags-aconfig",
+ "com.android.net.http.flags-aconfig",
"com.android.networksecurity.flags-aconfig",
],
}
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index cd7307f..0129e5c 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -247,3 +247,11 @@
}
+package android.net.http {
+
+ public abstract class HttpEngine {
+ method @FlaggedApi("android.net.http.preload_httpengine_in_zygote") public static void preload();
+ }
+
+}
+
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
index bd8f7b9..56a5ee5 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
@@ -75,34 +75,31 @@
}
}
- void startPublicKeyDownload(String publicKeyUrl) {
- long downloadId = download(publicKeyUrl);
- if (downloadId == -1) {
- Log.e(TAG, "Metadata download request failed for " + publicKeyUrl);
- return;
+ long startPublicKeyDownload() {
+ long downloadId = download(mDataStore.getProperty(Config.PUBLIC_KEY_URL));
+ if (downloadId != -1) {
+ mDataStore.setPropertyLong(Config.PUBLIC_KEY_DOWNLOAD_ID, downloadId);
+ mDataStore.store();
}
- mDataStore.setPropertyLong(Config.PUBLIC_KEY_URL_KEY, downloadId);
- mDataStore.store();
+ return downloadId;
}
- void startMetadataDownload(String metadataUrl) {
- long downloadId = download(metadataUrl);
- if (downloadId == -1) {
- Log.e(TAG, "Metadata download request failed for " + metadataUrl);
- return;
+ long startMetadataDownload() {
+ long downloadId = download(mDataStore.getProperty(Config.METADATA_URL));
+ if (downloadId != -1) {
+ mDataStore.setPropertyLong(Config.METADATA_DOWNLOAD_ID, downloadId);
+ mDataStore.store();
}
- mDataStore.setPropertyLong(Config.METADATA_URL_KEY, downloadId);
- mDataStore.store();
+ return downloadId;
}
- void startContentDownload(String contentUrl) {
- long downloadId = download(contentUrl);
- if (downloadId == -1) {
- Log.e(TAG, "Content download request failed for " + contentUrl);
- return;
+ long startContentDownload() {
+ long downloadId = download(mDataStore.getProperty(Config.CONTENT_URL));
+ if (downloadId != -1) {
+ mDataStore.setPropertyLong(Config.CONTENT_DOWNLOAD_ID, downloadId);
+ mDataStore.store();
}
- mDataStore.setPropertyLong(Config.CONTENT_URL_KEY, downloadId);
- mDataStore.store();
+ return downloadId;
}
@Override
@@ -157,7 +154,11 @@
return;
}
- startMetadataDownload(mDataStore.getProperty(Config.METADATA_URL_PENDING));
+ if (startMetadataDownload() == -1) {
+ Log.e(TAG, "Metadata download not started.");
+ } else if (Config.DEBUG) {
+ Log.d(TAG, "Metadata download started successfully.");
+ }
}
private void handleMetadataDownloadCompleted(long downloadId) {
@@ -166,7 +167,11 @@
handleDownloadFailed(status);
return;
}
- startContentDownload(mDataStore.getProperty(Config.CONTENT_URL_PENDING));
+ if (startContentDownload() == -1) {
+ Log.e(TAG, "Content download not started.");
+ } else if (Config.DEBUG) {
+ Log.d(TAG, "Content download started successfully.");
+ }
}
private void handleContentDownloadCompleted(long downloadId) {
@@ -204,8 +209,6 @@
return;
}
- String contentUrl = mDataStore.getProperty(Config.CONTENT_URL_PENDING);
- String metadataUrl = mDataStore.getProperty(Config.METADATA_URL_PENDING);
try (InputStream inputStream = mContext.getContentResolver().openInputStream(contentUri)) {
success = mInstaller.install(Config.COMPATIBILITY_VERSION, inputStream, version);
} catch (IOException e) {
@@ -216,8 +219,6 @@
if (success) {
// Update information about the stored version on successful install.
mDataStore.setProperty(Config.VERSION, version);
- mDataStore.setProperty(Config.CONTENT_URL, contentUrl);
- mDataStore.setProperty(Config.METADATA_URL, metadataUrl);
mDataStore.store();
}
}
@@ -237,29 +238,59 @@
}
@VisibleForTesting
+ long getPublicKeyDownloadId() {
+ return mDataStore.getPropertyLong(Config.PUBLIC_KEY_DOWNLOAD_ID, -1);
+ }
+
+ @VisibleForTesting
+ long getMetadataDownloadId() {
+ return mDataStore.getPropertyLong(Config.METADATA_DOWNLOAD_ID, -1);
+ }
+
+ @VisibleForTesting
+ long getContentDownloadId() {
+ return mDataStore.getPropertyLong(Config.CONTENT_DOWNLOAD_ID, -1);
+ }
+
+ @VisibleForTesting
+ boolean hasPublicKeyDownloadId() {
+ return getPublicKeyDownloadId() != -1;
+ }
+
+ @VisibleForTesting
+ boolean hasMetadataDownloadId() {
+ return getMetadataDownloadId() != -1;
+ }
+
+ @VisibleForTesting
+ boolean hasContentDownloadId() {
+ return getContentDownloadId() != -1;
+ }
+
+ @VisibleForTesting
boolean isPublicKeyDownloadId(long downloadId) {
- return mDataStore.getPropertyLong(Config.PUBLIC_KEY_URL_KEY, -1) == downloadId;
+ return getPublicKeyDownloadId() == downloadId;
}
@VisibleForTesting
boolean isMetadataDownloadId(long downloadId) {
- return mDataStore.getPropertyLong(Config.METADATA_URL_KEY, -1) == downloadId;
+ return getMetadataDownloadId() == downloadId;
}
@VisibleForTesting
boolean isContentDownloadId(long downloadId) {
- return mDataStore.getPropertyLong(Config.CONTENT_URL_KEY, -1) == downloadId;
+ return getContentDownloadId() == downloadId;
}
private Uri getPublicKeyDownloadUri() {
- return mDownloadHelper.getUri(mDataStore.getPropertyLong(Config.PUBLIC_KEY_URL_KEY, -1));
+ return mDownloadHelper.getUri(getPublicKeyDownloadId());
}
private Uri getMetadataDownloadUri() {
- return mDownloadHelper.getUri(mDataStore.getPropertyLong(Config.METADATA_URL_KEY, -1));
+ return mDownloadHelper.getUri(getMetadataDownloadId());
}
private Uri getContentDownloadUri() {
- return mDownloadHelper.getUri(mDataStore.getPropertyLong(Config.CONTENT_URL_KEY, -1));
+ return mDownloadHelper.getUri(getContentDownloadId());
}
}
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyFlagsListener.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyFlagsListener.java
index f359a2a..3138ea7 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyFlagsListener.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyFlagsListener.java
@@ -115,11 +115,14 @@
// TODO: handle the case where there is already a pending download.
- mDataStore.setProperty(Config.VERSION_PENDING, newVersion);
- mDataStore.setProperty(Config.CONTENT_URL_PENDING, newContentUrl);
- mDataStore.setProperty(Config.METADATA_URL_PENDING, newMetadataUrl);
+ mDataStore.setProperty(Config.CONTENT_URL, newContentUrl);
+ mDataStore.setProperty(Config.METADATA_URL, newMetadataUrl);
mDataStore.store();
- mCertificateTransparencyDownloader.startMetadataDownload(newMetadataUrl);
+ if (mCertificateTransparencyDownloader.startMetadataDownload() == -1) {
+ Log.e(TAG, "Metadata download not started.");
+ } else if (Config.DEBUG) {
+ Log.d(TAG, "Metadata download started successfully.");
+ }
}
}
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java
index c5d0413..bf23cb0 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java
@@ -78,11 +78,15 @@
Log.d(TAG, "Starting CT daily job.");
}
- mDataStore.setProperty(Config.CONTENT_URL_PENDING, Config.URL_LOG_LIST);
- mDataStore.setProperty(Config.METADATA_URL_PENDING, Config.URL_SIGNATURE);
- mDataStore.setProperty(Config.PUBLIC_KEY_URL_PENDING, Config.URL_PUBLIC_KEY);
+ mDataStore.setProperty(Config.CONTENT_URL, Config.URL_LOG_LIST);
+ mDataStore.setProperty(Config.METADATA_URL, Config.URL_SIGNATURE);
+ mDataStore.setProperty(Config.PUBLIC_KEY_URL, Config.URL_PUBLIC_KEY);
mDataStore.store();
- mCertificateTransparencyDownloader.startPublicKeyDownload(Config.URL_PUBLIC_KEY);
+ if (mCertificateTransparencyDownloader.startPublicKeyDownload() == -1) {
+ Log.e(TAG, "Public key download not started.");
+ } else if (Config.DEBUG) {
+ Log.d(TAG, "Public key download started successfully.");
+ }
}
}
diff --git a/networksecurity/service/src/com/android/server/net/ct/Config.java b/networksecurity/service/src/com/android/server/net/ct/Config.java
index ae30f3a..70d8e42 100644
--- a/networksecurity/service/src/com/android/server/net/ct/Config.java
+++ b/networksecurity/service/src/com/android/server/net/ct/Config.java
@@ -47,21 +47,17 @@
static final String FLAG_PUBLIC_KEY = FLAGS_PREFIX + "public_key";
// properties
- static final String VERSION_PENDING = "version_pending";
static final String VERSION = "version";
- static final String CONTENT_URL_PENDING = "content_url_pending";
static final String CONTENT_URL = "content_url";
- static final String CONTENT_URL_KEY = "content_url_key";
- static final String METADATA_URL_PENDING = "metadata_url_pending";
+ static final String CONTENT_DOWNLOAD_ID = "content_download_id";
static final String METADATA_URL = "metadata_url";
- static final String METADATA_URL_KEY = "metadata_url_key";
- static final String PUBLIC_KEY_URL_PENDING = "public_key_url_pending";
+ static final String METADATA_DOWNLOAD_ID = "metadata_download_id";
static final String PUBLIC_KEY_URL = "public_key_url";
- static final String PUBLIC_KEY_URL_KEY = "public_key_url_key";
+ static final String PUBLIC_KEY_DOWNLOAD_ID = "public_key_download_id";
// URLs
- static final String URL_BASE = "https://www.gstatic.com/android/certificate_transparency/";
- static final String URL_LOG_LIST = URL_BASE + "log_list.json";
- static final String URL_SIGNATURE = URL_BASE + "log_list.sig";
- static final String URL_PUBLIC_KEY = URL_BASE + "log_list.pub";
+ static final String URL_PREFIX = "https://www.gstatic.com/android/certificate_transparency/";
+ static final String URL_LOG_LIST = URL_PREFIX + "log_list.json";
+ static final String URL_SIGNATURE = URL_PREFIX + "log_list.sig";
+ static final String URL_PUBLIC_KEY = URL_PREFIX + "log_list.pub";
}
diff --git a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
index 87d75e6..ffa1283 100644
--- a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
+++ b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
@@ -27,14 +27,16 @@
import static java.nio.charset.StandardCharsets.UTF_8;
import android.app.DownloadManager;
+import android.app.DownloadManager.Query;
+import android.app.DownloadManager.Request;
import android.content.Context;
import android.content.Intent;
+import android.database.Cursor;
+import android.database.MatrixCursor;
import android.net.Uri;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.server.net.ct.DownloadHelper.DownloadStatus;
-
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.After;
@@ -63,7 +65,7 @@
@RunWith(JUnit4.class)
public class CertificateTransparencyDownloaderTest {
- @Mock private DownloadHelper mDownloadHelper;
+ @Mock private DownloadManager mDownloadManager;
@Mock private CertificateTransparencyInstaller mCertificateTransparencyInstaller;
private PrivateKey mPrivateKey;
@@ -79,7 +81,6 @@
@Before
public void setUp() throws IOException, GeneralSecurityException {
MockitoAnnotations.initMocks(this);
-
KeyPairGenerator instance = KeyPairGenerator.getInstance("RSA");
KeyPair keyPair = instance.generateKeyPair();
mPrivateKey = keyPair.getPrivate();
@@ -88,16 +89,17 @@
mContext = InstrumentationRegistry.getInstrumentation().getContext();
mTempFile = File.createTempFile("datastore-test", ".properties");
mDataStore = new DataStore(mTempFile);
- mDataStore.load();
mSignatureVerifier = new SignatureVerifier(mContext);
-
mCertificateTransparencyDownloader =
new CertificateTransparencyDownloader(
mContext,
mDataStore,
- mDownloadHelper,
+ new DownloadHelper(mDownloadManager),
mSignatureVerifier,
mCertificateTransparencyInstaller);
+
+ prepareDataStore();
+ prepareDownloadManager();
}
@After
@@ -108,116 +110,108 @@
@Test
public void testDownloader_startPublicKeyDownload() {
- String publicKeyUrl = "http://test-public-key.org";
- long downloadId = preparePublicKeyDownload(publicKeyUrl);
+ assertThat(mCertificateTransparencyDownloader.hasPublicKeyDownloadId()).isFalse();
+ long downloadId = mCertificateTransparencyDownloader.startPublicKeyDownload();
- assertThat(mCertificateTransparencyDownloader.isPublicKeyDownloadId(downloadId)).isFalse();
- mCertificateTransparencyDownloader.startPublicKeyDownload(publicKeyUrl);
+ assertThat(mCertificateTransparencyDownloader.hasPublicKeyDownloadId()).isTrue();
assertThat(mCertificateTransparencyDownloader.isPublicKeyDownloadId(downloadId)).isTrue();
}
@Test
public void testDownloader_startMetadataDownload() {
- String metadataUrl = "http://test-metadata.org";
- long downloadId = prepareMetadataDownload(metadataUrl);
+ assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
+ long downloadId = mCertificateTransparencyDownloader.startMetadataDownload();
- assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(downloadId)).isFalse();
- mCertificateTransparencyDownloader.startMetadataDownload(metadataUrl);
+ assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isTrue();
assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(downloadId)).isTrue();
}
@Test
public void testDownloader_startContentDownload() {
- String contentUrl = "http://test-content.org";
- long downloadId = prepareContentDownload(contentUrl);
+ assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse();
+ long downloadId = mCertificateTransparencyDownloader.startContentDownload();
- assertThat(mCertificateTransparencyDownloader.isContentDownloadId(downloadId)).isFalse();
- mCertificateTransparencyDownloader.startContentDownload(contentUrl);
+ assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isTrue();
assertThat(mCertificateTransparencyDownloader.isContentDownloadId(downloadId)).isTrue();
}
@Test
public void testDownloader_publicKeyDownloadSuccess_updatePublicKey_startMetadataDownload()
throws Exception {
- long publicKeyId = prepareSuccessfulPublicKeyDownload(writePublicKeyToFile(mPublicKey));
- long metadataId = prepareMetadataDownload("http://test-metadata.org");
+ long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
+ setSuccessfulDownload(publicKeyId, writePublicKeyToFile(mPublicKey));
assertThat(mSignatureVerifier.getPublicKey()).isEmpty();
- assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isFalse();
+ assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
mCertificateTransparencyDownloader.onReceive(
mContext, makeDownloadCompleteIntent(publicKeyId));
assertThat(mSignatureVerifier.getPublicKey()).hasValue(mPublicKey);
- assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isTrue();
+ assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isTrue();
}
@Test
public void
testDownloader_publicKeyDownloadSuccess_updatePublicKeyFail_doNotStartMetadataDownload()
throws Exception {
- long publicKeyId =
- prepareSuccessfulPublicKeyDownload(
- writeToFile("i_am_not_a_base64_encoded_public_key".getBytes()));
- long metadataId = prepareMetadataDownload("http://test-metadata.org");
+ long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
+ setSuccessfulDownload(
+ publicKeyId, writeToFile("i_am_not_a_base64_encoded_public_key".getBytes()));
assertThat(mSignatureVerifier.getPublicKey()).isEmpty();
- assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isFalse();
+ assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
mCertificateTransparencyDownloader.onReceive(
mContext, makeDownloadCompleteIntent(publicKeyId));
assertThat(mSignatureVerifier.getPublicKey()).isEmpty();
- assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isFalse();
- verify(mDownloadHelper, never()).startDownload(anyString());
+ assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
}
@Test
public void testDownloader_publicKeyDownloadFail_doNotUpdatePublicKey() throws Exception {
- long publicKeyId =
- prepareFailedPublicKeyDownload(
- // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
+ long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
+ setFailedDownload(
+ publicKeyId, // Failure cases where we give up on the download.
+ DownloadManager.ERROR_INSUFFICIENT_SPACE,
+ DownloadManager.ERROR_HTTP_DATA_ERROR);
Intent downloadCompleteIntent = makeDownloadCompleteIntent(publicKeyId);
- long metadataId = prepareMetadataDownload("http://test-metadata.org");
assertThat(mSignatureVerifier.getPublicKey()).isEmpty();
- assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isFalse();
+ assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
assertThat(mSignatureVerifier.getPublicKey()).isEmpty();
- assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isFalse();
- verify(mDownloadHelper, never()).startDownload(anyString());
+ assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
}
@Test
public void testDownloader_metadataDownloadSuccess_startContentDownload() {
- long metadataId = prepareSuccessfulMetadataDownload(new File("log_list.sig"));
- long contentId = prepareContentDownload("http://test-content.org");
+ long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
+ setSuccessfulDownload(metadataId, new File("log_list.sig"));
- assertThat(mCertificateTransparencyDownloader.isContentDownloadId(contentId)).isFalse();
+ assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse();
mCertificateTransparencyDownloader.onReceive(
mContext, makeDownloadCompleteIntent(metadataId));
- assertThat(mCertificateTransparencyDownloader.isContentDownloadId(contentId)).isTrue();
+ assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isTrue();
}
@Test
public void testDownloader_metadataDownloadFail_doNotStartContentDownload() {
- long metadataId =
- prepareFailedMetadataDownload(
- // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
+ long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
+ setFailedDownload(
+ metadataId,
+ // Failure cases where we give up on the download.
+ DownloadManager.ERROR_INSUFFICIENT_SPACE,
+ DownloadManager.ERROR_HTTP_DATA_ERROR);
Intent downloadCompleteIntent = makeDownloadCompleteIntent(metadataId);
- long contentId = prepareContentDownload("http://test-content.org");
- assertThat(mCertificateTransparencyDownloader.isContentDownloadId(contentId)).isFalse();
+ assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse();
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
- assertThat(mCertificateTransparencyDownloader.isContentDownloadId(contentId)).isFalse();
- verify(mDownloadHelper, never()).startDownload(anyString());
+ assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse();
}
@Test
@@ -227,8 +221,10 @@
File logListFile = makeLogListFile(newVersion);
File metadataFile = sign(logListFile);
mSignatureVerifier.setPublicKey(mPublicKey);
- prepareSuccessfulMetadataDownload(metadataFile);
- long contentId = prepareSuccessfulContentDownload(logListFile);
+ long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
+ setSuccessfulDownload(metadataId, metadataFile);
+ long contentId = mCertificateTransparencyDownloader.startContentDownload();
+ setSuccessfulDownload(contentId, logListFile);
when(mCertificateTransparencyInstaller.install(
eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
.thenReturn(true);
@@ -242,11 +238,12 @@
@Test
public void testDownloader_contentDownloadFail_doNotInstall() throws Exception {
- long contentId =
- prepareFailedContentDownload(
- // Failure cases where we give up on the download.
- DownloadManager.ERROR_INSUFFICIENT_SPACE,
- DownloadManager.ERROR_HTTP_DATA_ERROR);
+ long contentId = mCertificateTransparencyDownloader.startContentDownload();
+ setFailedDownload(
+ contentId,
+ // Failure cases where we give up on the download.
+ DownloadManager.ERROR_INSUFFICIENT_SPACE,
+ DownloadManager.ERROR_HTTP_DATA_ERROR);
Intent downloadCompleteIntent = makeDownloadCompleteIntent(contentId);
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
@@ -262,8 +259,10 @@
File logListFile = makeLogListFile("456");
File metadataFile = sign(logListFile);
mSignatureVerifier.setPublicKey(mPublicKey);
- prepareSuccessfulMetadataDownload(metadataFile);
- long contentId = prepareSuccessfulContentDownload(logListFile);
+ long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
+ setSuccessfulDownload(metadataId, metadataFile);
+ long contentId = mCertificateTransparencyDownloader.startContentDownload();
+ setSuccessfulDownload(contentId, logListFile);
when(mCertificateTransparencyInstaller.install(
eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
.thenReturn(false);
@@ -281,8 +280,10 @@
File logListFile = makeLogListFile("456");
File metadataFile = File.createTempFile("log_list-wrong_metadata", "sig");
mSignatureVerifier.setPublicKey(mPublicKey);
- prepareSuccessfulMetadataDownload(metadataFile);
- long contentId = prepareSuccessfulContentDownload(logListFile);
+ long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
+ setSuccessfulDownload(metadataId, metadataFile);
+ long contentId = mCertificateTransparencyDownloader.startContentDownload();
+ setSuccessfulDownload(contentId, logListFile);
assertNoVersionIsInstalled();
mCertificateTransparencyDownloader.onReceive(
@@ -299,8 +300,10 @@
File logListFile = makeLogListFile("456");
File metadataFile = sign(logListFile);
mSignatureVerifier.resetPublicKey();
- prepareSuccessfulMetadataDownload(metadataFile);
- long contentId = prepareSuccessfulContentDownload(logListFile);
+ long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
+ setSuccessfulDownload(metadataId, metadataFile);
+ long contentId = mCertificateTransparencyDownloader.startContentDownload();
+ setSuccessfulDownload(contentId, logListFile);
assertNoVersionIsInstalled();
mCertificateTransparencyDownloader.onReceive(
@@ -321,26 +324,23 @@
assertNoVersionIsInstalled();
// 1. Start download of public key.
- String publicKeyUrl = "http://test-public-key.org";
- long publicKeyId = preparePublicKeyDownload(publicKeyUrl);
-
- mCertificateTransparencyDownloader.startPublicKeyDownload(publicKeyUrl);
+ long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
// 2. On successful public key download, set the key and start the metatadata download.
setSuccessfulDownload(publicKeyId, publicKeyFile);
- long metadataId = prepareMetadataDownload("http://test-metadata.org");
mCertificateTransparencyDownloader.onReceive(
mContext, makeDownloadCompleteIntent(publicKeyId));
// 3. On successful metadata download, start the content download.
+ long metadataId = mCertificateTransparencyDownloader.getMetadataDownloadId();
setSuccessfulDownload(metadataId, metadataFile);
- long contentId = prepareContentDownload("http://test-content.org");
mCertificateTransparencyDownloader.onReceive(
mContext, makeDownloadCompleteIntent(metadataId));
// 4. On successful content download, verify the signature and install the new version.
+ long contentId = mCertificateTransparencyDownloader.getContentDownloadId();
setSuccessfulDownload(contentId, logListFile);
when(mCertificateTransparencyInstaller.install(
eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
@@ -354,16 +354,10 @@
private void assertNoVersionIsInstalled() {
assertThat(mDataStore.getProperty(Config.VERSION)).isNull();
- assertThat(mDataStore.getProperty(Config.CONTENT_URL)).isNull();
- assertThat(mDataStore.getProperty(Config.METADATA_URL)).isNull();
}
private void assertInstallSuccessful(String version) {
assertThat(mDataStore.getProperty(Config.VERSION)).isEqualTo(version);
- assertThat(mDataStore.getProperty(Config.CONTENT_URL))
- .isEqualTo(mDataStore.getProperty(Config.CONTENT_URL_PENDING));
- assertThat(mDataStore.getProperty(Config.METADATA_URL))
- .isEqualTo(mDataStore.getProperty(Config.METADATA_URL_PENDING));
}
private Intent makeDownloadCompleteIntent(long downloadId) {
@@ -371,110 +365,51 @@
.putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId);
}
- private long prepareDownloadId(String url) {
- long downloadId = mNextDownloadId++;
- when(mDownloadHelper.startDownload(url)).thenReturn(downloadId);
- return downloadId;
+ private void prepareDataStore() {
+ mDataStore.load();
+ mDataStore.setProperty(Config.CONTENT_URL, Config.URL_LOG_LIST);
+ mDataStore.setProperty(Config.METADATA_URL, Config.URL_SIGNATURE);
+ mDataStore.setProperty(Config.PUBLIC_KEY_URL, Config.URL_PUBLIC_KEY);
}
- private long preparePublicKeyDownload(String url) {
- long downloadId = prepareDownloadId(url);
- mDataStore.setProperty(Config.PUBLIC_KEY_URL_PENDING, url);
- return downloadId;
+ private void prepareDownloadManager() {
+ when(mDownloadManager.enqueue(any(Request.class)))
+ .thenAnswer(invocation -> mNextDownloadId++);
}
- private long prepareMetadataDownload(String url) {
- long downloadId = prepareDownloadId(url);
- mDataStore.setProperty(Config.METADATA_URL_PENDING, url);
- return downloadId;
- }
-
- private long prepareContentDownload(String url) {
- long downloadId = prepareDownloadId(url);
- mDataStore.setProperty(Config.CONTENT_URL_PENDING, url);
- return downloadId;
- }
-
- private long prepareSuccessfulDownload(String propertyKey) {
- long downloadId = mNextDownloadId++;
- mDataStore.setPropertyLong(propertyKey, downloadId);
- when(mDownloadHelper.getDownloadStatus(downloadId))
- .thenReturn(makeSuccessfulDownloadStatus(downloadId));
- return downloadId;
- }
-
- private long prepareSuccessfulDownload(String propertyKey, File file) {
- long downloadId = prepareSuccessfulDownload(propertyKey);
- when(mDownloadHelper.getUri(downloadId)).thenReturn(Uri.fromFile(file));
- return downloadId;
- }
-
- private long prepareSuccessfulPublicKeyDownload(File file) {
- long downloadId = prepareSuccessfulDownload(Config.PUBLIC_KEY_URL_KEY, file);
- mDataStore.setProperty(
- Config.METADATA_URL_PENDING, "http://public-key-was-downloaded-here.org");
- return downloadId;
- }
-
- private long prepareSuccessfulMetadataDownload(File file) {
- long downloadId = prepareSuccessfulDownload(Config.METADATA_URL_KEY, file);
- mDataStore.setProperty(
- Config.METADATA_URL_PENDING, "http://metadata-was-downloaded-here.org");
- return downloadId;
- }
-
- private long prepareSuccessfulContentDownload(File file) {
- long downloadId = prepareSuccessfulDownload(Config.CONTENT_URL_KEY, file);
- mDataStore.setProperty(
- Config.CONTENT_URL_PENDING, "http://content-was-downloaded-here.org");
- return downloadId;
+ private Cursor makeSuccessfulDownloadCursor() {
+ MatrixCursor cursor =
+ new MatrixCursor(
+ new String[] {
+ DownloadManager.COLUMN_STATUS, DownloadManager.COLUMN_REASON
+ });
+ cursor.addRow(new Object[] {DownloadManager.STATUS_SUCCESSFUL, -1});
+ return cursor;
}
private void setSuccessfulDownload(long downloadId, File file) {
- when(mDownloadHelper.getDownloadStatus(downloadId))
- .thenReturn(makeSuccessfulDownloadStatus(downloadId));
- when(mDownloadHelper.getUri(downloadId)).thenReturn(Uri.fromFile(file));
+ when(mDownloadManager.query(any(Query.class))).thenReturn(makeSuccessfulDownloadCursor());
+ when(mDownloadManager.getUriForDownloadedFile(downloadId)).thenReturn(Uri.fromFile(file));
}
- private long prepareFailedDownload(String propertyKey, int... downloadManagerErrors) {
- long downloadId = mNextDownloadId++;
- mDataStore.setPropertyLong(propertyKey, downloadId);
- DownloadStatus firstError =
- DownloadStatus.builder()
- .setDownloadId(downloadId)
- .setStatus(DownloadManager.STATUS_FAILED)
- .setReason(downloadManagerErrors[0])
- .build();
- DownloadStatus[] otherErrors = new DownloadStatus[downloadManagerErrors.length - 1];
+ private Cursor makeFailedDownloadCursor(int error) {
+ MatrixCursor cursor =
+ new MatrixCursor(
+ new String[] {
+ DownloadManager.COLUMN_STATUS, DownloadManager.COLUMN_REASON
+ });
+ cursor.addRow(new Object[] {DownloadManager.STATUS_FAILED, error});
+ return cursor;
+ }
+
+ private void setFailedDownload(long downloadId, int... downloadManagerErrors) {
+ Cursor first = makeFailedDownloadCursor(downloadManagerErrors[0]);
+ Cursor[] others = new Cursor[downloadManagerErrors.length - 1];
for (int i = 1; i < downloadManagerErrors.length; i++) {
- otherErrors[i - 1] =
- DownloadStatus.builder()
- .setDownloadId(downloadId)
- .setStatus(DownloadManager.STATUS_FAILED)
- .setReason(downloadManagerErrors[i])
- .build();
+ others[i - 1] = makeFailedDownloadCursor(downloadManagerErrors[i]);
}
- when(mDownloadHelper.getDownloadStatus(downloadId)).thenReturn(firstError, otherErrors);
- return downloadId;
- }
-
- private long prepareFailedPublicKeyDownload(int... downloadManagerErrors) {
- return prepareFailedDownload(Config.PUBLIC_KEY_URL_KEY, downloadManagerErrors);
- }
-
- private long prepareFailedMetadataDownload(int... downloadManagerErrors) {
- return prepareFailedDownload(Config.METADATA_URL_KEY, downloadManagerErrors);
- }
-
- private long prepareFailedContentDownload(int... downloadManagerErrors) {
- return prepareFailedDownload(Config.CONTENT_URL_KEY, downloadManagerErrors);
- }
-
- private DownloadStatus makeSuccessfulDownloadStatus(long downloadId) {
- return DownloadStatus.builder()
- .setDownloadId(downloadId)
- .setStatus(DownloadManager.STATUS_SUCCESSFUL)
- .build();
+ when(mDownloadManager.query(any())).thenReturn(first, others);
+ when(mDownloadManager.getUriForDownloadedFile(downloadId)).thenReturn(null);
}
private File writePublicKeyToFile(PublicKey publicKey)
diff --git a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt
index e634f0e..8e27c62 100644
--- a/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt
+++ b/staticlibs/testutils/app/connectivitychecker/src/com/android/testutils/connectivitypreparer/ConnectivityCheckTest.kt
@@ -16,27 +16,167 @@
package com.android.testutils.connectivitypreparer
+import android.Manifest.permission.NETWORK_SETTINGS
import android.content.pm.PackageManager.FEATURE_TELEPHONY
import android.content.pm.PackageManager.FEATURE_WIFI
+import android.net.LinkAddress
+import android.net.Network
+import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.NetworkRequest
+import android.net.wifi.WifiInfo
import android.telephony.TelephonyManager
+import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.net.module.util.HexDump
+import com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY
+import com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY
+import com.android.testutils.AutoReleaseNetworkCallbackRule
import com.android.testutils.ConnectUtil
+import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
+import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
+import com.android.testutils.runAsShell
+import com.android.testutils.tryTest
+import java.io.IOException
+import java.net.DatagramPacket
+import java.net.DatagramSocket
+import java.util.Random
+import kotlin.test.assertFalse
+import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import kotlin.test.fail
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+private const val QUIC_SOCKET_TIMEOUT_MS = 5_000
+private const val QUIC_RETRY_COUNT = 5
+
@RunWith(AndroidJUnit4::class)
class ConnectivityCheckTest {
+ @get:Rule
+ val networkCallbackRule = AutoReleaseNetworkCallbackRule()
+
+ private val logTag = ConnectivityCheckTest::class.simpleName
private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
private val pm by lazy { context.packageManager }
private val connectUtil by lazy { ConnectUtil(context) }
+ // Skip IPv6 checks on virtual devices which do not support it. Tests that require IPv6 will
+ // still fail even if the preparer does not.
+ private fun ipv6Unsupported(wifiSsid: String?) = ConnectUtil.VIRTUAL_SSIDS.contains(
+ WifiInfo.sanitizeSsid(wifiSsid))
+
@Test
fun testCheckWifiSetup() {
if (!pm.hasSystemFeature(FEATURE_WIFI)) return
connectUtil.ensureWifiValidated()
+
+ val (wifiNetwork, wifiSsid) = runAsShell(NETWORK_SETTINGS) {
+ val cb = networkCallbackRule.requestNetwork(
+ NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build()
+ )
+ val capChanged = cb.eventuallyExpect<CapabilitiesChanged>(from = 0)
+ val network = capChanged.network
+ val ssid = capChanged.caps.ssid
+ assertFalse(ssid.isNullOrEmpty(), "No SSID for wifi network $network")
+ // Expect a global IPv6 address, and native or stacked IPv4
+ val lpChange = cb.history.poll(
+ pos = 0,
+ timeoutMs = 30_000L
+ ) {
+ it is LinkPropertiesChanged &&
+ it.network == network &&
+ it.lp.allLinkAddresses.any(LinkAddress::isIpv4) &&
+ (ipv6Unsupported(ssid) || it.lp.hasGlobalIpv6Address())
+ }
+ assertNotNull(lpChange, "Wifi network $network needs an IPv4 address" +
+ if (ipv6Unsupported(ssid)) "" else " and a global IPv6 address")
+
+ Pair(network, ssid)
+ }
+
+ // Checking QUIC is more important on Wi-Fi than cellular, as it finds firewall
+ // configuration problems on Wi-Fi, but cellular is not actionable by the test lab.
+ checkQuic(wifiNetwork, wifiSsid, ipv6 = false)
+ if (!ipv6Unsupported(wifiSsid)) {
+ checkQuic(wifiNetwork, wifiSsid, ipv6 = true)
+ }
+ }
+
+ /**
+ * Check that QUIC is working on the specified network.
+ *
+ * Some tests require QUIC (UDP), and some lab networks have been observed to not let it
+ * through due to firewalling. Ensure that devices are setup on a network that has the proper
+ * allowlists before trying to run the tests.
+ */
+ private fun checkQuic(network: Network, ssid: String, ipv6: Boolean) {
+ // Same endpoint as used in MultinetworkApiTest in CTS
+ val hostname = "connectivitycheck.android.com"
+ val targetAddrs = network.getAllByName(hostname)
+ val bindAddr = if (ipv6) IPV6_ADDR_ANY else IPV4_ADDR_ANY
+ if (targetAddrs.isEmpty()) {
+ Log.d(logTag, "No addresses found for $hostname")
+ return
+ }
+
+ val socket = DatagramSocket(0, bindAddr)
+ tryTest {
+ socket.soTimeout = QUIC_SOCKET_TIMEOUT_MS
+ network.bindSocket(socket)
+
+ // For reference see Version-Independent Properties of QUIC:
+ // https://datatracker.ietf.org/doc/html/rfc8999
+ // This packet just contains a long header with an unsupported version number, to force
+ // a version-negotiation packet in response.
+ val connectionId = ByteArray(8).apply { Random().nextBytes(this) }
+ val quicData = byteArrayOf(
+ // long header
+ 0xc0.toByte(),
+ // version number (should be an unknown version for the server)
+ 0xaa.toByte(), 0xda.toByte(), 0xca.toByte(), 0xca.toByte(),
+ // destination connection ID length
+ 0x08,
+ ) + connectionId + byteArrayOf(
+ // source connection ID length
+ 0x00,
+ ) + ByteArray(1185) // Ensure the packet is 1200 bytes long
+ val targetAddr = targetAddrs.firstOrNull { it.javaClass == bindAddr.javaClass }
+ ?: fail("No ${bindAddr.javaClass} found for $hostname " +
+ "(got ${targetAddrs.joinToString()})")
+ repeat(QUIC_RETRY_COUNT) { i ->
+ socket.send(DatagramPacket(quicData, quicData.size, targetAddr, 443))
+
+ val receivedPacket = DatagramPacket(ByteArray(1500), 1500)
+ try {
+ socket.receive(receivedPacket)
+ } catch (e: IOException) {
+ Log.d(logTag, "No response from $hostname ($targetAddr) on QUIC try $i", e)
+ return@repeat
+ }
+
+ val receivedConnectionId = receivedPacket.data.copyOfRange(7, 7 + 8)
+ if (connectionId.contentEquals(receivedConnectionId)) {
+ return@tryTest
+ } else {
+ val headerBytes = receivedPacket.data.copyOfRange(
+ 0, receivedPacket.length.coerceAtMost(15))
+ Log.d(logTag, "Received invalid connection ID on QUIC try $i: " +
+ HexDump.toHexString(headerBytes))
+ }
+ }
+ fail("QUIC is not working on SSID $ssid connecting to $targetAddr " +
+ "with local source port ${socket.localPort}: check the firewall for UDP port " +
+ "443 access."
+ )
+ } cleanup {
+ socket.close()
+ }
}
@Test
@@ -53,12 +193,16 @@
if (tm.simState == TelephonyManager.SIM_STATE_ABSENT) {
fail("The device has no SIM card inserted. $commonError")
} else if (tm.simState != TelephonyManager.SIM_STATE_READY) {
- fail("The device is not setup with a usable SIM card. Sim state was ${tm.simState}. " +
- commonError)
+ fail(
+ "The device is not setup with a usable SIM card. Sim state was ${tm.simState}. " +
+ commonError
+ )
}
- assertTrue(tm.isDataConnectivityPossible,
+ assertTrue(
+ tm.isDataConnectivityPossible,
"The device has a SIM card, but it does not supports data connectivity. " +
- "Check the data plan, and verify that mobile data is working. " + commonError)
+ "Check the data plan, and verify that mobile data is working. " + commonError
+ )
connectUtil.ensureCellularValidated()
}
}
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt
index 3857810..d60ab59 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/ConnectUtil.kt
@@ -53,6 +53,10 @@
private const val WIFI_ERROR_BUSY = 2
class ConnectUtil(private val context: Context) {
+ companion object {
+ @JvmStatic
+ val VIRTUAL_SSIDS = listOf("VirtWifi", "AndroidWifi")
+ }
private val TAG = ConnectUtil::class.java.simpleName
private val cm = context.getSystemService(ConnectivityManager::class.java)
@@ -207,9 +211,8 @@
*/
private fun maybeConfigureVirtualNetwork(scanResults: List<ScanResult>): WifiConfiguration? {
// Virtual wifi networks used on the emulator and cloud testing infrastructure
- val virtualSsids = listOf("VirtWifi", "AndroidWifi")
Log.d(TAG, "Wifi scan results: $scanResults")
- val virtualScanResult = scanResults.firstOrNull { virtualSsids.contains(it.SSID) }
+ val virtualScanResult = scanResults.firstOrNull { VIRTUAL_SSIDS.contains(it.SSID) }
?: return null
// Only add the virtual configuration if the virtual AP is detected in scans
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java
index ce55fdc..31879af 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java
+++ b/staticlibs/testutils/devicetests/com/android/testutils/DeviceInfoUtils.java
@@ -16,6 +16,10 @@
package com.android.testutils;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
+
+import android.os.Build;
+import android.os.SystemProperties;
import android.os.VintfRuntimeInfo;
import android.text.TextUtils;
import android.util.Pair;
@@ -173,4 +177,14 @@
final KVersion from = DeviceInfoUtils.getMajorMinorSubminorVersion(version);
return current.isAtLeast(from);
}
+
+ /**
+ * Check if the current build is a debuggable build.
+ */
+ public static boolean isDebuggable() {
+ if (isAtLeastS()) {
+ return Build.isDebuggable();
+ }
+ return SystemProperties.getInt("ro.debuggable", 0) == 1;
+ }
}
diff --git a/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt b/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt
index d1d5649..176546a 100644
--- a/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt
+++ b/staticlibs/testutils/hostdevice/com/android/testutils/MiscAsserts.kt
@@ -20,6 +20,7 @@
import com.android.testutils.FunctionalUtils.ThrowingRunnable
import java.lang.reflect.Modifier
+import java.util.concurrent.TimeUnit
import java.util.function.BooleanSupplier
import kotlin.system.measureTimeMillis
import kotlin.test.assertEquals
@@ -134,7 +135,7 @@
// on host). When waiting for a condition during tests the device would generally not go into
// deep sleep, and the polling sleep would go over the timeout anyway in that case, so this is
// fine.
- val limit = System.nanoTime() + timeoutMs * 1000
+ val limit = System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(timeoutMs)
while (!fn.asBoolean) {
if (System.nanoTime() > limit) {
fail(descr)
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 88309ed..feb4621 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -952,9 +952,8 @@
final List<InetAddress> cellNetworkAddresses = cellLinkProperties.getAddresses();
// In userdebug build, on cellular network, if the onNetwork check failed, we also try to
// re-verify it by obtaining the IP address through DNS query.
- boolean isUserDebug = Build.isDebuggable();
if (cellAddress instanceof Inet6Address) {
- if (isUserDebug && !cellNetworkAddresses.contains(cellAddress)) {
+ if (DeviceInfoUtils.isDebuggable() && !cellNetworkAddresses.contains(cellAddress)) {
final InetAddress ipv6AddressThroughDns = InetAddresses.parseNumericAddress(
getDeviceIpv6AddressThroughDnsQuery(cellNetwork));
assertContains(cellNetworkAddresses, ipv6AddressThroughDns);