Почему загрузка https приостанавливается с PAUSED_WAITING_TO_RETRY?

Я использую службу DownloadManager в Android для загрузки файлов через URL-адреса https, например https://www.antennahouse.com/XSLsample/pdf/sample-link_1.pdf. Файлы (в настоящее время) не защищены паролем, если это имеет значение.

Как только я помещаю запрос на загрузку в очередь, DownloadManager начинает загрузку, но кажется, что она зависает. Когда я проверяю статус, я получаю

COLUMN_BYTES_DOWNLOADED_SO_FAR: 0
COLUMN_STATUS: 4
COLUMN_REASON: 1

COLUMN_STATUS 4: STATUS_PAUSED, "когда загрузка ожидает повторной попытки или возобновить».

COLUMN_REASON 1 — это PAUSED_WAITING_TO_RETRY, "когда загрузка приостановлена ​​из-за некоторых произошла ошибка сети, и диспетчер загрузок ожидает повторной попытки запроса." Но, похоже, нет способа определить, какая произошла сетевая ошибка. Загрузка никогда не завершается успешно.

Я проверил монитор logcat на наличие соответствующих предупреждений и ошибок, но ничего не нашел.

Я пробовал это с несколькими разными серверами, как внутренними, так и общедоступными, с тем же результатом.

Очевидных проблем с сетью нет: подключение к Wi-Fi установлено, и загрузка с использованием http:// работает нормально: файл загружается быстро и появляется в файловой системе по указанному адресу.

В случае загрузки через https наши журналы сервера показывают, что файлы успешно обслуживаются с точки зрения сервера. Тестирование тех же URL-адресов https в браузере на ноутбуке приводит к успешной загрузке файлов без каких-либо явных проблем или дополнительных согласований, отображаемых на сетевой панели инструментов разработчика.

Мой код (кратко):

sManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request req = new DownloadManager.Request(sourceURI);
final Uri destinationUri = Uri.fromFile(destinationFile);
req.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI
            | DownloadManager.Request.NETWORK_MOBILE)
        .setDestinationUri(destinationUri)
        .setMimeType(...);

long id = sManager.enqueue(req);

Резюме: загрузка https, начатая через DownloadManager, зависает на неопределенный срок, в то время как та же загрузка https отлично работает в браузере, а обычные загрузки HTTP прекрасно работают с тем же приложением, используя DownloadManager. Лучшее, что у меня есть, это то, что PAUSED_WAITING_TO_RETRY указывает на то, что «произошла какая-то сетевая ошибка». Как я могу определить, что такое сетевая ошибка?


person LarsH    schedule 02.01.2017    source источник
comment
Вы уверены, что SSL-сертификат URL-адреса выдан центром сертификации, которому Android доверяет?   -  person Prerak Sola    schedule 02.01.2017
comment
В стандартном Android компонент, который фактически выполняет загрузку похоже, использует HttpURLConnection. Вы можете собрать быстрое и грязное приложение, используя HttpURLConnection (или изменить один из моих) и посмотрите, что получится. Я согласен с Прераком, что это похоже на проблему рукопожатия SSL.   -  person CommonsWare    schedule 02.01.2017
comment
@PrerakSola: Хороший вопрос. Я посмотрю на это.   -  person LarsH    schedule 02.01.2017
comment
@PrerakSola: как в приведенном выше примере URL-адреса, так и на нашем внутреннем сервере корневым центром сертификации является AddTrust External CA Root, который указан в доверенных учетных данных моего устройства. Промежуточные ЦС разные... не уверен, что это имеет значение...   -  person LarsH    schedule 02.01.2017
comment
@CommonsWare: Хорошая идея. Я сделал это и получил CertificateException: CertPathValidatorException: Trust anchor for certification path not found. Итак... Я не уверен, что это значит, учитывая, что корневой ЦС для каждого сайта является ЦС, который находится в списке доверенных устройств.   -  person LarsH    schedule 03.01.2017
comment
Я не уверен, что это означает, учитывая, что корневой ЦС для каждого сайта является ЦС, который находится в списке доверенных устройств — как вы это определяете? Браузеры могут иметь свой собственный список CA, а не использовать какой-либо набор платформ (который, насколько мне известно, в любом случае может быть доступен только для приложений на основе Java).   -  person CommonsWare    schedule 03.01.2017
comment
@CommonsWare: как в приведенном выше URL-адресе антенны.com, так и на нашем внутреннем сервере корневым центром сертификации является AddTrust External CA Root, который указан в доверенных учетных данных моего устройства в разделе «Настройки» › «Безопасность» › «Доверенные учетные данные». Сейчас я просматриваю developer.android.com/training/articles/ чтобы попытаться выяснить, не является ли отсутствующий промежуточный ЦС причиной ошибки...   -  person LarsH    schedule 03.01.2017


Ответы (1)


Непосредственной причиной, по-видимому, является CertificateException: CertPathValidatorException: Trust anchor for certification path not found. Я узнал об этом с помощью используя HttpURLConnection напрямую (спасибо @CommonsWare за предложение) вместо DownloadManager, который давал более прямой доступ к исключениям. (Это было верно в случае с нашим внутренним сервером. Похоже, это не относится к упомянутому мной образцу URL, который, похоже, имел ту же проблему с DownloadManager ... но, возможно, та же проблема была другой) причина.)

Корневой ЦС (во всех случаях) — «AddTrust External CA Root», который присутствует в списке доверенных ЦС на устройстве в разделе «Настройки» > «Безопасность» > «Надежные учетные данные». Итак, если это доверенный корень ЦС, почему существует исключение «Якорь доверия для пути сертификации не найден»?

Похоже, что промежуточный ЦС не включен в цепочку, обслуживаемую сервером, как описано здесь. Фактически, использование openssl s_client -connect для проверки цепочки ЦС подтверждает, что промежуточные ЦС не включены. В статье документа Android предлагаются два возможных решения: включить промежуточный ЦС в цепочке серверов или явно доверять им в приложении, создав специальный TrustManager. Я надеюсь сделать первое.

person LarsH    schedule 02.01.2017
comment
P.S. Диагностика и исправление (включая промежуточные центры сертификации в обслуживаемой цепочке сертификатов) подтверждены. После внесения этого изменения на сервере проблема исчезла. - person LarsH; 03.01.2017