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.net.ConnectivityManager.TYPE_BLUETOOTH; 20 import static android.net.ConnectivityManager.TYPE_ETHERNET; 21 import static android.net.ConnectivityManager.TYPE_MOBILE; 22 import static android.net.ConnectivityManager.TYPE_PROXY; 23 import static android.net.ConnectivityManager.TYPE_WIFI; 24 import static android.net.ConnectivityManager.TYPE_WIFI_P2P; 25 import static android.net.ConnectivityManager.TYPE_WIMAX; 26 import static android.net.NetworkIdentity.OEM_NONE; 27 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; 28 import static android.net.NetworkStats.DEFAULT_NETWORK_NO; 29 import static android.net.NetworkStats.DEFAULT_NETWORK_YES; 30 import static android.net.NetworkStats.METERED_ALL; 31 import static android.net.NetworkStats.METERED_NO; 32 import static android.net.NetworkStats.METERED_YES; 33 import static android.net.NetworkStats.ROAMING_ALL; 34 import static android.net.NetworkStats.ROAMING_NO; 35 import static android.net.NetworkStats.ROAMING_YES; 36 import static android.net.wifi.WifiInfo.sanitizeSsid; 37 38 import android.annotation.NonNull; 39 import android.annotation.Nullable; 40 import android.compat.annotation.UnsupportedAppUsage; 41 import android.os.Build; 42 import android.os.Parcel; 43 import android.os.Parcelable; 44 import android.telephony.Annotation.NetworkType; 45 import android.telephony.TelephonyManager; 46 import android.text.TextUtils; 47 import android.util.BackupUtils; 48 import android.util.Log; 49 50 import com.android.internal.util.ArrayUtils; 51 import com.android.net.module.util.NetworkIdentityUtils; 52 53 import java.io.ByteArrayOutputStream; 54 import java.io.DataInputStream; 55 import java.io.DataOutputStream; 56 import java.io.IOException; 57 import java.util.Arrays; 58 import java.util.Collection; 59 import java.util.HashSet; 60 import java.util.List; 61 import java.util.Objects; 62 63 /** 64 * Predicate used to match {@link NetworkIdentity}, usually when collecting 65 * statistics. (It should probably have been named {@code NetworkPredicate}.) 66 * 67 * @hide 68 */ 69 public class NetworkTemplate implements Parcelable { 70 private static final String TAG = "NetworkTemplate"; 71 72 /** 73 * Current Version of the Backup Serializer. 74 */ 75 private static final int BACKUP_VERSION = 1; 76 77 public static final int MATCH_MOBILE = 1; 78 public static final int MATCH_WIFI = 4; 79 public static final int MATCH_ETHERNET = 5; 80 public static final int MATCH_MOBILE_WILDCARD = 6; 81 public static final int MATCH_WIFI_WILDCARD = 7; 82 public static final int MATCH_BLUETOOTH = 8; 83 public static final int MATCH_PROXY = 9; 84 public static final int MATCH_CARRIER = 10; 85 86 /** 87 * Value of the match rule of the subscriberId to match networks with specific subscriberId. 88 */ 89 public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0; 90 /** 91 * Value of the match rule of the subscriberId to match networks with any subscriberId which 92 * includes null and non-null. 93 */ 94 public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; 95 96 /** 97 * Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that 98 * should be fixed), so it's not possible to want to match null vs 99 * non-null. Therefore it's fine to use null as a sentinel for Network ID. 100 */ 101 public static final String WIFI_NETWORKID_ALL = null; 102 103 /** 104 * Include all network types when filtering. This is meant to merge in with the 105 * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. 106 * 107 * @hide 108 */ 109 public static final int NETWORK_TYPE_ALL = -1; 110 /** 111 * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is 112 * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along 113 * with NR state as connected. This should not be overlapped with any of the 114 * {@code TelephonyManager.NETWORK_TYPE_*} constants. 115 * 116 * @hide 117 */ 118 public static final int NETWORK_TYPE_5G_NSA = -2; 119 120 /** 121 * Value to match both OEM managed and unmanaged networks (all networks). 122 * @hide 123 */ 124 public static final int OEM_MANAGED_ALL = -1; 125 /** 126 * Value to match networks which are not OEM managed. 127 * @hide 128 */ 129 public static final int OEM_MANAGED_NO = OEM_NONE; 130 /** 131 * Value to match any OEM managed network. 132 * @hide 133 */ 134 public static final int OEM_MANAGED_YES = -2; 135 isKnownMatchRule(final int rule)136 private static boolean isKnownMatchRule(final int rule) { 137 switch (rule) { 138 case MATCH_MOBILE: 139 case MATCH_WIFI: 140 case MATCH_ETHERNET: 141 case MATCH_MOBILE_WILDCARD: 142 case MATCH_WIFI_WILDCARD: 143 case MATCH_BLUETOOTH: 144 case MATCH_PROXY: 145 case MATCH_CARRIER: 146 return true; 147 148 default: 149 return false; 150 } 151 } 152 153 /** 154 * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with 155 * the given IMSI. 156 */ 157 @UnsupportedAppUsage buildTemplateMobileAll(String subscriberId)158 public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { 159 return new NetworkTemplate(MATCH_MOBILE, subscriberId, null); 160 } 161 162 /** 163 * Template to match cellular networks with the given IMSI, {@code ratType} and 164 * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when 165 * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. 166 */ buildTemplateMobileWithRatType(@ullable String subscriberId, @NetworkType int ratType, int metered)167 public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, 168 @NetworkType int ratType, int metered) { 169 if (TextUtils.isEmpty(subscriberId)) { 170 return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, 171 metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, 172 SUBSCRIBER_ID_MATCH_RULE_EXACT); 173 } 174 return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, 175 metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, 176 SUBSCRIBER_ID_MATCH_RULE_EXACT); 177 } 178 179 /** 180 * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, 181 * regardless of IMSI. 182 */ 183 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) buildTemplateMobileWildcard()184 public static NetworkTemplate buildTemplateMobileWildcard() { 185 return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); 186 } 187 188 /** 189 * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, 190 * regardless of SSID. 191 */ 192 @UnsupportedAppUsage buildTemplateWifiWildcard()193 public static NetworkTemplate buildTemplateWifiWildcard() { 194 // TODO: Consider replace this with MATCH_WIFI with NETWORK_ID_ALL 195 // and SUBSCRIBER_ID_MATCH_RULE_ALL. 196 return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); 197 } 198 199 @Deprecated 200 @UnsupportedAppUsage buildTemplateWifi()201 public static NetworkTemplate buildTemplateWifi() { 202 return buildTemplateWifiWildcard(); 203 } 204 205 /** 206 * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the 207 * given SSID. 208 */ buildTemplateWifi(@onNull String networkId)209 public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) { 210 Objects.requireNonNull(networkId); 211 return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */, 212 new String[] { null } /* matchSubscriberIds */, 213 networkId, METERED_ALL, ROAMING_ALL, 214 DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, 215 SUBSCRIBER_ID_MATCH_RULE_ALL); 216 } 217 218 /** 219 * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID, 220 * and IMSI. 221 * 222 * Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID. 223 */ buildTemplateWifi(@ullable String networkId, @Nullable String subscriberId)224 public static NetworkTemplate buildTemplateWifi(@Nullable String networkId, 225 @Nullable String subscriberId) { 226 return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId }, 227 networkId, METERED_ALL, ROAMING_ALL, 228 DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, 229 SUBSCRIBER_ID_MATCH_RULE_EXACT); 230 } 231 232 /** 233 * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style 234 * networks together. 235 */ 236 @UnsupportedAppUsage buildTemplateEthernet()237 public static NetworkTemplate buildTemplateEthernet() { 238 return new NetworkTemplate(MATCH_ETHERNET, null, null); 239 } 240 241 /** 242 * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style 243 * networks together. 244 */ buildTemplateBluetooth()245 public static NetworkTemplate buildTemplateBluetooth() { 246 return new NetworkTemplate(MATCH_BLUETOOTH, null, null); 247 } 248 249 /** 250 * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style 251 * networks together. 252 */ buildTemplateProxy()253 public static NetworkTemplate buildTemplateProxy() { 254 return new NetworkTemplate(MATCH_PROXY, null, null); 255 } 256 257 /** 258 * Template to match all metered carrier networks with the given IMSI. 259 */ buildTemplateCarrierMetered(@onNull String subscriberId)260 public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) { 261 Objects.requireNonNull(subscriberId); 262 return new NetworkTemplate(MATCH_CARRIER, subscriberId, 263 new String[] { subscriberId }, null /* networkId */, METERED_YES, ROAMING_ALL, 264 DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, 265 SUBSCRIBER_ID_MATCH_RULE_EXACT); 266 } 267 268 private final int mMatchRule; 269 private final String mSubscriberId; 270 271 /** 272 * Ugh, templates are designed to target a single subscriber, but we might 273 * need to match several "merged" subscribers. These are the subscribers 274 * that should be considered to match this template. 275 * <p> 276 * Since the merge set is dynamic, it should <em>not</em> be persisted or 277 * used for determining equality. 278 */ 279 private final String[] mMatchSubscriberIds; 280 281 private final String mNetworkId; 282 283 // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. 284 private final int mMetered; 285 private final int mRoaming; 286 private final int mDefaultNetwork; 287 private final int mSubType; 288 private final int mSubscriberIdMatchRule; 289 290 // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. 291 private final int mOemManaged; 292 checkValidSubscriberIdMatchRule()293 private void checkValidSubscriberIdMatchRule() { 294 switch (mMatchRule) { 295 case MATCH_MOBILE: 296 case MATCH_CARRIER: 297 // MOBILE and CARRIER templates must always specify a subscriber ID. 298 if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { 299 throw new IllegalArgumentException("Invalid SubscriberIdMatchRule" 300 + "on match rule: " + getMatchRuleName(mMatchRule)); 301 } 302 return; 303 default: 304 return; 305 } 306 } 307 308 // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) 309 @UnsupportedAppUsage NetworkTemplate(int matchRule, String subscriberId, String networkId)310 public NetworkTemplate(int matchRule, String subscriberId, String networkId) { 311 this(matchRule, subscriberId, new String[] { subscriberId }, networkId); 312 } 313 NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId)314 public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, 315 String networkId) { 316 // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates 317 // to metered networks. It is now possible to match mobile with any meteredness, but 318 // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this 319 //constructor passes METERED_YES for these types. 320 this(matchRule, subscriberId, matchSubscriberIds, networkId, 321 (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES 322 : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, 323 OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); 324 } 325 326 // TODO: Remove it after updating all of the caller. NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork, int subType, int oemManaged)327 public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, 328 String networkId, int metered, int roaming, int defaultNetwork, int subType, 329 int oemManaged) { 330 this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming, 331 defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT); 332 } 333 NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork, int subType, int oemManaged, int subscriberIdMatchRule)334 public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, 335 String networkId, int metered, int roaming, int defaultNetwork, int subType, 336 int oemManaged, int subscriberIdMatchRule) { 337 mMatchRule = matchRule; 338 mSubscriberId = subscriberId; 339 // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when 340 // mSubscriberId is null 341 mMatchSubscriberIds = matchSubscriberIds; 342 mNetworkId = networkId; 343 mMetered = metered; 344 mRoaming = roaming; 345 mDefaultNetwork = defaultNetwork; 346 mSubType = subType; 347 mOemManaged = oemManaged; 348 mSubscriberIdMatchRule = subscriberIdMatchRule; 349 checkValidSubscriberIdMatchRule(); 350 if (!isKnownMatchRule(matchRule)) { 351 Log.e(TAG, "Unknown network template rule " + matchRule 352 + " will not match any identity."); 353 } 354 } 355 NetworkTemplate(Parcel in)356 private NetworkTemplate(Parcel in) { 357 mMatchRule = in.readInt(); 358 mSubscriberId = in.readString(); 359 mMatchSubscriberIds = in.createStringArray(); 360 mNetworkId = in.readString(); 361 mMetered = in.readInt(); 362 mRoaming = in.readInt(); 363 mDefaultNetwork = in.readInt(); 364 mSubType = in.readInt(); 365 mOemManaged = in.readInt(); 366 mSubscriberIdMatchRule = in.readInt(); 367 } 368 369 @Override writeToParcel(Parcel dest, int flags)370 public void writeToParcel(Parcel dest, int flags) { 371 dest.writeInt(mMatchRule); 372 dest.writeString(mSubscriberId); 373 dest.writeStringArray(mMatchSubscriberIds); 374 dest.writeString(mNetworkId); 375 dest.writeInt(mMetered); 376 dest.writeInt(mRoaming); 377 dest.writeInt(mDefaultNetwork); 378 dest.writeInt(mSubType); 379 dest.writeInt(mOemManaged); 380 dest.writeInt(mSubscriberIdMatchRule); 381 } 382 383 @Override describeContents()384 public int describeContents() { 385 return 0; 386 } 387 388 @Override toString()389 public String toString() { 390 final StringBuilder builder = new StringBuilder("NetworkTemplate: "); 391 builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); 392 if (mSubscriberId != null) { 393 builder.append(", subscriberId=").append( 394 NetworkIdentityUtils.scrubSubscriberId(mSubscriberId)); 395 } 396 if (mMatchSubscriberIds != null) { 397 builder.append(", matchSubscriberIds=").append( 398 Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds))); 399 } 400 if (mNetworkId != null) { 401 builder.append(", networkId=").append(mNetworkId); 402 } 403 if (mMetered != METERED_ALL) { 404 builder.append(", metered=").append(NetworkStats.meteredToString(mMetered)); 405 } 406 if (mRoaming != ROAMING_ALL) { 407 builder.append(", roaming=").append(NetworkStats.roamingToString(mRoaming)); 408 } 409 if (mDefaultNetwork != DEFAULT_NETWORK_ALL) { 410 builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( 411 mDefaultNetwork)); 412 } 413 if (mSubType != NETWORK_TYPE_ALL) { 414 builder.append(", subType=").append(mSubType); 415 } 416 if (mOemManaged != OEM_MANAGED_ALL) { 417 builder.append(", oemManaged=").append(mOemManaged); 418 } 419 builder.append(", subscriberIdMatchRule=") 420 .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule)); 421 return builder.toString(); 422 } 423 424 @Override hashCode()425 public int hashCode() { 426 return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, 427 mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule); 428 } 429 430 @Override equals(@ullable Object obj)431 public boolean equals(@Nullable Object obj) { 432 if (obj instanceof NetworkTemplate) { 433 final NetworkTemplate other = (NetworkTemplate) obj; 434 return mMatchRule == other.mMatchRule 435 && Objects.equals(mSubscriberId, other.mSubscriberId) 436 && Objects.equals(mNetworkId, other.mNetworkId) 437 && mMetered == other.mMetered 438 && mRoaming == other.mRoaming 439 && mDefaultNetwork == other.mDefaultNetwork 440 && mSubType == other.mSubType 441 && mOemManaged == other.mOemManaged 442 && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule; 443 } 444 return false; 445 } 446 subscriberIdMatchRuleToString(int rule)447 private String subscriberIdMatchRuleToString(int rule) { 448 switch (rule) { 449 case SUBSCRIBER_ID_MATCH_RULE_EXACT: 450 return "EXACT_MATCH"; 451 case SUBSCRIBER_ID_MATCH_RULE_ALL: 452 return "ALL"; 453 default: 454 return "Unknown rule " + rule; 455 } 456 } 457 isMatchRuleMobile()458 public boolean isMatchRuleMobile() { 459 switch (mMatchRule) { 460 case MATCH_MOBILE: 461 case MATCH_MOBILE_WILDCARD: 462 return true; 463 default: 464 return false; 465 } 466 } 467 isPersistable()468 public boolean isPersistable() { 469 switch (mMatchRule) { 470 case MATCH_MOBILE_WILDCARD: 471 case MATCH_WIFI_WILDCARD: 472 return false; 473 case MATCH_CARRIER: 474 return mSubscriberId != null; 475 case MATCH_WIFI: 476 if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) 477 && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { 478 return false; 479 } 480 return true; 481 default: 482 return true; 483 } 484 } 485 486 @UnsupportedAppUsage getMatchRule()487 public int getMatchRule() { 488 return mMatchRule; 489 } 490 491 @UnsupportedAppUsage getSubscriberId()492 public String getSubscriberId() { 493 return mSubscriberId; 494 } 495 getNetworkId()496 public String getNetworkId() { 497 return mNetworkId; 498 } 499 getSubscriberIdMatchRule()500 public int getSubscriberIdMatchRule() { 501 return mSubscriberIdMatchRule; 502 } 503 getMeteredness()504 public int getMeteredness() { 505 return mMetered; 506 } 507 508 /** 509 * Test if given {@link NetworkIdentity} matches this template. 510 */ matches(NetworkIdentity ident)511 public boolean matches(NetworkIdentity ident) { 512 if (!matchesMetered(ident)) return false; 513 if (!matchesRoaming(ident)) return false; 514 if (!matchesDefaultNetwork(ident)) return false; 515 if (!matchesOemNetwork(ident)) return false; 516 517 switch (mMatchRule) { 518 case MATCH_MOBILE: 519 return matchesMobile(ident); 520 case MATCH_WIFI: 521 return matchesWifi(ident); 522 case MATCH_ETHERNET: 523 return matchesEthernet(ident); 524 case MATCH_MOBILE_WILDCARD: 525 return matchesMobileWildcard(ident); 526 case MATCH_WIFI_WILDCARD: 527 return matchesWifiWildcard(ident); 528 case MATCH_BLUETOOTH: 529 return matchesBluetooth(ident); 530 case MATCH_PROXY: 531 return matchesProxy(ident); 532 case MATCH_CARRIER: 533 return matchesCarrier(ident); 534 default: 535 // We have no idea what kind of network template we are, so we 536 // just claim not to match anything. 537 return false; 538 } 539 } 540 matchesMetered(NetworkIdentity ident)541 private boolean matchesMetered(NetworkIdentity ident) { 542 return (mMetered == METERED_ALL) 543 || (mMetered == METERED_YES && ident.mMetered) 544 || (mMetered == METERED_NO && !ident.mMetered); 545 } 546 matchesRoaming(NetworkIdentity ident)547 private boolean matchesRoaming(NetworkIdentity ident) { 548 return (mRoaming == ROAMING_ALL) 549 || (mRoaming == ROAMING_YES && ident.mRoaming) 550 || (mRoaming == ROAMING_NO && !ident.mRoaming); 551 } 552 matchesDefaultNetwork(NetworkIdentity ident)553 private boolean matchesDefaultNetwork(NetworkIdentity ident) { 554 return (mDefaultNetwork == DEFAULT_NETWORK_ALL) 555 || (mDefaultNetwork == DEFAULT_NETWORK_YES && ident.mDefaultNetwork) 556 || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); 557 } 558 matchesOemNetwork(NetworkIdentity ident)559 private boolean matchesOemNetwork(NetworkIdentity ident) { 560 return (mOemManaged == OEM_MANAGED_ALL) 561 || (mOemManaged == OEM_MANAGED_YES 562 && ident.mOemManaged != OEM_NONE) 563 || (mOemManaged == ident.mOemManaged); 564 } 565 matchesCollapsedRatType(NetworkIdentity ident)566 private boolean matchesCollapsedRatType(NetworkIdentity ident) { 567 return mSubType == NETWORK_TYPE_ALL 568 || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); 569 } 570 571 /** 572 * Check if this template matches {@code subscriberId}. Returns true if this 573 * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a 574 * {@code mMatchSubscriberIds} array that contains {@code subscriberId}. 575 */ matchesSubscriberId(@ullable String subscriberId)576 public boolean matchesSubscriberId(@Nullable String subscriberId) { 577 return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL 578 || ArrayUtils.contains(mMatchSubscriberIds, subscriberId); 579 } 580 581 /** 582 * Check if network with matching SSID. Returns true when the SSID matches, or when 583 * {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}. 584 */ matchesWifiNetworkId(@ullable String networkId)585 private boolean matchesWifiNetworkId(@Nullable String networkId) { 586 return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) 587 || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId)); 588 } 589 590 /** 591 * Check if mobile network with matching IMSI. 592 */ matchesMobile(NetworkIdentity ident)593 private boolean matchesMobile(NetworkIdentity ident) { 594 if (ident.mType == TYPE_WIMAX) { 595 // TODO: consider matching against WiMAX subscriber identity 596 return true; 597 } else { 598 return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds) 599 && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) 600 && matchesCollapsedRatType(ident); 601 } 602 } 603 604 /** 605 * Get a Radio Access Technology(RAT) type that is representative of a group of RAT types. 606 * The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}. 607 * 608 * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. 609 */ 610 // TODO: 1. Consider move this to TelephonyManager if used by other modules. 611 // 2. Consider make this configurable. 612 // 3. Use TelephonyManager APIs when available. getCollapsedRatType(int ratType)613 public static int getCollapsedRatType(int ratType) { 614 switch (ratType) { 615 case TelephonyManager.NETWORK_TYPE_GPRS: 616 case TelephonyManager.NETWORK_TYPE_GSM: 617 case TelephonyManager.NETWORK_TYPE_EDGE: 618 case TelephonyManager.NETWORK_TYPE_IDEN: 619 case TelephonyManager.NETWORK_TYPE_CDMA: 620 case TelephonyManager.NETWORK_TYPE_1xRTT: 621 return TelephonyManager.NETWORK_TYPE_GSM; 622 case TelephonyManager.NETWORK_TYPE_EVDO_0: 623 case TelephonyManager.NETWORK_TYPE_EVDO_A: 624 case TelephonyManager.NETWORK_TYPE_EVDO_B: 625 case TelephonyManager.NETWORK_TYPE_EHRPD: 626 case TelephonyManager.NETWORK_TYPE_UMTS: 627 case TelephonyManager.NETWORK_TYPE_HSDPA: 628 case TelephonyManager.NETWORK_TYPE_HSUPA: 629 case TelephonyManager.NETWORK_TYPE_HSPA: 630 case TelephonyManager.NETWORK_TYPE_HSPAP: 631 case TelephonyManager.NETWORK_TYPE_TD_SCDMA: 632 return TelephonyManager.NETWORK_TYPE_UMTS; 633 case TelephonyManager.NETWORK_TYPE_LTE: 634 case TelephonyManager.NETWORK_TYPE_IWLAN: 635 return TelephonyManager.NETWORK_TYPE_LTE; 636 case TelephonyManager.NETWORK_TYPE_NR: 637 return TelephonyManager.NETWORK_TYPE_NR; 638 // Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. 639 case NetworkTemplate.NETWORK_TYPE_5G_NSA: 640 return NetworkTemplate.NETWORK_TYPE_5G_NSA; 641 default: 642 return TelephonyManager.NETWORK_TYPE_UNKNOWN; 643 } 644 } 645 646 /** 647 * Return all supported collapsed RAT types that could be returned by 648 * {@link #getCollapsedRatType(int)}. 649 */ 650 @NonNull getAllCollapsedRatTypes()651 public static final int[] getAllCollapsedRatTypes() { 652 final int[] ratTypes = TelephonyManager.getAllNetworkTypes(); 653 final HashSet<Integer> collapsedRatTypes = new HashSet<>(); 654 for (final int ratType : ratTypes) { 655 collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); 656 } 657 // Add NETWORK_TYPE_5G_NSA to the returned list since 5G NSA is a virtual RAT type and 658 // it is not in TelephonyManager#NETWORK_TYPE_* constants. 659 // See {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. 660 collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(NETWORK_TYPE_5G_NSA)); 661 // Ensure that unknown type is returned. 662 collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); 663 return toIntArray(collapsedRatTypes); 664 } 665 666 @NonNull toIntArray(@onNull Collection<Integer> list)667 private static int[] toIntArray(@NonNull Collection<Integer> list) { 668 final int[] array = new int[list.size()]; 669 int i = 0; 670 for (final Integer item : list) { 671 array[i++] = item; 672 } 673 return array; 674 } 675 676 /** 677 * Check if matches Wi-Fi network template. 678 */ matchesWifi(NetworkIdentity ident)679 private boolean matchesWifi(NetworkIdentity ident) { 680 switch (ident.mType) { 681 case TYPE_WIFI: 682 return matchesSubscriberId(ident.mSubscriberId) 683 && matchesWifiNetworkId(ident.mNetworkId); 684 default: 685 return false; 686 } 687 } 688 689 /** 690 * Check if matches Ethernet network template. 691 */ matchesEthernet(NetworkIdentity ident)692 private boolean matchesEthernet(NetworkIdentity ident) { 693 if (ident.mType == TYPE_ETHERNET) { 694 return true; 695 } 696 return false; 697 } 698 699 /** 700 * Check if matches carrier network. The carrier networks means it includes the subscriberId. 701 */ matchesCarrier(NetworkIdentity ident)702 private boolean matchesCarrier(NetworkIdentity ident) { 703 return ident.mSubscriberId != null 704 && !ArrayUtils.isEmpty(mMatchSubscriberIds) 705 && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); 706 } 707 matchesMobileWildcard(NetworkIdentity ident)708 private boolean matchesMobileWildcard(NetworkIdentity ident) { 709 if (ident.mType == TYPE_WIMAX) { 710 return true; 711 } else { 712 return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident); 713 } 714 } 715 matchesWifiWildcard(NetworkIdentity ident)716 private boolean matchesWifiWildcard(NetworkIdentity ident) { 717 switch (ident.mType) { 718 case TYPE_WIFI: 719 case TYPE_WIFI_P2P: 720 return true; 721 default: 722 return false; 723 } 724 } 725 726 /** 727 * Check if matches Bluetooth network template. 728 */ matchesBluetooth(NetworkIdentity ident)729 private boolean matchesBluetooth(NetworkIdentity ident) { 730 if (ident.mType == TYPE_BLUETOOTH) { 731 return true; 732 } 733 return false; 734 } 735 736 /** 737 * Check if matches Proxy network template. 738 */ matchesProxy(NetworkIdentity ident)739 private boolean matchesProxy(NetworkIdentity ident) { 740 return ident.mType == TYPE_PROXY; 741 } 742 getMatchRuleName(int matchRule)743 private static String getMatchRuleName(int matchRule) { 744 switch (matchRule) { 745 case MATCH_MOBILE: 746 return "MOBILE"; 747 case MATCH_WIFI: 748 return "WIFI"; 749 case MATCH_ETHERNET: 750 return "ETHERNET"; 751 case MATCH_MOBILE_WILDCARD: 752 return "MOBILE_WILDCARD"; 753 case MATCH_WIFI_WILDCARD: 754 return "WIFI_WILDCARD"; 755 case MATCH_BLUETOOTH: 756 return "BLUETOOTH"; 757 case MATCH_PROXY: 758 return "PROXY"; 759 case MATCH_CARRIER: 760 return "CARRIER"; 761 default: 762 return "UNKNOWN(" + matchRule + ")"; 763 } 764 } 765 766 /** 767 * Examine the given template and normalize it. 768 * We pick the "lowest" merged subscriber as the primary 769 * for key purposes, and expand the template to match all other merged 770 * subscribers. 771 * <p> 772 * For example, given an incoming template matching B, and the currently 773 * active merge set [A,B], we'd return a new template that primarily matches 774 * A, but also matches B. 775 * TODO: remove and use {@link #normalize(NetworkTemplate, List)}. 776 */ 777 @UnsupportedAppUsage normalize(NetworkTemplate template, String[] merged)778 public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { 779 return normalize(template, Arrays.<String[]>asList(merged)); 780 } 781 782 /** 783 * Examine the given template and normalize it. 784 * We pick the "lowest" merged subscriber as the primary 785 * for key purposes, and expand the template to match all other merged 786 * subscribers. 787 * 788 * There can be multiple merged subscriberIds for multi-SIM devices. 789 * 790 * <p> 791 * For example, given an incoming template matching B, and the currently 792 * active merge set [A,B], we'd return a new template that primarily matches 793 * A, but also matches B. 794 */ normalize(NetworkTemplate template, List<String[]> mergedList)795 public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) { 796 // Now there are several types of network which uses SubscriberId to store network 797 // information. For instances: 798 // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network. 799 // The TYPE_CARRIER means that the network associate to specific carrier network. 800 801 if (template.mSubscriberId == null) return template; 802 803 for (String[] merged : mergedList) { 804 if (ArrayUtils.contains(merged, template.mSubscriberId)) { 805 // Requested template subscriber is part of the merge group; return 806 // a template that matches all merged subscribers. 807 return new NetworkTemplate(template.mMatchRule, merged[0], merged, 808 template.mNetworkId); 809 } 810 } 811 812 return template; 813 } 814 815 @UnsupportedAppUsage 816 public static final @android.annotation.NonNull Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() { 817 @Override 818 public NetworkTemplate createFromParcel(Parcel in) { 819 return new NetworkTemplate(in); 820 } 821 822 @Override 823 public NetworkTemplate[] newArray(int size) { 824 return new NetworkTemplate[size]; 825 } 826 }; 827 getBytesForBackup()828 public byte[] getBytesForBackup() throws IOException { 829 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 830 DataOutputStream out = new DataOutputStream(baos); 831 832 out.writeInt(BACKUP_VERSION); 833 834 out.writeInt(mMatchRule); 835 BackupUtils.writeString(out, mSubscriberId); 836 BackupUtils.writeString(out, mNetworkId); 837 838 return baos.toByteArray(); 839 } 840 getNetworkTemplateFromBackup(DataInputStream in)841 public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in) 842 throws IOException, BackupUtils.BadVersionException { 843 int version = in.readInt(); 844 if (version < 1 || version > BACKUP_VERSION) { 845 throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version"); 846 } 847 848 int matchRule = in.readInt(); 849 String subscriberId = BackupUtils.readString(in); 850 String networkId = BackupUtils.readString(in); 851 852 if (!isKnownMatchRule(matchRule)) { 853 throw new BackupUtils.BadVersionException( 854 "Restored network template contains unknown match rule " + matchRule); 855 } 856 857 return new NetworkTemplate(matchRule, subscriberId, networkId); 858 } 859 } 860