Add base async io interfaces for wear tethering

Bug: 245971639

Change-Id: I31ccd7193409c82a0902e4ae318cc096f93f32da
diff --git a/staticlibs/device/com/android/net/module/util/async/AsyncFile.java b/staticlibs/device/com/android/net/module/util/async/AsyncFile.java
new file mode 100644
index 0000000..2a3231b
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/async/AsyncFile.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2022 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;
+
+/**
+ * Represents an EventManager-managed file with Async IO semantics.
+ *
+ * Implements level-based Asyn IO semantics. This means that:
+ *   - onReadReady() callback would keep happening as long as there's any remaining
+ *     data to read, or the user calls enableReadEvents(false)
+ *   - onWriteReady() callback would keep happening as long as there's remaining space
+ *     to write to, or the user calls enableWriteEvents(false)
+ *
+ * All operations except close() must be called on the EventManager thread.
+ *
+ * @hide
+ */
+public interface AsyncFile {
+    /**
+     * Receives notifications when file readability or writeability changes.
+     * @hide
+     */
+    public interface Listener {
+        /** Invoked after the underlying file has been closed. */
+        void onClosed(AsyncFile file);
+
+        /** Invoked while the file has readable data and read notifications are enabled. */
+        void onReadReady(AsyncFile file);
+
+        /** Invoked while the file has writeable space and write notifications are enabled. */
+        void onWriteReady(AsyncFile file);
+    }
+
+    /** Requests this file to be closed. */
+    void close();
+
+    /** Enables or disables onReadReady() events. */
+    void enableReadEvents(boolean enable);
+
+    /** Enables or disables onWriteReady() events. */
+    void enableWriteEvents(boolean enable);
+
+    /** Returns true if the input stream has reached its end, or has been closed. */
+    boolean reachedEndOfFile();
+
+    /**
+     * Reads available data from the given non-blocking file descriptor.
+     *
+     * Returns zero if there's no data to read at this moment.
+     * Returns -1 if the file has reached its end or the input stream has been closed.
+     * Otherwise returns the number of bytes read.
+     */
+    int read(byte[] buffer, int pos, int len) throws IOException;
+
+    /**
+     * Writes data into the given non-blocking file descriptor.
+     *
+     * Returns zero if there's no buffer space to write to at this moment.
+     * Otherwise returns the number of bytes written.
+     */
+    int write(byte[] buffer, int pos, int len) throws IOException;
+}
diff --git a/staticlibs/device/com/android/net/module/util/async/EventManager.java b/staticlibs/device/com/android/net/module/util/async/EventManager.java
new file mode 100644
index 0000000..4ed4a70
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/async/EventManager.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 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.Executor;
+
+/**
+ * Manages Async IO files and scheduled alarms, and executes all related callbacks
+ * in its own thread.
+ *
+ * All callbacks of AsyncFile, Alarm and EventManager will execute on EventManager's thread.
+ *
+ * Methods of this interface can be called from any thread.
+ *
+ * @hide
+ */
+public interface EventManager extends Executor {
+    /**
+     * Represents a scheduled alarm, allowing caller to attempt to cancel that alarm
+     * before it executes.
+     *
+     * @hide
+     */
+    public interface Alarm {
+        /** @hide */
+        public interface Listener {
+            void onAlarm(Alarm alarm, long elapsedTimeMs);
+            void onAlarmCancelled(Alarm alarm);
+        }
+
+        /**
+         * Attempts to cancel this alarm. Note that this request is inherently
+         * racy if executed close to the alarm's expiration time.
+         */
+        void cancel();
+    }
+
+    /**
+     * Requests EventManager to manage the given file.
+     *
+     * The file descriptors are not cloned, and EventManager takes ownership of all files passed.
+     *
+     * No event callbacks are enabled by this method.
+     */
+    AsyncFile registerFile(FileHandle fileHandle, AsyncFile.Listener listener) throws IOException;
+
+    /**
+     * Schedules Alarm with the given timeout.
+     *
+     * Timeout of zero can be used for immediate execution.
+     */
+    Alarm scheduleAlarm(long timeout, Alarm.Listener callback);
+
+    /** Schedules Runnable for immediate execution. */
+    @Override
+    void execute(Runnable callback);
+
+    /** Throws a runtime exception if the caller is not executing on this EventManager's thread. */
+    void assertInThread();
+}
diff --git a/staticlibs/device/com/android/net/module/util/async/FileHandle.java b/staticlibs/device/com/android/net/module/util/async/FileHandle.java
new file mode 100644
index 0000000..9f7942d
--- /dev/null
+++ b/staticlibs/device/com/android/net/module/util/async/FileHandle.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2022 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 android.os.ParcelFileDescriptor;
+
+import java.io.Closeable;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Represents an file descriptor or another way to access a file.
+ *
+ * @hide
+ */
+public final class FileHandle {
+    private final ParcelFileDescriptor mFd;
+    private final Closeable mCloseable;
+    private final InputStream mInputStream;
+    private final OutputStream mOutputStream;
+
+    public static FileHandle fromFileDescriptor(ParcelFileDescriptor fd) {
+        if (fd == null) {
+            throw new NullPointerException();
+        }
+        return new FileHandle(fd, null, null, null);
+    }
+
+    public static FileHandle fromBlockingStream(
+            Closeable closeable, InputStream is, OutputStream os) {
+        if (closeable == null || is == null || os == null) {
+            throw new NullPointerException();
+        }
+        return new FileHandle(null, closeable, is, os);
+    }
+
+    private FileHandle(ParcelFileDescriptor fd, Closeable closeable,
+            InputStream is, OutputStream os) {
+        mFd = fd;
+        mCloseable = closeable;
+        mInputStream = is;
+        mOutputStream = os;
+    }
+
+    ParcelFileDescriptor getFileDescriptor() {
+        return mFd;
+    }
+
+    Closeable getCloseable() {
+        return mCloseable;
+    }
+
+    InputStream getInputStream() {
+        return mInputStream;
+    }
+
+    OutputStream getOutputStream() {
+        return mOutputStream;
+    }
+}