Merge "Add isDebuggable() to DeviceInfoUtils for Android R compatibility" into main
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/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)