• 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.session;
18 
19 import static android.ranging.RangingPreference.DEVICE_ROLE_INITIATOR;
20 
21 import android.ranging.RangingConfig;
22 import android.ranging.RangingDevice;
23 import android.ranging.RangingManager;
24 import android.ranging.RangingPreference;
25 import android.ranging.SessionConfig;
26 import android.ranging.raw.RawRangingDevice;
27 import android.ranging.uwb.UwbAddress;
28 import android.ranging.uwb.UwbRangingParams;
29 
30 import androidx.annotation.NonNull;
31 
32 import com.android.server.ranging.RangingTechnology;
33 import com.android.server.ranging.blerssi.BleRssiConfig;
34 import com.android.server.ranging.cs.CsConfig;
35 import com.android.server.ranging.rtt.RttConfig;
36 import com.android.server.ranging.uwb.UwbConfig;
37 
38 import com.google.common.collect.BiMap;
39 import com.google.common.collect.HashBiMap;
40 import com.google.common.collect.ImmutableBiMap;
41 import com.google.common.collect.ImmutableSet;
42 import com.google.common.collect.Sets;
43 
44 import java.util.Arrays;
45 import java.util.HashMap;
46 import java.util.HashSet;
47 import java.util.Map;
48 import java.util.Objects;
49 import java.util.Set;
50 
51 public class RangingSessionConfig {
52     private final @RangingPreference.DeviceRole int mDeviceRole;
53     private final @RangingConfig.RangingSessionType int mSessionType;
54     private final SessionConfig mSessionConfig;
55 
56     /** A complete configuration for a session within a specific ranging technology's stack */
57     public interface TechnologyConfig {
58         @NonNull
getTechnology()59         RangingTechnology getTechnology();
60 
getDeviceRole()61         @RangingPreference.DeviceRole int getDeviceRole();
62     }
63 
64     /** A config for a technology that only supports 1 peer per session. */
65     public interface UnicastTechnologyConfig extends TechnologyConfig {
66         @NonNull
getPeerDevice()67         RangingDevice getPeerDevice();
68     }
69 
70     /** A config for a technology that supports multiple peers per session. */
71     public interface MulticastTechnologyConfig extends TechnologyConfig {
72         /**
73          * @return the set of peers within this technology-specific session.
74          */
75         @NonNull
getPeerDevices()76         ImmutableSet<RangingDevice> getPeerDevices();
77     }
78 
RangingSessionConfig(Builder builder)79     private RangingSessionConfig(Builder builder) {
80         mDeviceRole = builder.mDeviceRole;
81         mSessionType = builder.mSessionType;
82         mSessionConfig = builder.mSessionConfig;
83     }
84 
getTechnologyConfigs( @onNull Set<RawRangingDevice> peerParams )85     public @NonNull ImmutableSet<TechnologyConfig> getTechnologyConfigs(
86             @NonNull Set<RawRangingDevice> peerParams
87     ) {
88         return ImmutableSet.copyOf(Sets.union(
89                 getConfigsForUnicastTechnologies(peerParams),
90                 getConfigsForMulticastTechnologies(peerParams)));
91     }
92 
getConfigsForMulticastTechnologies( @onNull Set<RawRangingDevice> peerParams )93     private @NonNull Set<MulticastTechnologyConfig> getConfigsForMulticastTechnologies(
94             @NonNull Set<RawRangingDevice> peerParams
95     ) {
96         Set<MulticastTechnologyConfig> configs = new HashSet<>();
97 
98         Map<PeerIgnoringParamsHasher<UwbRangingParams>, BiMap<RangingDevice, UwbAddress>>
99                 uwbPeersByParams = PeerIgnoringParamsHasher.groupUwbPeersByParams(peerParams);
100 
101         // Create a config for each unique params. When multiple peers share the same params, this
102         // config will specify a multicast session containing all of them.
103         for (PeerIgnoringParamsHasher<UwbRangingParams> key : uwbPeersByParams.keySet()) {
104             configs.add(new UwbConfig.Builder(key.mParams)
105                     .setDeviceRole(mDeviceRole)
106                     .setPeerAddresses(ImmutableBiMap.copyOf(uwbPeersByParams.get(key)))
107                     .setSessionConfig(mSessionConfig)
108                     .build());
109         }
110 
111         return configs;
112     }
113 
getConfigsForUnicastTechnologies( @onNull Set<RawRangingDevice> peerParams )114     private @NonNull Set<UnicastTechnologyConfig> getConfigsForUnicastTechnologies(
115             @NonNull Set<RawRangingDevice> peerParams
116     ) {
117         Set<UnicastTechnologyConfig> configs = new HashSet<>();
118 
119         for (RawRangingDevice peer : peerParams) {
120             if (peer.getRttRangingParams() != null) {
121                 configs.add(new RttConfig(
122                         mDeviceRole,
123                         peer.getRttRangingParams(),
124                         mSessionConfig,
125                         peer.getRangingDevice()));
126             }
127             if (peer.getBleRssiRangingParams() != null) {
128                 configs.add(new BleRssiConfig(
129                         mDeviceRole,
130                         peer.getBleRssiRangingParams(),
131                         mSessionConfig,
132                         peer.getRangingDevice()));
133             }
134             // Only CS initiator needs to be configured.
135             if (peer.getCsRangingParams() != null && mDeviceRole == DEVICE_ROLE_INITIATOR) {
136                 configs.add(new CsConfig(
137                         peer.getCsRangingParams(),
138                         mSessionConfig,
139                         peer.getRangingDevice()));
140             }
141         }
142 
143         return configs;
144     }
145 
getDeviceRole()146     public @RangingPreference.DeviceRole int getDeviceRole() {
147         return mDeviceRole;
148     }
149 
getSessionType()150     public @RangingConfig.RangingSessionType int getSessionType() {
151         return mSessionType;
152     }
153 
getSessionConfig()154     public SessionConfig getSessionConfig() {
155         return mSessionConfig;
156     }
157 
158     public static class Builder {
159         private @RangingPreference.DeviceRole int mDeviceRole;
160         private @RangingConfig.RangingSessionType int mSessionType;
161         private SessionConfig mSessionConfig;
162 
build()163         public RangingSessionConfig build() {
164             return new RangingSessionConfig(this);
165         }
166 
setDeviceRole(@angingPreference.DeviceRole int role)167         public Builder setDeviceRole(@RangingPreference.DeviceRole int role) {
168             mDeviceRole = role;
169             return this;
170         }
171 
setSessionType(@angingConfig.RangingSessionType int type)172         public Builder setSessionType(@RangingConfig.RangingSessionType int type) {
173             mSessionType = type;
174             return this;
175         }
176 
setSessionConfig(@onNull SessionConfig config)177         public Builder setSessionConfig(@NonNull SessionConfig config) {
178             mSessionConfig = config;
179             return this;
180         }
181     }
182 
183     private static class PeerIgnoringParamsHasher<P> {
184         private final P mParams;
185 
186         /**
187          * Group together UWB peer devices that share the same params so that they can be put into a
188          * a multicast session.
189          */
190         public static Map<PeerIgnoringParamsHasher<UwbRangingParams>, BiMap<RangingDevice,
191                 UwbAddress>>
groupUwbPeersByParams(@onNull Set<RawRangingDevice> peerParams)192         groupUwbPeersByParams(@NonNull Set<RawRangingDevice> peerParams) {
193             Map<PeerIgnoringParamsHasher<UwbRangingParams>, BiMap<RangingDevice, UwbAddress>>
194                     peersByParams = new HashMap<>();
195             for (RawRangingDevice peer : peerParams) {
196                 if (peer.getUwbRangingParams() == null) continue;
197 
198                 PeerIgnoringParamsHasher<UwbRangingParams> key =
199                         new PeerIgnoringParamsHasher<>(peer.getUwbRangingParams());
200 
201                 if (peersByParams.containsKey(key)) {
202                     peersByParams.get(key).put(
203                             peer.getRangingDevice(),
204                             key.mParams.getPeerAddress());
205                 } else {
206                     peersByParams.put(key, HashBiMap.create(Map.of(
207                             peer.getRangingDevice(),
208                             key.mParams.getPeerAddress())));
209                 }
210             }
211             return peersByParams;
212         }
213 
PeerIgnoringParamsHasher(P params)214         PeerIgnoringParamsHasher(P params) {
215             mParams = params;
216         }
217 
218         @Override
hashCode()219         public int hashCode() {
220             if (mParams instanceof UwbRangingParams params) {
221                 return Objects.hash(
222                         RangingManager.UWB,
223                         params.getSessionId(),
224                         params.getSubSessionId(),
225                         params.getConfigId(),
226                         params.getDeviceAddress(),
227                         Arrays.hashCode(params.getSessionKeyInfo()),
228                         Arrays.hashCode(params.getSubSessionKeyInfo()),
229                         params.getComplexChannel(),
230                         params.getRangingUpdateRate(),
231                         params.getSlotDuration());
232             } else {
233                 throw new IllegalArgumentException("Provided params object is not supported");
234             }
235         }
236 
237         @Override
equals(Object o)238         public boolean equals(Object o) {
239             if (this == o) return true;
240             if (!(o instanceof PeerIgnoringParamsHasher<?> hasher)) return false;
241 
242             if (mParams instanceof UwbRangingParams me
243                     && hasher.mParams instanceof UwbRangingParams other
244             ) {
245                 return me.getSessionId() == other.getSessionId()
246                         && me.getSubSessionId() == other.getSubSessionId()
247                         && me.getConfigId() == other.getConfigId()
248                         && me.getDeviceAddress().equals(other.getDeviceAddress())
249                         && Arrays.equals(me.getSessionKeyInfo(), other.getSessionKeyInfo())
250                         && Arrays.equals(me.getSubSessionKeyInfo(), other.getSubSessionKeyInfo())
251                         && me.getComplexChannel().equals(other.getComplexChannel())
252                         && me.getRangingUpdateRate() == other.getRangingUpdateRate()
253                         && me.getSlotDuration() == other.getSlotDuration();
254             }
255 
256             return false;
257         }
258     }
259 
260     @Override
toString()261     public String toString() {
262         return "RangingSessionConfig{"
263                 + "mDeviceRole="
264                 + mDeviceRole
265                 + ", mSessionConfig="
266                 + mSessionConfig
267                 + '}';
268     }
269 }
270