From 9d0352210d3bc1933d84f1d855004edc9b20345a Mon Sep 17 00:00:00 2001 From: Jeremy Meyer Date: Fri, 1 Oct 2021 18:29:33 +0000 Subject: [PATCH] Have AssetFileDescriptor.AutoCloseInputStream use pread Previously two AssetFileDescriptors pointing to the same file could be using the same underlying file descriptor and reading from both would provide unexpected results since they would both modify the file offset in the kernel data structure. Test: Added testTwoFileDescriptorsWorkIndependently() to android.content.res.cts.AssetFileDescriptor_AutoCloseInputStreamTest Test: atest AssetFileDescriptor_AutoCloseInputStreamTest Fix: 168310122 Change-Id: I6c9f9d1de193992736bf39516ab9364af34a47cd --- .../content/res/AssetFileDescriptor.java | 73 ++++++++++--------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java index e93ec00468f5d..c622ca461c050 100644 --- a/core/java/android/content/res/AssetFileDescriptor.java +++ b/core/java/android/content/res/AssetFileDescriptor.java @@ -21,6 +21,8 @@ import android.os.Bundle; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; +import android.system.ErrnoException; +import android.system.Os; import java.io.Closeable; import java.io.FileDescriptor; @@ -203,19 +205,22 @@ public class AssetFileDescriptor implements Parcelable, Closeable { */ public static class AutoCloseInputStream extends ParcelFileDescriptor.AutoCloseInputStream { - private long mRemaining; + private long mTotalSize; + private final long mFileOffset; + private long mOffset; public AutoCloseInputStream(AssetFileDescriptor fd) throws IOException { super(fd.getParcelFileDescriptor()); - super.skip(fd.getStartOffset()); - mRemaining = (int)fd.getLength(); + mTotalSize = fd.getLength(); + mFileOffset = fd.getStartOffset(); } @Override public int available() throws IOException { - return mRemaining >= 0 - ? (mRemaining < 0x7fffffff ? (int)mRemaining : 0x7fffffff) - : super.available(); + long available = mTotalSize - mOffset; + return available >= 0 + ? (available < 0x7fffffff ? (int) available : 0x7fffffff) + : 0; } @Override @@ -227,15 +232,21 @@ public class AssetFileDescriptor implements Parcelable, Closeable { @Override public int read(byte[] buffer, int offset, int count) throws IOException { - if (mRemaining >= 0) { - if (mRemaining == 0) return -1; - if (count > mRemaining) count = (int)mRemaining; - int res = super.read(buffer, offset, count); - if (res >= 0) mRemaining -= res; - return res; + int available = available(); + if (available <= 0) { + return -1; + } + + if (count > available) count = available; + try { + int res = Os.pread(getFD(), buffer, offset, count, mFileOffset + mOffset); + // pread returns 0 at end of file, while java's InputStream interface requires -1 + if (res == 0) res = -1; + if (res >= 0) mOffset += res; + return res; + } catch (ErrnoException e) { + throw new IOException(e); } - - return super.read(buffer, offset, count); } @Override @@ -245,41 +256,31 @@ public class AssetFileDescriptor implements Parcelable, Closeable { @Override public long skip(long count) throws IOException { - if (mRemaining >= 0) { - if (mRemaining == 0) return -1; - if (count > mRemaining) count = mRemaining; - long res = super.skip(count); - if (res >= 0) mRemaining -= res; - return res; + int available = available(); + if (available <= 0) { + return -1; } - - return super.skip(count); + + if (count > available) count = available; + mOffset += count; + return count; } @Override public void mark(int readlimit) { - if (mRemaining >= 0) { - // Not supported. - return; - } - super.mark(readlimit); + // Not supported. + return; } @Override public boolean markSupported() { - if (mRemaining >= 0) { - return false; - } - return super.markSupported(); + return false; } @Override public synchronized void reset() throws IOException { - if (mRemaining >= 0) { - // Not supported. - return; - } - super.reset(); + // Not supported. + return; } }