From 71884c16b11d28c47ea2061bde272c33015c510a Mon Sep 17 00:00:00 2001
From: Hans-Christoph Steiner <hans@eds.org>
Date: Mon, 14 Jan 2019 17:16:18 +0100
Subject: [PATCH] clarify mirror timeout logic with constants

This should make the timeout logic clearer, without changing the logic at
all.  This does increase the timeouts, with the second pass using 1 minute
instead of 30 seconds, and the third pass using 10 minutes instead of 1
minute.  Since this often or usually runs in the background, it should
allow some pretty long timeouts in the worst case.
---
 .../java/org/fdroid/fdroid/FDroidApp.java     | 29 +++++++++++++++----
 .../java/org/fdroid/fdroid/data/Repo.java     |  4 +++
 .../org/fdroid/fdroid/net/Downloader.java     |  8 +++--
 3 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java
index 9c8567ffa..55ceaf3b2 100644
--- a/app/src/main/java/org/fdroid/fdroid/FDroidApp.java
+++ b/app/src/main/java/org/fdroid/fdroid/FDroidApp.java
@@ -71,6 +71,7 @@ import org.fdroid.fdroid.installer.ApkFileProvider;
 import org.fdroid.fdroid.installer.InstallHistoryService;
 import org.fdroid.fdroid.localrepo.SDCardScannerService;
 import org.fdroid.fdroid.net.ConnectivityMonitorService;
+import org.fdroid.fdroid.net.Downloader;
 import org.fdroid.fdroid.net.HttpDownloader;
 import org.fdroid.fdroid.net.ImageLoaderForUIL;
 import org.fdroid.fdroid.net.WifiStateChangeService;
@@ -126,7 +127,7 @@ public class FDroidApp extends Application {
 
     private static volatile LongSparseArray<String> lastWorkingMirrorArray = new LongSparseArray<>(1);
     private static volatile int numTries = Integer.MAX_VALUE;
-    private static volatile int timeout = 10000;
+    private static volatile int timeout = Downloader.DEFAULT_TIMEOUT;
 
     // Leaving the fully qualified class name here to help clarify the difference between spongy/bouncy castle.
     private static final org.bouncycastle.jce.provider.BouncyCastleProvider BOUNCYCASTLE_PROVIDER;
@@ -244,10 +245,26 @@ public class FDroidApp extends Application {
         repo = new Repo();
     }
 
+    /**
+     * @see #getMirror(String, Repo)
+     */
     public static String getMirror(String urlString, long repoId) throws IOException {
         return getMirror(urlString, RepoProvider.Helper.findById(getInstance(), repoId));
     }
 
+    /**
+     * Each time this is called, it will return a mirror from the pool of
+     * mirrors.  If it reaches the end of the list of mirrors, it will start
+     * again from the stop, while setting the timeout to
+     * {@link Downloader#SECOND_TIMEOUT}.  If it reaches the end of the list
+     * again, it will do one last pass through the list with the timeout set to
+     * {@link Downloader#LONGEST_TIMEOUT}.  After that, this gives up with a
+     * {@link IOException}.
+     *
+     * @see #resetMirrorVars()
+     * @see #getTimeout()
+     * @see Repo#getMirror(String)
+     */
     public static String getMirror(String urlString, Repo repo2) throws IOException {
         if (repo2.hasMirrors()) {
             String lastWorkingMirror = lastWorkingMirrorArray.get(repo2.getId());
@@ -255,11 +272,11 @@ public class FDroidApp extends Application {
                 lastWorkingMirror = repo2.address;
             }
             if (numTries <= 0) {
-                if (timeout == 10000) {
-                    timeout = 30000;
+                if (timeout == Downloader.DEFAULT_TIMEOUT) {
+                    timeout = Downloader.SECOND_TIMEOUT;
                     numTries = Integer.MAX_VALUE;
-                } else if (timeout == 30000) {
-                    timeout = 60000;
+                } else if (timeout == Downloader.SECOND_TIMEOUT) {
+                    timeout = Downloader.LONGEST_TIMEOUT;
                     numTries = Integer.MAX_VALUE;
                 } else {
                     Utils.debugLog(TAG, "Mirrors: Giving up");
@@ -291,7 +308,7 @@ public class FDroidApp extends Application {
             lastWorkingMirrorArray.removeAt(i);
         }
         numTries = Integer.MAX_VALUE;
-        timeout = 10000;
+        timeout = Downloader.DEFAULT_TIMEOUT;
     }
 
     @Override
diff --git a/app/src/main/java/org/fdroid/fdroid/data/Repo.java b/app/src/main/java/org/fdroid/fdroid/data/Repo.java
index 1a9929789..43fbe65e8 100644
--- a/app/src/main/java/org/fdroid/fdroid/data/Repo.java
+++ b/app/src/main/java/org/fdroid/fdroid/data/Repo.java
@@ -389,6 +389,10 @@ public class Repo extends ValueObject {
      * URL in the mirrors list so the mirror logic works on the first index
      * update.  That makes it possible to do the first index update via SD Card
      * or USB OTG drive.
+     *
+     * @see FDroidApp#resetMirrorVars()
+     * @see FDroidApp#getMirror(String, Repo)
+     * @see FDroidApp#getTimeout()
      */
     public String getMirror(String lastWorkingMirror) {
         if (TextUtils.isEmpty(lastWorkingMirror)) {
diff --git a/app/src/main/java/org/fdroid/fdroid/net/Downloader.java b/app/src/main/java/org/fdroid/fdroid/net/Downloader.java
index 2175344dd..7a7ebb232 100644
--- a/app/src/main/java/org/fdroid/fdroid/net/Downloader.java
+++ b/app/src/main/java/org/fdroid/fdroid/net/Downloader.java
@@ -2,7 +2,7 @@ package org.fdroid.fdroid.net;
 
 import android.net.Uri;
 import android.support.annotation.NonNull;
-
+import android.text.format.DateUtils;
 import org.fdroid.fdroid.ProgressListener;
 import org.fdroid.fdroid.Utils;
 
@@ -33,6 +33,10 @@ public abstract class Downloader {
     public static final String EXTRA_CANONICAL_URL = "org.fdroid.fdroid.net.Downloader.extra.ERROR_CANONICAL_URL";
     public static final String EXTRA_MIRROR_URL = "org.fdroid.fdroid.net.Downloader.extra.ERROR_MIRROR_URL";
 
+    public static final int DEFAULT_TIMEOUT = 10000;
+    public static final int SECOND_TIMEOUT = (int) DateUtils.MINUTE_IN_MILLIS;
+    public static final int LONGEST_TIMEOUT = 600000; // 10 minutes
+
     private volatile boolean cancelled = false;
     private volatile long bytesRead;
     private volatile long totalBytes;
@@ -43,7 +47,7 @@ public abstract class Downloader {
     String cacheTag;
     boolean notFound;
 
-    private volatile int timeout = 10000;
+    private volatile int timeout = DEFAULT_TIMEOUT;
 
     /**
      * For sending download progress, should only be called in {@link #progressTask}