1 /*
2  * Copyright (C) 2021 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 package android.net.vcn;
17 
18 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
19 import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY;
20 
21 import static com.android.internal.annotations.VisibleForTesting.Visibility;
22 import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER;
23 import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER;
24 
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.annotation.SuppressLint;
28 import android.net.NetworkCapabilities;
29 import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria;
30 import android.os.PersistableBundle;
31 import android.util.ArraySet;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.internal.util.IndentingPrintWriter;
35 import com.android.server.vcn.util.PersistableBundleUtils;
36 
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.Map;
40 import java.util.Objects;
41 import java.util.Set;
42 
43 /**
44  * This class represents a configuration for a network template class of underlying Carrier WiFi
45  * networks.
46  *
47  * <p>See {@link VcnUnderlyingNetworkTemplate}
48  */
49 public final class VcnWifiUnderlyingNetworkTemplate extends VcnUnderlyingNetworkTemplate {
50     private static final String SSIDS_KEY = "mSsids";
51     @Nullable private final Set<String> mSsids;
52 
VcnWifiUnderlyingNetworkTemplate( int meteredMatchCriteria, int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps, int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps, Set<String> ssids)53     private VcnWifiUnderlyingNetworkTemplate(
54             int meteredMatchCriteria,
55             int minEntryUpstreamBandwidthKbps,
56             int minExitUpstreamBandwidthKbps,
57             int minEntryDownstreamBandwidthKbps,
58             int minExitDownstreamBandwidthKbps,
59             Set<String> ssids) {
60         super(
61                 NETWORK_PRIORITY_TYPE_WIFI,
62                 meteredMatchCriteria,
63                 minEntryUpstreamBandwidthKbps,
64                 minExitUpstreamBandwidthKbps,
65                 minEntryDownstreamBandwidthKbps,
66                 minExitDownstreamBandwidthKbps);
67         mSsids = new ArraySet<>(ssids);
68 
69         validate();
70     }
71 
72     /** @hide */
73     @Override
validate()74     protected void validate() {
75         super.validate();
76         validateSsids(mSsids);
77     }
78 
validateSsids(Set<String> ssids)79     private static void validateSsids(Set<String> ssids) {
80         Objects.requireNonNull(ssids, "ssids is null");
81 
82         for (String ssid : ssids) {
83             Objects.requireNonNull(ssid, "found null value ssid");
84         }
85     }
86 
87     /** @hide */
88     @NonNull
89     @VisibleForTesting(visibility = Visibility.PROTECTED)
fromPersistableBundle( @onNull PersistableBundle in)90     public static VcnWifiUnderlyingNetworkTemplate fromPersistableBundle(
91             @NonNull PersistableBundle in) {
92         Objects.requireNonNull(in, "PersistableBundle is null");
93 
94         final int meteredMatchCriteria = in.getInt(METERED_MATCH_KEY);
95 
96         final int minEntryUpstreamBandwidthKbps =
97                 in.getInt(MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
98         final int minExitUpstreamBandwidthKbps =
99                 in.getInt(MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
100         final int minEntryDownstreamBandwidthKbps =
101                 in.getInt(MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
102         final int minExitDownstreamBandwidthKbps =
103                 in.getInt(MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
104 
105         final PersistableBundle ssidsBundle = in.getPersistableBundle(SSIDS_KEY);
106         Objects.requireNonNull(ssidsBundle, "ssidsBundle is null");
107         final Set<String> ssids =
108                 new ArraySet<String>(
109                         PersistableBundleUtils.toList(ssidsBundle, STRING_DESERIALIZER));
110         return new VcnWifiUnderlyingNetworkTemplate(
111                 meteredMatchCriteria,
112                 minEntryUpstreamBandwidthKbps,
113                 minExitUpstreamBandwidthKbps,
114                 minEntryDownstreamBandwidthKbps,
115                 minExitDownstreamBandwidthKbps,
116                 ssids);
117     }
118 
119     /** @hide */
120     @Override
121     @NonNull
122     @VisibleForTesting(visibility = Visibility.PROTECTED)
toPersistableBundle()123     public PersistableBundle toPersistableBundle() {
124         final PersistableBundle result = super.toPersistableBundle();
125 
126         final PersistableBundle ssidsBundle =
127                 PersistableBundleUtils.fromList(new ArrayList<>(mSsids), STRING_SERIALIZER);
128         result.putPersistableBundle(SSIDS_KEY, ssidsBundle);
129 
130         return result;
131     }
132 
133     @Override
hashCode()134     public int hashCode() {
135         return Objects.hash(super.hashCode(), mSsids);
136     }
137 
138     @Override
equals(@ullable Object other)139     public boolean equals(@Nullable Object other) {
140         if (!super.equals(other)) {
141             return false;
142         }
143 
144         if (!(other instanceof VcnWifiUnderlyingNetworkTemplate)) {
145             return false;
146         }
147 
148         final VcnWifiUnderlyingNetworkTemplate rhs = (VcnWifiUnderlyingNetworkTemplate) other;
149         return mSsids.equals(rhs.mSsids);
150     }
151 
152     /** @hide */
153     @Override
dumpTransportSpecificFields(IndentingPrintWriter pw)154     void dumpTransportSpecificFields(IndentingPrintWriter pw) {
155         if (!mSsids.isEmpty()) {
156             pw.println("mSsids: " + mSsids);
157         }
158     }
159 
160     /**
161      * Retrieve the matching SSIDs, or an empty set if any SSID is acceptable.
162      *
163      * @see Builder#setSsids(Set)
164      */
165     @NonNull
getSsids()166     public Set<String> getSsids() {
167         return Collections.unmodifiableSet(mSsids);
168     }
169 
170     /** @hide */
171     @Override
getCapabilitiesMatchCriteria()172     public Map<Integer, Integer> getCapabilitiesMatchCriteria() {
173         return Collections.singletonMap(NET_CAPABILITY_INTERNET, MATCH_REQUIRED);
174     }
175 
176     /** This class is used to incrementally build VcnWifiUnderlyingNetworkTemplate objects. */
177     public static final class Builder {
178         private int mMeteredMatchCriteria = MATCH_ANY;
179         @NonNull private final Set<String> mSsids = new ArraySet<>();
180 
181         private int mMinEntryUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
182         private int mMinExitUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
183         private int mMinEntryDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
184         private int mMinExitDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
185 
186         /** Construct a Builder object. */
Builder()187         public Builder() {}
188 
189         /**
190          * Set the matching criteria for metered networks.
191          *
192          * <p>A template where setMetered(MATCH_REQUIRED) will only match metered networks (one
193          * without NET_CAPABILITY_NOT_METERED). A template where setMetered(MATCH_FORBIDDEN) will
194          * only match a network that is not metered (one with NET_CAPABILITY_NOT_METERED).
195          *
196          * @param matchCriteria the matching criteria for metered networks. Defaults to {@link
197          *     #MATCH_ANY}.
198          * @see NetworkCapabilities#NET_CAPABILITY_NOT_METERED
199          */
200         // The matching getter is defined in the super class. Please see {@link
201         // VcnUnderlyingNetworkTemplate#getMetered()}
202         @SuppressLint("MissingGetterMatchingBuilder")
203         @NonNull
setMetered(@atchCriteria int matchCriteria)204         public Builder setMetered(@MatchCriteria int matchCriteria) {
205             validateMatchCriteria(matchCriteria, "setMetered");
206 
207             mMeteredMatchCriteria = matchCriteria;
208             return this;
209         }
210 
211         /**
212          * Set the SSIDs with which a network can match this priority rule.
213          *
214          * @param ssids the matching SSIDs. Network with one of the matching SSIDs can match this
215          *     priority rule. If the set is empty, any SSID will match. The default is an empty set.
216          */
217         @NonNull
setSsids(@onNull Set<String> ssids)218         public Builder setSsids(@NonNull Set<String> ssids) {
219             validateSsids(ssids);
220 
221             mSsids.clear();
222             mSsids.addAll(ssids);
223             return this;
224         }
225 
226         /**
227          * Set the minimum upstream bandwidths that this template will match.
228          *
229          * <p>This template will not match a network that does not provide at least the bandwidth
230          * passed as the entry bandwidth, except in the case that the network is selected as the VCN
231          * Gateway Connection's underlying network, where it will continue to match until the
232          * bandwidth drops under the exit bandwidth.
233          *
234          * <p>The entry criteria MUST be greater than, or equal to the exit criteria to avoid the
235          * invalid case where a network fulfills the entry criteria, but at the same time fails the
236          * exit criteria.
237          *
238          * <p>Estimated bandwidth of a network is provided by the transport layer, and reported in
239          * {@link NetworkCapabilities}. The provided estimates will be used without modification.
240          *
241          * @param minEntryUpstreamBandwidthKbps the minimum accepted upstream bandwidth for networks
242          *     that ARE NOT the already-selected underlying network, or {@code 0} to disable this
243          *     requirement. Disabled by default.
244          * @param minExitUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a network
245          *     that IS the already-selected underlying network, or {@code 0} to disable this
246          *     requirement. Disabled by default.
247          * @return this {@link Builder} instance, for chaining
248          */
249         @NonNull
250         // The getter for the two integers are separated, and in the superclass. Please see {@link
251         // VcnUnderlyingNetworkTemplate#getMinEntryUpstreamBandwidthKbps()} and {@link
252         // VcnUnderlyingNetworkTemplate#getMinExitUpstreamBandwidthKbps()}
253         @SuppressLint("MissingGetterMatchingBuilder")
setMinUpstreamBandwidthKbps( int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps)254         public Builder setMinUpstreamBandwidthKbps(
255                 int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps) {
256             validateMinBandwidthKbps(minEntryUpstreamBandwidthKbps, minExitUpstreamBandwidthKbps);
257 
258             mMinEntryUpstreamBandwidthKbps = minEntryUpstreamBandwidthKbps;
259             mMinExitUpstreamBandwidthKbps = minExitUpstreamBandwidthKbps;
260 
261             return this;
262         }
263 
264         /**
265          * Set the minimum upstream bandwidths that this template will match.
266          *
267          * <p>This template will not match a network that does not provide at least the bandwidth
268          * passed as the entry bandwidth, except in the case that the network is selected as the VCN
269          * Gateway Connection's underlying network, where it will continue to match until the
270          * bandwidth drops under the exit bandwidth.
271          *
272          * <p>The entry criteria MUST be greater than, or equal to the exit criteria to avoid the
273          * invalid case where a network fulfills the entry criteria, but at the same time fails the
274          * exit criteria.
275          *
276          * <p>Estimated bandwidth of a network is provided by the transport layer, and reported in
277          * {@link NetworkCapabilities}. The provided estimates will be used without modification.
278          *
279          * @param minEntryDownstreamBandwidthKbps the minimum accepted downstream bandwidth for
280          *     networks that ARE NOT the already-selected underlying network, or {@code 0} to
281          *     disable this requirement. Disabled by default.
282          * @param minExitDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a
283          *     network that IS the already-selected underlying network, or {@code 0} to disable this
284          *     requirement. Disabled by default.
285          * @return this {@link Builder} instance, for chaining
286          */
287         @NonNull
288         // The getter for the two integers are separated, and in the superclass. Please see {@link
289         // VcnUnderlyingNetworkTemplate#getMinEntryDownstreamBandwidthKbps()} and {@link
290         // VcnUnderlyingNetworkTemplate#getMinExitDownstreamBandwidthKbps()}
291         @SuppressLint("MissingGetterMatchingBuilder")
setMinDownstreamBandwidthKbps( int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps)292         public Builder setMinDownstreamBandwidthKbps(
293                 int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps) {
294             validateMinBandwidthKbps(
295                     minEntryDownstreamBandwidthKbps, minExitDownstreamBandwidthKbps);
296 
297             mMinEntryDownstreamBandwidthKbps = minEntryDownstreamBandwidthKbps;
298             mMinExitDownstreamBandwidthKbps = minExitDownstreamBandwidthKbps;
299 
300             return this;
301         }
302 
303         /** Build the VcnWifiUnderlyingNetworkTemplate. */
304         @NonNull
build()305         public VcnWifiUnderlyingNetworkTemplate build() {
306             return new VcnWifiUnderlyingNetworkTemplate(
307                     mMeteredMatchCriteria,
308                     mMinEntryUpstreamBandwidthKbps,
309                     mMinExitUpstreamBandwidthKbps,
310                     mMinEntryDownstreamBandwidthKbps,
311                     mMinExitDownstreamBandwidthKbps,
312                     mSsids);
313         }
314     }
315 }
316