Merge "Introduce LegacyStruct to expose writeToBytes(ByteOrder)" into main

This commit is contained in:
Treehugger Robot 2025-07-29 13:14:53 -07:00 • committed by Android (Google) Code Review
commit bd78be51a5
16 changed files with 83 additions and 59 deletions

View file

@ -178,6 +178,7 @@ java_library {
java_library {
name: "net-utils-device-common-struct-base",
srcs: [
"device/com/android/net/module/util/LegacyStruct.java",
"device/com/android/net/module/util/Struct.java",
],
sdk_version: "module_current",
@ -688,6 +689,7 @@ filegroup {
"device/com/android/net/module/util/BpfUtils.java",
"device/com/android/net/module/util/IBpfMap.java",
"device/com/android/net/module/util/JniUtil.java",
"device/com/android/net/module/util/LegacyStruct.java",
"device/com/android/net/module/util/SingleWriterBpfMap.java",
"device/com/android/net/module/util/Struct.java",
"device/com/android/net/module/util/TcUtils.java",

View file

@ -0,0 +1,34 @@
/*
* Copyright (C) 2025 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 java.nio.ByteOrder;
/**
* LegacyStruct is solely used for providing access to the deprecated writeToBytes(ByteOrder)
* method.
*
* The goal is to slowly move all Struct classes to defining the ByteOrder directly on the field (by
* virtue of using the BE int types) after which LegacyStruct can be deleted.
*/
public class LegacyStruct extends Struct {
/** A wrapper around {@code Struct#legacyWriteToBytes} */
public final byte[] writeToBytes(final ByteOrder order) {
return legacyWriteToBytes(order);
}
}

View file

@ -706,9 +706,12 @@ public class Struct {
/**
* Convert the parsed Struct subclass object to byte array.
*
* WARNING: Structs should use byteorder annotations on the field, rather than using
* legacyWriteToBytes. This method will be deleted in the future.
*
* @param order indicate ByteBuffer is outputted as little-endian or big-endian.
*/
public final byte[] writeToBytes(final ByteOrder order) {
protected final byte[] legacyWriteToBytes(final ByteOrder order) {
final FieldInfo[] fieldInfos = getClassFieldInfo(this.getClass());
final byte[] output = new byte[getSizeInternal(fieldInfos)];
final ByteBuffer buffer = ByteBuffer.wrap(output);
@ -719,7 +722,7 @@ public class Struct {
/** Convert the parsed Struct subclass object to byte array with native order. */
public final byte[] writeToBytes() {
return writeToBytes(ByteOrder.nativeOrder());
return legacyWriteToBytes(ByteOrder.nativeOrder());
}
@Override
@ -788,7 +791,7 @@ public class Struct {
}
/** A simple Struct which only contains a bool field. */
public static class Bool extends Struct {
public static class Bool extends LegacyStruct {
@Struct.Field(order = 0, type = Struct.Type.Bool)
public final boolean val;

View file

@ -16,7 +16,7 @@
package com.android.net.module.util.structs;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -31,7 +31,7 @@ import com.android.net.module.util.Struct.Type;
* | Identification |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class FragmentHeader extends Struct {
public class FragmentHeader extends LegacyStruct {
@Field(order = 0, type = Type.U8)
public final short nextHeader;
@Field(order = 1, type = Type.S8)

View file

@ -18,7 +18,7 @@ package com.android.net.module.util.structs;
import static com.android.net.module.util.NetworkStackConstants.DHCP6_OPTION_IA_ADDR;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -49,7 +49,7 @@ import java.nio.ByteOrder;
* . .
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class IaAddressOption extends Struct {
public class IaAddressOption extends LegacyStruct {
public static final int LENGTH = 24; // option length excluding IAaddr-options
@Field(order = 0, type = Type.S16)

View file

@ -18,7 +18,7 @@ package com.android.net.module.util.structs;
import static com.android.net.module.util.NetworkStackConstants.DHCP6_OPTION_IA_PD;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -46,7 +46,7 @@ import java.nio.ByteOrder;
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
*/
public class IaPdOption extends Struct {
public class IaPdOption extends LegacyStruct {
public static final int LENGTH = 12; // option length excluding IA_PD options
@Field(order = 0, type = Type.S16)

View file

@ -21,7 +21,7 @@ import static com.android.net.module.util.NetworkStackConstants.DHCP6_OPTION_IAP
import android.net.IpPrefix;
import android.util.Log;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Computed;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -58,7 +58,7 @@ import java.nio.ByteOrder;
* . .
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class IaPrefixOption extends Struct {
public class IaPrefixOption extends LegacyStruct {
private static final String TAG = IaPrefixOption.class.getSimpleName();
public static final int LENGTH = 25; // option length excluding IAprefix-options

View file

@ -18,7 +18,7 @@ package com.android.net.module.util.structs;
import android.net.MacAddress;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -34,7 +34,7 @@ import java.nio.ByteOrder;
* | Type | Length | Link-Layer Address ...
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class LlaOption extends Struct {
public class LlaOption extends LegacyStruct {
@Field(order = 0, type = Type.S8)
public final byte type;
@Field(order = 1, type = Type.S8)

View file

@ -18,7 +18,7 @@ package com.android.net.module.util.structs;
import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_MTU;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -36,7 +36,7 @@ import java.nio.ByteOrder;
* | MTU |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class MtuOption extends Struct {
public class MtuOption extends LegacyStruct {
@Field(order = 0, type = Type.S8)
public final byte type;
@Field(order = 1, type = Type.S8)

View file

@ -16,7 +16,7 @@
package com.android.net.module.util.structs;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -44,7 +44,7 @@ import java.net.Inet6Address;
* | Options ...
* +-+-+-+-+-+-+-+-+-+-+-+-
*/
public class NaHeader extends Struct {
public class NaHeader extends LegacyStruct {
@Field(order = 0, type = Type.S32)
public int flags; // Router flag, Solicited flag, Override flag and 29 Reserved bits.
@Field(order = 1, type = Type.Ipv6Address)

View file

@ -16,7 +16,7 @@
package com.android.net.module.util.structs;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -44,7 +44,7 @@ import java.net.Inet6Address;
* | Options ...
* +-+-+-+-+-+-+-+-+-+-+-+-
*/
public class NsHeader extends Struct {
public class NsHeader extends LegacyStruct {
@Field(order = 0, type = Type.S32)
public int reserved; // 32 Reserved bits.
@Field(order = 1, type = Type.Ipv6Address)

View file

@ -23,7 +23,7 @@ import android.net.IpPrefix;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Computed;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -57,7 +57,7 @@ import java.nio.ByteOrder;
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class PrefixInformationOption extends Struct {
public class PrefixInformationOption extends LegacyStruct {
@Field(order = 0, type = Type.S8)
public final byte type;
@Field(order = 1, type = Type.S8)

View file

@ -16,7 +16,7 @@
package com.android.net.module.util.structs;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -38,7 +38,7 @@ import com.android.net.module.util.Struct.Type;
* | Options ...
* +-+-+-+-+-+-+-+-+-+-+-+-
*/
public class RaHeader extends Struct {
public class RaHeader extends LegacyStruct {
@Field(order = 0, type = Type.S8)
public final byte hopLimit;
// "Managed address configuration", "Other configuration" bits, and 6 reserved bits

View file

@ -22,7 +22,7 @@ import android.net.IpPrefix;
import androidx.annotation.NonNull;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -44,7 +44,7 @@ import java.nio.ByteOrder;
* . .
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class RouteInformationOption extends Struct {
public class RouteInformationOption extends LegacyStruct {
public enum Preference {
HIGH((byte) 0x1),
MEDIUM((byte) 0x0),

View file

@ -16,7 +16,7 @@
package com.android.net.module.util.structs;
import com.android.net.module.util.Struct;
import com.android.net.module.util.LegacyStruct;
import com.android.net.module.util.Struct.Field;
import com.android.net.module.util.Struct.Type;
@ -34,7 +34,7 @@ import com.android.net.module.util.Struct.Type;
* | Options ...
* +-+-+-+-+-+-+-+-+-+-+-+-
*/
public class RsHeader extends Struct {
public class RsHeader extends LegacyStruct {
@Field(order = 0, type = Type.S32)
public final int reserved;

View file

@ -123,8 +123,7 @@ public class StructTest {
assertEquals(0, msg.mIcmpCode);
assertEquals(16, Struct.getSize(HeaderMsgWithConstructor.class));
assertArrayEquals(toByteBuffer(HDR_EMPTY).array(),
msg.writeToBytes(ByteOrder.LITTLE_ENDIAN));
assertArrayEquals(toByteBuffer(HDR_EMPTY).array(), msg.writeToBytes());
}
@Test
@ -184,8 +183,7 @@ public class StructTest {
assertEquals(0, msg.mIcmpCode);
assertEquals(16, Struct.getSize(HeaderMsgWithoutConstructor.class));
assertArrayEquals(toByteBuffer(HDR_EMPTY).array(),
msg.writeToBytes(ByteOrder.LITTLE_ENDIAN));
assertArrayEquals(toByteBuffer(HDR_EMPTY).array(), msg.writeToBytes());
}
public static class HeaderMessage {
@ -255,8 +253,7 @@ public class StructTest {
assertEquals(9151314442816847871L, msg.mUBE63);
assertEquals(22, Struct.getSize(NetworkOrderMessage.class));
assertArrayEquals(toByteBuffer(NETWORK_ORDER_MSG).array(),
msg.writeToBytes(ByteOrder.LITTLE_ENDIAN));
assertArrayEquals(toByteBuffer(NETWORK_ORDER_MSG).array(), msg.writeToBytes());
}
public static class UnsignedDataMessage extends Struct {
@ -296,8 +293,7 @@ public class StructTest {
assertEquals(-1L, msg.mLU64);
assertEquals(31, Struct.getSize(UnsignedDataMessage.class));
assertArrayEquals(toByteBuffer(UNSIGNED_DATA).array(),
msg.writeToBytes(ByteOrder.LITTLE_ENDIAN));
assertArrayEquals(toByteBuffer(UNSIGNED_DATA).array(), msg.writeToBytes());
}
public static class U64DataMessage extends Struct {
@ -336,11 +332,10 @@ public class StructTest {
assertEquals(new BigInteger("0"), msg.mZero);
assertEquals(24, Struct.getSize(SmallValueBigInteger.class));
assertArrayEquals(toByteBuffer(SMALL_VALUE_BIGINTEGER).array(),
msg.writeToBytes(ByteOrder.LITTLE_ENDIAN));
assertArrayEquals(toByteBuffer(SMALL_VALUE_BIGINTEGER).array(), msg.writeToBytes());
}
public static class SignedDataMessage extends Struct {
public static class SignedDataMessage extends LegacyStruct {
@Field(order = 0, type = Type.S8)
public final byte mS8;
@Field(order = 1, type = Type.S16)
@ -368,8 +363,7 @@ public class StructTest {
assertEquals(9223372036854775807L, msg.mS64);
assertEquals(15, Struct.getSize(SignedDataMessage.class));
assertArrayEquals(toByteBuffer(SIGNED_DATA).array(),
msg.writeToBytes(ByteOrder.LITTLE_ENDIAN));
assertArrayEquals(toByteBuffer(SIGNED_DATA).array(), msg.writeToBytes());
}
@Test
@ -382,8 +376,7 @@ public class StructTest {
assertEquals(-9223372036854775807L, msg.mS64);
assertEquals(15, Struct.getSize(SignedDataMessage.class));
assertArrayEquals(toByteBuffer(SIGNED_NEGATIVE_DATA).array(),
msg.writeToBytes(ByteOrder.LITTLE_ENDIAN));
assertArrayEquals(toByteBuffer(SIGNED_NEGATIVE_DATA).array(), msg.writeToBytes());
}
public static class HeaderMessageWithDuplicateOrder extends Struct {
@ -489,8 +482,7 @@ public class StructTest {
assertTrue(prefix.equals(new IpPrefix("2001:db8:3:4:5:6::/96")));
assertEquals(14, Struct.getSize(PrefixMessage.class));
assertArrayEquals(toByteBuffer(OPT_PREF64).array(),
msg.writeToBytes(ByteOrder.LITTLE_ENDIAN));
assertArrayEquals(toByteBuffer(OPT_PREF64).array(), msg.writeToBytes());
}
public static class PrefixMessageWithZeroLengthArray extends Struct {
@ -581,8 +573,7 @@ public class StructTest {
assertEquals(0, msg.mIcmpCode);
assertEquals(16, Struct.getSize(HeaderMsgWithStaticConstant.class));
assertArrayEquals(toByteBuffer(HDR_EMPTY).array(),
msg.writeToBytes(ByteOrder.LITTLE_ENDIAN));
assertArrayEquals(toByteBuffer(HDR_EMPTY).array(), msg.writeToBytes());
}
public static class MismatchedConstructor extends Struct {
@ -622,8 +613,7 @@ public class StructTest {
assertEquals(30806 /* 0x7856 */, msg.mInt2);
assertEquals(4, Struct.getSize(ClassWithTwoConstructors.class));
assertArrayEquals(toByteBuffer("1234" + "5678").array(),
msg.writeToBytes(ByteOrder.LITTLE_ENDIAN));
assertArrayEquals(toByteBuffer("1234" + "5678").array(), msg.writeToBytes());
}
@Test
@ -669,7 +659,7 @@ public class StructTest {
}
}
public static class BigEndianDataMessage extends Struct {
public static class BigEndianDataMessage extends LegacyStruct {
@Field(order = 0, type = Type.S32) public int mInt1;
@Field(order = 1, type = Type.S32) public int mInt2;
@Field(order = 2, type = Type.UBE16) public int mInt3;
@ -724,7 +714,7 @@ public class StructTest {
assertEquals(12, Struct.getSize(MacAddressMessage.class));
assertArrayEquals(toByteBuffer("001122334455" + "ffffffffffff").array(),
msg.writeToBytes(ByteOrder.BIG_ENDIAN));
msg.writeToBytes());
}
public static class BadMacAddressType extends Struct {
@ -748,11 +738,6 @@ public class StructTest {
SignedDataMessage.class, ByteOrder.BIG_ENDIAN);
assertArrayEquals(toByteBuffer(SIGNED_DATA).array(),
bigEndianMsg.writeToBytes(ByteOrder.BIG_ENDIAN));
final SignedDataMessage nativeOrderMsg = ByteOrder.nativeOrder().equals(
ByteOrder.LITTLE_ENDIAN) ? littleEndianMsg : bigEndianMsg;
assertArrayEquals(toByteBuffer(SIGNED_DATA).array(),
nativeOrderMsg.writeToBytes());
}
@Test
@ -786,7 +771,7 @@ public class StructTest {
assertEquals(20, Struct.getSize(IpAddressMessage.class));
assertArrayEquals(toByteBuffer("c0a86401" + "20010db8000300040005000600070008").array(),
msg.writeToBytes(ByteOrder.BIG_ENDIAN));
msg.writeToBytes());
}
@Test
@ -823,7 +808,7 @@ public class StructTest {
"00000000000000000000ffffc0a86401", InetAddressMessage.class, ByteOrder.BIG_ENDIAN);
assertEquals(TEST_IPV4_ADDRESS, msg.ipAddress);
assertArrayEquals(toByteBuffer("00000000000000000000ffffc0a86401").array(),
msg.writeToBytes(ByteOrder.BIG_ENDIAN));
msg.writeToBytes());
}
@Test
public void testV6AddressInIpAddress() {
@ -831,10 +816,10 @@ public class StructTest {
"20010db8000300040005000600070008", InetAddressMessage.class, ByteOrder.BIG_ENDIAN);
assertEquals(TEST_IPV6_ADDRESS, msg.ipAddress);
assertArrayEquals(toByteBuffer("20010db8000300040005000600070008").array(),
msg.writeToBytes(ByteOrder.BIG_ENDIAN));
msg.writeToBytes());
}
public static class FullTypeMessage extends Struct {
public static class FullTypeMessage extends LegacyStruct {
@Field(order = 0, type = Type.U8) public final short u8;
@Field(order = 1, type = Type.U16) public final int u16;
@Field(order = 2, type = Type.U32) public final long u32;