Skip to content

下载卡死的解决方法 #448

Description

@sparkmars321

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());
        }
    }

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions