To pass large amounts of data over binder, we create a pipe, then pass the read end of the pipe over the binder as a ParcelFileDescriptor
, and start a thread to write data to the write end of the pipe. It basically looks like this:
public void writeToParcel(Parcel out, int flags) {
ParcelFileDescriptor[] fds;
try {
fds = ParcelFileDescriptor.createPipe();
} catch (IOException e) {
throw new RuntimeException(e);
}
out.writeParcelable(fds[0], 0);
byte[] bytes = ...; // Marshall object data to bytes
write(bytes, fds[1]); // Starts a thread to write the data
}
The receiving end reads the data from the read end of the pipe. It looks like this:
ParcelFileDescriptor readFd = in.readFileDescriptor();
FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(readFd);
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] b = new byte[16 * 1024];
int n;
try {
while ((n = fis.read(b)) != -1) {
out.write(b, 0, n);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
Log.i(TAG, "Closing read file descriptor..."); // I see this
fis.close();
Log.i(TAG, "Closed read file descriptor"); // And I see this
} catch (IOException e) {
e.printStackTrace();
}
}
This works, but when strictmode is enabled, we crash with this:
01-03 14:26:48.099 E/StrictMode(25346): A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks.
01-03 14:26:48.099 E/StrictMode(25346): java.lang.Throwable: Explicit termination method 'close' not called
01-03 14:26:48.099 E/StrictMode(25346): at dalvik.system.CloseGuard.open(CloseGuard.java:223)
01-03 14:26:48.099 E/StrictMode(25346): at android.os.ParcelFileDescriptor.<init>(ParcelFileDescriptor.java:192)
01-03 14:26:48.099 E/StrictMode(25346): at android.os.ParcelFileDescriptor.<init>(ParcelFileDescriptor.java:181)
01-03 14:26:48.099 E/StrictMode(25346): at android.os.ParcelFileDescriptor.createPipe(ParcelFileDescriptor.java:425)
01-03 14:26:48.099 E/StrictMode(25346): at com.clover.sdk.FdParcelable.writeToParcel(FdParcelable.java:118)
Line 118 is the creation of the pipe (ParcelFileDescriptor.createPipe()).
So it seems the sender needs to close the read end as well as the write end. My problem is that I don't know when I can close the read end, as I don't know when the reader will finish reading.
What am I missing?