summaryrefslogtreecommitdiff
path: root/common/device/com/android/net/module/util/async/BufferedFile.java
diff options
context:
space:
mode:
Diffstat (limited to 'common/device/com/android/net/module/util/async/BufferedFile.java')
-rw-r--r--common/device/com/android/net/module/util/async/BufferedFile.java292
1 files changed, 0 insertions, 292 deletions
diff --git a/common/device/com/android/net/module/util/async/BufferedFile.java b/common/device/com/android/net/module/util/async/BufferedFile.java
deleted file mode 100644
index bb5736b0..00000000
--- a/common/device/com/android/net/module/util/async/BufferedFile.java
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.net.module.util.async;
-
-import java.io.IOException;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * Buffers inbound and outbound file data within given strict limits.
- *
- * Automatically manages all readability and writeability events in EventManager:
- * - When read buffer has more space - asks EventManager to notify on more data
- * - When write buffer has more space - asks the user to provide more data
- * - When underlying file cannot accept more data - registers EventManager callback
- *
- * @hide
- */
-public final class BufferedFile implements AsyncFile.Listener {
- /**
- * Receives notifications when new data or output space is available.
- * @hide
- */
- public interface Listener {
- /** Invoked after the underlying file has been closed. */
- void onBufferedFileClosed();
-
- /** Invoked when there's new data in the inbound buffer. */
- void onBufferedFileInboundData(int readByteCount);
-
- /** Notifies on data being flushed from output buffer. */
- void onBufferedFileOutboundSpace();
-
- /** Notifies on unrecoverable error in file access. */
- void onBufferedFileIoError(String message);
- }
-
- private final Listener mListener;
- private final EventManager mEventManager;
- private AsyncFile mFile;
-
- private final CircularByteBuffer mInboundBuffer;
- private final AtomicLong mTotalBytesRead = new AtomicLong();
- private boolean mIsReadingShutdown;
-
- private final CircularByteBuffer mOutboundBuffer;
- private final AtomicLong mTotalBytesWritten = new AtomicLong();
-
- /** Creates BufferedFile based on the given file descriptor. */
- public static BufferedFile create(
- EventManager eventManager,
- FileHandle fileHandle,
- Listener listener,
- int inboundBufferSize,
- int outboundBufferSize) throws IOException {
- if (fileHandle == null) {
- throw new NullPointerException();
- }
- BufferedFile file = new BufferedFile(
- eventManager, listener, inboundBufferSize, outboundBufferSize);
- file.mFile = eventManager.registerFile(fileHandle, file);
- return file;
- }
-
- private BufferedFile(
- EventManager eventManager,
- Listener listener,
- int inboundBufferSize,
- int outboundBufferSize) {
- if (eventManager == null || listener == null) {
- throw new NullPointerException();
- }
- mEventManager = eventManager;
- mListener = listener;
-
- mInboundBuffer = new CircularByteBuffer(inboundBufferSize);
- mOutboundBuffer = new CircularByteBuffer(outboundBufferSize);
- }
-
- /** Requests this file to be closed. */
- public void close() {
- mFile.close();
- }
-
- @Override
- public void onClosed(AsyncFile file) {
- mListener.onBufferedFileClosed();
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // READ PATH
- ///////////////////////////////////////////////////////////////////////////
-
- /** Returns buffer that is automatically filled with inbound data. */
- public ReadableByteBuffer getInboundBuffer() {
- return mInboundBuffer;
- }
-
- public int getInboundBufferFreeSizeForTest() {
- return mInboundBuffer.freeSize();
- }
-
- /** Permanently disables reading of this file, and clears all buffered data. */
- public void shutdownReading() {
- mIsReadingShutdown = true;
- mInboundBuffer.clear();
- mFile.enableReadEvents(false);
- }
-
- /** Returns true after shutdownReading() has been called. */
- public boolean isReadingShutdown() {
- return mIsReadingShutdown;
- }
-
- /** Starts or resumes async read operations on this file. */
- public void continueReading() {
- if (!mIsReadingShutdown && mInboundBuffer.freeSize() > 0) {
- mFile.enableReadEvents(true);
- }
- }
-
- @Override
- public void onReadReady(AsyncFile file) {
- if (mIsReadingShutdown) {
- return;
- }
-
- int readByteCount;
- try {
- readByteCount = bufferInputData();
- } catch (IOException e) {
- mListener.onBufferedFileIoError("IOException while reading: " + e.toString());
- return;
- }
-
- if (readByteCount > 0) {
- mListener.onBufferedFileInboundData(readByteCount);
- }
-
- continueReading();
- }
-
- private int bufferInputData() throws IOException {
- int totalReadCount = 0;
- while (true) {
- final int maxReadCount = mInboundBuffer.getDirectWriteSize();
- if (maxReadCount == 0) {
- mFile.enableReadEvents(false);
- break;
- }
-
- final int bufferOffset = mInboundBuffer.getDirectWritePos();
- final byte[] buffer = mInboundBuffer.getDirectWriteBuffer();
-
- final int readCount = mFile.read(buffer, bufferOffset, maxReadCount);
- if (readCount <= 0) {
- break;
- }
-
- mInboundBuffer.accountForDirectWrite(readCount);
- totalReadCount += readCount;
- }
-
- mTotalBytesRead.addAndGet(totalReadCount);
- return totalReadCount;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // WRITE PATH
- ///////////////////////////////////////////////////////////////////////////
-
- /** Returns the number of bytes currently buffered for output. */
- public int getOutboundBufferSize() {
- return mOutboundBuffer.size();
- }
-
- /** Returns the number of bytes currently available for buffering for output. */
- public int getOutboundBufferFreeSize() {
- return mOutboundBuffer.freeSize();
- }
-
- /**
- * Queues the given data for output.
- * Throws runtime exception if there is not enough space.
- */
- public boolean enqueueOutboundData(byte[] data, int pos, int len) {
- return enqueueOutboundData(data, pos, len, null, 0, 0);
- }
-
- /**
- * Queues data1, then data2 for output.
- * Throws runtime exception if there is not enough space.
- */
- public boolean enqueueOutboundData(
- byte[] data1, int pos1, int len1,
- byte[] buffer2, int pos2, int len2) {
- Assertions.throwsIfOutOfBounds(data1, pos1, len1);
- Assertions.throwsIfOutOfBounds(buffer2, pos2, len2);
-
- final int totalLen = len1 + len2;
-
- if (totalLen > mOutboundBuffer.freeSize()) {
- flushOutboundBuffer();
-
- if (totalLen > mOutboundBuffer.freeSize()) {
- return false;
- }
- }
-
- mOutboundBuffer.writeBytes(data1, pos1, len1);
-
- if (buffer2 != null) {
- mOutboundBuffer.writeBytes(buffer2, pos2, len2);
- }
-
- flushOutboundBuffer();
-
- return true;
- }
-
- private void flushOutboundBuffer() {
- try {
- while (mOutboundBuffer.getDirectReadSize() > 0) {
- final int maxReadSize = mOutboundBuffer.getDirectReadSize();
- final int writeCount = mFile.write(
- mOutboundBuffer.getDirectReadBuffer(),
- mOutboundBuffer.getDirectReadPos(),
- maxReadSize);
-
- if (writeCount == 0) {
- mFile.enableWriteEvents(true);
- break;
- }
-
- if (writeCount > maxReadSize) {
- throw new IllegalArgumentException(
- "Write count " + writeCount + " above max " + maxReadSize);
- }
-
- mOutboundBuffer.accountForDirectRead(writeCount);
- }
- } catch (IOException e) {
- scheduleOnIoError("IOException while writing: " + e.toString());
- }
- }
-
- private void scheduleOnIoError(String message) {
- mEventManager.execute(() -> {
- mListener.onBufferedFileIoError(message);
- });
- }
-
- @Override
- public void onWriteReady(AsyncFile file) {
- mFile.enableWriteEvents(false);
- flushOutboundBuffer();
- mListener.onBufferedFileOutboundSpace();
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("file={");
- sb.append(mFile);
- sb.append("}");
- if (mIsReadingShutdown) {
- sb.append(", readingShutdown");
- }
- sb.append("}, inboundBuffer={");
- sb.append(mInboundBuffer);
- sb.append("}, outboundBuffer={");
- sb.append(mOutboundBuffer);
- sb.append("}, totalBytesRead=");
- sb.append(mTotalBytesRead);
- sb.append(", totalBytesWritten=");
- sb.append(mTotalBytesWritten);
- return sb.toString();
- }
-}