Move bit utility methods to a new BitUtils class.
In particular this moves NetworkCapabilies#
appendStringRepresentationOfBitMaskToStringBuilder to this
class. It also moves some other NetworkCapabilitiesUtils
methods that are better homed in this new class.
Test: new test in this patch
Change-Id: I16374d7ca1da92052bb814bde796602d62f5c42e
diff --git a/staticlibs/framework/com/android/net/module/util/BitUtils.java b/staticlibs/framework/com/android/net/module/util/BitUtils.java
new file mode 100644
index 0000000..2b32e86
--- /dev/null
+++ b/staticlibs/framework/com/android/net/module/util/BitUtils.java
@@ -0,0 +1,110 @@
+/*
+ * 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;
+
+import android.annotation.NonNull;
+
+/**
+ * @hide
+ */
+public class BitUtils {
+ /**
+ * Unpacks long value into an array of bits.
+ */
+ public static int[] unpackBits(long val) {
+ int size = Long.bitCount(val);
+ int[] result = new int[size];
+ int index = 0;
+ int bitPos = 0;
+ while (val != 0) {
+ if ((val & 1) == 1) result[index++] = bitPos;
+ val = val >>> 1;
+ bitPos++;
+ }
+ return result;
+ }
+
+ /**
+ * Packs a list of ints in the same way as packBits()
+ *
+ * Each passed int is the rank of a bit that should be set in the returned long.
+ * Example : passing (1,3) will return in 0b00001010 and passing (5,6,0) will return 0b01100001
+ *
+ * @param bits bits to pack
+ * @return a long with the specified bits set.
+ */
+ public static long packBitList(int... bits) {
+ return packBits(bits);
+ }
+
+ /**
+ * Packs array of bits into a long value.
+ *
+ * Each passed int is the rank of a bit that should be set in the returned long.
+ * Example : passing [1,3] will return in 0b00001010 and passing [5,6,0] will return 0b01100001
+ *
+ * @param bits bits to pack
+ * @return a long with the specified bits set.
+ */
+ public static long packBits(int[] bits) {
+ long packed = 0;
+ for (int b : bits) {
+ packed |= (1L << b);
+ }
+ return packed;
+ }
+
+ /**
+ * An interface for a function that can retrieve a name associated with an int.
+ *
+ * This is useful for bitfields like network capabilities or network score policies.
+ */
+ @FunctionalInterface
+ public interface NameOf {
+ /** Retrieve the name associated with the passed value */
+ String nameOf(int value);
+ }
+
+ /**
+ * Given a bitmask and a name fetcher, append names of all set bits to the builder
+ *
+ * This method takes all bit sets in the passed bitmask, will figure out the name associated
+ * with the weight of each bit with the passed name fetcher, and append each name to the
+ * passed StringBuilder, separated by the passed separator.
+ *
+ * For example, if the bitmask is 0110, and the name fetcher return "BIT_1" to "BIT_4" for
+ * numbers from 1 to 4, and the separator is "&", this method appends "BIT_2&BIT3" to the
+ * StringBuilder.
+ */
+ public static void appendStringRepresentationOfBitMaskToStringBuilder(@NonNull StringBuilder sb,
+ long bitMask, @NonNull NameOf nameFetcher, @NonNull String separator) {
+ int bitPos = 0;
+ boolean firstElementAdded = false;
+ while (bitMask != 0) {
+ if ((bitMask & 1) != 0) {
+ if (firstElementAdded) {
+ sb.append(separator);
+ } else {
+ firstElementAdded = true;
+ }
+ sb.append(nameFetcher.nameOf(bitPos));
+ }
+ bitMask >>>= 1;
+ ++bitPos;
+ }
+ }
+}
diff --git a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
index 26c24f8..54ce01e 100644
--- a/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
+++ b/staticlibs/framework/com/android/net/module/util/NetworkCapabilitiesUtils.java
@@ -44,6 +44,9 @@
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
+import static com.android.net.module.util.BitUtils.packBitList;
+import static com.android.net.module.util.BitUtils.unpackBits;
+
import android.annotation.NonNull;
import android.net.NetworkCapabilities;
@@ -181,49 +184,4 @@
return false;
}
- /**
- * Unpacks long value into an array of bits.
- */
- public static int[] unpackBits(long val) {
- int size = Long.bitCount(val);
- int[] result = new int[size];
- int index = 0;
- int bitPos = 0;
- while (val != 0) {
- if ((val & 1) == 1) result[index++] = bitPos;
- val = val >>> 1;
- bitPos++;
- }
- return result;
- }
-
- /**
- * Packs a list of ints in the same way as packBits()
- *
- * Each passed int is the rank of a bit that should be set in the returned long.
- * Example : passing (1,3) will return in 0b00001010 and passing (5,6,0) will return 0b01100001
- *
- * @param bits bits to pack
- * @return a long with the specified bits set.
- */
- public static long packBitList(int... bits) {
- return packBits(bits);
- }
-
- /**
- * Packs array of bits into a long value.
- *
- * Each passed int is the rank of a bit that should be set in the returned long.
- * Example : passing [1,3] will return in 0b00001010 and passing [5,6,0] will return 0b01100001
- *
- * @param bits bits to pack
- * @return a long with the specified bits set.
- */
- public static long packBits(int[] bits) {
- long packed = 0;
- for (int b : bits) {
- packed |= (1L << b);
- }
- return packed;
- }
}
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/BitUtilsTests.kt b/staticlibs/tests/unit/src/com/android/net/module/util/BitUtilsTests.kt
new file mode 100644
index 0000000..0236716
--- /dev/null
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/BitUtilsTests.kt
@@ -0,0 +1,61 @@
+/*
+ * 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
+
+import com.android.net.module.util.BitUtils.appendStringRepresentationOfBitMaskToStringBuilder
+import com.android.net.module.util.BitUtils.packBits
+import com.android.net.module.util.BitUtils.unpackBits
+import org.junit.Test
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+class BitUtilsTests {
+ @Test
+ fun testBitPackingTestCase() {
+ runBitPackingTestCase(0, intArrayOf())
+ runBitPackingTestCase(1, intArrayOf(0))
+ runBitPackingTestCase(3, intArrayOf(0, 1))
+ runBitPackingTestCase(4, intArrayOf(2))
+ runBitPackingTestCase(63, intArrayOf(0, 1, 2, 3, 4, 5))
+ runBitPackingTestCase(Long.MAX_VALUE.inv(), intArrayOf(63))
+ runBitPackingTestCase(Long.MAX_VALUE.inv() + 1, intArrayOf(0, 63))
+ runBitPackingTestCase(Long.MAX_VALUE.inv() + 2, intArrayOf(1, 63))
+ }
+
+ fun runBitPackingTestCase(packedBits: Long, bits: IntArray) {
+ assertEquals(packedBits, packBits(bits))
+ assertTrue(bits contentEquals unpackBits(packedBits))
+ }
+
+ @Test
+ fun testAppendStringRepresentationOfBitMaskToStringBuilder() {
+ runTestAppendStringRepresentationOfBitMaskToStringBuilder("", 0)
+ runTestAppendStringRepresentationOfBitMaskToStringBuilder("BIT0", 0b1)
+ runTestAppendStringRepresentationOfBitMaskToStringBuilder("BIT1&BIT2&BIT4", 0b10110)
+ runTestAppendStringRepresentationOfBitMaskToStringBuilder(
+ "BIT0&BIT60&BIT61&BIT62&BIT63",
+ (0b11110000_00000000_00000000_00000000 shl 32) +
+ 0b00000000_00000000_00000000_00000001)
+ }
+
+ fun runTestAppendStringRepresentationOfBitMaskToStringBuilder(expected: String, bitMask: Long) {
+ StringBuilder().let {
+ appendStringRepresentationOfBitMaskToStringBuilder(it, bitMask, { i -> "BIT$i" }, "&")
+ assertEquals(expected, it.toString())
+ }
+ }
+}
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt
index 256ea1e..958f45f 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/NetworkCapabilitiesUtilsTest.kt
@@ -22,7 +22,6 @@
import android.net.NetworkCapabilities.NET_CAPABILITY_CBS
import android.net.NetworkCapabilities.NET_CAPABILITY_EIMS
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
-import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID
import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
@@ -38,8 +37,6 @@
import com.android.net.module.util.NetworkCapabilitiesUtils.RESTRICTED_CAPABILITIES
import com.android.net.module.util.NetworkCapabilitiesUtils.UNRESTRICTED_CAPABILITIES
import com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport
-import com.android.net.module.util.NetworkCapabilitiesUtils.packBits
-import com.android.net.module.util.NetworkCapabilitiesUtils.unpackBits
import org.junit.Test
import org.junit.runner.RunWith
import java.lang.IllegalArgumentException
@@ -75,23 +72,6 @@
}
}
- @Test
- fun testBitPackingTestCase() {
- runBitPackingTestCase(0, intArrayOf())
- runBitPackingTestCase(1, intArrayOf(0))
- runBitPackingTestCase(3, intArrayOf(0, 1))
- runBitPackingTestCase(4, intArrayOf(2))
- runBitPackingTestCase(63, intArrayOf(0, 1, 2, 3, 4, 5))
- runBitPackingTestCase(Long.MAX_VALUE.inv(), intArrayOf(63))
- runBitPackingTestCase(Long.MAX_VALUE.inv() + 1, intArrayOf(0, 63))
- runBitPackingTestCase(Long.MAX_VALUE.inv() + 2, intArrayOf(1, 63))
- }
-
- fun runBitPackingTestCase(packedBits: Long, bits: IntArray) {
- assertEquals(packedBits, packBits(bits))
- assertTrue(bits contentEquals unpackBits(packedBits))
- }
-
// NetworkCapabilities constructor and Builder are not available until R. Mark TargetApi to
// ignore the linter error since it's used in only unit test.
@Test @TargetApi(Build.VERSION_CODES.R)