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.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY; 19 import static android.net.vcn.VcnUnderlyingNetworkTemplate.getMatchCriteriaString; 20 21 import static com.android.internal.annotations.VisibleForTesting.Visibility; 22 import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_DESERIALIZER; 23 import static com.android.server.vcn.util.PersistableBundleUtils.INTEGER_SERIALIZER; 24 import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; 25 import static com.android.server.vcn.util.PersistableBundleUtils.STRING_SERIALIZER; 26 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.annotation.SuppressLint; 30 import android.net.NetworkCapabilities; 31 import android.net.vcn.VcnUnderlyingNetworkTemplate.MatchCriteria; 32 import android.os.PersistableBundle; 33 import android.telephony.SubscriptionInfo; 34 import android.telephony.SubscriptionManager; 35 import android.telephony.TelephonyManager; 36 import android.util.ArraySet; 37 38 import com.android.internal.annotations.VisibleForTesting; 39 import com.android.internal.util.IndentingPrintWriter; 40 import com.android.server.vcn.util.PersistableBundleUtils; 41 42 import java.util.ArrayList; 43 import java.util.Collections; 44 import java.util.Objects; 45 import java.util.Set; 46 47 /** 48 * This class represents a configuration for a network template class of underlying cellular 49 * networks. 50 * 51 * <p>See {@link VcnUnderlyingNetworkTemplate} 52 */ 53 public final class VcnCellUnderlyingNetworkTemplate extends VcnUnderlyingNetworkTemplate { 54 private static final String ALLOWED_NETWORK_PLMN_IDS_KEY = "mAllowedNetworkPlmnIds"; 55 @NonNull private final Set<String> mAllowedNetworkPlmnIds; 56 private static final String ALLOWED_SPECIFIC_CARRIER_IDS_KEY = "mAllowedSpecificCarrierIds"; 57 @NonNull private final Set<Integer> mAllowedSpecificCarrierIds; 58 59 private static final String ROAMING_MATCH_KEY = "mRoamingMatchCriteria"; 60 private static final int DEFAULT_ROAMING_MATCH_CRITERIA = MATCH_ANY; 61 private final int mRoamingMatchCriteria; 62 63 private static final String OPPORTUNISTIC_MATCH_KEY = "mOpportunisticMatchCriteria"; 64 private static final int DEFAULT_OPPORTUNISTIC_MATCH_CRITERIA = MATCH_ANY; 65 private final int mOpportunisticMatchCriteria; 66 VcnCellUnderlyingNetworkTemplate( int meteredMatchCriteria, int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps, int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps, Set<String> allowedNetworkPlmnIds, Set<Integer> allowedSpecificCarrierIds, int roamingMatchCriteria, int opportunisticMatchCriteria)67 private VcnCellUnderlyingNetworkTemplate( 68 int meteredMatchCriteria, 69 int minEntryUpstreamBandwidthKbps, 70 int minExitUpstreamBandwidthKbps, 71 int minEntryDownstreamBandwidthKbps, 72 int minExitDownstreamBandwidthKbps, 73 Set<String> allowedNetworkPlmnIds, 74 Set<Integer> allowedSpecificCarrierIds, 75 int roamingMatchCriteria, 76 int opportunisticMatchCriteria) { 77 super( 78 NETWORK_PRIORITY_TYPE_CELL, 79 meteredMatchCriteria, 80 minEntryUpstreamBandwidthKbps, 81 minExitUpstreamBandwidthKbps, 82 minEntryDownstreamBandwidthKbps, 83 minExitDownstreamBandwidthKbps); 84 mAllowedNetworkPlmnIds = new ArraySet<>(allowedNetworkPlmnIds); 85 mAllowedSpecificCarrierIds = new ArraySet<>(allowedSpecificCarrierIds); 86 mRoamingMatchCriteria = roamingMatchCriteria; 87 mOpportunisticMatchCriteria = opportunisticMatchCriteria; 88 89 validate(); 90 } 91 92 /** @hide */ 93 @Override validate()94 protected void validate() { 95 super.validate(); 96 validatePlmnIds(mAllowedNetworkPlmnIds); 97 Objects.requireNonNull(mAllowedSpecificCarrierIds, "matchingCarrierIds is null"); 98 validateMatchCriteria(mRoamingMatchCriteria, "mRoamingMatchCriteria"); 99 validateMatchCriteria(mOpportunisticMatchCriteria, "mOpportunisticMatchCriteria"); 100 } 101 validatePlmnIds(Set<String> matchingOperatorPlmnIds)102 private static void validatePlmnIds(Set<String> matchingOperatorPlmnIds) { 103 Objects.requireNonNull(matchingOperatorPlmnIds, "matchingOperatorPlmnIds is null"); 104 105 // A valid PLMN is a concatenation of MNC and MCC, and thus consists of 5 or 6 decimal 106 // digits. 107 for (String id : matchingOperatorPlmnIds) { 108 if ((id.length() == 5 || id.length() == 6) && id.matches("[0-9]+")) { 109 continue; 110 } else { 111 throw new IllegalArgumentException("Found invalid PLMN ID: " + id); 112 } 113 } 114 } 115 116 /** @hide */ 117 @NonNull 118 @VisibleForTesting(visibility = Visibility.PROTECTED) fromPersistableBundle( @onNull PersistableBundle in)119 public static VcnCellUnderlyingNetworkTemplate fromPersistableBundle( 120 @NonNull PersistableBundle in) { 121 Objects.requireNonNull(in, "PersistableBundle is null"); 122 123 final int meteredMatchCriteria = in.getInt(METERED_MATCH_KEY); 124 125 final int minEntryUpstreamBandwidthKbps = 126 in.getInt(MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); 127 final int minExitUpstreamBandwidthKbps = 128 in.getInt(MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); 129 final int minEntryDownstreamBandwidthKbps = 130 in.getInt(MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); 131 final int minExitDownstreamBandwidthKbps = 132 in.getInt(MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS); 133 134 final PersistableBundle plmnIdsBundle = 135 in.getPersistableBundle(ALLOWED_NETWORK_PLMN_IDS_KEY); 136 Objects.requireNonNull(plmnIdsBundle, "plmnIdsBundle is null"); 137 final Set<String> allowedNetworkPlmnIds = 138 new ArraySet<String>( 139 PersistableBundleUtils.toList(plmnIdsBundle, STRING_DESERIALIZER)); 140 141 final PersistableBundle specificCarrierIdsBundle = 142 in.getPersistableBundle(ALLOWED_SPECIFIC_CARRIER_IDS_KEY); 143 Objects.requireNonNull(specificCarrierIdsBundle, "specificCarrierIdsBundle is null"); 144 final Set<Integer> allowedSpecificCarrierIds = 145 new ArraySet<Integer>( 146 PersistableBundleUtils.toList( 147 specificCarrierIdsBundle, INTEGER_DESERIALIZER)); 148 149 final int roamingMatchCriteria = in.getInt(ROAMING_MATCH_KEY); 150 final int opportunisticMatchCriteria = in.getInt(OPPORTUNISTIC_MATCH_KEY); 151 152 return new VcnCellUnderlyingNetworkTemplate( 153 meteredMatchCriteria, 154 minEntryUpstreamBandwidthKbps, 155 minExitUpstreamBandwidthKbps, 156 minEntryDownstreamBandwidthKbps, 157 minExitDownstreamBandwidthKbps, 158 allowedNetworkPlmnIds, 159 allowedSpecificCarrierIds, 160 roamingMatchCriteria, 161 opportunisticMatchCriteria); 162 } 163 164 /** @hide */ 165 @Override 166 @NonNull 167 @VisibleForTesting(visibility = Visibility.PROTECTED) toPersistableBundle()168 public PersistableBundle toPersistableBundle() { 169 final PersistableBundle result = super.toPersistableBundle(); 170 171 final PersistableBundle plmnIdsBundle = 172 PersistableBundleUtils.fromList( 173 new ArrayList<>(mAllowedNetworkPlmnIds), STRING_SERIALIZER); 174 result.putPersistableBundle(ALLOWED_NETWORK_PLMN_IDS_KEY, plmnIdsBundle); 175 176 final PersistableBundle specificCarrierIdsBundle = 177 PersistableBundleUtils.fromList( 178 new ArrayList<>(mAllowedSpecificCarrierIds), INTEGER_SERIALIZER); 179 result.putPersistableBundle(ALLOWED_SPECIFIC_CARRIER_IDS_KEY, specificCarrierIdsBundle); 180 181 result.putInt(ROAMING_MATCH_KEY, mRoamingMatchCriteria); 182 result.putInt(OPPORTUNISTIC_MATCH_KEY, mOpportunisticMatchCriteria); 183 184 return result; 185 } 186 187 /** 188 * Retrieve the matching operator PLMN IDs, or an empty set if any PLMN ID is acceptable. 189 * 190 * @see Builder#setOperatorPlmnIds(Set) 191 */ 192 @NonNull getOperatorPlmnIds()193 public Set<String> getOperatorPlmnIds() { 194 return Collections.unmodifiableSet(mAllowedNetworkPlmnIds); 195 } 196 197 /** 198 * Retrieve the matching sim specific carrier IDs, or an empty set if any sim specific carrier 199 * ID is acceptable. 200 * 201 * @see Builder#setSimSpecificCarrierIds(Set) 202 */ 203 @NonNull getSimSpecificCarrierIds()204 public Set<Integer> getSimSpecificCarrierIds() { 205 return Collections.unmodifiableSet(mAllowedSpecificCarrierIds); 206 } 207 208 /** 209 * Return the matching criteria for roaming networks. 210 * 211 * @see Builder#setRoaming(int) 212 */ 213 @MatchCriteria getRoaming()214 public int getRoaming() { 215 return mRoamingMatchCriteria; 216 } 217 218 /** 219 * Return the matching criteria for opportunistic cellular subscriptions. 220 * 221 * @see Builder#setOpportunistic(int) 222 */ 223 @MatchCriteria getOpportunistic()224 public int getOpportunistic() { 225 return mOpportunisticMatchCriteria; 226 } 227 228 @Override hashCode()229 public int hashCode() { 230 return Objects.hash( 231 super.hashCode(), 232 mAllowedNetworkPlmnIds, 233 mAllowedSpecificCarrierIds, 234 mRoamingMatchCriteria, 235 mOpportunisticMatchCriteria); 236 } 237 238 @Override equals(@ullable Object other)239 public boolean equals(@Nullable Object other) { 240 if (!super.equals(other)) { 241 return false; 242 } 243 244 if (!(other instanceof VcnCellUnderlyingNetworkTemplate)) { 245 return false; 246 } 247 248 final VcnCellUnderlyingNetworkTemplate rhs = (VcnCellUnderlyingNetworkTemplate) other; 249 return Objects.equals(mAllowedNetworkPlmnIds, rhs.mAllowedNetworkPlmnIds) 250 && Objects.equals(mAllowedSpecificCarrierIds, rhs.mAllowedSpecificCarrierIds) 251 && mRoamingMatchCriteria == rhs.mRoamingMatchCriteria 252 && mOpportunisticMatchCriteria == rhs.mOpportunisticMatchCriteria; 253 } 254 255 /** @hide */ 256 @Override dumpTransportSpecificFields(IndentingPrintWriter pw)257 void dumpTransportSpecificFields(IndentingPrintWriter pw) { 258 if (!mAllowedNetworkPlmnIds.isEmpty()) { 259 pw.println("mAllowedNetworkPlmnIds: " + mAllowedNetworkPlmnIds); 260 } 261 if (!mAllowedNetworkPlmnIds.isEmpty()) { 262 pw.println("mAllowedSpecificCarrierIds: " + mAllowedSpecificCarrierIds); 263 } 264 if (mRoamingMatchCriteria != DEFAULT_ROAMING_MATCH_CRITERIA) { 265 pw.println("mRoamingMatchCriteria: " + getMatchCriteriaString(mRoamingMatchCriteria)); 266 } 267 if (mOpportunisticMatchCriteria != DEFAULT_OPPORTUNISTIC_MATCH_CRITERIA) { 268 pw.println( 269 "mOpportunisticMatchCriteria: " 270 + getMatchCriteriaString(mOpportunisticMatchCriteria)); 271 } 272 } 273 274 /** This class is used to incrementally build VcnCellUnderlyingNetworkTemplate objects. */ 275 public static final class Builder { 276 private int mMeteredMatchCriteria = DEFAULT_METERED_MATCH_CRITERIA; 277 278 @NonNull private final Set<String> mAllowedNetworkPlmnIds = new ArraySet<>(); 279 @NonNull private final Set<Integer> mAllowedSpecificCarrierIds = new ArraySet<>(); 280 281 private int mRoamingMatchCriteria = DEFAULT_ROAMING_MATCH_CRITERIA; 282 private int mOpportunisticMatchCriteria = DEFAULT_OPPORTUNISTIC_MATCH_CRITERIA; 283 284 private int mMinEntryUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; 285 private int mMinExitUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; 286 private int mMinEntryDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; 287 private int mMinExitDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS; 288 289 /** Construct a Builder object. */ Builder()290 public Builder() {} 291 292 /** 293 * Set the matching criteria for metered networks. 294 * 295 * <p>A template where setMetered(MATCH_REQUIRED) will only match metered networks (one 296 * without NET_CAPABILITY_NOT_METERED). A template where setMetered(MATCH_FORBIDDEN) will 297 * only match a network that is not metered (one with NET_CAPABILITY_NOT_METERED). 298 * 299 * @param matchCriteria the matching criteria for metered networks. Defaults to {@link 300 * #MATCH_ANY}. 301 * @see NetworkCapabilities#NET_CAPABILITY_NOT_METERED 302 */ 303 // The matching getter is defined in the super class. Please see {@link 304 // VcnUnderlyingNetworkTemplate#getMetered()} 305 @SuppressLint("MissingGetterMatchingBuilder") 306 @NonNull setMetered(@atchCriteria int matchCriteria)307 public Builder setMetered(@MatchCriteria int matchCriteria) { 308 validateMatchCriteria(matchCriteria, "setMetered"); 309 310 mMeteredMatchCriteria = matchCriteria; 311 return this; 312 } 313 314 /** 315 * Set operator PLMN IDs with which a network can match this template. 316 * 317 * <p>This is used to distinguish cases where roaming agreements may dictate a different 318 * priority from a partner's networks. 319 * 320 * @param operatorPlmnIds the matching operator PLMN IDs in String. Network with one of the 321 * matching PLMN IDs can match this template. If the set is empty, any PLMN ID will 322 * match. The default is an empty set. A valid PLMN is a concatenation of MNC and MCC, 323 * and thus consists of 5 or 6 decimal digits. 324 * @see SubscriptionInfo#getMccString() 325 * @see SubscriptionInfo#getMncString() 326 */ 327 @NonNull setOperatorPlmnIds(@onNull Set<String> operatorPlmnIds)328 public Builder setOperatorPlmnIds(@NonNull Set<String> operatorPlmnIds) { 329 validatePlmnIds(operatorPlmnIds); 330 331 mAllowedNetworkPlmnIds.clear(); 332 mAllowedNetworkPlmnIds.addAll(operatorPlmnIds); 333 return this; 334 } 335 336 /** 337 * Set sim specific carrier IDs with which a network can match this template. 338 * 339 * @param simSpecificCarrierIds the matching sim specific carrier IDs. Network with one of 340 * the sim specific carrier IDs can match this template. If the set is empty, any 341 * carrier ID will match. The default is an empty set. 342 * @see TelephonyManager#getSimSpecificCarrierId() 343 */ 344 @NonNull setSimSpecificCarrierIds(@onNull Set<Integer> simSpecificCarrierIds)345 public Builder setSimSpecificCarrierIds(@NonNull Set<Integer> simSpecificCarrierIds) { 346 Objects.requireNonNull(simSpecificCarrierIds, "simSpecificCarrierIds is null"); 347 348 mAllowedSpecificCarrierIds.clear(); 349 mAllowedSpecificCarrierIds.addAll(simSpecificCarrierIds); 350 return this; 351 } 352 353 /** 354 * Set the matching criteria for roaming networks. 355 * 356 * <p>A template where setRoaming(MATCH_REQUIRED) will only match roaming networks (one 357 * without NET_CAPABILITY_NOT_ROAMING). A template where setRoaming(MATCH_FORBIDDEN) will 358 * only match a network that is not roaming (one with NET_CAPABILITY_NOT_ROAMING). 359 * 360 * @param matchCriteria the matching criteria for roaming networks. Defaults to {@link 361 * #MATCH_ANY}. 362 * @see NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING 363 */ 364 @NonNull setRoaming(@atchCriteria int matchCriteria)365 public Builder setRoaming(@MatchCriteria int matchCriteria) { 366 validateMatchCriteria(matchCriteria, "setRoaming"); 367 368 mRoamingMatchCriteria = matchCriteria; 369 return this; 370 } 371 372 /** 373 * Set the matching criteria for opportunistic cellular subscriptions. 374 * 375 * @param matchCriteria the matching criteria for opportunistic cellular subscriptions. 376 * Defaults to {@link #MATCH_ANY}. 377 * @see SubscriptionManager#setOpportunistic(boolean, int) 378 */ 379 @NonNull setOpportunistic(@atchCriteria int matchCriteria)380 public Builder setOpportunistic(@MatchCriteria int matchCriteria) { 381 validateMatchCriteria(matchCriteria, "setOpportunistic"); 382 383 mOpportunisticMatchCriteria = matchCriteria; 384 return this; 385 } 386 387 /** 388 * Set the minimum upstream bandwidths that this template will match. 389 * 390 * <p>This template will not match a network that does not provide at least the bandwidth 391 * passed as the entry bandwidth, except in the case that the network is selected as the VCN 392 * Gateway Connection's underlying network, where it will continue to match until the 393 * bandwidth drops under the exit bandwidth. 394 * 395 * <p>The entry criteria MUST be greater than, or equal to the exit criteria to avoid the 396 * invalid case where a network fulfills the entry criteria, but at the same time fails the 397 * exit criteria. 398 * 399 * <p>Estimated bandwidth of a network is provided by the transport layer, and reported in 400 * {@link NetworkCapabilities}. The provided estimates will be used without modification. 401 * 402 * @param minEntryUpstreamBandwidthKbps the minimum accepted upstream bandwidth for networks 403 * that ARE NOT the already-selected underlying network, or {@code 0} to disable this 404 * requirement. Disabled by default. 405 * @param minExitUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a network 406 * that IS the already-selected underlying network, or {@code 0} to disable this 407 * requirement. Disabled by default. 408 * @return this {@link Builder} instance, for chaining 409 */ 410 @NonNull 411 // The getter for the two integers are separated, and in the superclass. Please see {@link 412 // VcnUnderlyingNetworkTemplate#getMinEntryUpstreamBandwidthKbps()} and {@link 413 // VcnUnderlyingNetworkTemplate#getMinExitUpstreamBandwidthKbps()} 414 @SuppressLint("MissingGetterMatchingBuilder") setMinUpstreamBandwidthKbps( int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps)415 public Builder setMinUpstreamBandwidthKbps( 416 int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps) { 417 validateMinBandwidthKbps(minEntryUpstreamBandwidthKbps, minExitUpstreamBandwidthKbps); 418 419 mMinEntryUpstreamBandwidthKbps = minEntryUpstreamBandwidthKbps; 420 mMinExitUpstreamBandwidthKbps = minExitUpstreamBandwidthKbps; 421 422 return this; 423 } 424 425 /** 426 * Set the minimum upstream bandwidths that this template will match. 427 * 428 * <p>This template will not match a network that does not provide at least the bandwidth 429 * passed as the entry bandwidth, except in the case that the network is selected as the VCN 430 * Gateway Connection's underlying network, where it will continue to match until the 431 * bandwidth drops under the exit bandwidth. 432 * 433 * <p>The entry criteria MUST be greater than, or equal to the exit criteria to avoid the 434 * invalid case where a network fulfills the entry criteria, but at the same time fails the 435 * exit criteria. 436 * 437 * <p>Estimated bandwidth of a network is provided by the transport layer, and reported in 438 * {@link NetworkCapabilities}. The provided estimates will be used without modification. 439 * 440 * @param minEntryDownstreamBandwidthKbps the minimum accepted downstream bandwidth for 441 * networks that ARE NOT the already-selected underlying network, or {@code 0} to 442 * disable this requirement. Disabled by default. 443 * @param minExitDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a 444 * network that IS the already-selected underlying network, or {@code 0} to disable this 445 * requirement. Disabled by default. 446 * @return this {@link Builder} instance, for chaining 447 */ 448 @NonNull 449 // The getter for the two integers are separated, and in the superclass. Please see {@link 450 // VcnUnderlyingNetworkTemplate#getMinEntryDownstreamBandwidthKbps()} and {@link 451 // VcnUnderlyingNetworkTemplate#getMinExitDownstreamBandwidthKbps()} 452 @SuppressLint("MissingGetterMatchingBuilder") setMinDownstreamBandwidthKbps( int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps)453 public Builder setMinDownstreamBandwidthKbps( 454 int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps) { 455 validateMinBandwidthKbps( 456 minEntryDownstreamBandwidthKbps, minExitDownstreamBandwidthKbps); 457 458 mMinEntryDownstreamBandwidthKbps = minEntryDownstreamBandwidthKbps; 459 mMinExitDownstreamBandwidthKbps = minExitDownstreamBandwidthKbps; 460 461 return this; 462 } 463 464 /** Build the VcnCellUnderlyingNetworkTemplate. */ 465 @NonNull build()466 public VcnCellUnderlyingNetworkTemplate build() { 467 return new VcnCellUnderlyingNetworkTemplate( 468 mMeteredMatchCriteria, 469 mMinEntryUpstreamBandwidthKbps, 470 mMinExitUpstreamBandwidthKbps, 471 mMinEntryDownstreamBandwidthKbps, 472 mMinExitDownstreamBandwidthKbps, 473 mAllowedNetworkPlmnIds, 474 mAllowedSpecificCarrierIds, 475 mRoamingMatchCriteria, 476 mOpportunisticMatchCriteria); 477 } 478 } 479 } 480