• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.ranging.cs;
18 
19 import android.ranging.ble.cs.BleCsRangingCapabilities;
20 
21 import com.android.server.ranging.RangingTechnology;
22 import com.android.server.ranging.RangingUtils.Conversions;
23 import com.android.server.ranging.cs.CsOobConfig.CsSecurityType;
24 import com.android.server.ranging.oob.TechnologyHeader;
25 
26 import com.google.auto.value.AutoValue;
27 import com.google.common.collect.ImmutableList;
28 
29 import java.nio.ByteBuffer;
30 import java.util.Arrays;
31 
32 /** Capability data for CS sent as part of CapabilityResponseMessage. */
33 @AutoValue
34 public abstract class CsOobCapabilities {
35 
36     /** Size in bytes of all properties when serialized. */
37     private static final int EXPECTED_SIZE_BYTES = 9;
38 
39     // Size in bytes of properties for serialization/deserialization.
40     private static final int SECURITY_TYPE_SIZE = 1;
41     private static final int BLUETOOTH_ADDRESS_SIZE = 6;
42 
43     private static final int SECURITY_TYPE_SHIFT = 0;
44 
45     /** Returns the size of the object in bytes when serialized. */
getSize()46     public static int getSize() {
47         return EXPECTED_SIZE_BYTES;
48     }
49 
50     /**
51      * Parses the given byte array and returns {@link CsOobCapabilities} object. Throws {@link
52      * IllegalArgumentException} on invalid input.
53      */
parseBytes(byte[] capabilitiesBytes)54     public static CsOobCapabilities parseBytes(byte[] capabilitiesBytes) {
55         TechnologyHeader header = TechnologyHeader.parseBytes(capabilitiesBytes);
56 
57         if (capabilitiesBytes.length < EXPECTED_SIZE_BYTES) {
58             throw new IllegalArgumentException(
59                     String.format(
60                             "CsOobCapabilities size is %d, expected at least %d",
61                             capabilitiesBytes.length, EXPECTED_SIZE_BYTES));
62         }
63 
64         if (capabilitiesBytes.length < header.getSize()) {
65             throw new IllegalArgumentException(
66                     String.format(
67                             "CsOobCapabilities header size field is %d, but the size of the array"
68                                     + " is"
69                                     + " %d",
70                             header.getSize(), capabilitiesBytes.length));
71         }
72 
73         if (header.getRangingTechnology() != RangingTechnology.CS) {
74             throw new IllegalArgumentException(
75                     String.format(
76                             "CsOobCapabilities header technology field is %s, expected %s",
77                             header.getRangingTechnology(), RangingTechnology.CS));
78         }
79 
80         int parseCursor = header.getHeaderSize();
81 
82         // Supported security type
83         ImmutableList<CsSecurityType> securityTypes =
84                 Conversions.byteArrayToIntList(
85                                 Arrays.copyOfRange(
86                                         capabilitiesBytes, parseCursor,
87                                         parseCursor + SECURITY_TYPE_SIZE),
88                                 SECURITY_TYPE_SHIFT)
89                         .stream()
90                         .map(CsSecurityType::fromValue)
91                         .collect(ImmutableList.toImmutableList());
92         parseCursor += SECURITY_TYPE_SIZE;
93 
94         // CS Address
95         String bluetoothAddress =
96                 Conversions.macAddressToString(
97                         Arrays.copyOfRange(
98                                 capabilitiesBytes, parseCursor,
99                                 parseCursor + BLUETOOTH_ADDRESS_SIZE));
100         parseCursor += BLUETOOTH_ADDRESS_SIZE;
101 
102         return CsOobCapabilities.builder()
103                 .setSupportedSecurityTypes(securityTypes)
104                 .setBluetoothAddress(bluetoothAddress)
105                 .build();
106     }
107 
108     /** Serializes this {@link CsOobCapabilities} object to bytes. */
toBytes()109     public final byte[] toBytes() {
110         ByteBuffer byteBuffer = ByteBuffer.allocate(EXPECTED_SIZE_BYTES);
111         byteBuffer
112                 .put(RangingTechnology.CS.toByte())
113                 .put((byte) EXPECTED_SIZE_BYTES)
114                 .put(
115                         Conversions.intListToByteArrayBitmap(
116                                 getSupportedSecurityTypes().stream()
117                                         .map(CsSecurityType::getValue)
118                                         .collect(ImmutableList.toImmutableList()),
119                                 SECURITY_TYPE_SIZE,
120                                 SECURITY_TYPE_SHIFT))
121                 .put(Conversions.macAddressToBytes(getBluetoothAddress()));
122 
123         return byteBuffer.array();
124     }
125 
fromRangingCapabilities( BleCsRangingCapabilities capabilities )126     public static CsOobCapabilities fromRangingCapabilities(
127             BleCsRangingCapabilities capabilities
128     ) {
129         return CsOobCapabilities.builder()
130                 .setBluetoothAddress(capabilities.getBluetoothAddress())
131                 .setSupportedSecurityTypes(capabilities.getSupportedSecurityLevels().stream()
132                         .map(CsSecurityType.SECURITY_TYPES::get)
133                         .collect(ImmutableList.toImmutableList()))
134                 .build();
135     }
136 
137     /** Returns the security type for CS. */
getSupportedSecurityTypes()138     public abstract ImmutableList<CsSecurityType> getSupportedSecurityTypes();
139 
140     /** Returns the Bluetooth address of the device. */
getBluetoothAddress()141     public abstract String getBluetoothAddress();
142 
143     /** Returns a builder for {@link CsOobCapabilities}. */
builder()144     public static Builder builder() {
145         return new AutoValue_CsOobCapabilities.Builder();
146     }
147 
148     /** Builder for {@link CsOobCapabilities}. */
149     @AutoValue.Builder
150     public abstract static class Builder {
151 
setSupportedSecurityTypes( ImmutableList<CsSecurityType> securityTypes)152         public abstract Builder setSupportedSecurityTypes(
153                 ImmutableList<CsSecurityType> securityTypes);
154 
setBluetoothAddress(String bluetoothAddress)155         public abstract Builder setBluetoothAddress(String bluetoothAddress);
156 
autoBuild()157         public abstract CsOobCapabilities autoBuild();
158 
build()159         public CsOobCapabilities build() {
160             CsOobCapabilities csCapabilities = autoBuild();
161             // Validate Bluetooth Address, will throw if invalid.
162             var unused = Conversions.macAddressToBytes(csCapabilities.getBluetoothAddress());
163             return csCapabilities;
164         }
165     }
166 }