1 /* 2 * Copyright (C) 2011 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 android.net; 18 19 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; 20 import static android.net.ConnectivityManager.TYPE_BLUETOOTH; 21 import static android.net.ConnectivityManager.TYPE_ETHERNET; 22 import static android.net.ConnectivityManager.TYPE_MOBILE; 23 import static android.net.ConnectivityManager.TYPE_PROXY; 24 import static android.net.ConnectivityManager.TYPE_WIFI; 25 import static android.net.ConnectivityManager.TYPE_WIFI_P2P; 26 import static android.net.ConnectivityManager.TYPE_WIMAX; 27 import static android.net.NetworkIdentity.OEM_NONE; 28 import static android.net.NetworkIdentity.OEM_PAID; 29 import static android.net.NetworkIdentity.OEM_PRIVATE; 30 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; 31 import static android.net.NetworkStats.DEFAULT_NETWORK_NO; 32 import static android.net.NetworkStats.DEFAULT_NETWORK_YES; 33 import static android.net.NetworkStats.METERED_ALL; 34 import static android.net.NetworkStats.METERED_NO; 35 import static android.net.NetworkStats.METERED_YES; 36 import static android.net.NetworkStats.ROAMING_ALL; 37 import static android.net.NetworkStats.ROAMING_NO; 38 import static android.net.NetworkStats.ROAMING_YES; 39 40 import android.annotation.IntDef; 41 import android.annotation.NonNull; 42 import android.annotation.Nullable; 43 import android.annotation.SystemApi; 44 import android.app.usage.NetworkStatsManager; 45 import android.compat.annotation.UnsupportedAppUsage; 46 import android.net.wifi.WifiInfo; 47 import android.os.Build; 48 import android.os.Parcel; 49 import android.os.Parcelable; 50 import android.text.TextUtils; 51 import android.util.ArraySet; 52 import android.util.Log; 53 54 import com.android.internal.annotations.VisibleForTesting; 55 import com.android.modules.utils.build.SdkLevel; 56 import com.android.net.module.util.CollectionUtils; 57 import com.android.net.module.util.NetworkIdentityUtils; 58 59 import java.lang.annotation.Retention; 60 import java.lang.annotation.RetentionPolicy; 61 import java.util.Arrays; 62 import java.util.Collections; 63 import java.util.Comparator; 64 import java.util.HashSet; 65 import java.util.List; 66 import java.util.Objects; 67 import java.util.Set; 68 import java.util.SortedSet; 69 import java.util.TreeSet; 70 71 /** 72 * Predicate used to match {@link NetworkIdentity}, usually when collecting 73 * statistics. (It should probably have been named {@code NetworkPredicate}.) 74 * 75 * @hide 76 */ 77 @SystemApi(client = MODULE_LIBRARIES) 78 public final class NetworkTemplate implements Parcelable { 79 private static final String TAG = NetworkTemplate.class.getSimpleName(); 80 81 /** @hide */ 82 @Retention(RetentionPolicy.SOURCE) 83 @IntDef(prefix = { "MATCH_" }, value = { 84 MATCH_MOBILE, 85 MATCH_WIFI, 86 MATCH_ETHERNET, 87 MATCH_BLUETOOTH, 88 MATCH_PROXY, 89 MATCH_CARRIER, 90 }) 91 public @interface TemplateMatchRule{} 92 93 /** Match rule to match cellular networks with given Subscriber Ids. */ 94 public static final int MATCH_MOBILE = 1; 95 /** Match rule to match wifi networks. */ 96 public static final int MATCH_WIFI = 4; 97 /** Match rule to match ethernet networks. */ 98 public static final int MATCH_ETHERNET = 5; 99 /** Match rule to match bluetooth networks. */ 100 public static final int MATCH_BLUETOOTH = 8; 101 /** 102 * Match rule to match networks with {@link ConnectivityManager#TYPE_PROXY} as the legacy 103 * network type. 104 */ 105 public static final int MATCH_PROXY = 9; 106 /** 107 * Match rule to match all networks with subscriberId inside the template. Some carriers 108 * may offer non-cellular networks like WiFi, which will be matched by this rule. 109 */ 110 public static final int MATCH_CARRIER = 10; 111 /** 112 * Match rule to match networks with {@link ConnectivityManager#TYPE_TEST} as the legacy 113 * network type. 114 * 115 * @hide 116 */ 117 @VisibleForTesting 118 public static final int MATCH_TEST = 11; 119 120 // TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL. 121 /** @hide */ 122 public static final String WIFI_NETWORKID_ALL = null; 123 124 /** 125 * Wi-Fi Network Key is never supposed to be null (if it is, it is a bug that 126 * should be fixed), so it's not possible to want to match null vs 127 * non-null. Therefore it's fine to use null as a sentinel for Wifi Network Key. 128 * 129 * @hide 130 */ 131 public static final String WIFI_NETWORK_KEY_ALL = WIFI_NETWORKID_ALL; 132 133 /** 134 * Include all network types when filtering. This is meant to merge in with the 135 * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. 136 */ 137 public static final int NETWORK_TYPE_ALL = -1; 138 139 /** @hide */ 140 @Retention(RetentionPolicy.SOURCE) 141 @IntDef(prefix = { "OEM_MANAGED_" }, value = { 142 OEM_MANAGED_ALL, 143 OEM_MANAGED_NO, 144 OEM_MANAGED_YES, 145 OEM_MANAGED_PAID, 146 OEM_MANAGED_PRIVATE 147 }) 148 public @interface OemManaged{} 149 150 /** 151 * Value to match both OEM managed and unmanaged networks (all networks). 152 */ 153 public static final int OEM_MANAGED_ALL = -1; 154 /** 155 * Value to match networks which are not OEM managed. 156 */ 157 public static final int OEM_MANAGED_NO = OEM_NONE; 158 /** 159 * Value to match any OEM managed network. 160 */ 161 public static final int OEM_MANAGED_YES = -2; 162 /** 163 * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}. 164 */ 165 public static final int OEM_MANAGED_PAID = OEM_PAID; 166 /** 167 * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}. 168 */ 169 public static final int OEM_MANAGED_PRIVATE = OEM_PRIVATE; 170 isKnownMatchRule(final int rule)171 private static boolean isKnownMatchRule(final int rule) { 172 switch (rule) { 173 case MATCH_MOBILE: 174 case MATCH_WIFI: 175 case MATCH_ETHERNET: 176 case MATCH_BLUETOOTH: 177 case MATCH_PROXY: 178 case MATCH_CARRIER: 179 case MATCH_TEST: 180 return true; 181 182 default: 183 return false; 184 } 185 } 186 setOf(@ullable final String item)187 private static Set<String> setOf(@Nullable final String item) { 188 if (item == null) { 189 // Set.of will throw if item is null 190 final Set<String> set = new HashSet<>(); 191 set.add(null); 192 return Collections.unmodifiableSet(set); 193 } else { 194 return Set.of(item); 195 } 196 } 197 throwAtLeastU()198 private static void throwAtLeastU() { 199 if (SdkLevel.isAtLeastU()) { 200 throw new UnsupportedOperationException("Method not supported on Android U or above"); 201 } 202 } 203 204 /** 205 * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with 206 * the given IMSI. 207 * 208 * @deprecated Use {@link Builder} to build a template. 209 * @hide 210 */ 211 @Deprecated 212 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU, 213 publicAlternatives = "Use {@code Builder} instead.") buildTemplateMobileAll(@onNull String subscriberId)214 public static NetworkTemplate buildTemplateMobileAll(@NonNull String subscriberId) { 215 return new NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES) 216 .setSubscriberIds(setOf(subscriberId)).build(); 217 } 218 219 /** 220 * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, 221 * regardless of IMSI. 222 * 223 * @deprecated Use {@link Builder} to build a template. 224 * @hide 225 */ 226 @Deprecated 227 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) buildTemplateMobileWildcard()228 public static NetworkTemplate buildTemplateMobileWildcard() { 229 return new NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES).build(); 230 } 231 232 /** 233 * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, 234 * regardless of key of the wifi network. 235 * 236 * @deprecated Use {@link Builder} to build a template. 237 * @hide 238 */ 239 @Deprecated 240 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU, 241 publicAlternatives = "Use {@code Builder} instead.") buildTemplateWifiWildcard()242 public static NetworkTemplate buildTemplateWifiWildcard() { 243 return new NetworkTemplate.Builder(MATCH_WIFI).build(); 244 } 245 246 /** 247 * @deprecated Use {@link Builder} to build a template. 248 * @hide 249 */ 250 @Deprecated 251 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU, 252 publicAlternatives = "Use {@code Builder} instead.") buildTemplateWifi()253 public static NetworkTemplate buildTemplateWifi() { 254 return buildTemplateWifiWildcard(); 255 } 256 257 /** 258 * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style 259 * networks together. 260 * 261 * @deprecated Use {@link Builder} to build a template. 262 * @hide 263 */ 264 @Deprecated 265 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU, 266 publicAlternatives = "Use {@code Builder} instead.") buildTemplateEthernet()267 public static NetworkTemplate buildTemplateEthernet() { 268 return new NetworkTemplate.Builder(MATCH_ETHERNET).build(); 269 } 270 271 /** 272 * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style 273 * networks together. 274 * 275 * @hide 276 */ 277 // TODO(b/270089918): Remove this method. This can only be done after there are no more callers, 278 // including in OEM code which can access this by linking against the framework. buildTemplateBluetooth()279 public static NetworkTemplate buildTemplateBluetooth() { 280 // TODO : this is part of hidden-o txt, does that mean it should be annotated with 281 // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps 282 // targeting O- crash on those devices. 283 return new NetworkTemplate.Builder(MATCH_BLUETOOTH).build(); 284 } 285 286 /** 287 * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style 288 * networks together. 289 * 290 * @hide 291 */ 292 // TODO(b/270089918): Remove this method. This can only be done after there are no more callers, 293 // including in OEM code which can access this by linking against the framework. buildTemplateProxy()294 public static NetworkTemplate buildTemplateProxy() { 295 // TODO : this is part of hidden-o txt, does that mean it should be annotated with 296 // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps 297 // targeting O- crash on those devices. 298 return new NetworkTemplate(MATCH_PROXY, null, null); 299 } 300 301 /** 302 * Template to match all metered carrier networks with the given IMSI. 303 * 304 * @hide 305 */ 306 // TODO(b/273963543): Remove this method. This can only be done after there are no more callers, 307 // including in OEM code which can access this by linking against the framework. buildTemplateCarrierMetered(@onNull String subscriberId)308 public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) { 309 throwAtLeastU(); 310 return new NetworkTemplate.Builder(MATCH_CARRIER) 311 // Set.of will throw if subscriberId is null, which is the historical 312 // behavior and should be preserved. 313 .setSubscriberIds(Set.of(subscriberId)) 314 .setMeteredness(METERED_YES) 315 .build(); 316 } 317 318 /** 319 * Template to match cellular networks with the given IMSI, {@code ratType} and 320 * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when 321 * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. 322 * 323 * @hide 324 */ 325 // TODO(b/273963543): Remove this method. This can only be done after there are no more callers, 326 // including in OEM code which can access this by linking against the framework. buildTemplateMobileWithRatType(@ullable String subscriberId, int ratType, int metered)327 public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, 328 int ratType, int metered) { 329 throwAtLeastU(); 330 return new NetworkTemplate.Builder(MATCH_MOBILE) 331 .setSubscriberIds(TextUtils.isEmpty(subscriberId) 332 ? Collections.emptySet() 333 : Set.of(subscriberId)) 334 .setMeteredness(metered) 335 .setRatType(ratType) 336 .build(); 337 } 338 339 /** 340 * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the 341 * given key of the wifi network. 342 * 343 * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} 344 * to know details about the key. 345 * @hide 346 */ 347 // TODO(b/273963543): Remove this method. This can only be done after there are no more callers, 348 // including in OEM code which can access this by linking against the framework. buildTemplateWifi(@onNull String wifiNetworkKey)349 public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) { 350 // TODO : this is part of hidden-o txt, does that mean it should be annotated with 351 // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps 352 // targeting O- crash on those devices. 353 return new NetworkTemplate.Builder(MATCH_WIFI) 354 // Set.of will throw if wifiNetworkKey is null, which is the historical 355 // behavior and should be preserved. 356 .setWifiNetworkKeys(Set.of(wifiNetworkKey)) 357 .build(); 358 } 359 360 /** 361 * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given 362 * key of the wifi network and IMSI. 363 * 364 * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless 365 * of key of the wifi network. 366 * 367 * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} 368 * to know details about the key. 369 * @param subscriberId the IMSI associated to this wifi network. 370 * 371 * @hide 372 */ 373 // TODO(b/273963543): Remove this method. This can only be done after there are no more callers, 374 // including in OEM code which can access this by linking against the framework. buildTemplateWifi(@ullable String wifiNetworkKey, @Nullable String subscriberId)375 public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey, 376 @Nullable String subscriberId) { 377 throwAtLeastU(); 378 return new NetworkTemplate.Builder(MATCH_WIFI) 379 .setSubscriberIds(setOf(subscriberId)) 380 .setWifiNetworkKeys(wifiNetworkKey == null 381 ? Collections.emptySet() 382 : Set.of(wifiNetworkKey)) 383 .build(); 384 } 385 386 private final int mMatchRule; 387 388 /** 389 * Ugh, templates are designed to target a single subscriber, but we might 390 * need to match several "merged" subscribers. These are the subscribers 391 * that should be considered to match this template. 392 * <p> 393 * Since the merge set is dynamic, it should <em>not</em> be persisted or 394 * used for determining equality. 395 */ 396 @NonNull 397 private final String[] mMatchSubscriberIds; 398 399 @NonNull 400 private final String[] mMatchWifiNetworkKeys; 401 402 // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. 403 private final int mMetered; 404 private final int mRoaming; 405 private final int mDefaultNetwork; 406 private final int mRatType; 407 408 // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. 409 private final int mOemManaged; 410 checkValidMatchSubscriberIds(int matchRule, String[] matchSubscriberIds)411 private static void checkValidMatchSubscriberIds(int matchRule, String[] matchSubscriberIds) { 412 switch (matchRule) { 413 // CARRIER templates must always specify a valid subscriber ID. 414 // MOBILE templates can have empty matchSubscriberIds but it must not contain a null 415 // subscriber ID. 416 case MATCH_CARRIER: 417 if (matchSubscriberIds.length == 0) { 418 throw new IllegalArgumentException("matchSubscriberIds may not contain" 419 + " null for rule " + getMatchRuleName(matchRule)); 420 } 421 if (CollectionUtils.contains(matchSubscriberIds, null)) { 422 throw new IllegalArgumentException("matchSubscriberIds may not contain" 423 + " null for rule " + getMatchRuleName(matchRule)); 424 } 425 break; 426 case MATCH_MOBILE: 427 // Prevent from crash for b/273963543, where the OEMs still call into unsupported 428 // buildTemplateMobileAll with null subscriberId and get crashed. 429 final int firstSdk = Build.VERSION.DEVICE_INITIAL_SDK_INT; 430 if (firstSdk > Build.VERSION_CODES.TIRAMISU 431 && CollectionUtils.contains(matchSubscriberIds, null)) { 432 throw new IllegalArgumentException("checkValidMatchSubscriberIds list of ids" 433 + " may not contain null for rule " + getMatchRuleName(matchRule)); 434 } 435 return; 436 default: 437 return; 438 } 439 } 440 441 /** 442 * @deprecated Use {@link Builder} to build a template. 443 * @hide 444 */ 445 @Deprecated 446 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU, 447 publicAlternatives = "Use {@code Builder} instead.") NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey)448 public NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey) { 449 // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates 450 // to metered networks. It is now possible to match mobile with any meteredness, but 451 // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this 452 // constructor passes METERED_YES for these types. 453 // For backwards compatibility, still accept old wildcard match rules (6 and 7 for 454 // MATCH_{MOBILE,WIFI}_WILDCARD) but convert into functionally equivalent non-wildcard 455 // ones. 456 this(getBackwardsCompatibleMatchRule(matchRule), 457 subscriberId != null ? new String[] { subscriberId } : new String[0], 458 wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0], 459 getMeterednessForBackwardsCompatibility(matchRule), ROAMING_ALL, 460 DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); 461 if (matchRule == 6 || matchRule == 7) { 462 Log.e(TAG, "Use MATCH_MOBILE with empty subscriberIds or MATCH_WIFI with empty " 463 + "wifiNetworkKeys instead of template with matchRule=" + matchRule); 464 } 465 } 466 getBackwardsCompatibleMatchRule(int matchRule)467 private static int getBackwardsCompatibleMatchRule(int matchRule) { 468 // Backwards compatibility old constants 469 // Old MATCH_MOBILE_WILDCARD 470 if (6 == matchRule) return MATCH_MOBILE; 471 // Old MATCH_WIFI_WILDCARD 472 if (7 == matchRule) return MATCH_WIFI; 473 return matchRule; 474 } 475 getMeterednessForBackwardsCompatibility(int matchRule)476 private static int getMeterednessForBackwardsCompatibility(int matchRule) { 477 if (getBackwardsCompatibleMatchRule(matchRule) == MATCH_MOBILE 478 || matchRule == MATCH_CARRIER) { 479 return METERED_YES; 480 } 481 return METERED_ALL; 482 } 483 484 /** @hide */ 485 // TODO(b/270089918): Remove this method after no callers. NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String wifiNetworkKey)486 public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, 487 String wifiNetworkKey) { 488 // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates 489 // to metered networks. It is now possible to match mobile with any meteredness, but 490 // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this 491 // constructor passes METERED_YES for these types. 492 this(getBackwardsCompatibleMatchRule(matchRule), matchSubscriberIds, 493 wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0], 494 getMeterednessForBackwardsCompatibility(matchRule), 495 ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, 496 OEM_MANAGED_ALL); 497 // TODO : this is part of hidden-o txt, does that mean it should be annotated with 498 // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps 499 // targeting O- crash on those devices. 500 } 501 502 /** @hide */ 503 // TODO(b/269974916): Remove this method after Android U is released. 504 // This is only used by CTS of Android T. NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String[] matchWifiNetworkKeys, int metered, int roaming, int defaultNetwork, int ratType, int oemManaged, int subscriberIdMatchRule)505 public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, 506 String[] matchWifiNetworkKeys, int metered, int roaming, 507 int defaultNetwork, int ratType, int oemManaged, int subscriberIdMatchRule) { 508 // subscriberId and subscriberIdMatchRule aren't used since they are replaced by 509 // matchSubscriberIds, which could be null to indicate the intention of matching any 510 // subscriberIds. 511 this(getBackwardsCompatibleMatchRule(matchRule), 512 matchSubscriberIds == null ? new String[]{} : matchSubscriberIds, 513 matchWifiNetworkKeys, metered, roaming, defaultNetwork, ratType, oemManaged); 514 throwAtLeastU(); 515 } 516 517 /** @hide */ NetworkTemplate(int matchRule, String[] matchSubscriberIds, String[] matchWifiNetworkKeys, int metered, int roaming, int defaultNetwork, int ratType, int oemManaged)518 public NetworkTemplate(int matchRule, String[] matchSubscriberIds, 519 String[] matchWifiNetworkKeys, int metered, int roaming, int defaultNetwork, 520 int ratType, int oemManaged) { 521 Objects.requireNonNull(matchWifiNetworkKeys); 522 Objects.requireNonNull(matchSubscriberIds); 523 mMatchRule = matchRule; 524 mMatchSubscriberIds = matchSubscriberIds; 525 mMatchWifiNetworkKeys = matchWifiNetworkKeys; 526 mMetered = metered; 527 mRoaming = roaming; 528 mDefaultNetwork = defaultNetwork; 529 mRatType = ratType; 530 mOemManaged = oemManaged; 531 checkValidMatchSubscriberIds(matchRule, matchSubscriberIds); 532 if (!isKnownMatchRule(matchRule)) { 533 throw new IllegalArgumentException("Unknown network template rule " + matchRule 534 + " will not match any identity."); 535 } 536 } 537 NetworkTemplate(Parcel in)538 private NetworkTemplate(Parcel in) { 539 mMatchRule = in.readInt(); 540 mMatchSubscriberIds = in.createStringArray(); 541 mMatchWifiNetworkKeys = in.createStringArray(); 542 mMetered = in.readInt(); 543 mRoaming = in.readInt(); 544 mDefaultNetwork = in.readInt(); 545 mRatType = in.readInt(); 546 mOemManaged = in.readInt(); 547 } 548 549 @Override writeToParcel(@onNull Parcel dest, int flags)550 public void writeToParcel(@NonNull Parcel dest, int flags) { 551 dest.writeInt(mMatchRule); 552 dest.writeStringArray(mMatchSubscriberIds); 553 dest.writeStringArray(mMatchWifiNetworkKeys); 554 dest.writeInt(mMetered); 555 dest.writeInt(mRoaming); 556 dest.writeInt(mDefaultNetwork); 557 dest.writeInt(mRatType); 558 dest.writeInt(mOemManaged); 559 } 560 561 @Override describeContents()562 public int describeContents() { 563 return 0; 564 } 565 566 @Override toString()567 public String toString() { 568 final StringBuilder builder = new StringBuilder("NetworkTemplate: "); 569 builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); 570 if (mMatchSubscriberIds != null) { 571 builder.append(", matchSubscriberIds=").append( 572 Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds))); 573 } 574 builder.append(", matchWifiNetworkKeys=").append(Arrays.toString(mMatchWifiNetworkKeys)); 575 if (mMetered != METERED_ALL) { 576 builder.append(", metered=").append(NetworkStats.meteredToString(mMetered)); 577 } 578 if (mRoaming != ROAMING_ALL) { 579 builder.append(", roaming=").append(NetworkStats.roamingToString(mRoaming)); 580 } 581 if (mDefaultNetwork != DEFAULT_NETWORK_ALL) { 582 builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( 583 mDefaultNetwork)); 584 } 585 if (mRatType != NETWORK_TYPE_ALL) { 586 builder.append(", ratType=").append(mRatType); 587 } 588 if (mOemManaged != OEM_MANAGED_ALL) { 589 builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); 590 } 591 return builder.toString(); 592 } 593 594 @Override hashCode()595 public int hashCode() { 596 return Objects.hash(mMatchRule, Arrays.hashCode(mMatchSubscriberIds), 597 Arrays.hashCode(mMatchWifiNetworkKeys), mMetered, mRoaming, mDefaultNetwork, 598 mRatType, mOemManaged); 599 } 600 601 @Override equals(@ullable Object obj)602 public boolean equals(@Nullable Object obj) { 603 if (obj instanceof NetworkTemplate) { 604 final NetworkTemplate other = (NetworkTemplate) obj; 605 return mMatchRule == other.mMatchRule 606 && mMetered == other.mMetered 607 && mRoaming == other.mRoaming 608 && mDefaultNetwork == other.mDefaultNetwork 609 && mRatType == other.mRatType 610 && mOemManaged == other.mOemManaged 611 && Arrays.equals(mMatchSubscriberIds, other.mMatchSubscriberIds) 612 && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys); 613 } 614 return false; 615 } 616 617 // TODO(b/270089918): Remove this method. This can only be done after there are no more callers, 618 // including in OEM code which can access this by linking against the framework. 619 /** @hide */ isMatchRuleMobile()620 public boolean isMatchRuleMobile() { 621 // TODO : this is part of hidden-o txt, does that mean it should be annotated with 622 // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps 623 // targeting O- crash on those devices. 624 switch (mMatchRule) { 625 case MATCH_MOBILE: 626 // Old MATCH_MOBILE_WILDCARD 627 case 6: 628 return true; 629 default: 630 return false; 631 } 632 } 633 634 /** 635 * Get match rule of the template. See {@code MATCH_*}. 636 */ getMatchRule()637 public int getMatchRule() { 638 return mMatchRule; 639 } 640 641 /** 642 * Get subscriber Id of the template. 643 * 644 * @deprecated User should use {@link #getSubscriberIds} instead. 645 * @hide 646 */ 647 @Deprecated 648 @Nullable 649 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU, 650 publicAlternatives = "Caller should use {@code getSubscriberIds} instead.") getSubscriberId()651 public String getSubscriberId() { 652 return CollectionUtils.isEmpty(mMatchSubscriberIds) ? null : mMatchSubscriberIds[0]; 653 } 654 655 /** 656 * Get set of subscriber Ids of the template. 657 */ 658 @NonNull getSubscriberIds()659 public Set<String> getSubscriberIds() { 660 return new ArraySet<>(Arrays.asList(mMatchSubscriberIds)); 661 } 662 663 /** 664 * Get the set of Wifi Network Keys of the template. 665 * See {@link WifiInfo#getNetworkKey()}. 666 */ 667 @NonNull getWifiNetworkKeys()668 public Set<String> getWifiNetworkKeys() { 669 return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys)); 670 } 671 672 /** @hide */ 673 // TODO: Remove this and replace all callers with {@link #getWifiNetworkKeys()}. 674 @Nullable getNetworkId()675 public String getNetworkId() { 676 return getWifiNetworkKeys().isEmpty() ? null : getWifiNetworkKeys().iterator().next(); 677 } 678 679 /** 680 * Get meteredness filter of the template. 681 */ 682 @NetworkStats.Meteredness getMeteredness()683 public int getMeteredness() { 684 return mMetered; 685 } 686 687 /** 688 * Get roaming filter of the template. 689 */ 690 @NetworkStats.Roaming getRoaming()691 public int getRoaming() { 692 return mRoaming; 693 } 694 695 /** 696 * Get the default network status filter of the template. 697 */ 698 @NetworkStats.DefaultNetwork getDefaultNetworkStatus()699 public int getDefaultNetworkStatus() { 700 return mDefaultNetwork; 701 } 702 703 /** 704 * Get the Radio Access Technology(RAT) type filter of the template. 705 */ getRatType()706 public int getRatType() { 707 return mRatType; 708 } 709 710 /** 711 * Get the OEM managed filter of the template. See {@code OEM_MANAGED_*} or 712 * {@code android.net.NetworkIdentity#OEM_*}. 713 */ 714 @OemManaged getOemManaged()715 public int getOemManaged() { 716 return mOemManaged; 717 } 718 719 /** 720 * Test if given {@link NetworkIdentity} matches this template. 721 * 722 * @hide 723 */ 724 @SystemApi(client = MODULE_LIBRARIES) matches(@onNull NetworkIdentity ident)725 public boolean matches(@NonNull NetworkIdentity ident) { 726 Objects.requireNonNull(ident); 727 if (!matchesMetered(ident)) return false; 728 if (!matchesRoaming(ident)) return false; 729 if (!matchesDefaultNetwork(ident)) return false; 730 if (!matchesOemNetwork(ident)) return false; 731 732 switch (mMatchRule) { 733 case MATCH_MOBILE: 734 return matchesMobile(ident); 735 case MATCH_WIFI: 736 return matchesWifi(ident); 737 case MATCH_ETHERNET: 738 return matchesEthernet(ident); 739 case MATCH_BLUETOOTH: 740 return matchesBluetooth(ident); 741 case MATCH_PROXY: 742 return matchesProxy(ident); 743 case MATCH_CARRIER: 744 return matchesCarrier(ident); 745 case MATCH_TEST: 746 return matchesTest(ident); 747 default: 748 // We have no idea what kind of network template we are, so we 749 // just claim not to match anything. 750 return false; 751 } 752 } 753 matchesMetered(NetworkIdentity ident)754 private boolean matchesMetered(NetworkIdentity ident) { 755 return (mMetered == METERED_ALL) 756 || (mMetered == METERED_YES && ident.mMetered) 757 || (mMetered == METERED_NO && !ident.mMetered); 758 } 759 matchesRoaming(NetworkIdentity ident)760 private boolean matchesRoaming(NetworkIdentity ident) { 761 return (mRoaming == ROAMING_ALL) 762 || (mRoaming == ROAMING_YES && ident.mRoaming) 763 || (mRoaming == ROAMING_NO && !ident.mRoaming); 764 } 765 matchesDefaultNetwork(NetworkIdentity ident)766 private boolean matchesDefaultNetwork(NetworkIdentity ident) { 767 return (mDefaultNetwork == DEFAULT_NETWORK_ALL) 768 || (mDefaultNetwork == DEFAULT_NETWORK_YES && ident.mDefaultNetwork) 769 || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); 770 } 771 matchesOemNetwork(NetworkIdentity ident)772 private boolean matchesOemNetwork(NetworkIdentity ident) { 773 return (mOemManaged == OEM_MANAGED_ALL) 774 || (mOemManaged == OEM_MANAGED_YES 775 && ident.mOemManaged != OEM_NONE) 776 || (mOemManaged == ident.mOemManaged); 777 } 778 matchesCollapsedRatType(NetworkIdentity ident)779 private boolean matchesCollapsedRatType(NetworkIdentity ident) { 780 return mRatType == NETWORK_TYPE_ALL 781 || NetworkStatsManager.getCollapsedRatType(mRatType) 782 == NetworkStatsManager.getCollapsedRatType(ident.mRatType); 783 } 784 785 /** 786 * Check if this template matches {@code subscriberId}. Returns true if this 787 * template was created with a {@code mMatchSubscriberIds} array that contains 788 * {@code subscriberId} or if {@code mMatchSubscriberIds} is empty. 789 * 790 * @hide 791 */ matchesSubscriberId(@ullable String subscriberId)792 public boolean matchesSubscriberId(@Nullable String subscriberId) { 793 return mMatchSubscriberIds.length == 0 794 || CollectionUtils.contains(mMatchSubscriberIds, subscriberId); 795 } 796 797 /** 798 * Check if network matches key of the wifi network. 799 * Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is 800 * empty. 801 * 802 * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} 803 * to know details about the key. 804 */ matchesWifiNetworkKey(@onNull String wifiNetworkKey)805 private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) { 806 // Note that this code accepts null wifi network keys because of a past bug where wifi 807 // code was sending a null network key for some connected networks, which isn't expected 808 // and ended up stored in the data on many devices. 809 // A null network key in the data matches a wildcard template (one where 810 // {@code mMatchWifiNetworkKeys} is empty), but not one where {@code MatchWifiNetworkKeys} 811 // contains null. See b/266598304. 812 if (wifiNetworkKey == null) { 813 return CollectionUtils.isEmpty(mMatchWifiNetworkKeys); 814 } 815 return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) 816 || CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey); 817 } 818 819 /** 820 * Check if mobile network matches IMSI. 821 */ matchesMobile(NetworkIdentity ident)822 private boolean matchesMobile(NetworkIdentity ident) { 823 if (ident.mType == TYPE_WIMAX) { 824 // TODO: consider matching against WiMAX subscriber identity 825 return true; 826 } else { 827 return (CollectionUtils.isEmpty(mMatchSubscriberIds) 828 || CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)) 829 && (ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident)); 830 } 831 } 832 833 /** 834 * Check if matches Wi-Fi network template. 835 */ matchesWifi(NetworkIdentity ident)836 private boolean matchesWifi(NetworkIdentity ident) { 837 switch (ident.mType) { 838 case TYPE_WIFI: 839 return matchesSubscriberId(ident.mSubscriberId) 840 && matchesWifiNetworkKey(ident.mWifiNetworkKey); 841 case TYPE_WIFI_P2P: 842 return CollectionUtils.isEmpty(mMatchWifiNetworkKeys); 843 default: 844 return false; 845 } 846 } 847 848 /** 849 * Check if matches Ethernet network template. 850 */ matchesEthernet(NetworkIdentity ident)851 private boolean matchesEthernet(NetworkIdentity ident) { 852 if (ident.mType == TYPE_ETHERNET) { 853 return true; 854 } 855 return false; 856 } 857 858 /** 859 * Check if matches carrier network. The carrier networks means it includes the subscriberId. 860 */ matchesCarrier(NetworkIdentity ident)861 private boolean matchesCarrier(NetworkIdentity ident) { 862 return ident.mSubscriberId != null 863 && !CollectionUtils.isEmpty(mMatchSubscriberIds) 864 && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); 865 } 866 867 /** 868 * Check if matches test network. If the wifiNetworkKeys in the template is specified, Then it 869 * will only match a network containing any of the specified the wifi network key. Otherwise, 870 * all test networks would be matched. 871 */ matchesTest(NetworkIdentity ident)872 private boolean matchesTest(NetworkIdentity ident) { 873 return ident.mType == NetworkIdentity.TYPE_TEST 874 && ((CollectionUtils.isEmpty(mMatchWifiNetworkKeys) 875 || CollectionUtils.contains(mMatchWifiNetworkKeys, ident.mWifiNetworkKey))); 876 } 877 878 /** 879 * Check if matches Bluetooth network template. 880 */ matchesBluetooth(NetworkIdentity ident)881 private boolean matchesBluetooth(NetworkIdentity ident) { 882 if (ident.mType == TYPE_BLUETOOTH) { 883 return true; 884 } 885 return false; 886 } 887 888 /** 889 * Check if matches Proxy network template. 890 */ matchesProxy(NetworkIdentity ident)891 private boolean matchesProxy(NetworkIdentity ident) { 892 return ident.mType == TYPE_PROXY; 893 } 894 getMatchRuleName(int matchRule)895 private static String getMatchRuleName(int matchRule) { 896 switch (matchRule) { 897 case MATCH_MOBILE: 898 return "MOBILE"; 899 case MATCH_WIFI: 900 return "WIFI"; 901 case MATCH_ETHERNET: 902 return "ETHERNET"; 903 case MATCH_BLUETOOTH: 904 return "BLUETOOTH"; 905 case MATCH_PROXY: 906 return "PROXY"; 907 case MATCH_CARRIER: 908 return "CARRIER"; 909 case MATCH_TEST: 910 return "TEST"; 911 default: 912 return "UNKNOWN(" + matchRule + ")"; 913 } 914 } 915 getOemManagedNames(int oemManaged)916 private static String getOemManagedNames(int oemManaged) { 917 switch (oemManaged) { 918 case OEM_MANAGED_ALL: 919 return "OEM_MANAGED_ALL"; 920 case OEM_MANAGED_NO: 921 return "OEM_MANAGED_NO"; 922 case OEM_MANAGED_YES: 923 return "OEM_MANAGED_YES"; 924 default: 925 return NetworkIdentity.getOemManagedNames(oemManaged); 926 } 927 } 928 929 /** 930 * Examine the given template and normalize it. 931 * We pick the "lowest" merged subscriber as the primary 932 * for key purposes, and expand the template to match all other merged 933 * subscribers. 934 * <p> 935 * For example, given an incoming template matching B, and the currently 936 * active merge set [A,B], we'd return a new template that matches both A and B. 937 * 938 * @hide 939 */ 940 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU, 941 publicAlternatives = "There is no alternative for {@code NetworkTemplate.normalize}." 942 + "Callers should have their own logic to merge template for" 943 + " different IMSIs and stop calling this function.") normalize(NetworkTemplate template, String[] merged)944 public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { 945 return normalizeImpl(template, Collections.singletonList(merged)); 946 } 947 948 /** 949 * Examine the given template and normalize it. 950 * We pick the "lowest" merged subscriber as the primary 951 * for key purposes, and expand the template to match all other merged 952 * subscribers. 953 * 954 * There can be multiple merged subscriberIds for multi-SIM devices. 955 * 956 * <p> 957 * For example, given an incoming template matching B, and the currently 958 * active merge set [A,B], we'd return a new template that matches both A and B. 959 * 960 * @hide 961 */ 962 // TODO(b/273963543): Remove this method. This can only be done after there are no more callers, 963 // including in OEM code which can access this by linking against the framework. normalize(NetworkTemplate template, List<String[]> mergedList)964 public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) { 965 throwAtLeastU(); 966 return normalizeImpl(template, mergedList); 967 } 968 969 /** 970 * Examine the given template and normalize it. 971 * We pick the "lowest" merged subscriber as the primary 972 * for key purposes, and expand the template to match all other merged 973 * subscribers. 974 * 975 * There can be multiple merged subscriberIds for multi-SIM devices. 976 * 977 * <p> 978 * For example, given an incoming template matching B, and the currently 979 * active merge set [A,B], we'd return a new template that matches both A and B. 980 * 981 * @hide 982 */ normalizeImpl(NetworkTemplate template, List<String[]> mergedList)983 private static NetworkTemplate normalizeImpl(NetworkTemplate template, 984 List<String[]> mergedList) { 985 // Now there are several types of network which uses SubscriberId to store network 986 // information. For instances: 987 // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network. 988 // The TYPE_CARRIER means that the network associate to specific carrier network. 989 990 if (CollectionUtils.isEmpty(template.mMatchSubscriberIds)) return template; 991 992 for (String[] merged : mergedList) { 993 if (CollectionUtils.contains(merged, template.mMatchSubscriberIds[0])) { 994 // Requested template subscriber is part of the merge group; return 995 // a template that matches all merged subscribers. 996 final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys; 997 // TODO: Use NetworkTemplate.Builder to build a template after NetworkTemplate 998 // could handle incompatible subscriberIds. See b/217805241. 999 return new NetworkTemplate(template.mMatchRule, merged, 1000 CollectionUtils.isEmpty(matchWifiNetworkKeys) 1001 ? new String[0] : new String[] { matchWifiNetworkKeys[0] }, 1002 (template.mMatchRule == MATCH_MOBILE 1003 || template.mMatchRule == MATCH_CARRIER) 1004 ? METERED_YES : METERED_ALL, 1005 ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); 1006 } 1007 } 1008 1009 return template; 1010 } 1011 1012 @UnsupportedAppUsage 1013 public static final @android.annotation.NonNull Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() { 1014 @Override 1015 public NetworkTemplate createFromParcel(Parcel in) { 1016 return new NetworkTemplate(in); 1017 } 1018 1019 @Override 1020 public NetworkTemplate[] newArray(int size) { 1021 return new NetworkTemplate[size]; 1022 } 1023 }; 1024 1025 /** 1026 * Builder class for NetworkTemplate. 1027 */ 1028 public static final class Builder { 1029 private final int mMatchRule; 1030 // Use a SortedSet to provide a deterministic order when fetching the first one. 1031 @NonNull 1032 private final SortedSet<String> mMatchSubscriberIds = 1033 new TreeSet<>(Comparator.nullsFirst(Comparator.naturalOrder())); 1034 @NonNull 1035 private final SortedSet<String> mMatchWifiNetworkKeys = new TreeSet<>(); 1036 1037 // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. 1038 private int mMetered; 1039 private int mRoaming; 1040 private int mDefaultNetwork; 1041 private int mRatType; 1042 1043 // Bitfield containing OEM network properties {@code NetworkIdentity#OEM_*}. 1044 private int mOemManaged; 1045 1046 /** 1047 * Creates a new Builder with given match rule to construct NetworkTemplate objects. 1048 * 1049 * @param matchRule the match rule of the template, see {@code MATCH_*}. 1050 */ Builder(@emplateMatchRule final int matchRule)1051 public Builder(@TemplateMatchRule final int matchRule) { 1052 assertRequestableMatchRule(matchRule); 1053 // Initialize members with default values. 1054 mMatchRule = matchRule; 1055 mMetered = METERED_ALL; 1056 mRoaming = ROAMING_ALL; 1057 mDefaultNetwork = DEFAULT_NETWORK_ALL; 1058 mRatType = NETWORK_TYPE_ALL; 1059 mOemManaged = OEM_MANAGED_ALL; 1060 } 1061 1062 /** 1063 * Set the Subscriber Ids. Calling this function with an empty set represents 1064 * the intention of matching any Subscriber Ids. 1065 * 1066 * @param subscriberIds the list of Subscriber Ids. 1067 * @return this builder. 1068 */ 1069 @NonNull setSubscriberIds(@onNull Set<String> subscriberIds)1070 public Builder setSubscriberIds(@NonNull Set<String> subscriberIds) { 1071 Objects.requireNonNull(subscriberIds); 1072 mMatchSubscriberIds.clear(); 1073 mMatchSubscriberIds.addAll(subscriberIds); 1074 return this; 1075 } 1076 1077 /** 1078 * Set the Wifi Network Keys. Calling this function with an empty set represents 1079 * the intention of matching any Wifi Network Key. 1080 * 1081 * @param wifiNetworkKeys the list of Wifi Network Key, 1082 * see {@link WifiInfo#getNetworkKey()}. 1083 * Or an empty list to match all networks. 1084 * Note that {@code getNetworkKey()} might get null key 1085 * when wifi disconnects. However, the caller should never invoke 1086 * this function with a null Wifi Network Key since such statistics 1087 * never exists. 1088 * @return this builder. 1089 */ 1090 @NonNull setWifiNetworkKeys(@onNull Set<String> wifiNetworkKeys)1091 public Builder setWifiNetworkKeys(@NonNull Set<String> wifiNetworkKeys) { 1092 Objects.requireNonNull(wifiNetworkKeys); 1093 for (String key : wifiNetworkKeys) { 1094 if (key == null) { 1095 throw new IllegalArgumentException("Null is not a valid key"); 1096 } 1097 } 1098 mMatchWifiNetworkKeys.clear(); 1099 mMatchWifiNetworkKeys.addAll(wifiNetworkKeys); 1100 return this; 1101 } 1102 1103 /** 1104 * Set the meteredness filter. 1105 * 1106 * @param metered the meteredness filter. 1107 * @return this builder. 1108 */ 1109 @NonNull setMeteredness(@etworkStats.Meteredness int metered)1110 public Builder setMeteredness(@NetworkStats.Meteredness int metered) { 1111 mMetered = metered; 1112 return this; 1113 } 1114 1115 /** 1116 * Set the roaming filter. 1117 * 1118 * @param roaming the roaming filter. 1119 * @return this builder. 1120 */ 1121 @NonNull setRoaming(@etworkStats.Roaming int roaming)1122 public Builder setRoaming(@NetworkStats.Roaming int roaming) { 1123 mRoaming = roaming; 1124 return this; 1125 } 1126 1127 /** 1128 * Set the default network status filter. 1129 * 1130 * @param defaultNetwork the default network status filter. 1131 * @return this builder. 1132 */ 1133 @NonNull setDefaultNetworkStatus(@etworkStats.DefaultNetwork int defaultNetwork)1134 public Builder setDefaultNetworkStatus(@NetworkStats.DefaultNetwork int defaultNetwork) { 1135 mDefaultNetwork = defaultNetwork; 1136 return this; 1137 } 1138 1139 /** 1140 * Set the Radio Access Technology(RAT) type filter. 1141 * 1142 * @param ratType the Radio Access Technology(RAT) type filter. Use 1143 * {@link #NETWORK_TYPE_ALL} to include all network types when filtering. 1144 * See {@code TelephonyManager.NETWORK_TYPE_*}. 1145 * @return this builder. 1146 */ 1147 @NonNull setRatType(int ratType)1148 public Builder setRatType(int ratType) { 1149 // Input will be validated with the match rule when building the template. 1150 mRatType = ratType; 1151 return this; 1152 } 1153 1154 /** 1155 * Set the OEM managed filter. 1156 * 1157 * @param oemManaged the match rule to match different type of OEM managed network or 1158 * unmanaged networks. See {@code OEM_MANAGED_*}. 1159 * @return this builder. 1160 */ 1161 @NonNull setOemManaged(@emManaged int oemManaged)1162 public Builder setOemManaged(@OemManaged int oemManaged) { 1163 mOemManaged = oemManaged; 1164 return this; 1165 } 1166 1167 /** 1168 * Check whether the match rule is requestable. 1169 * 1170 * @param matchRule the target match rule to be checked. 1171 */ assertRequestableMatchRule(final int matchRule)1172 private static void assertRequestableMatchRule(final int matchRule) { 1173 if (!isKnownMatchRule(matchRule)) { 1174 throw new IllegalArgumentException("Invalid match rule: " 1175 + getMatchRuleName(matchRule)); 1176 } 1177 } 1178 assertRequestableParameters()1179 private void assertRequestableParameters() { 1180 validateWifiNetworkKeys(); 1181 // TODO: Check all the input are legitimate. 1182 } 1183 validateWifiNetworkKeys()1184 private void validateWifiNetworkKeys() { 1185 // Also allow querying test networks which use wifi network key as identifier. 1186 if (mMatchRule != MATCH_WIFI && mMatchRule != MATCH_TEST 1187 && !mMatchWifiNetworkKeys.isEmpty()) { 1188 throw new IllegalArgumentException("Trying to build non wifi match rule: " 1189 + mMatchRule + " with wifi network keys"); 1190 } 1191 } 1192 1193 /** 1194 * Builds the instance of the NetworkTemplate. 1195 * 1196 * @return the built instance of NetworkTemplate. 1197 */ 1198 @NonNull build()1199 public NetworkTemplate build() { 1200 assertRequestableParameters(); 1201 return new NetworkTemplate(mMatchRule, 1202 mMatchSubscriberIds.toArray(new String[0]), 1203 mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming, 1204 mDefaultNetwork, mRatType, mOemManaged); 1205 } 1206 } 1207 } 1208