summaryrefslogtreecommitdiff
path: root/common/device/com/android/net/module/util/FdEventsReader.java
diff options
context:
space:
mode:
Diffstat (limited to 'common/device/com/android/net/module/util/FdEventsReader.java')
-rw-r--r--common/device/com/android/net/module/util/FdEventsReader.java294
1 files changed, 0 insertions, 294 deletions
diff --git a/common/device/com/android/net/module/util/FdEventsReader.java b/common/device/com/android/net/module/util/FdEventsReader.java
deleted file mode 100644
index f88883bf..00000000
--- a/common/device/com/android/net/module/util/FdEventsReader.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2016 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;
-
-import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
-import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.net.util.SocketUtils;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.MessageQueue;
-import android.system.ErrnoException;
-import android.system.OsConstants;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-
-/**
- * This class encapsulates the mechanics of registering a file descriptor
- * with a thread's Looper and handling read events (and errors).
- *
- * Subclasses MUST implement createFd() and SHOULD override handlePacket(). They MAY override
- * onStop() and onStart().
- *
- * Subclasses can expect a call life-cycle like the following:
- *
- * [1] when a client calls start(), createFd() is called, followed by the onStart() hook if all
- * goes well. Implementations may override onStart() for additional initialization.
- *
- * [2] yield, waiting for read event or error notification:
- *
- * [a] readPacket() && handlePacket()
- *
- * [b] if (no error):
- * goto 2
- * else:
- * goto 3
- *
- * [3] when a client calls stop(), the onStop() hook is called (unless already stopped or never
- * started). Implementations may override onStop() for additional cleanup.
- *
- * The packet receive buffer is recycled on every read call, so subclasses
- * should make any copies they would like inside their handlePacket()
- * implementation.
- *
- * All public methods MUST only be called from the same thread with which
- * the Handler constructor argument is associated.
- *
- * @param <BufferType> the type of the buffer used to read data.
- */
-public abstract class FdEventsReader<BufferType> {
- private static final String TAG = FdEventsReader.class.getSimpleName();
- private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
- private static final int UNREGISTER_THIS_FD = 0;
-
- @NonNull
- private final Handler mHandler;
- @NonNull
- private final MessageQueue mQueue;
- @NonNull
- private final BufferType mBuffer;
- @Nullable
- private FileDescriptor mFd;
- private long mPacketsReceived;
-
- protected static void closeFd(FileDescriptor fd) {
- try {
- SocketUtils.closeSocket(fd);
- } catch (IOException ignored) {
- }
- }
-
- protected FdEventsReader(@NonNull Handler h, @NonNull BufferType buffer) {
- mHandler = h;
- mQueue = mHandler.getLooper().getQueue();
- mBuffer = buffer;
- }
-
- @VisibleForTesting
- @NonNull
- protected MessageQueue getMessageQueue() {
- return mQueue;
- }
-
- /** Start this FdEventsReader. */
- public boolean start() {
- if (!onCorrectThread()) {
- throw new IllegalStateException("start() called from off-thread");
- }
-
- return createAndRegisterFd();
- }
-
- /** Stop this FdEventsReader and destroy the file descriptor. */
- public void stop() {
- if (!onCorrectThread()) {
- throw new IllegalStateException("stop() called from off-thread");
- }
-
- unregisterAndDestroyFd();
- }
-
- @NonNull
- public Handler getHandler() {
- return mHandler;
- }
-
- protected abstract int recvBufSize(@NonNull BufferType buffer);
-
- /** Returns the size of the receive buffer. */
- public int recvBufSize() {
- return recvBufSize(mBuffer);
- }
-
- /**
- * Get the number of successful calls to {@link #readPacket(FileDescriptor, Object)}.
- *
- * <p>A call was successful if {@link #readPacket(FileDescriptor, Object)} returned a value > 0.
- */
- public final long numPacketsReceived() {
- return mPacketsReceived;
- }
-
- /**
- * Subclasses MUST create the listening socket here, including setting all desired socket
- * options, interface or address/port binding, etc. The socket MUST be created nonblocking.
- */
- @Nullable
- protected abstract FileDescriptor createFd();
-
- /**
- * Implementations MUST return the bytes read or throw an Exception.
- *
- * <p>The caller may throw a {@link ErrnoException} with {@link OsConstants#EAGAIN} or
- * {@link OsConstants#EINTR}, in which case {@link FdEventsReader} will ignore the buffer
- * contents and respectively wait for further input or retry the read immediately. For all other
- * exceptions, the {@link FdEventsReader} will be stopped with no more interactions with this
- * method.
- */
- protected abstract int readPacket(@NonNull FileDescriptor fd, @NonNull BufferType buffer)
- throws Exception;
-
- /**
- * Called by the main loop for every packet. Any desired copies of
- * |recvbuf| should be made in here, as the underlying byte array is
- * reused across all reads.
- */
- protected void handlePacket(@NonNull BufferType recvbuf, int length) {}
-
- /**
- * Called by the subclasses of FdEventsReader, decide whether it should stop reading packet or
- * just ignore the specific error other than EAGAIN or EINTR.
- *
- * @return {@code true} if this FdEventsReader should stop reading from the socket.
- * {@code false} if it should continue.
- */
- protected boolean handleReadError(@NonNull ErrnoException e) {
- logError("readPacket error: ", e);
- return true; // by default, stop reading on any error.
- }
-
- /**
- * Called by the subclasses of FdEventsReader, decide whether it should stop reading from the
- * socket or process the packet and continue to read upon receiving a zero-length packet.
- *
- * @return {@code true} if this FdEventsReader should process the zero-length packet.
- * {@code false} if it should stop reading from the socket.
- */
- protected boolean shouldProcessZeroLengthPacket() {
- return false; // by default, stop reading upon receiving zero-length packet.
- }
-
- /**
- * Called by the main loop to log errors. In some cases |e| may be null.
- */
- protected void logError(@NonNull String msg, @Nullable Exception e) {}
-
- /**
- * Called by start(), if successful, just prior to returning.
- */
- protected void onStart() {}
-
- /**
- * Called by stop() just prior to returning.
- */
- protected void onStop() {}
-
- private boolean createAndRegisterFd() {
- if (mFd != null) return true;
-
- try {
- mFd = createFd();
- } catch (Exception e) {
- logError("Failed to create socket: ", e);
- closeFd(mFd);
- mFd = null;
- }
-
- if (mFd == null) return false;
-
- getMessageQueue().addOnFileDescriptorEventListener(
- mFd,
- FD_EVENTS,
- (fd, events) -> {
- // Always call handleInput() so read/recvfrom are given
- // a proper chance to encounter a meaningful errno and
- // perhaps log a useful error message.
- if (!isRunning() || !handleInput()) {
- unregisterAndDestroyFd();
- return UNREGISTER_THIS_FD;
- }
- return FD_EVENTS;
- });
- onStart();
- return true;
- }
-
- protected boolean isRunning() {
- return (mFd != null) && mFd.valid();
- }
-
- // Keep trying to read until we get EAGAIN/EWOULDBLOCK or some fatal error.
- private boolean handleInput() {
- while (isRunning()) {
- final int bytesRead;
-
- try {
- bytesRead = readPacket(mFd, mBuffer);
- if (bytesRead == 0 && !shouldProcessZeroLengthPacket()) {
- if (isRunning()) logError("Socket closed, exiting", null);
- break;
- }
- mPacketsReceived++;
- } catch (ErrnoException e) {
- if (e.errno == OsConstants.EAGAIN) {
- // We've read everything there is to read this time around.
- return true;
- } else if (e.errno == OsConstants.EINTR) {
- continue;
- } else {
- if (!isRunning()) break;
- final boolean shouldStop = handleReadError(e);
- if (shouldStop) break;
- continue;
- }
- } catch (Exception e) {
- if (isRunning()) logError("readPacket error: ", e);
- break;
- }
-
- try {
- handlePacket(mBuffer, bytesRead);
- } catch (Exception e) {
- logError("handlePacket error: ", e);
- Log.wtf(TAG, "Error handling packet", e);
- }
- }
-
- return false;
- }
-
- private void unregisterAndDestroyFd() {
- if (mFd == null) return;
-
- getMessageQueue().removeOnFileDescriptorEventListener(mFd);
- closeFd(mFd);
- mFd = null;
- onStop();
- }
-
- private boolean onCorrectThread() {
- return (mHandler.getLooper() == Looper.myLooper());
- }
-}