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
This commit is contained in:
Jeremy Meyer
2021-10-01 18:29:33 +00:00
parent 00b3b61f5a
commit 9d0352210d

View File

@@ -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;
}
}