Передача чтения FD parcelable: когда закрыть? - PullRequest
0 голосов
/ 03 января 2019

Чтобы передать большие объемы данных через связыватель, мы создаем канал, затем передаем конец чтения канала над связывателем как ParcelFileDescriptor и запускаем поток для записи данных в конец записи канала.В основном это выглядит так:

  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
  }

Принимающая сторона считывает данные с конца чтения канала.Выглядит это так:

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

Это работает, но когда строгий режим включен, мы терпим крах с этим:

 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) 

Строка 118 - это создание канала (ParcelFileDescriptor.createPipe ()).

Таким образом, кажется, что отправителю необходимо закрыть конец чтения, а также конец записи.Моя проблема в том, что я не знаю, когда смогу закрыть конец чтения, так как я не знаю, когда читатель закончит читать.

Чего мне не хватает?

1 Ответ

0 голосов
/ 03 января 2019
  1. Как только вы закончите запись, закройте выходной поток.

  2. Потребитель всегда несет ответственность за закрытие своего входного потока, как только онзакончил читать.Это не ваша ответственность (если только вы не выступаете в роли потребителя).

То, что вы описываете, аналогично открытию FileOutputStream (я использую API)и ожидая, что среда выполнения закроет его для меня только потому, что я не закрыл его явно, когда закончил его использовать.

Так что отправьте FD в Parcel, и тот, кто его использует, отвечает за его закрытие.Они могут использовать что-то вроде этого:

val fd = parcel.readFileDescriptor()
val input = ParcelFileDescriptor.AutoCloseInputStream(fd)
// Use input. When #close() is called it will also close the FD.

См .: https://developer.android.com/reference/android/os/ParcelFileDescriptor.AutoCloseInputStream

Вы можете скрыть эту реализацию в своей клиентской библиотеке SDK.В любом случае, документируйте это хорошо для потребителей.

...