lingochamp / okdownload

A Reliable, Flexible, Fast and Powerful download engine.
Apache License 2.0
5.19k stars 776 forks source link

下载卡死的解决方法 #448

Open sparkmars321 opened 3 years ago

sparkmars321 commented 3 years ago

OkDownload Version

v1.0.7

Problem Describe

下载稍大文件就会发生下载进度卡死的问题,导致不会回调taskEnd;将targetSdkVersion改为29,在Android 10上复现概率不低。

Log

日志如下,只摘了这一条: The current offset on block-info isn't update correct, 2920 != 10006923 on 1.

Reason

MultiPointOutputStream 的 flushProcess 方法没有catch住其他exception,导致刷新下载进度时 syncFuture 线程异常退出 ,使其他下载线程无法同步下载状态而陷入等待状态,导致下载进度卡死。

Solution

修改 MultiPointOutputStream 类的 close 和 flushProcess 方法。该解决方法只保证在下载出错时会回调taskEnd,因此只解决了下载卡死的问题,下载出错问题暂未解决,待后续研究。 具体修改如下:

// close 方法要保证 outputStreamMap 和 noSyncLengthMap 的元素个数相等,只修改这里没有作用
synchronized void close(int blockIndex) throws IOException {
        final DownloadOutputStream outputStream = outputStreamMap.get(blockIndex);
        if (outputStream != null) {
            outputStream.close();
            // outputStreamMap.remove(blockIndex);
            synchronized (noSyncLengthMap) {
                // make sure the length of noSyncLengthMap is equal to outputStreamMap
                outputStreamMap.remove(blockIndex);
                noSyncLengthMap.remove(blockIndex);
            }
            Util.d(TAG, "OutputStream close task[" + task.getId() + "] block[" + blockIndex + "]");
        }
    }

// flushProcess 增加 catch 块
void flushProcess() throws IOException {
        boolean success;
        final int size;
        synchronized (noSyncLengthMap) {
            // make sure the length of noSyncLengthMap is equal to outputStreamMap
            size = noSyncLengthMap.size();
        }
        final SparseArray<Long> increaseLengthMap = new SparseArray<>(size);
        try {
            for (int i = 0; i < size; i++) {
                final int blockIndex = outputStreamMap.keyAt(i);
                // because we get no sync length value before flush and sync,
                // so the length only possible less than or equal to the real persist
                // length.
                final long noSyncLength = noSyncLengthMap.get(blockIndex).get();
                if (noSyncLength > 0) {
                    increaseLengthMap.put(blockIndex, noSyncLength);
                    final DownloadOutputStream outputStream = outputStreamMap
                            .get(blockIndex);
                    outputStream.flushAndSync();
                }
            }
            success = true;
        } catch (IOException ex) {
            Util.w(TAG, "OutputStream flush and sync data to filesystem failed " + ex);
            success = false;
        } catch (Exception ex) { // 增加这部分,catch住其他类型exception
            Util.w(TAG, "OutputStream flush and sync data to filesystem failed " + ex);
            success = false;
        }

        if (success) {
            final int increaseLengthSize = increaseLengthMap.size();
            long allIncreaseLength = 0;
            for (int i = 0; i < increaseLengthSize; i++) {
                final int blockIndex = increaseLengthMap.keyAt(i);
                final long noSyncLength = increaseLengthMap.valueAt(i);
                store.onSyncToFilesystemSuccess(info, blockIndex, noSyncLength);
                allIncreaseLength += noSyncLength;
                noSyncLengthMap.get(blockIndex).addAndGet(-noSyncLength);
                Util.d(TAG, "OutputStream sync success (" + task.getId() + ") "
                        + "block(" + blockIndex + ") " + " syncLength(" + noSyncLength + ")"
                        + " currentOffset(" + info.getBlock(blockIndex).getCurrentOffset()
                        + ")");
            }
            allNoSyncLength.addAndGet(-allIncreaseLength);
            lastSyncTimestamp.set(SystemClock.uptimeMillis());
        }
    }
NBXXF commented 3 years ago

遇到一样的问题

xuyang123 commented 3 years ago

我也遇到了, 下着下着就没回调了

Haoxiqiang commented 3 years ago

maybe you could try the pr: https://github.com/lingochamp/okdownload/pull/425