Add wear tethering util classes
Bug: 245971639
Change-Id: I97655ece334ca93743896e89e12f8501f4e24776
diff --git a/staticlibs/tests/unit/Android.bp b/staticlibs/tests/unit/Android.bp
index 21e8c64..6e223bd 100644
--- a/staticlibs/tests/unit/Android.bp
+++ b/staticlibs/tests/unit/Android.bp
@@ -12,14 +12,15 @@
min_sdk_version: "29",
defaults: ["framework-connectivity-test-defaults"],
static_libs: [
- "net-utils-framework-common",
- "net-utils-device-common-ip",
"androidx.test.rules",
"mockito-target-extended-minus-junit4",
- "net-utils-device-common",
- "net-utils-device-common-bpf",
- "net-tests-utils",
"netd-client",
+ "net-tests-utils",
+ "net-utils-framework-common",
+ "net-utils-device-common",
+ "net-utils-device-common-async",
+ "net-utils-device-common-bpf",
+ "net-utils-device-common-ip",
],
libs: [
"android.test.runner",
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/async/CircularByteBufferTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/async/CircularByteBufferTest.java
new file mode 100644
index 0000000..01abee2
--- /dev/null
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/async/CircularByteBufferTest.java
@@ -0,0 +1,267 @@
+/*
+ * 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 static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.fail;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class CircularByteBufferTest {
+ @Test
+ public void writeBytes() {
+ final int capacity = 23;
+ CircularByteBuffer buffer = new CircularByteBuffer(capacity);
+ assertEquals(0, buffer.size());
+ assertEquals(0, buffer.getDirectReadSize());
+ assertEquals(capacity, buffer.freeSize());
+ assertEquals(capacity, buffer.getDirectWriteSize());
+
+ final byte[] writeBuffer = new byte[15];
+ buffer.writeBytes(writeBuffer, 0, writeBuffer.length);
+
+ assertEquals(writeBuffer.length, buffer.size());
+ assertEquals(writeBuffer.length, buffer.getDirectReadSize());
+ assertEquals(capacity - writeBuffer.length, buffer.freeSize());
+ assertEquals(capacity - writeBuffer.length, buffer.getDirectWriteSize());
+
+ buffer.clear();
+ assertEquals(0, buffer.size());
+ assertEquals(0, buffer.getDirectReadSize());
+ assertEquals(capacity, buffer.freeSize());
+ assertEquals(capacity, buffer.getDirectWriteSize());
+ }
+
+ @Test
+ public void writeBytes_withRollover() {
+ doTestReadWriteWithRollover(new BufferAccessor(false, false));
+ }
+
+ @Test
+ public void writeBytes_withFullBuffer() {
+ doTestReadWriteWithFullBuffer(new BufferAccessor(false, false));
+ }
+
+ @Test
+ public void directWriteBytes_withRollover() {
+ doTestReadWriteWithRollover(new BufferAccessor(true, true));
+ }
+
+ @Test
+ public void directWriteBytes_withFullBuffer() {
+ doTestReadWriteWithFullBuffer(new BufferAccessor(true, true));
+ }
+
+ private void doTestReadWriteWithFullBuffer(BufferAccessor accessor) {
+ CircularByteBuffer buffer = doTestReadWrite(accessor, 20, 5, 4);
+
+ assertEquals(0, buffer.size());
+ assertEquals(20, buffer.freeSize());
+ }
+
+ private void doTestReadWriteWithRollover(BufferAccessor accessor) {
+ // All buffer sizes are prime numbers to ensure that some read or write
+ // operations will roll over the end of the internal buffer.
+ CircularByteBuffer buffer = doTestReadWrite(accessor, 31, 13, 7);
+
+ assertNotEquals(0, buffer.size());
+ }
+
+ private CircularByteBuffer doTestReadWrite(BufferAccessor accessor,
+ final int capacity, final int writeLen, final int readLen) {
+ CircularByteBuffer buffer = new CircularByteBuffer(capacity);
+
+ final byte[] writeBuffer = new byte[writeLen + 2];
+ final byte[] peekBuffer = new byte[readLen + 2];
+ final byte[] readBuffer = new byte[readLen + 2];
+
+ final int numIterations = 1011;
+ final int maxRemaining = readLen - 1;
+
+ int currentWriteSymbol = 0;
+ int expectedReadSymbol = 0;
+ int expectedSize = 0;
+ int totalWritten = 0;
+ int totalRead = 0;
+
+ for (int i = 0; i < numIterations; i++) {
+ // Fill in with write buffers as much as possible.
+ while (buffer.freeSize() >= writeLen) {
+ currentWriteSymbol = fillTestBytes(writeBuffer, 1, writeLen, currentWriteSymbol);
+ accessor.writeBytes(buffer, writeBuffer, 1, writeLen);
+
+ expectedSize += writeLen;
+ totalWritten += writeLen;
+ assertEquals(expectedSize, buffer.size());
+ assertEquals(capacity - expectedSize, buffer.freeSize());
+ }
+
+ // Keep reading into read buffers while there's still data.
+ while (buffer.size() >= readLen) {
+ peekBuffer[1] = 0;
+ peekBuffer[2] = 0;
+ buffer.peekBytes(2, peekBuffer, 3, readLen - 2);
+ assertEquals(0, peekBuffer[1]);
+ assertEquals(0, peekBuffer[2]);
+
+ peekBuffer[2] = buffer.peek(1);
+
+ accessor.readBytes(buffer, readBuffer, 1, readLen);
+ peekBuffer[1] = readBuffer[1];
+
+ expectedReadSymbol = checkTestBytes(
+ readBuffer, 1, readLen, expectedReadSymbol, totalRead);
+
+ assertArrayEquals(peekBuffer, readBuffer);
+
+ expectedSize -= readLen;
+ totalRead += readLen;
+ assertEquals(expectedSize, buffer.size());
+ assertEquals(capacity - expectedSize, buffer.freeSize());
+ }
+
+ if (buffer.size() > maxRemaining) {
+ fail("Too much data remaining: " + buffer.size());
+ }
+ }
+
+ final int maxWritten = capacity * numIterations;
+ final int minWritten = maxWritten / 2;
+ if (totalWritten < minWritten || totalWritten > maxWritten
+ || (totalWritten - totalRead) > maxRemaining) {
+ fail("Unexpected counts: read=" + totalRead + ", written=" + totalWritten
+ + ", minWritten=" + minWritten + ", maxWritten=" + maxWritten);
+ }
+
+ return buffer;
+ }
+
+ @Test
+ public void readBytes_overflow() {
+ CircularByteBuffer buffer = new CircularByteBuffer(23);
+
+ final byte[] dataBuffer = new byte[15];
+ buffer.writeBytes(dataBuffer, 0, dataBuffer.length - 2);
+
+ try {
+ buffer.readBytes(dataBuffer, 0, dataBuffer.length);
+ assertTrue(false);
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ assertEquals(13, buffer.size());
+ assertEquals(10, buffer.freeSize());
+ }
+
+ @Test
+ public void writeBytes_overflow() {
+ CircularByteBuffer buffer = new CircularByteBuffer(23);
+
+ final byte[] dataBuffer = new byte[15];
+ buffer.writeBytes(dataBuffer, 0, dataBuffer.length);
+
+ try {
+ buffer.writeBytes(dataBuffer, 0, dataBuffer.length);
+ assertTrue(false);
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ assertEquals(15, buffer.size());
+ assertEquals(8, buffer.freeSize());
+ }
+
+ private static int fillTestBytes(byte[] buffer, int pos, int len, int startValue) {
+ for (int i = 0; i < len; i++) {
+ buffer[pos + i] = (byte) (startValue & 0xFF);
+ startValue = (startValue + 1) % 256;
+ }
+ return startValue;
+ }
+
+ private static int checkTestBytes(
+ byte[] buffer, int pos, int len, int startValue, int totalRead) {
+ for (int i = 0; i < len; i++) {
+ byte expectedValue = (byte) (startValue & 0xFF);
+ if (expectedValue != buffer[pos + i]) {
+ fail("Unexpected byte=" + (((int) buffer[pos + i]) & 0xFF)
+ + ", expected=" + (((int) expectedValue) & 0xFF)
+ + ", pos=" + (totalRead + i));
+ }
+ startValue = (startValue + 1) % 256;
+ }
+ return startValue;
+ }
+
+ private static final class BufferAccessor {
+ private final boolean mDirectRead;
+ private final boolean mDirectWrite;
+
+ BufferAccessor(boolean directRead, boolean directWrite) {
+ mDirectRead = directRead;
+ mDirectWrite = directWrite;
+ }
+
+ void writeBytes(CircularByteBuffer buffer, byte[] src, int pos, int len) {
+ if (mDirectWrite) {
+ while (len > 0) {
+ if (buffer.getDirectWriteSize() == 0) {
+ fail("Direct write size is zero: free=" + buffer.freeSize()
+ + ", size=" + buffer.size());
+ }
+ int copyLen = Math.min(len, buffer.getDirectWriteSize());
+ System.arraycopy(src, pos, buffer.getDirectWriteBuffer(),
+ buffer.getDirectWritePos(), copyLen);
+ buffer.accountForDirectWrite(copyLen);
+ len -= copyLen;
+ pos += copyLen;
+ }
+ } else {
+ buffer.writeBytes(src, pos, len);
+ }
+ }
+
+ void readBytes(CircularByteBuffer buffer, byte[] dst, int pos, int len) {
+ if (mDirectRead) {
+ while (len > 0) {
+ if (buffer.getDirectReadSize() == 0) {
+ fail("Direct read size is zero: free=" + buffer.freeSize()
+ + ", size=" + buffer.size());
+ }
+ int copyLen = Math.min(len, buffer.getDirectReadSize());
+ System.arraycopy(
+ buffer.getDirectReadBuffer(), buffer.getDirectReadPos(), dst, pos, copyLen);
+ buffer.accountForDirectRead(copyLen);
+ len -= copyLen;
+ pos += copyLen;
+ }
+ } else {
+ buffer.readBytes(dst, pos, len);
+ }
+ }
+ }
+}