• 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.oob;
18 
19 import com.android.server.ranging.RangingTechnology;
20 import com.android.server.ranging.blerssi.BleRssiOobConfig;
21 import com.android.server.ranging.cs.CsOobConfig;
22 import com.android.server.ranging.rtt.RttOobConfig;
23 import com.android.server.ranging.uwb.UwbOobConfig;
24 
25 import com.google.auto.value.AutoValue;
26 import com.google.common.base.Preconditions;
27 import com.google.common.collect.ImmutableList;
28 
29 import java.nio.ByteBuffer;
30 import java.util.Arrays;
31 
32 import javax.annotation.Nullable;
33 
34 /** The Set Configuration Message Additional Data for Finder OOB. */
35 @AutoValue
36 public abstract class SetConfigurationMessage {
37 
38     public interface TechnologyOobConfig { }
39 
40     // Size in bytes of properties when serialized.
41     private static final int MIN_SIZE_BYTES = 4;
42     private static final int RANGING_TECHNOLOGIES_SET_SIZE = 2;
43     private static final int START_RANGING_LIST_SIZE = 2;
44 
45     /**
46      * Parses the given byte array and returns {@link SetConfigurationMessage} object. Throws {@link
47      * IllegalArgumentException} on invalid input.
48      */
parseBytes(byte[] payload)49     public static SetConfigurationMessage parseBytes(byte[] payload) {
50         OobHeader header = OobHeader.parseBytes(payload);
51 
52         if (header.getMessageType() != MessageType.SET_CONFIGURATION) {
53             throw new IllegalArgumentException(
54                     String.format(
55                             "Invalid message type: %s, expected %s",
56                             header.getMessageType(), MessageType.SET_CONFIGURATION));
57         }
58 
59         if (payload.length < header.getSize() + MIN_SIZE_BYTES) {
60             throw new IllegalArgumentException(
61                     String.format(
62                             "CapabilityResponseMessage payload size is %d bytes", payload.length));
63         }
64 
65         int parseCursor = header.getSize();
66 
67         // Parse Ranging Technologies Set
68         var rangingTechnologiesSet =
69                 RangingTechnology.fromBitmap(Arrays.copyOfRange(
70                         payload, parseCursor, parseCursor + RANGING_TECHNOLOGIES_SET_SIZE));
71         parseCursor += RANGING_TECHNOLOGIES_SET_SIZE;
72 
73         // Parse Start Ranging List
74         var startRangingList =
75                 RangingTechnology.fromBitmap(Arrays.copyOfRange(
76                         payload, parseCursor, parseCursor + START_RANGING_LIST_SIZE));
77         parseCursor += START_RANGING_LIST_SIZE;
78 
79         // Parse Configs for ranging technologies that are set
80         UwbOobConfig uwbConfig = null;
81         CsOobConfig csConfig = null;
82         RttOobConfig rttConfig = null;
83         BleRssiOobConfig bleRssiConfig = null;
84         int countTechsParsed = 0;
85         while (parseCursor < payload.length && countTechsParsed++ < rangingTechnologiesSet.size()) {
86             byte[] remainingBytes = Arrays.copyOfRange(payload, parseCursor, payload.length);
87             TechnologyHeader techHeader = TechnologyHeader.parseBytes(remainingBytes);
88             switch (techHeader.getRangingTechnology()) {
89                 case UWB:
90                     if (uwbConfig != null) {
91                         throw new IllegalArgumentException(
92                                 "Failed to parse SetConfigurationMessage, UwbConfig already set. "
93                                         + "Bytes: " + Arrays.toString(payload));
94                     }
95                     uwbConfig = UwbOobConfig.parseBytes(remainingBytes);
96                     parseCursor += uwbConfig.getSize();
97                     break;
98                 case CS:
99                     if (csConfig != null) {
100                         throw new IllegalArgumentException(
101                                 "Failed to parse SetConfigurationMessage, CsConfig already set. "
102                                         + "Bytes: " + Arrays.toString(payload));
103                     }
104                     csConfig = CsOobConfig.parseBytes(remainingBytes);
105                     parseCursor += csConfig.getSize();
106                     break;
107                 case RTT:
108                     if (rttConfig != null) {
109                         throw new IllegalArgumentException(
110                                 "Failed to parse SetConfigurationMessage, RttConfig already set. "
111                                         + "Bytes: " + Arrays.toString(payload));
112                     }
113                     rttConfig = RttOobConfig.parseBytes(remainingBytes);
114                     parseCursor += rttConfig.getSize();
115                     break;
116                 case RSSI:
117                     if (bleRssiConfig != null) {
118                         throw new IllegalArgumentException(
119                                 "Failed to parse SetConfigurationMessage, BleRssiConfig already "
120                                         + "set. Bytes: " + Arrays.toString(payload));
121                     }
122                     bleRssiConfig = BleRssiOobConfig.parseBytes(remainingBytes);
123                     parseCursor += bleRssiConfig.getSize();
124                     break;
125                 default:
126                     parseCursor += techHeader.getSize();
127             }
128         }
129 
130         return builder()
131                 .setHeader(header)
132                 .setRangingTechnologiesSet(rangingTechnologiesSet)
133                 .setStartRangingList(startRangingList)
134                 .setUwbConfig(uwbConfig)
135                 .setCsConfig(csConfig)
136                 .setRttConfig(rttConfig)
137                 .setBleRssiConfig(bleRssiConfig)
138                 .build();
139     }
140 
141     /** Serializes this {@link SetConfigurationMessage} object to bytes. */
toBytes()142     public final byte[] toBytes() {
143         int size = MIN_SIZE_BYTES + getHeader().getSize();
144         UwbOobConfig uwbConfig = getUwbConfig();
145         CsOobConfig csConfig = getCsConfig();
146         RttOobConfig rttConfig = getRttConfig();
147         BleRssiOobConfig bleRssiConfig = getBleRssiConfig();
148         if (uwbConfig != null) {
149             size += uwbConfig.getSize();
150         }
151         if (csConfig != null) {
152             size += csConfig.getSize();
153         }
154         if (rttConfig != null) {
155             size += rttConfig.getSize();
156         }
157         if (bleRssiConfig != null) {
158             size += bleRssiConfig.getSize();
159         }
160         ByteBuffer byteBuffer = ByteBuffer.allocate(size);
161         byteBuffer
162                 .put(getHeader().toBytes())
163                 .put(RangingTechnology.toBitmap(getRangingTechnologiesSet()))
164                 .put(RangingTechnology.toBitmap(getStartRangingList()));
165         if (uwbConfig != null) {
166             byteBuffer.put(uwbConfig.toBytes());
167         }
168         if (csConfig != null) {
169             byteBuffer.put(csConfig.toBytes());
170         }
171         if (rttConfig != null) {
172             byteBuffer.put(rttConfig.toBytes());
173         }
174         if (bleRssiConfig != null) {
175             byteBuffer.put(bleRssiConfig.toBytes());
176         }
177         return byteBuffer.array();
178     }
179 
180     /** Returns the OOB header. */
getHeader()181     public abstract OobHeader getHeader();
182 
183     /** Returns a list of ranging technologies that are set as part of this message. */
getRangingTechnologiesSet()184     public abstract ImmutableList<RangingTechnology> getRangingTechnologiesSet();
185 
186     /**
187      * Returns a list of ranging technologies that should start ranging as soon as this message is
188      * received.
189      */
getStartRangingList()190     public abstract ImmutableList<RangingTechnology> getStartRangingList();
191 
192     /** Returns @Nullable UwbConfig data that should be used to configure UWB ranging session. */
193     @Nullable
getUwbConfig()194     public abstract UwbOobConfig getUwbConfig();
195 
196     /** Returns @Nullable CsConfig data that should be used to configure CS ranging session. */
197     @Nullable
getCsConfig()198     public abstract CsOobConfig getCsConfig();
199 
200     @Nullable
getRttConfig()201     public abstract RttOobConfig getRttConfig();
202 
203     @Nullable
getBleRssiConfig()204     public abstract BleRssiOobConfig getBleRssiConfig();
205 
206     /** Returns a builder for {@link SetConfigurationMessage}. */
builder()207     public static Builder builder() {
208         return new AutoValue_SetConfigurationMessage.Builder()
209                 .setRangingTechnologiesSet(ImmutableList.of())
210                 .setStartRangingList(ImmutableList.of());
211     }
212 
213     /** Builder for {@link SetConfigurationMessage}. */
214     @AutoValue.Builder
215     public abstract static class Builder {
216 
setHeader(OobHeader header)217         public abstract Builder setHeader(OobHeader header);
218 
setRangingTechnologiesSet( ImmutableList<RangingTechnology> rangingTechnologiesSet)219         public abstract Builder setRangingTechnologiesSet(
220                 ImmutableList<RangingTechnology> rangingTechnologiesSet);
221 
setStartRangingList( ImmutableList<RangingTechnology> startRangingList )222         public abstract Builder setStartRangingList(
223                 ImmutableList<RangingTechnology> startRangingList
224         );
225 
setUwbConfig(@ullable UwbOobConfig uwbConfig)226         public abstract Builder setUwbConfig(@Nullable UwbOobConfig uwbConfig);
227 
setCsConfig(@ullable CsOobConfig csConfig)228         public abstract Builder setCsConfig(@Nullable CsOobConfig csConfig);
229 
setRttConfig(@ullable RttOobConfig rttConfig)230         public abstract Builder setRttConfig(@Nullable RttOobConfig rttConfig);
231 
setBleRssiConfig(@ullable BleRssiOobConfig bleRssiConfig)232         public abstract Builder setBleRssiConfig(@Nullable BleRssiOobConfig bleRssiConfig);
233 
setTechnologyConfig(@ullable TechnologyOobConfig config)234         public Builder setTechnologyConfig(@Nullable TechnologyOobConfig config) {
235             return switch (config) {
236                 case UwbOobConfig c -> setUwbConfig(c);
237                 case CsOobConfig c -> setCsConfig(c);
238                 case RttOobConfig c -> setRttConfig(c);
239                 case BleRssiOobConfig c -> setBleRssiConfig(c);
240                 default -> this;
241             };
242         }
243 
autoBuild()244         abstract SetConfigurationMessage autoBuild();
245 
build()246         public SetConfigurationMessage build() {
247             SetConfigurationMessage setConfigurationMessage = autoBuild();
248             Preconditions.checkArgument(
249                     setConfigurationMessage
250                             .getRangingTechnologiesSet()
251                             .containsAll(setConfigurationMessage.getStartRangingList()),
252                     "startRangingList contains items that are not in rangingTechnologiesSet list.");
253             Preconditions.checkArgument(
254                     setConfigurationMessage
255                             .getRangingTechnologiesSet()
256                             .contains(RangingTechnology.UWB)
257                             == (setConfigurationMessage.getUwbConfig() != null),
258                     "UwbConfig or rangingTechnologiesSet for UWB not set properly.");
259             Preconditions.checkArgument(
260                     setConfigurationMessage
261                             .getRangingTechnologiesSet()
262                             .contains(RangingTechnology.CS)
263                             == (setConfigurationMessage.getCsConfig() != null),
264                     "csConfig or rangingTechnologiesSet for CS not set properly.");
265             Preconditions.checkArgument(
266                     setConfigurationMessage
267                             .getRangingTechnologiesSet()
268                             .contains(RangingTechnology.RTT)
269                             == (setConfigurationMessage.getRttConfig() != null),
270                     "rttConfig or rangingTechnologiesSet for Rtt not set properly.");
271             Preconditions.checkArgument(
272                     setConfigurationMessage
273                             .getRangingTechnologiesSet()
274                             .contains(RangingTechnology.RSSI)
275                             == (setConfigurationMessage.getBleRssiConfig() != null),
276                     "BleRssiConfig or rangingTechnologiesSet for BLE RSSI not set properly.");
277             return setConfigurationMessage;
278         }
279     }
280 }
281